; ChainEther*.mu -- Chained input microcode for the Alto Ethernet ; Last modified HGM December 14, 1978 6:24 PM ; typing in fix for 4,,371 posting again ; Last modified HGM October 18, 1978 8:57 PM ; trying to shrink it a few words ; Last modified HGM October 9, 1978 11:27 PM ; fix for 377B,,0 posting ; Last modified September 23, 1978 5:19 PM ;4-way branches using NEXT6 and NEXT7 !17,20,2EIFB00,2EODOK,2EO2EOK,2ENOCMD,2EIFB01,2EODPST,2EOEPST,2ERESTO,2EIFB10,2EODCOL,2EOECOL,2ERESTI,2EIFB11,2EODUGH,2EOEUGH,2ERBRES; ;2-way branches using NEXT7 ;2EOCDW1, 2EOCDWX, and 2EIGO are all related. Be careful! !7,10,,2EIFOK,,2EOCDW1,,2EIFBAD,2EOCDWX,2EIGO; ;Miscellaneous address constraints !7,10,,2EOCDW0,2EODATA,2EIDFUL,2EIDZ4,2EOCDRS,2EIDATA,2EIPOST; !7,10,,2EIDOK,,,2EIDMOR,2EIDPST,,2EAPOST; !1,1,2EIFB1; !1,1,2EIFRST; !1,1,2ELOOK4; !1,1,2EODCOR; ;2-way branches using NEXT9 !1,2,2EOREST,2ELOOK1; !1,2,2ELOOK3,2ELOOK2; !1,2,2EODDCB,2EIREST; !1,2,2EPNTOK,2EPNTZ; !1,2,2EOINPR,2EOINPN; !1,2,2EODMOR,2EODEND; !1,2,2EOLDOK,2EOLDBD; !1,2,2EIFCHK,2EIFPRM; !1,2,2EOCDWT,2EOCDGO; !1,2,2ECNTOK,2ECNTZR; !1,2,2EIFIGN,2EISET; !1,2,2EIFNBC,2EIFBC; ;Ethernet microcode Status codes $ESIDON $377; Input Done $ESODON $777; Output Done $ESIFUL $1377; Input Buffer full - words lost from tail of packet $ESLOAD $1777; Load location overflowed $ESCZER $2377; Zero word count for input or output command, ; or odd input chain pointer, or zero input pointer $ESABRT $2777; Abort - usually caused by reset command $ESNEVR $3377; Never Happen - Very bad if it does ;Function Definitions $EIDFCT $L000000,014004,000100; BS = 4, Input data $EILFCT $L016013,070013,000100; F1 = 13, Input Look $EPFCT $L016014,070014,000100; F1 = 14, Post $EWFCT $L016015,000000,000000; F1 = 15, Wake-Up $EODFCT $L026010,000000,124000; F2 = 10, Output data $EOSFCT $L024011,000000,000000; F2 = 11, Start output $ERBFCT $L024012,000000,000000; F2 = 12, Rest branch $EEFCT $L024013,000000,000000; F2 = 13, End of output $EBFCT $L024014,000000,000000; F2 = 14, Branch $ECBFCT $L024015,000000,000000; F2 = 15, Countdown branch $EISFCT $L024016,000000,000000; F2 = 16, Start input ;Main memory locations in page 1 reserved for Ethernet. ;There aren't constants for these locations for the second+third ;Ethernet boards, so we manufacture them. To avoid extensive editing, ;the code for the normal ethernet also manufactures them. ;Odd addresses for double word references are not needed, thus "---". ;Constants 630, 631, and 642 do exist. ; R11 is normally used by MRT ; R21 and R26 are normaly used by the display and cursor tasks ;ELOC 600, 630, 642 Base location of Main Control block ;ECNTR R12, R11, R42 Number of words left to transfer ;EPNTR R13, R14, R21 Points before word to transfer ;EPLOC 600, 630, 642 = ELOC Post location ;EBLOC 601, 631, 643 = --- Interrupt bit mask ;EELOC 602, 632, 644 = ELOC+2 Ending count location ;ELLOC 603, 633, 645 = ELOC+3 Load location ;EICLOC 604, 634, 646 = ELOC+4 Input buffer Count ;EIPLOC 605, 635, 647 = --- Input buffer Pointer ;EOCLOC 606, 636, 650 = ELOC+6 Output buffer Count ;EOPLOC 607, 637, 651 = --- Output buffer Pointer ;EHLOC 610, 640, 652 = ELOC+10 Host Address ;ECHLOC 611, 641, 653 = ELOC+11 Chain Pointer for Input Control Block ; This section of code is designed to be included several times in one ; mu file. Thats why all the tags have a 0 in front of them. To make ; a version for another board, let Bravo change all 2E to 2E for you. ; For each instance of this microcode that you wish to include in ; your RAM, you will have to have something like the following: ; $*ECNTR $R12; ; $*EPNTR $R13; ; $*ELOC $600; ; #ChainEther*.mu; ; Don't forget to include *EREST in your PREDEF for the Boot Vector ; - Whenever a label has a pending branch, the list of possible ; destination addresses is shown in brackets in the comment field. ; - Special functions are explained in a comment near their first use. ; - To avoid naming conflicts, all labels and special functions ; have "E" as the first letter. ;Top of Ethernet Task loop ;Ether Rest Branch Function - ERBFCT ;merge ICMD and OCMD Flip Flops into NEXT6 and NEXT7 ;ICMD and OCMD are set from AC0 [14:15] by the SIO instruction ; 00 neither ; 01 OCMD - Start output ; 10 ICMD - Start input ; 11 Both - Reset interface ; *** Ethernet task is idle -- waiting for StartIO from emulator 2EREST: ERBFCT; What's happening ? :2ENOCMD; [2ENOCMD,2ERESTO,2ERESTI,2ERBRES] 2ENOCMD: L_ ESNEVR,:2EAPOST; Shouldn't happen 2ERESTO: :2ELOOK; Output when no input buffers 2ERESTI: :2ELOOK; Probably new input buffer 2ERBRES: L_ ESABRT,:2EAPOST; Reset Command ;Post status and halt. Microcode status in L. ;Put microstatus,,hardstatus in EPLOC, merge c(EBLOC) into NWW. ;Note that we write EPLOC and read EBLOC in one operation ;Ether Post Function - EPFCT. Gate the hardware status ;(LOW TRUE) to Bus [10:15], reset interface. ; Get here if we are Aborting ; Next7 must be a one to shake pending branch from EOCRDS 2EAPOST: 2EPNTR_ L,TASK; Save microcode status in 2EPNTR NOP; MAR_ 2ELOC; (EPLOC) double word reference T_ NWW; MD_ 2EPNTR,EPFCT; BUS AND 2EPNTR with Status L_ MD OR T, TASK; NWW OR c(EBLOC) NWW_ L, :2EREST; ; Non-Abort Post from Input routine ; L has microcode status, something is waking us up 2EIPOST: T_ 11; MAR_ 2ELOC+T; (ECHLOC) 2EPNTR_ L; Save microcode status in 2EPNTR T_ MD; MAR_ 2+T; L_ T; MD_ 2ECNTR, TASK; Save ending count 2ECNTR_ L; 2ECNTR Points to Current Input Control Block ; Advance Chain Pointer to next Input Control Block T_ 11; MAR_ 2ECNTR+T; (ECHLOC) of Current Input Control Block L_ MD; MAR_ 2ELOC+T; (ECHLOC) MTEMP_ L, TASK; MTEMP _ new Input Control Block MD_ MTEMP; MAR_ 2ECNTR, :2EWAKE; (EPLOC) double word reference ; Non-Abort Post from Output routine ; L has microcode status, something is waking us up 2EOPOST: T_ 7; MAR_ 2ELOC+T; (EOPLOC) Zero output pointer so we won't send it again 2EPNTR_ L, TASK; MD_ 0; ; don't bother to save ending count on output MAR_ 2ELOC; (EPLOC) double word reference ; Store status and generate interrupt(s) 2EWAKE: T_ NWW; MD_ 2EPNTR,EPFCT; BUS AND 2EPNTR with Status L_ MD OR T; NWW OR c(EBLOC) NWW_ L,TASK; EOSFCT, :2ELOOK; Generate more Wakeups ; Look for something to do, Something must be generating Wakeups 2ELOOK: T_ 7; MAR_ 2ELOC+T; (EOPLOC) Look to see if there is output ready NOP; SINK_ MD,BUS=0; T_ 11, :2EOREST; [2EOREST,2ELOOK1] Check for Input buffer ready 2ELOOK1: MAR_ 2ELOC+T; (ECHLOC) T_ 1; L_ MD AND T, T_ MD, BUS=0; EPFCT, SH=0, :2ELOOK3; [2ELOOK3,2ELOOK2] 2ELOOK2: TASK, :2ELOOK4; [2ELOOK4] Nothing to do 2ELOOK4: :2EREST; 2ELOOK3: 2EPNTR_ L, :2EODDCB; [2EODDCB,2EIREST] ; Interface has been reset, use EOSFCT to generate another wakeup 2EODDCB: EOSFCT,:2ECNTZR; Odd Control Block Pointer ;This is a subroutine called from both input and output (2EOCDGO ;and 2EISET). The return address is determined by testing ECBFCT, ;which will branch if the buffer has any words in it, which can ;only happen during input. 2ESETUP: NOP; L_ MD,BUS=0; check for zero length T_ MD-1,:2ECNTOK; [2ECNTOK,2ECNTZR] start-1 2ECNTZR: L_ ESCZER,:2EAPOST; Zero word count. Abort ;Ether Countdown Branch Function - ECBFCT. ;NEXT7 = Interface buffer not empty. 2ECNTOK: 2ECNTR_ L, L_ 0+T+1; SH=0, L_ T; ECBFCT, 2EPNTR_ L, :2EPNTOK; [2EPNTOK,2EPNTZ] 2EPNTZ: L_ ESCZER, :2EAPOST; [2EAPOST] Empty Pointer 2EPNTOK: :2EODATA; [2EODATA,2EIDATA] ;Ethernet Input ;It turns out that starting the receiver for the first time and ;restarting it after ignoring a packet do the same things. 2EIREST: :2EIFIGN; 2EPNTR is 0 to flag input mode ;Address filtering code. ;When the first word of a packet is available in the interface ;buffer, a wakeup request is generated. The microcode then ;decides whether to accept the packet. Decision must be reached ;before the buffer overflows, within about 14*5.44 usec. ;if EHLOC is zero, machine is 'promiscuous' - accept all packets ;if destination byte is zero, it is a 'broadcast' packet, accept. ;if destination byte equals EHLOC, packet is for us, accept. ;2EIFRST is really a subroutine that can be called from 2EIREST ;or from 2EIGO, output countdown wait. If a packet is ignored ;and 2EPNTR is zero, 2EIFRST loops back and waits for more ;packets, else it returns to the countdown code. ;Ether Branch Function - EBFCT ;NEXT7 = IDL % OCMD % ICMD % OUTGONE % INGONE (also known as POST) ;NEXT6 = COLLision - Can't happen during input ; *** Ethernet task may wait for a packet to arrive ; if called from EIGO via EOCDWT, a packet is already arriving ; if called from EIGO via 2EIFIGN, it waits here 2EIFRST: T_ 10; MAR_ 2ELOC+T; (EHLOC) Get Ethernet address T_ 377,EBFCT; What's happening? L_ MD AND T,BUS=0,:2EIFOK;[2EIFOK,2EIFBAD] promiscuous? 2EIFOK: MTEMP_ LLCY8,:2EIFCHK; [2EIFCHK,2EIFPRM] Data wakeup 2EIFBAD: ERBFCT,TASK,:2EIFB1; [2EIFB1] POST wakeup; xCMD FF set? 2EIFB1: :2EIFB00; [2EIFB00,2EIFB01,2EIFB10,2EIFB11] 2EIFB00: :2EIFIGN; IDL or INGONE, restart rcvr 2EIFB01: :2ELOOK; Probably Output to do 2EIFB10: :2ELOOK; Other way to look for Output 2EIFB11: L_ ESABRT,:2EAPOST; ICMD and OCMD, abort 2EIFPRM: TASK,:2EIFBC; Promiscuous. Accept ;Ether Look Function - EILFCT. Gate the first word of the ;data buffer to the bus, but do not increment the read pointer. 2EIFCHK: L_ T_ 177400,EILFCT; Mask off src addr byte (BUS AND) L_ MTEMP-T,SH=0; Broadcast? SH=0,TASK,:2EIFNBC; [2EIFNBC,2EIFBC] Our Address? 2EIFNBC: :2EIFIGN; [2EIFIGN,2EISET] 2EIFBC: :2EISET; [2EISET] Enter input main loop ;Ether Input Start Function - EISFCT. Start receiver. Interface ;will generate a data wakeup when the first word of the next ;packet arrives, ignoring any packet currently passing. 2EIFIGN: SINK_ 2EPNTR,BUS=0,EPFCT;Reset; Called from output? EISFCT,TASK,:2EOCDWX; [2EOCDWX,2EIGO] Restart rcvr 2EOCDWX: EWFCT,:2EOCDWT; Return to countdown wait loop 2EISET: T_ 11; Get Pointer and Count out of Current Input Control Block MAR_ 2ELOC+T; (ECHLOC) NOP; T_ MD; MAR_ 4+T,:2ESETUP; (EICLOC) Double word reference ;Input Main Loop ;Ether Input Data Function - EIDFCT. Gate a word of data to ;the bus from the interface data buffer, increment the read ptr. ; * * * * * W A R N I N G * * * * * ;The delay from decoding EIDFCT to gating data to the bus is ;marginal. Some logic in the interface detects the situation ;(which only happens occasionally) and stops SysClk for one cycle. ;Since memory data must be available during cycle 4, and SysClk ;may stop for one cycle, this means that the MD_ EIDFCT must ;happen in cycle 3. There is a bug in this logic which occasionally ;stops the clock in the instruction following the EIDFCT, so ;the EIDFCT instruction should not be the last one of the task, ;or it may screw up someone else (such as RDRAM). ;2EIDOK, 2EIDMOR, and 2EIDPST must have address bits in the pattern: ;xxx1 xxx4 xxx5 ;ECBFCT is used to force an unconditional branch on NEXT7 ; *** Ethernet task may wait for next input word 2EIDATA: T_ 2ECNTR-1, BUS=0; MAR_ L_ 2EPNTR+1, EBFCT; [2EIDMOR,2EIDPST] What's happening 2EIDMOR: 2EPNTR_ L, L_ T, ECBFCT; [2EIDOK,2EIDPST] Guaranteed to branch 2EIDOK: MD_ EIDFCT, TASK; [2EIDZ4] Read a word from the interface 2EIDZ4: 2ECNTR_ L, :2EIDATA; ; We get to 2EIDPST for one of two reasons: ; (1) The buffer is full. In this case, an EBFCT (NEXT[7]) is pending. ; We want to post "full" if this is a normal data wakeup (no branch) ; but just "input done" if hardware input terminated (branch). ; (2) Hardware input terminated while the buffer was not full. ; In this case, an unconditional branch on NEXT[7] is pending, so ; we always terminate with "input done". 2EIDPST: L_ ESIDON, :2EIDFUL; [2EIDFUL,2EIPOST] Presumed to be INGONE 2EIDFUL: L_ ESIFUL, :2EIPOST; Input buffer overrun ;Ethernet output ;It is possible to get here due to a collision. If a collision ;happened, the interface was reset (EPFCT) to shut off the ;transmitter. EOSFCT is issued to guarantee more wakeups while ;generating the countdown. When this is done, the interface is ;again reset, without really doing an output. 2EOREST: T_ 3; MAR_ 2ELOC+T; (ELLOC) Get load L_ R37; Use clock as random # gen 2EPNTR_ LRSH1; Use bits [6:13] L_ MD,EOSFCT; L_ current load SH<0,2ECNTR_ L; Overflowed? MTEMP_ LLSH1,:2EOLDOK; [2EOLDOK,2EOLDBD] 2EOLDBD: L_ ESLOAD,:2EOPOST; Load overlow 2EOLDOK: L_ MTEMP+1; Write updated load MAR_ 2ELOC+T; (ELLOC); MTEMP_ L,TASK; MD_ MTEMP,:2EORST1; New load = (old lshift 1) + 1 2EORST1: L_ 2EPNTR; Continue making random # 2EPNTR_ LRSH1; T_ 377; L_ 2EPNTR AND T,TASK; 2EPNTR_ L,:2EORST2; ;At this point, 2EPNTR has 0,,random number, ENCTR has old load. 2EORST2: T_ 11; MAR_ 2ELOC+T; (ECHLOC) Has an input buffer been set up? T_ 2ECNTR; L_ 2EPNTR AND T; L_ Random & Load SINK_ MD,BUS=0; 2ECNTR_ L,SH=0,EPFCT,:2EOINPR;[2EOINPR,2EOINPN] 2EOINPR: EISFCT,:2EOCDWT; [2EOCDWT,2EOCDGO] Enable in under out 2EOINPN: :2EOCDWT; [2EOCDWT,2EOCDGO] No input. ;Countdown wait loop. MRT will generate a wakeup every ;37 usec which will decrement 2ECNTR. When it is zero, start ;the transmitter. ;Ether Wake Function - EWFCT. Sets a flip flop which will cause ;a wakeup to this task the next time MRT wakes up (every 37 usec). ;Wakeup is cleared when Ether task next runs. EWFCT must be ;issued in the instruction AFTER a task. ; *** Ethernet task is waiting for first input word or retransmission clock 2EOCDWT: L_ 177400,EBFCT; What's happening? 2EPNTR_ L,ECBFCT,:2EOCDW0;[2EOCDW0,2EOCDRS] Packet coming in? 2EOCDW0: L_ 2ECNTR-1,BUS=0,TASK,:2EOCDW1; [2EOCDW1,2EIGO] 2EOCDW1: 2ECNTR_ L,EWFCT,:2EOCDWT; [2EOCDWT,2EOCDGO] ; We have probably been reset 2EOCDRS: L_ ESABRT,:2EAPOST; [2EAPOST] POST event 2EIGO: :2EIFRST; [2EIFRST] Input under output ;Output main loop setup 2EOCDGO: T_ 6; MAR_ 2ELOC+T; (EOCLOC) Double word reference EPFCT; Reset interface EOSFCT,:2ESETUP; Start Transmitter ;Ether Output Start Function - EOSFCT. The interface will generate ;a burst of data requests until the interface buffer is full or the ;memory buffer is empty, wait for silence on the Ether, and begin ;transmitting. Thereafter it will request a word every 5.44 us. ;Ether Output Data Function - EODFCT. Copy the bus into the ;interface data buffer, increment the write pointer, clears wakeup ;request if the buffer is now nearly full (one slot available). ;Output main loop ; *** Ethernet task may wait to send next output word 2EODATA: L_ MAR_ 2EPNTR+1,EBFCT; What's happening? T_ 2ECNTR-1,BUS=0,:2EODOK; [2EODOK,2EODPST,2EODCOL,2EODUGH] 2EODOK: 2EPNTR_ L,L_ T,:2EODMOR; [2EODMOR,2EODEND] 2EODMOR: 2ECNTR_ L,TASK; EODFCT_ MD,:2EODATA; Output word to transmitter 2EODPST: L_ ESABRT,:2EAPOST; [2EAPOST] POST event 2EODCOL: EPFCT,:2EODCOR; [2EODCOR] Collision 2EODCOR: :2EOREST; Wait for Outgone 2EODUGH: L_ ESABRT,:2EAPOST; [2EAPOST] POST + Collision ;Ether 2EOT Function - EEFCT. Stop generating output data wakeups, ;the interface has all of the packet. When the data buffer runs ;dry, the interface will append the CRC and then generate an ;OUTGONE post wakeup. 2EODEND: EEFCT; Disable data wakeups TASK; Wait for EEFCT to take :2EO2EOT; Wait for Outgone ;Output completion. We are waiting for the interface buffer to ;empty, and the interface to generate an OUTGONE Post wakeup. ; *** Ethernet task may wait for output buffer to empty 2EO2EOT: EBFCT; What's happening? :2EO2EOK; [2EO2EOK,2EOEPST,2EOECOL,2EOEUGH] 2EO2EOK: L_ ESNEVR,:2EAPOST; Runaway Transmitter. Never Never. 2EOEPST: L_ ESODON,:2EOPOST; POST event. Output done 2EOECOL: EPFCT,:2EOREST; Collision 2EOEUGH: L_ ESABRT,:2EAPOST; POST + Collision