*---------------------------------------------------------------------------- Title[LNSEther.Mc]; * Edit history * 18-Mar-85 19:46:37, Masinter, move defs to beginning * May 22, 1984 10:10 AM...W.D. Evans]; * [PilotNSEther.mc...July 13, 1984 2:47 PM...Willie-Sue] * NS Ethernet microcode for Pilot. Rework of PilotEther.mc by Taft *---------------------------------------------------------------------------- * Lisp definitions for 10MB Ether BR[NSIBR, 14]; * 10 MB Ethernet Input base register BR[NSOBR, 15]; * 10 MB Ethernet Output base register BR[IOBR, 36]; * = MDS MC[NSCSB.host, 177700]; * Three word Host number MC[NSCSB.NextIn,NSCSB.host, 3]; * ShortIocb pointer to input IOCB MC[NSCSB.NextOut,NSCSB.host, 5]; * ShortIocb pointer to output IOCB MC[NSCSB.missed,NSCSB.host, 7]; *---------------------------------------------------------------------------- * RM Assignments *---------------------------------------------------------------------------- * INPUT TASK Set[!NSIRegs, !Region16]; * RMRegion[NSIRegs] SetRMRegion[NSIRegs]; RVN[NSIIocb]; * Must match location of NSOIocb RVN[NSILength]; * Must match location of NSOLength RVN[NSIPtr]; * Must match location of NSOPtr RVN[NSITemp1]; * Must match location of NSOTemp1 RVN[NSIHost0]; * Host number checking storage RVN[NSIHost1]; * Host number checking storage RVN[NSIHost2]; * Host number checking storage * OUTPUT TASK Set[!NSORegs, !Region17]; * RMRegion[NSORegs] SetRMRegion[NSORegs]; RVN[NSOIocb]; * Must match location of NSIIocb RVN[NSOLength]; * Must match location of NSILength RVN[NSOPtr]; * Must match location of NSIPtr RVN[NSOTemp1]; * Must match location of NSITemp1 * COMMON SUBROUTINES RvRel[NSxCB,And[IP[NSIIocb],17]]; * IOCB Base RvRel[NSxTemp1,And[IP[NSITemp1],17]]; RvRel[NSxPtr,And[IP[NSIPtr],17]]; RvRel[NSxLength,And[IP[NSILength],17]]; *---------------------------------------------------------------------------- * Data structures *---------------------------------------------------------------------------- % CSB: TYPE = LONG POINTER TO ControllerStatusBlock; * ControllerStatusBlock: TYPE = MACHINE DEPENDENT RECORD [ * host: NSPilotSystem.HostNumber, -- Three words. First all ones for all packets * input: ShortIocb, * inputWakeups: WORD, * output: ShortIocb, * outputWakeups: WORD, * missed: CARDINAL, * lastInput: IOCB, -- last IOCB on input queue, valid if input#noIocb * lastOutput: IOCB]; -- last IOCB on output queue, valid if output#noIocb NOTE: The wakeups are indexed to relative to the shortiocb location in the csb by a common subroutine.) % % IOCB: TYPE = LONG POINTER TO IOControlBlock; * ShortIocb: TYPE = Base RELATIVE POINTER TO IOControlBlock; * IOControlBlock: TYPE = MACHINE DEPENDENT RECORD [ * bufferLen: CARDINAL, -- 0 Buffer length in Bytes * buffer: LONG POINTER, -- 1,2 * retries: WORD, -- 3 Retry Count * packetLen: CARDINAL, -- 4 Packet Length in bytes * completion: WORD, -- 5 Ending Status * next: ShortIocb]; -- 6 Next IOCB location % MC[IOCB.bufferLen, 0]; MC[IOCB.bufferHi, 2]; MC[IOCB.bufferLow, 1]; MC[IOCB.retries, 3]; MC[IOCB.packetLen, 4]; MC[IOCB.completion, 5]; MC[IOCB.next, 6]; *---------------------------------------------------------------------------- * TASK assignments *---------------------------------------------------------------------------- TaskN[NSIT,12]; TaskN[NSOT,10]; *---------------------------------------------------------------------------- * TIOA assignments *---------------------------------------------------------------------------- Device[NSData, 25]; * 10 Megabit Ethernet data input/output Device[NSControl, 26]; * NS Ethernet control reg [Tx,Rx,Test] *---------------------------------------------------------------------------- * Status Bits -- Transmitter and Control *---------------------------------------------------------------------------- * Transmitter and general interface status bits (NSControl) * Left byte is Ethernet host address. * Bits 5 and 6 of the low byte are the IEC transmitter status, valid on abort or end of * a packet. Their meanings are: * 00 = Good transmission * 01 = Late data (underrun) to the IEC during the transmission * 10 = Collision * 11 = The 16th collision has occured during this transmission MC[RxOn, 200]; * Receiver on MC[TxOn, 100]; * Transmitter on MC[LoopBack, 40]; * Loop-back mode on MC[IECBypass, 20]; * The IEC chip is bypassed for testing MC[NoWakeups, 10]; * Task wakeups enabled if 0, disabled if 1 MC[TxDataLate, 4]; * Output data late MC[TxFifoPE, 1]; * Transmitter-detected IOB or Fifo parity error *---------------------------------------------------------------------------- * Status Bits -- Receiver *---------------------------------------------------------------------------- * The receiver status is passed to user, via IOCB, in the upper byte of the completion code. * When one, the bits of the word have the following meaning: * Bit.0 = Buffer overrun on input. Set by the MC * Bit.1 = Receiver had good alignment * Bit.3=Packet had a good CRC * Bit.6 = Packet contained an odd number of bytes. * Bit.7 = The receiver overrun the Dorado input and data was lost * All others will be zero. MC[NSBufferOver,100000]; MC[OddByteStatus,1000]; *---------------------------------------------------------------------------- * Control Register Constants *---------------------------------------------------------------------------- * Control bits (NSControl) -- Transmitter control (bits 0-3) MC[TxCmdEnbl, 007777]; * Bit 0 = 0 enables decoding of output commands MC[STxOn, 40000]; * Turn on output if 1, off if 0 MC[STxEOP, 20000]; * Send end of packet if 1 MC[STxOdd, 10000]; * Send on upper byte of next word (Odd byte length packet) MC[TurnOnTx,TxCmdEnbl,STxOn]; MC[TurnOffTx,TxCmdEnbl]; * Control bits (NSControl) -- Receiver control (bits 4-7) MC[RxCmdEnbl, 170377]; * Bit 4 = 0 enables decoding of input commands MC[SRxOn, 2000]; * Turn on input if 1, off if 0 MC[SRxBOP', 1000]; * Wait for beginning of next packet if 0 MC[TurnOnRx, RxCmdEnbl, SRxOn, SRxBOP']; MC[TurnOffRx, RxCmdEnbl]; MC[WaitForBOP, RxCmdEnbl, SRxOn]; * Control bits (EControl) -- Test control (bits 8-15) MC[TestCmdEnbl, 177400]; * Bit 8 = 0 enables decoding of test commands MC[SLoopBack, 100]; * Turn on loop-back mode if 1, off if 0 MC[STxReset, 40]; * Turn on single-step mode if 1, off if 0 MC[SNoWakeups, 20]; * Enable task wakeups if 0, disable if 1 MC[SIECByPass, 2]; * Bypass the IEC and reset its Rx MC[SCollisionTest, 1]; * Force a collision in the IEC * Values needed MC[STxEnd,STxEOP,STxOn,TxCmdEnbl]; * Turn on Tx EOP and leave others on MC[STxOddEnd,STxEOP,STxOn,STxOdd,TxCmdEnbl]; * Turn on Tx EOP and leave others on MC[STxOddOn,STxOn,STxOdd,TxCmdEnbl]; * Only change the Odd Byte control in Tx MC[SByTxR,STxReset,SIECByPass]; * Cause both in IEC to reset *---------------------------------------------------------------------------- * Emulator Task -- TurnOnNS instruction. * Branched to from Mesa/Lisp emulator to reset NS Ethernet hardware and tasks. * the hardware is left turned off, the tasks are re-inited.. *---------------------------------------------------------------------------- Set[XTask, IP[EMU]]; * Emulator mode TopLevel; DontKnowRBase; Reset10MBEther: T← NSControl; TIOA← T; TaskingOff; * Smash the hardware off T← SByTxR, Call[OutputGetsT]; T← A0, Call[OutputGetsT]; * Now they are reseting for microseconds * leave hardware off Call[NSITInitPC]; * Reset the tasks LdTPC← T, Wakeup[NSIT]; Call[NSOTInitPC]; LdTPC← T, Wakeup[NSOT]; T← A0, TaskingOn; TIOA← T, IFUJump[0]; *---------------------------------------------------------------------------- * Initialization code for Input Task *---------------------------------------------------------------------------- Set[XTask, IP[NSIT]]; Subroutine; NSITInitPC: T← NSIT, CoReturn; TopLevel; T← NSControl; TIOA← T; * Allow a long branch! Block, Branch[NSIIdle]; * full TIOA for initialization *---------------------------------------------------------------------------- * Initialization code for Output Task *---------------------------------------------------------------------------- Set[XTask, IP[NSOT]]; Subroutine; NSOTInitPC: T← NSOT, CoReturn; TopLevel; T← NSControl; TIOA← T; * Allow a long branch! Block, Branch[NSOIdle]; * full TIOA for initialization *---------------------------------------------------------------------------- * Input Task *---------------------------------------------------------------------------- Set[XTask, IP[NSIT]]; * Non-emulator mode * Idle state of the NS Ethernet input task. * Wake up here when first word of a new packet arrives. NSIIdle: MemBase← IOBR; RBase← RBase[NSIRegs]; NSIPtr ← NSCSB.host; TIOA[NSData]; NSITemp1 ← A0,Call[NSINxtHost]; * Get first packet host word NSIHost0 ← (NSILength),Branch[NSIAll,alu<0]; * Test if we are to take all, save (1) Branch[.+1]; * Placement Call[NSINxtHost]; * Get second host word NSIHost1 ← (NSILength),Call[NSINxtHost]; * Get the third word Pd ← NSITemp1; * See if our packet NSIHost2 ← (NSILength),Branch[NSIIgnore1,alu#0]; * Go if not ours Call[NSITstBuf]; * See if we have a place to put it Call[NSIOCBSetup]; *++++++++++ We do so get it ready (Long call) T ← (NSIHost0),Call[NSIPutIt]; * Place first one in buffer T ← (NSIHost1),Call[NSIPutIt]; * Place second one in buffer T ← (NSIHost2),Branch[NSILoop]; * Go due rest of packet NSIAll: Call[NSITstBuf]; * See if there is room to put it Call[NSIOCBSetup]; *++++++++++ Set "In" flg, get location and count T ← (NSIHost0),Branch[NSILoop]; * Let main loop put it in buffer NSIIgnore1: Branch[NSIIgnore]; * Placement -- Conditional to Call NSIIgnore2: T ← Input; * Get status -- Call nxt is placement Call[NSIOverTst]; * Go see if this is overrun condition NSIIgnore: Call[NSISkipP]; * Skip remainder of packet Block,Branch[NSIIdle]; * Go wait for another Subroutine; NSIPutIt: NSIPtr ← (Store ← NSIPtr)+1,DBuf ← T,Return; * Place one in buffer NSINxtHost: NSIPtr ← (Fetch←NSIPtr)+1, Branch[NSIIgnore2,IOAtten]; * Get our number and test end packet NSILength ← T ← Input,Block; * Get first word and wait a while T ← T xor MD; * Compare the numbers NSITemp1 ← (NSITemp1) or T; * Keep a running total of diff's Pd ← (NSILength) or MD,Return; * Do the accept all test NSITstBuf: T ← NSCSB.NextIn; * Get pointer to buffer Fetch ← T,NSIPtr ← A0; * Does this work? Need to get long call pd← Md; * In location SetUp needs NSIIocb← Md, Branch[NSINoCB,alu=0]; * Don't have one so add to missed Return; TopLevel; * Input main loop. * Each iteration stores the word previously input from the interface * and inputs the next word. This facilitates end-of-packet handling. * EIPtr has negative of number of words remaining in the buffer. * IOAtten branches if the data word being read is the end-of-packet status. NSILoop: NSIPtr ← (Store← NSIPtr)+1, DBuf← T, Branch[NSIEnd, IOAtten]; T ← Input, Block, DblBranch[NSILoop,NSILast,alu#0]; * Get here when buffer is exactly full (NSIPtr=0). * We know that the word in T is not EOP status since we would have taken * the IOAtten branch if it were. There can be one, or zero CRC words in the buffer at this * point. If there is one the word up for reading is the second and we can throw it out and try * for the status. If not there then we have overflow. NSILast: NSIPtr ← (-2C); * Set packet length for one CRC T ← ((NSILength)+1) rsh 1; * When incremented at instruction NSILastLp: NSIPtr ← (NSIPtr) + 1,Branch[NSIEnd1,IOAtten]; * See if this is the status byte NSIHost2 ← Input,Block,Branch[NSILastLp,alu#0]; * Throw away what can be CRC Call[NSISkipP]; * Will not fit--skip remainder T ← NSBufferOver,Branch[NSIPost]; * Set the overflow status bit NSIEnd: T ← ((NSILength) - 1) rsh 1; NSIEnd1: NSIPtr← ((NSIPtr)+T) Lsh1; * Actual packet length in bytes T ← Input,Call[NSIOverTst]; * Get status and test of overrun Pd ← (NSIPtr) - (16C); * As in DLion?? Require 6 words Branch[.+2,alu>=0]; * Status byte (in upper byte) Branch[NSIShort]; * Placement (Better way??) Pd ← (T) and (OddByteStatus); T ← (T) and (177400C),Branch[NSIPost,alu=0]; * Input status is upper byte NSIPtr ← (NSIPtr) - 1; * Post input completion status now in T and length (in bytes) in NSIPtr. NSIPost: NSITemp1← NSCSB.NextIn; Call[NSPost]; *+++++++++ Allow long Call for placement NSIShort: TIOA[NSControl],Block, Branch[NSIIdle]; * Await next packet * Discard packet because IOCB queue is empty. NSINoCB: T← NSCSB.missed; * Increment ICSB.missed Fetch← T,Call[NSISkipP]; * Ignore rest of packet NSITemp1← MD+1; Store← T,DBuf← NSITemp1,Block,Branch[NSIIdle]; Subroutine; NSISkipP: TIOA[NSControl]; * Throw away rest of packet NSISkipP1: NSITemp1 ← WaitForBOP; * Save T for no iocb routine Output ← NSITemp1,Return; * By using temp * Routine to test for an overflow and handle the IEC kludge for the condition. * We must turn off and then on the controller and skip the next packet. * T has status on input. T must be saved in the testing. Subroutine; NSIOverTst: Pd ← (T) and (400C); * get the overrun status bit NSITemp1 ← TurnOffRx,Branch[NSIOverTstX,alu=0]; TIOA[NSControl]; Output ← NSITemp1; * Set Rx off NSITemp1 ← TurnOnRx; Output ← NSITemp1,Branch[NSISkipP1]; * Logic is clear when it comes on NSIOverTstX: Return; TopLevel; *---------------------------------------------------------------------------- * Output Task *---------------------------------------------------------------------------- Set[XTask, IP[NSOT]]; * Idle state of the NS Ethernet output task. TIOA=NSControl. * Wake up here at end of previous packet or when poked by software. NSOIdle: MemBase← IOBR; RBase← RBase[NSORegs]; T← NSCSB.NextOut; * Fetch CSB.next for output Fetch← T,; NSOIocb ← MD; * Save base of IOCB for later Branch[NSONoIocb, ALU=0]; * Go shut off transmitter if no IOCB NSOPtr ← (-1C); * Signal who we are for BR selection Call[NSIOCBSetup]; * Get data location and length NSOPtr ← (Fetch ← NSOPtr) + 1; * Get first word to output Branch[NSONone,alu>=0]; * Post end if there are no more words TIOA[NSData]; * Ready to do the packet output * Output main loop. * Data transfer is pipelined: each iteration outputs a data word * fetched in the previous iteration and starts the fetch of the data for * the next iteration. This way, cache misses generally occur while our * task is blocked, and lower-priority tasks are permitted to run while * the cache is being loaded. * NSOPtr is the negative of the number of words remaining to be fetched. * IOAtten branches if a collision, data late, or Fifo PE has aborted output. NSOPtr← (Fetch← NSOPtr)+1, T← MD, Branch[NSOAbort, IOAtten]; Output← T, Block, Branch[.-1, ALU#0]; * Next-to-last word has been output and last word has been fetched * Now see if this is an odd or even length packet NSOEnd: NSOPtr ← (NSOLength), Branch[NSOAbort1, IOAtten]; * See if trouble NSOLength, T ← STxEnd, * No problems so see if odd or even DblBranch[NSOOddEnd,NSOEnd1,R odd]; NSOAbort: TIOA[NSControl],Branch[NSONone]; * Ready for status--Second IOAtten does it NSOOddEnd: TIOA[NSControl]; T ← STxOddOn; * Set the odd byte control on Output ← T; * For the last load of TxBusReg TIOA[NSData]; T ← STxOddEnd; NSOEnd1: Output ← MD; * Output the last word TIOA[NSControl]; Output ← T,Block,Branch[NSONone]; * End output and wait till end * Wake up here only when packet completely sent or collision has occurred. NSOAbort1: TIOA[NSControl]; * Got bad before sent last word--get status NSONone: T ← Input; * Get the ending status bad or good here NSOTemp1 ← T ← T and (377C), * Need status in T for Done if no IOAtten Branch[NSOAbort2, IOAtten]; * Remove the host number or trash NSOPtr ← (NSOLength),Branch[NSODone]; * Set all gone-post status-go for next NSOAbort2: * All bad if we get here -- Now ans why Pd ← (NSOTemp1) and (4C); * Isolate the collsion bit MemBase ← IOBR,Branch[.+2,alu#0]; * Go post if none T ← (NSOTemp1),Branch[NSODone]; * Not collsion--let Head find it T ← (NSOIocb) + (IOCB.Retries); * Up count for the user Fetch ← T; NSOLength ← MD + 1; * Don't need length any more Store ← T,DBuf ← NSOLength; Pd ← (NSOTemp1) and (2C); * Check if this is the last collision (16th) T ← TurnOffTx,Branch[.+2,alu=0]; * End it if too many T ← (NSOTemp1),Branch[NSODone]; NSOGoAgain: Output ← T; * Try again with the same packet T ← TurnOnTx; * Or new IOCB if there was one Output ← T,Block,Branch[NSOIdle]; * Off then on clears abort status NSODone: NSOTemp1 ← NSCSB.NextOut; * Post status and go for next IOCB Call[NSPost]; *++++++++++ Allow Long Call for placement Pd ← T; T ← TurnOffTx,Branch[.+2,alu=0]; * T has next ShortIOCB on return Branch[NSOGoAgain]; * There was another one so go to it Output ← T,Block,Branch[NSOIdle]; * No more so stop NSONoIOCB: T ← TurnOffTx,Branch[.-1]; * Who knows how but kill it *---------------------------------------------------------------------------- * Task-independent Subroutines *---------------------------------------------------------------------------- *---------------------------------------------------------------------------- NSIOCBSetup: * Set up IOCB pointers and counts * Enter: NSxCB = IOCB being worked on * NSxPtr = 0 for input, -1 for output * MemBase = IOBR * * Exit: NSxPtr = negative word count * NSxLength = Byte Length from IOCB * MemBase = NSxBR * NSxBR = base register properly set up for indexing by ExPtr * Points the base register beyond the end of the buffer -2↑16, and * addresses the buffer with a negative index in ExPtr. * Clobbers NSxTemp1, T *---------------------------------------------------------------------------- Subroutine; T← (NSxCB)+(IOCB.bufferLen); T← (Fetch← T)+1; * Fetch IOCB.length NSxLength← MD; T← (Fetch← T)+1; * Fetch low buffer pointer NSxTemp1 ← (NSxLength)+1; * Form the length in words NSxTemp1 ← (NSxTemp1) rsh 1; Fetch← T, T← MD, * Fetch high buffer pointer NSxPtr, Branch[.+2, R<0]; * Which base register? T← T+(NSxTemp1), MemBase← NSIBR, Branch[.+2]; * Low pointer + length T← T+(NSxTemp1), MemBase← NSOBR; * Low pointer + length T← MD, BRLo← T; T← T-1, XorSavedCarry; * Adjust high for negative indexing T← NSxTemp1, BRHi← T; NSxPtr← (0S)-T, Return; * NSxPtr← negative count *---------------------------------------------------------------------------- NSPost: * Post command completion. * Enter: T = completion status word * NSxPtr = actual packet length * NSxCB = IOCB being worked on * NSxTemp1 = Position of next IOCB short pointer (Interupt word follows it) * Exit: MemBase = IOBR * T = Shortpointer to next IOCB * Clobbers T, NSxCB, NSxTemp1, RBase *---------------------------------------------------------------------------- Subroutine; MemBase← IOBR; NSxCB ← (NSxCb) + (IOCB.next); NSxCB← (Fetch← NSxCB)-1; * Fetch IOCB.next T← (Store← NSxCB)-1, DBuf← T; * Store IOCB.completion Store← T, DBuf← NSxPtr, T← MD; * Store IOCB.wordsUsed NSxTemp1← (Store← NSxTemp1)+1, DBuf← T; * Store xCSB.next Fetch← NSxTemp1; * Fetch xCSB.interruptMask RBase← RBase[NWW]; * Initiate interrupts NWW← (NWW) OR MD, Reschedule, Return; TopLevel;