-- File: TedLocked.mesa, Last Edit: HGM July 17, 1979 1:08 PM -- Copyright Xerox Corporation 1979, 1980 DIRECTORY CommUtilDefs: FROM "CommUtilDefs" USING [GetTicks], AltoEthernetDefs: FROM "AltoEthernetDefs" USING [ StartIO, ShortenData, EthernetDeviceBlockHandle, NIL0, EthernetPost, EthernetNotPosted, hardwareAOK, inputDone, outputDone, inputBufferOverflow, outputLoadOverflow, zeroLengthBuffer, hardwareReset, interfaceBroken], TedDefs: FROM "TedDefs" USING [ lock, hardware, myNetwork, myDevice, ethernetEncapsulationOffset, interruptBit, inputCommand, resetCommand, outputCommand], DriverDefs: FROM "DriverDefs" USING [ Glitch, GetInputBuffer, PutOnGlobalDoneQueue, PutOnGlobalInputQueue], BufferDefs: FROM "BufferDefs" USING [Buffer, QueueObject, Dequeue]; TedLocked: MONITOR LOCKS TedDefs.lock IMPORTS CommUtilDefs, DriverDefs, BufferDefs, AltoEthernetDefs, TedDefs EXPORTS TedDefs SHARES BufferDefs = BEGIN OPEN TedDefs; tedPleaseStop: PUBLIC BOOLEAN; nextBufferPointer: PUBLIC POINTER; currentInputBuffer: PUBLIC BufferDefs.Buffer; nextInputBuffer: PUBLIC BufferDefs.Buffer; currentOutputBuffer: PUBLIC BufferDefs.Buffer; timeSendStarted: PUBLIC CARDINAL; outputQueue: PUBLIC BufferDefs.QueueObject; ZeroLengthBuffer: PUBLIC ERROR = CODE; HardwareBroken: PUBLIC ERROR = CODE; ImpossibleMicrocodeStatus: PUBLIC ERROR = CODE; Interrupt: PUBLIC ENTRY PROCEDURE = BEGIN myDevice: AltoEthernetDefs.EthernetDeviceBlockHandle _ TedDefs.myDevice; b, temporaryBuffer: BufferDefs.Buffer; savedWordsLeft: CARDINAL; savedPostData: AltoEthernetDefs.EthernetPost; UNTIL tedPleaseStop DO UNTIL myDevice.postData#AltoEthernetDefs.EthernetNotPosted DO WAIT hardware; ENDLOOP; savedPostData _ myDevice.postData; savedWordsLeft _ myDevice.wordsLeft; -- Turn on input as soon as we can, so we don't drop as many packets. myDevice.postData _ AltoEthernetDefs.EthernetNotPosted; myDevice.inputBuffer _ [ nextInputBuffer.length-ethernetEncapsulationOffset,nextBufferPointer]; AltoEthernetDefs.StartIO[inputCommand]; SELECT savedPostData.microcodeStatus FROM AltoEthernetDefs.inputDone => IF savedPostData.hardwareStatus=AltoEthernetDefs.hardwareAOK THEN BEGIN IF (temporaryBuffer_DriverDefs.GetInputBuffer[])#NIL THEN BEGIN temporaryBuffer.device _ ethernet; b _ currentInputBuffer; b.length _ (b.length-ethernetEncapsulationOffset)-savedWordsLeft; b.network _ @myNetwork; DriverDefs.PutOnGlobalInputQueue[b]; currentInputBuffer _ temporaryBuffer; END; END; AltoEthernetDefs.outputDone, AltoEthernetDefs.outputLoadOverflow => FlushTheCurrentOutputBuffer[]; AltoEthernetDefs.hardwareReset => -- There are three reasons for getting here: -- 1) getting back from the Debugger -- 2) lost interrupt, and the Watcher poked us -- 3) stuck output packet (transciever not plugged in), and the Watcher killed it BEGIN IF currentOutputBuffer#NIL THEN FlushTheCurrentOutputBuffer[]; END; AltoEthernetDefs.inputBufferOverflow => NULL; AltoEthernetDefs.zeroLengthBuffer => DriverDefs.Glitch[ZeroLengthBuffer]; AltoEthernetDefs.interfaceBroken => DriverDefs.Glitch[HardwareBroken]; ENDCASE => DriverDefs.Glitch[ImpossibleMicrocodeStatus]; -- There are two buffers used for input: the current one, and a hot standby. -- Way up at the beginning of this loop, a read was started into the standby buffer. -- At this point, currentInputBuffer has a buffer to be setup for use next time. -- If we just finished a read then it is a new one left there by the inputDone processing, -- (or the old one if we are recycling it because we couldn't get a new one) -- otherwise, we are reusing the previous one. temporaryBuffer _ nextInputBuffer; nextInputBuffer _ currentInputBuffer; currentInputBuffer _ temporaryBuffer; nextBufferPointer _ AltoEthernetDefs.ShortenData[ @nextInputBuffer.encapsulation+ethernetEncapsulationOffset]; nextBufferPointer^ _ 0; -- see if there is output to do, there will be some for several reasons: -- 1 output finished, and another buffer was queued -- 2 input finished, and leftover outputBuffer (in under out) -- 3 input finished, and somebody didn't kick us because a packet was pouring in -- 4 (chained) we got some input first BEGIN IF currentOutputBuffer#NIL THEN GOTO SendThisOne; IF outputQueue.length=0 THEN GOTO NothingToSend; currentOutputBuffer _ BufferDefs.Dequeue[@outputQueue]; timeSendStarted _ CommUtilDefs.GetTicks[]; GOTO SendThisOne; EXITS SendThisOne => BEGIN -- start output if not already input coming in IF myDevice.inputBuffer.pointer^#0 THEN GOTO PouringIn; myDevice.interruptBit _ 0; -- inhibit interrupts for reset myDevice.postData _ AltoEthernetDefs.EthernetNotPosted; -- beware of hardware/microcode screwup -- it seems to hang while sending, after a collision, until a gateway packet arrives UNTIL myDevice.postData#AltoEthernetDefs.EthernetNotPosted DO AltoEthernetDefs.StartIO[resetCommand]; ENDLOOP; myDevice.interruptBit _ interruptBit; --interrupts back on myDevice.postData _ AltoEthernetDefs.EthernetNotPosted; myDevice.retransmissionMask _ 0; -- zero the load for new packet myDevice.outputBuffer.count _ currentOutputBuffer.length; myDevice.outputBuffer.pointer _ AltoEthernetDefs.ShortenData[ @currentOutputBuffer.encapsulation+ethernetEncapsulationOffset]; AltoEthernetDefs.StartIO[outputCommand]; EXITS PouringIn => NULL; END; NothingToSend => NULL; END; ENDLOOP; END; -- Interrupt FlushTheCurrentOutputBuffer: PROCEDURE = BEGIN myDevice.outputBuffer _ [0,AltoEthernetDefs.NIL0]; DriverDefs.PutOnGlobalDoneQueue[currentOutputBuffer]; currentOutputBuffer _ NIL; END; END. -- TedLocked(2048)\1345b9B4404b27B