*---------------------------------------------------------------------------- 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;