DIRECTORY Basics USING [BITAND, bytesPerWord, HighByte, LowHalf], DeviceCleanup USING [Item, Await], DoradoInputOutput USING [Input, IOAddress, Output, ResetEther], EthernetOneFace USING [HostArray, Status], MPCodes USING [Code, ethernetHostChanged], ProcessorFace USING [SetMP]; EthernetOneHeadDorado: CEDAR PROGRAM IMPORTS Basics, DeviceCleanup, DoradoInputOutput, ProcessorFace EXPORTS EthernetOneFace = { BYTE: TYPE = [0..100H); HostArray: TYPE = EthernetOneFace.HostArray; Status: TYPE = EthernetOneFace.Status; csb: Handle _ LOOPHOLE[LONG[177600B]]; ControllerStatusBlock: TYPE = MACHINE DEPENDENT RECORD [ nextInput: ShortIocb, inInterruptBit: WORD, host: WORD _ 0FFFFH, -- <0 => compatability with old microcode missed: CARDINAL, lastInput: IOCB, -- valid IFF nextInput # NIL, not used by microcode firstInterstices: ARRAY [6..10B) OF WORD _ ALL[0], nextOutput: ShortIocb, outInterruptBit: WORD, minPacketSpacing: CARDINAL, lastOutput: IOCB, -- valid IFF nextOutput # NIL, not used by microcode secondInterstices: ARRAY [15B..30B) OF WORD _ ALL[0], hosts: HostArray]; -- current set of hosts to which receiver code responds IOCB: TYPE = LONG POINTER TO IOControlBlock; ShortIocb: TYPE = -- BASE RELATIVE-- POINTER TO IOControlBlock; IOControlBlock: TYPE = MACHINE DEPENDENT RECORD [ next: ShortIocb, completion: CompletionStatus, used: CARDINAL, -- input only load: CARDINAL, -- output only words: CARDINAL, buffer: LONG POINTER ]; CompletionStatus: TYPE = MACHINE DEPENDENT RECORD [ microcode (0: 0..7): {pending (0), done (1), bufferOverflow (2), loadOverflow (3), killed(37)}, hardware (0: 8..15): SELECT OVERLAID * FROM input => [ rxCollision (0: 8..8), fill1 (0: 9..9), rxDataLate (0: 10..10), fill2 (0: 11..11), rxCRCError (0: 12..12), fill3 (0: 13..14), rxIncTrans (0: 15..15): BOOLEAN], output => [ rxOn (0: 8..8), txOn (0: 9..9), loopBack (0: 10..10), txCollision (0: 11..11), noWakeups (0: 12..12), txDataLate (0: 13..13), singleStep (0: 14..14), txFifoPE (0: 15..15): BOOLEAN], ENDCASE]; inputErrorMask: input CompletionStatus = [ microcode: pending, hardware: input[rxCollision: TRUE, fill1: FALSE, rxDataLate: TRUE, fill2: FALSE, rxCRCError: TRUE, fill3: FALSE, rxIncTrans: TRUE]]; outputErrorMask: output CompletionStatus = [ microcode: pending, hardware: output[rxOn: FALSE, txOn: FALSE, loopBack: FALSE, txCollision: TRUE, noWakeups: FALSE, txDataLate: TRUE, singleStep: FALSE, txFifoPE: TRUE]]; nullCompletion: CompletionStatus = LOOPHOLE[0]; Command: TYPE = RECORD [WORD]; enableInput: Command = [173377B]; enableOutput: Command = [047777B]; control: DoradoInputOutput.IOAddress = 16B; Shorten: PROCEDURE [iocb: IOCB] RETURNS [ShortIocb] = TRUSTED INLINE { RETURN[LOOPHOLE[Basics.LowHalf[LOOPHOLE[iocb]]]]; }; Handle: PUBLIC TYPE = LONG POINTER TO ControllerStatusBlock; ControlBlockRecord: PUBLIC TYPE = IOControlBlock; nullHandle: PUBLIC Handle _ NIL; controlBlockSize: PUBLIC CARDINAL _ SIZE[IOControlBlock]; hearSelf: PUBLIC BOOLEAN _ TRUE; QueueOutput: PUBLIC PROC [ handle: Handle, buffer: LONG POINTER, bytes: NAT, iocb: IOCB] = TRUSTED { words: CARDINAL _ (bytes+Basics.bytesPerWord-1)/2; -- Round up iocb^ _ [next: NIL, completion: nullCompletion, used: 0, load: 0, words: words, buffer: buffer]; IF handle.nextOutput # NIL THEN handle.lastOutput.next _ Shorten[iocb]; IF handle.nextOutput = NIL AND iocb.completion = nullCompletion THEN { handle.nextOutput _ Shorten[iocb]; DoradoInputOutput.Output[enableOutput, control]; }; handle.lastOutput _ iocb; }; QueueInput: PUBLIC PROC [ handle: Handle, buffer: LONG POINTER, bytes: NAT, iocb: IOCB] = TRUSTED { words: CARDINAL _ (bytes+Basics.bytesPerWord-1)/2; -- Round up iocb^ _ [next: NIL, completion: nullCompletion, used: 0, load: 0, words: words, buffer: buffer]; IF handle.nextInput # NIL THEN handle.lastInput.next _ Shorten[iocb]; IF handle.nextInput = NIL AND iocb.completion = nullCompletion THEN handle.nextInput _ Shorten[iocb]; handle.lastInput _ iocb; }; MarkKilled: PUBLIC PROC [iocb: IOCB] = TRUSTED { iocb.completion.microcode _ killed; }; GetStatusAndLength: PUBLIC PROC [iocb: IOCB] RETURNS [status: Status, bytes: NAT] = TRUSTED { SELECT iocb.completion.microcode FROM pending => RETURN[pending, 0]; done => { IF Basics.BITAND[ LOOPHOLE[iocb.completion], LOOPHOLE[inputErrorMask] ]=0 THEN status _ ok ELSE SELECT TRUE FROM iocb.completion.rxCollision => status _ otherError; iocb.completion.rxDataLate => status _ overrun; iocb.completion.rxCRCError => status _ IF iocb.completion.rxIncTrans THEN crcAndBadAlignment ELSE crc; iocb.completion.rxIncTrans => status _ badAlignmentButOkCrc; ENDCASE => status _ otherError; }; bufferOverflow => status _ packetTooLong; loadOverflow => status _ tooManyCollisions; ENDCASE => status _ otherError; bytes _ iocb.used*2; }; GetStatusAndCollisions: PUBLIC PROC [iocb: IOCB] RETURNS [status: Status, collisions: NAT] = TRUSTED { SELECT iocb.completion.microcode FROM pending => RETURN[pending, 0]; done => { IF Basics.BITAND[LOOPHOLE[iocb.completion], LOOPHOLE[outputErrorMask] ]=0 THEN status _ ok ELSE SELECT TRUE FROM iocb.completion.txCollision => status _ tooManyCollisions; iocb.completion.txDataLate => status _ underrun; iocb.completion.txFifoPE => status _ otherError; ENDCASE => status _ otherError; }; bufferOverflow => status _ packetTooLong; loadOverflow => status _ tooManyCollisions; ENDCASE => status _ otherError; collisions _ SELECT iocb.load FROM 1 => 0, 3 => 1, 7 => 2, 17B => 3, 37B => 4, 77B => 5, 177B => 6, 377B => 7, 777B => 8, 1777B => 9, 3777B => 10, 7777B => 11, 17777B => 12, 37777B => 13, 77777B => 14, 177777B => 15, ENDCASE => 16; }; GetPacketsMissed: PUBLIC PROC [handle: Handle] RETURNS [CARDINAL] = TRUSTED { RETURN[handle.missed]; }; GetNextDevice: PUBLIC PROC [handle: Handle] RETURNS [Handle] = TRUSTED { RETURN[IF handle=nullHandle THEN csb ELSE nullHandle]; }; GetHostNumber: PUBLIC PROC [handle: Handle] RETURNS [host: BYTE] = TRUSTED { RETURN[Basics.HighByte[DoradoInputOutput.Input[control]]]; }; once: BOOL _ FALSE; TurnOn: PUBLIC PROC [handle: Handle, inInterrupt, outInterrupt: WORD] = TRUSTED { me: BYTE _ GetHostNumber[handle]; DoradoInputOutput.ResetEther[]; IF ~once THEN { once _ TRUE; handle^ _ [ nextInput: NIL, inInterruptBit: inInterrupt, host: 0FFFFH, missed: 0, lastInput: NIL, firstInterstices: ALL[0], nextOutput: NIL, outInterruptBit: outInterrupt, minPacketSpacing: 500/32, lastOutput: NIL, secondInterstices: ALL[0], hosts: ALL[FALSE] ]; }; handle.nextInput _ NIL; handle.inInterruptBit _ inInterrupt; handle.host _ 0FFFFH; handle.nextOutput _ NIL; handle.outInterruptBit _ outInterrupt; handle.minPacketSpacing _ 500/32; handle.hosts _ ALL[FALSE]; handle.hosts[0] _ TRUE; handle.hosts[me] _ TRUE; DoradoInputOutput.Output[enableInput, control]; }; TurnOff: PUBLIC PROC [handle: Handle] = TRUSTED { DoradoInputOutput.ResetEther[]; handle.nextInput _ NIL; handle.nextOutput _ NIL; }; SetOutputDelay: PUBLIC PROC [handle: Handle, microseconds: CARDINAL] = TRUSTED { handle.minPacketSpacing _ microseconds/32; }; SetInputHosts: PUBLIC PROC [handle: Handle, hosts: LONG POINTER TO HostArray] = TRUSTED { IF hosts = NIL THEN { me: BYTE _ GetHostNumber[handle]; handle.hosts _ ALL[FALSE]; handle.hosts[0] _ TRUE; handle.hosts[me] _ TRUE; } ELSE handle.hosts _ hosts^; }; alreadyInitializedCleanup: BOOLEAN _ FALSE; savedCSB: ControllerStatusBlock; AddCleanup: PUBLIC PROC [handle: Handle] = TRUSTED { item: DeviceCleanup.Item; originalHost: BYTE _ GetHostNumber[handle]; IF alreadyInitializedCleanup THEN RETURN; alreadyInitializedCleanup _ TRUE; DO SELECT DeviceCleanup.Await[@item] FROM kill => DoradoInputOutput.ResetEther[]; turnOff => { DoradoInputOutput.ResetEther[]; savedCSB _ handle^; handle.nextInput _ NIL; handle.nextOutput _ NIL; }; turnOn => { me: BYTE _ Basics.HighByte[DoradoInputOutput.Input[control]]; DoradoInputOutput.ResetEther[]; IF me # originalHost THEN ErrorHalt[MPCodes.ethernetHostChanged]; -- InLoaded on another machine? handle^ _ [ nextInput: NIL, inInterruptBit: 0, host: 0FFFFH, missed: savedCSB.missed, lastInput: NIL, firstInterstices: ALL[0], nextOutput: NIL, outInterruptBit: 0, minPacketSpacing: savedCSB.minPacketSpacing, lastOutput: NIL, secondInterstices: ALL[0], hosts: savedCSB.hosts ]; DoradoInputOutput.Output[enableInput, control]; }; ENDCASE; ENDLOOP; }; ErrorHalt: PROC [code: MPCodes.Code] = INLINE { ProcessorFace.SetMP[code]; DO ENDLOOP }; }. vEthernetOneHeadDorado.mesa Copyright c 1985, 1986 by Xerox Corporation. All rights reserved. Taft, February 13, 1983 1:20 pm Levin, August 8, 1983 3:04 pm Russ Atkinson (RRA) February 19, 1985 2:07:23 pm PST Hal Murray, May 24, 1986 6:52:35 pm PDT Some modifications should be made to clean up multicast receiving, but they would cause incompatibilities in existing volumes (Germ, Othello, CoPilot, etc.) The microcode assumes that NIL is 0. Maybe we should check to be sure that the high half is zero EXPORTed TYPEs EXPORTed variables Non EXPORTed things. Note that all the state information lives in the CSBs. hosts is complete specification (including 0, if broadcasts are to be accepted), of the hosts whose input packets the microcode will accept. NIL => revert to normal mode Note that this does NOT really put things back together. It simply smashes things to a safe state. The intention is that the driver will notice that nothing is happening and then call TurnOff+TurnOn to reset things. That allows Pilot to reset the GMT clock on the way back from the debugger without getting tangled up with the normal Ethernet driver. Κ ˜codešœ™Kšœ Οmœ7™BKšœ™K™K™4K™'—K˜KšœW™WKšœD™DK˜šΟk ˜ Kšœžœžœ#˜7Kšœžœ˜"Kšœžœ(˜?Kšœžœ˜*Kšœžœ˜*Kšœžœ ˜K˜—šœžœž˜$Kšžœ8˜?Kšžœ˜K˜Kšžœžœ ˜K˜Kšœ žœ˜,Kšœžœ˜&K˜Kšœžœžœ ˜&K˜š œžœžœž œžœ˜8Kšœ˜Kšœžœ˜Kšœž œΟc*˜>Kšœžœ˜Kšœ žœŸ ΠckŸ  Ÿ˜DKš œžœ žœžœžœ˜2Kšœ˜Kšœžœ˜Kšœžœ˜Kšœ žœŸ  Ÿ Ÿ˜FKš œžœ žœžœžœ˜5KšœŸ7˜JK˜—Kš žœžœžœžœžœ˜,Kš œ žœŸœžœžœ˜?š œžœžœž œžœ˜1Kšœ˜K˜KšœžœŸ ˜KšœžœŸ˜Kšœžœ˜Kšœžœžœ˜K˜—š œžœžœž œžœ˜3K˜_šœžœžœž˜+˜ K˜K˜K˜K˜K˜K˜Kšœžœ˜!—˜ K˜K˜K˜K˜K˜K˜K˜Kšœžœ˜—Kšžœ˜ K˜——˜*K˜š œžœ žœžœ žœ˜PKšœ žœ žœžœ˜3——˜,K˜š œžœžœ žœžœ˜NKš œ žœžœžœ žœ˜H——Kšœ#žœ˜/K˜Kšœ žœžœžœ˜K˜!K˜"K˜+K˜Kšœžœ™$K˜š Οnœž œžœžœžœžœ˜FKšœ;™;Kšžœžœžœ ˜1Kšœ˜K˜K˜—Kšœ™K˜Kš œžœžœžœžœžœ˜šœžœ=˜OKšœ˜—Kšžœžœžœ(˜Gšžœžœžœ"žœ˜FKšœ"˜"K˜3—Kšœ˜Kšœ˜K˜—š‘ œžœžœ˜Kš œžœžœ žœžœžœ˜IKšœžœ$Ÿ ˜>šœžœ=˜OKšœ˜—Kšžœžœžœ'˜Ešžœžœžœ"ž˜CKšœ!˜!—Kšœ˜Kšœ˜K˜—š ‘ œžœžœžœžœ˜0Kšœ#˜#Kšœ˜K˜—š‘œžœžœžœžœžœžœ˜]šžœž˜%Kšœ žœ ˜šœ ˜ šžœžœ˜Kšžœžœžœ ˜H—šžœžœžœž˜Kšœ3˜3Kšœ/˜/šœ˜Kšœ žœžœžœ˜H—Kšœ<˜