; 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,1EIFB00,1EODOK,1EO1EOK,1ENOCMD,1EIFB01,1EODPST,1EOEPST,1ERESTO,1EIFB10,1EODCOL,1EOECOL,1ERESTI,1EIFB11,1EODUGH,1EOEUGH,1ERBRES; ;2-way branches using NEXT7 ;1EOCDW1, 1EOCDWX, and 1EIGO are all related. Be careful! !7,10,,1EIFOK,,1EOCDW1,,1EIFBAD,1EOCDWX,1EIGO; ;Miscellaneous address constraints !7,10,,1EOCDW0,1EODATA,1EIDFUL,1EIDZ4,1EOCDRS,1EIDATA,1EIPOST; !7,10,,1EIDOK,,,1EIDMOR,1EIDPST,,1EAPOST; !1,1,1EIFB1; !1,1,1EIFRST; !1,1,1ELOOK4; !1,1,1EODCOR; ;2-way branches using NEXT9 !1,2,1EOREST,1ELOOK1; !1,2,1ELOOK3,1ELOOK2; !1,2,1EODDCB,1EIREST; !1,2,1EPNTOK,1EPNTZ; !1,2,1EOINPR,1EOINPN; !1,2,1EODMOR,1EODEND; !1,2,1EOLDOK,1EOLDBD; !1,2,1EIFCHK,1EIFPRM; !1,2,1EOCDWT,1EOCDGO; !1,2,1ECNTOK,1ECNTZR; !1,2,1EIFIGN,1EISET; !1,2,1EIFNBC,1EIFBC; ;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 1E to 1E 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 1EREST: ERBFCT; What's happening ? :1ENOCMD; [1ENOCMD,1ERESTO,1ERESTI,1ERBRES] 1ENOCMD: L_ ESNEVR,:1EAPOST; Shouldn't happen 1ERESTO: :1ELOOK; Output when no input buffers 1ERESTI: :1ELOOK; Probably new input buffer 1ERBRES: L_ ESABRT,:1EAPOST; 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 1EAPOST: 1EPNTR_ L,TASK; Save microcode status in 1EPNTR NOP; MAR_ 1ELOC; (EPLOC) double word reference T_ NWW; MD_ 1EPNTR,EPFCT; BUS AND 1EPNTR with Status L_ MD OR T, TASK; NWW OR c(EBLOC) NWW_ L, :1EREST; ; Non-Abort Post from Input routine ; L has microcode status, something is waking us up 1EIPOST: T_ 11; MAR_ 1ELOC+T; (ECHLOC) 1EPNTR_ L; Save microcode status in 1EPNTR T_ MD; MAR_ 2+T; L_ T; MD_ 1ECNTR, TASK; Save ending count 1ECNTR_ L; 1ECNTR Points to Current Input Control Block ; Advance Chain Pointer to next Input Control Block T_ 11; MAR_ 1ECNTR+T; (ECHLOC) of Current Input Control Block L_ MD; MAR_ 1ELOC+T; (ECHLOC) MTEMP_ L, TASK; MTEMP _ new Input Control Block MD_ MTEMP; MAR_ 1ECNTR, :1EWAKE; (EPLOC) double word reference ; Non-Abort Post from Output routine ; L has microcode status, something is waking us up 1EOPOST: T_ 7; MAR_ 1ELOC+T; (EOPLOC) Zero output pointer so we won't send it again 1EPNTR_ L, TASK; MD_ 0; ; don't bother to save ending count on output MAR_ 1ELOC; (EPLOC) double word reference ; Store status and generate interrupt(s) 1EWAKE: T_ NWW; MD_ 1EPNTR,EPFCT; BUS AND 1EPNTR with Status L_ MD OR T; NWW OR c(EBLOC) NWW_ L,TASK; EOSFCT, :1ELOOK; Generate more Wakeups ; Look for something to do, Something must be generating Wakeups 1ELOOK: T_ 7; MAR_ 1ELOC+T; (EOPLOC) Look to see if there is output ready NOP; SINK_ MD,BUS=0; T_ 11, :1EOREST; [1EOREST,1ELOOK1] Check for Input buffer ready 1ELOOK1: MAR_ 1ELOC+T; (ECHLOC) T_ 1; L_ MD AND T, T_ MD, BUS=0; EPFCT, SH=0, :1ELOOK3; [1ELOOK3,1ELOOK2] 1ELOOK2: TASK, :1ELOOK4; [1ELOOK4] Nothing to do 1ELOOK4: :1EREST; 1ELOOK3: 1EPNTR_ L, :1EODDCB; [1EODDCB,1EIREST] ; Interface has been reset, use EOSFCT to generate another wakeup 1EODDCB: EOSFCT,:1ECNTZR; Odd Control Block Pointer ;This is a subroutine called from both input and output (1EOCDGO ;and 1EISET). 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. 1ESETUP: NOP; L_ MD,BUS=0; check for zero length T_ MD-1,:1ECNTOK; [1ECNTOK,1ECNTZR] start-1 1ECNTZR: L_ ESCZER,:1EAPOST; Zero word count. Abort ;Ether Countdown Branch Function - ECBFCT. ;NEXT7 = Interface buffer not empty. 1ECNTOK: 1ECNTR_ L, L_ 0+T+1; SH=0, L_ T; ECBFCT, 1EPNTR_ L, :1EPNTOK; [1EPNTOK,1EPNTZ] 1EPNTZ: L_ ESCZER, :1EAPOST; [1EAPOST] Empty Pointer 1EPNTOK: :1EODATA; [1EODATA,1EIDATA] ;Ethernet Input ;It turns out that starting the receiver for the first time and ;restarting it after ignoring a packet do the same things. 1EIREST: :1EIFIGN; 1EPNTR 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. ;1EIFRST is really a subroutine that can be called from 1EIREST ;or from 1EIGO, output countdown wait. If a packet is ignored ;and 1EPNTR is zero, 1EIFRST 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 1EIFIGN, it waits here 1EIFRST: T_ 10; MAR_ 1ELOC+T; (EHLOC) Get Ethernet address T_ 377,EBFCT; What's happening? L_ MD AND T,BUS=0,:1EIFOK;[1EIFOK,1EIFBAD] promiscuous? 1EIFOK: MTEMP_ LLCY8,:1EIFCHK; [1EIFCHK,1EIFPRM] Data wakeup 1EIFBAD: ERBFCT,TASK,:1EIFB1; [1EIFB1] POST wakeup; xCMD FF set? 1EIFB1: :1EIFB00; [1EIFB00,1EIFB01,1EIFB10,1EIFB11] 1EIFB00: :1EIFIGN; IDL or INGONE, restart rcvr 1EIFB01: :1ELOOK; Probably Output to do 1EIFB10: :1ELOOK; Other way to look for Output 1EIFB11: L_ ESABRT,:1EAPOST; ICMD and OCMD, abort 1EIFPRM: TASK,:1EIFBC; Promiscuous. Accept ;Ether Look Function - EILFCT. Gate the first word of the ;data buffer to the bus, but do not increment the read pointer. 1EIFCHK: L_ T_ 177400,EILFCT; Mask off src addr byte (BUS AND) L_ MTEMP-T,SH=0; Broadcast? SH=0,TASK,:1EIFNBC; [1EIFNBC,1EIFBC] Our Address? 1EIFNBC: :1EIFIGN; [1EIFIGN,1EISET] 1EIFBC: :1EISET; [1EISET] 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. 1EIFIGN: SINK_ 1EPNTR,BUS=0,EPFCT;Reset; Called from output? EISFCT,TASK,:1EOCDWX; [1EOCDWX,1EIGO] Restart rcvr 1EOCDWX: EWFCT,:1EOCDWT; Return to countdown wait loop 1EISET: T_ 11; Get Pointer and Count out of Current Input Control Block MAR_ 1ELOC+T; (ECHLOC) NOP; T_ MD; MAR_ 4+T,:1ESETUP; (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). ;1EIDOK, 1EIDMOR, and 1EIDPST 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 1EIDATA: T_ 1ECNTR-1, BUS=0; MAR_ L_ 1EPNTR+1, EBFCT; [1EIDMOR,1EIDPST] What's happening 1EIDMOR: 1EPNTR_ L, L_ T, ECBFCT; [1EIDOK,1EIDPST] Guaranteed to branch 1EIDOK: MD_ EIDFCT, TASK; [1EIDZ4] Read a word from the interface 1EIDZ4: 1ECNTR_ L, :1EIDATA; ; We get to 1EIDPST 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". 1EIDPST: L_ ESIDON, :1EIDFUL; [1EIDFUL,1EIPOST] Presumed to be INGONE 1EIDFUL: L_ ESIFUL, :1EIPOST; 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. 1EOREST: T_ 3; MAR_ 1ELOC+T; (ELLOC) Get load L_ R37; Use clock as random # gen 1EPNTR_ LRSH1; Use bits [6:13] L_ MD,EOSFCT; L_ current load SH<0,1ECNTR_ L; Overflowed? MTEMP_ LLSH1,:1EOLDOK; [1EOLDOK,1EOLDBD] 1EOLDBD: L_ ESLOAD,:1EOPOST; Load overlow 1EOLDOK: L_ MTEMP+1; Write updated load MAR_ 1ELOC+T; (ELLOC); MTEMP_ L,TASK; MD_ MTEMP,:1EORST1; New load = (old lshift 1) + 1 1EORST1: L_ 1EPNTR; Continue making random # 1EPNTR_ LRSH1; T_ 377; L_ 1EPNTR AND T,TASK; 1EPNTR_ L,:1EORST2; ;At this point, 1EPNTR has 0,,random number, ENCTR has old load. 1EORST2: T_ 11; MAR_ 1ELOC+T; (ECHLOC) Has an input buffer been set up? T_ 1ECNTR; L_ 1EPNTR AND T; L_ Random & Load SINK_ MD,BUS=0; 1ECNTR_ L,SH=0,EPFCT,:1EOINPR;[1EOINPR,1EOINPN] 1EOINPR: EISFCT,:1EOCDWT; [1EOCDWT,1EOCDGO] Enable in under out 1EOINPN: :1EOCDWT; [1EOCDWT,1EOCDGO] No input. ;Countdown wait loop. MRT will generate a wakeup every ;37 usec which will decrement 1ECNTR. 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 1EOCDWT: L_ 177400,EBFCT; What's happening? 1EPNTR_ L,ECBFCT,:1EOCDW0;[1EOCDW0,1EOCDRS] Packet coming in? 1EOCDW0: L_ 1ECNTR-1,BUS=0,TASK,:1EOCDW1; [1EOCDW1,1EIGO] 1EOCDW1: 1ECNTR_ L,EWFCT,:1EOCDWT; [1EOCDWT,1EOCDGO] ; We have probably been reset 1EOCDRS: L_ ESABRT,:1EAPOST; [1EAPOST] POST event 1EIGO: :1EIFRST; [1EIFRST] Input under output ;Output main loop setup 1EOCDGO: T_ 6; MAR_ 1ELOC+T; (EOCLOC) Double word reference EPFCT; Reset interface EOSFCT,:1ESETUP; 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 1EODATA: L_ MAR_ 1EPNTR+1,EBFCT; What's happening? T_ 1ECNTR-1,BUS=0,:1EODOK; [1EODOK,1EODPST,1EODCOL,1EODUGH] 1EODOK: 1EPNTR_ L,L_ T,:1EODMOR; [1EODMOR,1EODEND] 1EODMOR: 1ECNTR_ L,TASK; EODFCT_ MD,:1EODATA; Output word to transmitter 1EODPST: L_ ESABRT,:1EAPOST; [1EAPOST] POST event 1EODCOL: EPFCT,:1EODCOR; [1EODCOR] Collision 1EODCOR: :1EOREST; Wait for Outgone 1EODUGH: L_ ESABRT,:1EAPOST; [1EAPOST] POST + Collision ;Ether 1EOT 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. 1EODEND: EEFCT; Disable data wakeups TASK; Wait for EEFCT to take :1EO1EOT; 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 1EO1EOT: EBFCT; What's happening? :1EO1EOK; [1EO1EOK,1EOEPST,1EOECOL,1EOEUGH] 1EO1EOK: L_ ESNEVR,:1EAPOST; Runaway Transmitter. Never Never. 1EOEPST: L_ ESODON,:1EOPOST; POST event. Output done 1EOECOL: EPFCT,:1EOREST; Collision 1EOEUGH: L_ ESABRT,:1EAPOST; POST + Collision