<> <> <> <> <> <> <> DIRECTORY DeviceCleanup USING [Item, Await], DoradoInputOutput USING [Output, IOAddress], NSPilotSystem USING [HostNumber], PrincOps USING [zMISC], PrincOpsUtils USING [BITAND, BITOR, LowHalf], NewEthernetFace, NewEthernetFaceExtras; NewEthernetHeadDorado: PROGRAM IMPORTS DeviceCleanup, DoradoInputOutput, PrincOpsUtils EXPORTS NewEthernetFace, NewEthernetFaceExtras = BEGIN OPEN PrincOpsUtils, NewEthernetFace; <> <> CSB: TYPE = LONG POINTER TO ControllerStatusBlock; ControllerStatusBlock: TYPE = MACHINE DEPENDENT RECORD [ host: NSPilotSystem.HostNumber, 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 Base: TYPE = LONG BASE POINTER--Environment.Base--; IOCB: TYPE = LONG POINTER TO IOControlBlock; ShortIocb: TYPE = Base RELATIVE POINTER TO IOControlBlock; IOControlBlock: TYPE = MACHINE DEPENDENT RECORD [ bufferLen: CARDINAL, -- length is in BYTES, not words buffer: LONG POINTER, retries: WORD_ 0, -- set by device packetLen: CARDINAL, -- input only, length of the received packet, in bytes completion: CompletionStatus_ nullCompletion, -- raw status from microcode, nonzero at end next: ShortIocb]; Command: TYPE = RECORD [WORD]; eEnableTrn: Command = [1B]; -- (Start Tx) Dispatch to TIOA_ with 047777B eTurnOn: Command = [0B]; -- Dispatch to the startup code with T_ Normal reset eByPassOn: Command = [2B]; -- Dispatch to the startup code with T_ Bypass eTurnNSOff: Command = [3]; -- Dispatch to TIOA_ with T_A0 <<>> <> ECtl: DoradoInputOutput.IOAddress = 26B; CompletionStatus: TYPE = MACHINE DEPENDENT RECORD [ hardware (0: 0..15): SELECT OVERLAID * FROM input => [ overflow (0: 0..0): BOOLEAN, noDribble (0: 1..1): BOOLEAN, fill1 (0: 2..2): [0..1)_ 0, goodCRC (0: 3..3): BOOLEAN, fill2 (0: 4..5): [0..3)_ 0, oddByte (0: 6..6): BOOLEAN, overRun (0: 7..7): BOOLEAN, fill3 (0: 8..15): [0..400B)_ 0], output => [ fill4 (0: 0..7): [0..400B)_ 0, rxOn (0: 8..8): BOOLEAN, txOn (0: 9..9): BOOLEAN, loopBack (0: 10..10): BOOLEAN, IECByPass (0: 11..11): BOOLEAN, -- error if found one by the head noWakeups (0: 12..12): BOOLEAN, -- error if found one by the head txStatus (0: 13..14): {txOK (0), underRun (1), collision (2), maxCollisions (3)}, txDataParityError (0: 15..15): BOOLEAN], ENDCASE]; pendingCompletion: CompletionStatus = LOOPHOLE[0]; nullCompletion: CompletionStatus = LOOPHOLE[0]; inputStatusBits: input CompletionStatus = LOOPHOLE[177400B]; inputGoodStatus: input CompletionStatus = [input[overflow: FALSE, noDribble: TRUE, goodCRC: TRUE, oddByte: FALSE, overRun: FALSE]]; outputErrorMask: output CompletionStatus = [output[rxOn: FALSE, txOn: FALSE, loopBack: FALSE, IECByPass: TRUE, noWakeups: TRUE, txStatus: maxCollisions, txDataParityError: TRUE]]; outputStatusBits: CompletionStatus = LOOPHOLE[377B]; noIocb: ShortIocb = LOOPHOLE[0]; <> csb: CSB_ LOOPHOLE[LONG[177700B]]; Shorten: PROCEDURE [iocb: IOCB] RETURNS [ShortIocb] = INLINE { <> RETURN[LOOPHOLE[PrincOpsUtils.LowHalf[iocb]]]}; Reset10MBEther: PROC = MACHINE CODE <> { PrincOps.zMISC, 250B}; <> DeviceHandle: PUBLIC TYPE = RECORD [CARDINAL]; ControlBlockRecord: PUBLIC TYPE = IOControlBlock; <> nullDeviceHandle: PUBLIC DeviceHandle _ [123456B]; self: DeviceHandle = [0]; globalStateSize: PUBLIC CARDINAL _ 0; controlBlockSize: PUBLIC CARDINAL _ SIZE[IOControlBlock]; hearSelf: PUBLIC BOOLEAN _ FALSE; <> <<>> <> HWMode: TYPE = MACHINE DEPENDENT {hwNormal (173000B), hwLoopBack (173100B)}; ResetBits: WORD = 40B + 20B; EnableTx: WORD = 47777B; ModeFor10MBEther: TYPE = NewEthernetFaceExtras.ModeFor10MBEther; curMode: ModeFor10MBEther_ normal; hwMode: HWMode_ hwNormal; SetModeFor10MBEther: PUBLIC PROC[mode: ModeFor10MBEther_ normal] RETURNS [prev: ModeFor10MBEther] = BEGIN prev_ SELECT hwMode FROM hwNormal => normal, hwLoopBack => loopBack, ENDCASE => other; hwMode _ SELECT mode FROM normal => hwNormal, loopBack => hwLoopBack, ENDCASE => hwNormal; END; QueueOutput: PUBLIC PROCEDURE [ device: DeviceHandle, buffer: LONG POINTER, length: CARDINAL, cb: IOCB] = BEGIN p: LONG POINTER _ buffer; IF device # self THEN RETURN; cb^ _ [ next: noIocb, retries: 0, packetLen: 0, bufferLen: 2*length, buffer: buffer]; IF csb.output = noIocb THEN { -- new iocb, hardware idle csb.output _ Shorten[cb]; DoradoInputOutput.Output[EnableTx, ECtl]} -- poke hardware ELSE -- output active, add to end of chain BEGIN csb.lastOutput.next _ Shorten[cb]; IF csb.output = noIocb AND cb.completion = nullCompletion THEN { -- oops, hardware went idle csb.output _ Shorten[cb]; DoradoInputOutput.Output[EnableTx, ECtl]}; -- poke hardware END; csb.lastOutput _ cb; END; QueueInput: PUBLIC PROC[ device: DeviceHandle, buffer: LONG POINTER, length: CARDINAL, cb: IOCB] = BEGIN IF device # self THEN RETURN; cb^ _ [ next: noIocb, retries: 0, packetLen: 0, bufferLen: 2*length, buffer: buffer]; IF csb.input # noIocb THEN csb.lastInput.next _ Shorten[cb]; IF csb.input = noIocb AND cb.completion = nullCompletion THEN csb.input _ Shorten[cb]; csb.lastInput _ cb; END; GetStatus: PUBLIC PROCEDURE [cb: IOCB] RETURNS [status: Status] = { completion: CompletionStatus; -- *+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+* <> <> -- *+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+* IF (completion_ cb.completion) = pendingCompletion THEN RETURN[pending]; IF PrincOpsUtils.BITAND[LOOPHOLE[completion], LOOPHOLE[inputStatusBits]] # 0 THEN { IF LOOPHOLE[PrincOpsUtils.BITAND[LOOPHOLE[completion], LOOPHOLE[inputGoodStatus]], CompletionStatus] = inputGoodStatus THEN RETURN[ok]; RETURN[ SELECT TRUE FROM completion.overflow => packetTooLong, completion.overRun => overrun, NOT completion.goodCRC => crc, NOT completion.noDribble, completion.oddByte => badAlignmentButOkCrc ENDCASE => otherError]}; IF PrincOpsUtils.BITAND[LOOPHOLE[completion], LOOPHOLE[outputStatusBits]] # 0 THEN { IF PrincOpsUtils.BITAND[LOOPHOLE[completion], LOOPHOLE[outputErrorMask]] = 0 THEN RETURN[ok]; RETURN[ SELECT completion.txStatus FROM txOK => ok, underRun, collision => underrun, maxCollisions => tooManyCollisions, ENDCASE => otherError]}; RETURN[otherError]}; GetRetries: PUBLIC PROCEDURE [cb: IOCB] RETURNS [CARDINAL] = { IF cb.retries = 17 THEN RETURN[cb.retries-1] ELSE RETURN[cb.retries]}; GetPacketLength: PUBLIC PROCEDURE [cb: IOCB] RETURNS [used: CARDINAL] = BEGIN used _ (cb.packetLen/2); IF ~cb.completion.noDribble AND cb.completion.oddByte THEN used _ used - 1; END; GetPacketsMissed: PUBLIC PROCEDURE [device: DeviceHandle] RETURNS [CARDINAL] = { RETURN[IF device # self THEN 0 ELSE csb.missed]}; GetNextDevice: PUBLIC PROCEDURE [device: DeviceHandle] RETURNS [DeviceHandle] = { IF device = nullDeviceHandle THEN RETURN[self] ELSE RETURN[nullDeviceHandle]}; TurnOn: PUBLIC PROCEDURE [ device: DeviceHandle, host: NSPilotSystem.HostNumber, inInterrupt, outInterrupt: WORD, globalState: GlobalStatePtr] = BEGIN IF device # self THEN RETURN; Reset10MBEther[]; csb^ _ [ host: host, input: noIocb, inputWakeups: inInterrupt, output: noIocb, outputWakeups: outInterrupt, missed: 0, lastInput: NIL, lastOutput: NIL]; DoradoInputOutput.Output[PrincOpsUtils.BITOR[LOOPHOLE[hwMode], ResetBits], ECtl]; DoradoInputOutput.Output[LOOPHOLE[hwMode], ECtl]; -- turns on receiver END; TurnOff: PUBLIC PROCEDURE [device: DeviceHandle] = { IF device # self THEN RETURN; Reset10MBEther[]}; <> cleanupInitialized: BOOLEAN _ FALSE; savedCSB: ControllerStatusBlock; AddCleanup: PUBLIC PROCEDURE [device: DeviceHandle] = { OPEN DeviceCleanup; item: Item; oldHost: NSPilotSystem.HostNumber; IF cleanupInitialized THEN RETURN; cleanupInitialized _ TRUE; DO SELECT Await[@item] FROM kill => Reset10MBEther[]; turnOff => {Reset10MBEther[]; savedCSB _ csb^; oldHost _ csb.host}; turnOn => { <> Reset10MBEther[]; csb^ _ [ host: oldHost, -- Ugh, it would be nice if we could do something better input: noIocb, inputWakeups: 0, output: noIocb, outputWakeups: 0, missed: 0, lastInput: NIL, lastOutput: NIL]; DoradoInputOutput.Output[PrincOpsUtils.BITOR[LOOPHOLE[hwMode], ResetBits], ECtl]; DoradoInputOutput.Output[LOOPHOLE[hwMode], ECtl]}; ENDCASE; ENDLOOP}; RemoveCleanup: PUBLIC PROCEDURE [device: DeviceHandle] = {}; END. -- EthernetHeadDorado.