<> <> <> <> <> DIRECTORY Basics USING [LongNumber], PrincOps USING [wordsPerPage], PrincOpsUtils USING [BITAND, LowHalf], DeviceCleanup USING [Item, Await], DLionInputOutput USING [IOPage, Input, Output], EthernetFace; EthernetHeadDLion: PROGRAM IMPORTS DLionInputOutput, DeviceCleanup, PrincOpsUtils EXPORTS EthernetFace = BEGIN OPEN EthernetFace; <> CSB: TYPE = LONG POINTER TO ControllerStatusBlock; ControllerStatusBlock: TYPE = MACHINE DEPENDENT RECORD [ host: physical 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 EthernetCSBOffset: CARDINAL = 12*16 + 0; -- 0C0X IOCB: TYPE = LONG POINTER TO IOControlBlock; Base: TYPE = LONG BASE POINTER; ShortIocb: TYPE = Base RELATIVE POINTER TO IOControlBlock; IOControlBlock: TYPE = MACHINE DEPENDENT RECORD [ length: CARDINAL, buffer: LONG POINTER, mask: WORD, -- load location for output used: CARDINAL, -- input only completion: WORD, next: ShortIocb, spare: WORD]; -- NB: QuadWord Alignment Input: PROC [Register] RETURNS [Data] = LOOPHOLE[DLionInputOutput.Input]; Output: PROC [Command, Register] = LOOPHOLE[DLionInputOutput.Output]; Data: TYPE = RECORD [WORD]; Command: TYPE = RECORD [WORD]; eOff: Command = [0B]; eEnableTrn: Command = [1B]; eEnableRcv: Command = [1B]; eTurnOff: Command = [2B]; Register: TYPE = RECORD [[0..17B]]; eEOCtl: Register = [14B]; eEICtl: Register = [5B]; eEStatus: Register = [1B]; eHaveEther: Register = [12B]; <> collision: WORD = 100B; underRun: WORD = 40B; notGoodAlign: WORD = 20B; overRun: WORD = 10B; notGoodCRC: WORD = 4B; notEvenLen: WORD = 2B; <> eRcvEnabled: WORD = 2000B; eTrnEnabled: WORD = 400B; noIocb: ShortIocb = LOOPHOLE[0]; Shorten: PROC [iocb: IOCB] RETURNS [ShortIocb] = INLINE { <> RETURN[LOOPHOLE[PrincOpsUtils.LowHalf[iocb]]]}; FixAlignment: PROC [iocb: IOCB] RETURNS [IOCB] = INLINE { LOOPHOLE[iocb, Basics.LongNumber].lowbits _ PrincOpsUtils.BITAND[ LOOPHOLE[iocb, Basics.LongNumber].lowbits + 7, 177770B]; RETURN[iocb]}; MakeSureOff: PROC = INLINE { Output[eTurnOff, eEICtl]; THROUGH [0..2) UNTIL PrincOpsUtils.BITAND[Input[eEStatus], eRcvEnabled + eTrnEnabled] = 0 DO ENDLOOP}; <> DeviceHandle: PUBLIC TYPE = RECORD [CARDINAL]; ControlBlockRecord: PUBLIC TYPE = IOControlBlock; <> nullDeviceHandle: PUBLIC DeviceHandle _ [123456B]; self: DeviceHandle = [0]; globalStateSize: PUBLIC CARDINAL _ 0; controlBlockSize: PUBLIC CARDINAL; hearSelf: PUBLIC BOOLEAN _ FALSE; <> csb: CSB _ DLionInputOutput.IOPage + EthernetCSBOffset; haveEther: BOOLEAN; QueueOutput: PUBLIC PROC [device: DeviceHandle, buffer: LONG POINTER, length: CARDINAL, cb: IOCB] = { count: CARDINAL; p: LONG POINTER _ buffer; IF device # self THEN RETURN; count _ length - 1; DO foo: UNSPECIFIED _ (p + count)^; IF count < PrincOps.wordsPerPage THEN {foo _ p^; EXIT}; count _ count - PrincOps.wordsPerPage; ENDLOOP; cb _ FixAlignment[cb]; cb^ _ [ next: noIocb, mask: 0, spare: 1, completion: 0, used: 0, length: length - 1, buffer: buffer]; IF csb.output = noIocb THEN { <> csb.output _ Shorten[cb]; Output[eEnableTrn, eEOCtl]} -- poke hardware ELSE { <> csb.lastOutput.next _ Shorten[cb]; IF csb.output = noIocb AND cb.completion = 0 THEN { <> csb.output _ Shorten[cb]; Output[eEnableTrn, eEOCtl]}}; -- poke hardware csb.lastOutput _ cb}; QueueInput: PUBLIC PROC [ device: DeviceHandle, buffer: LONG POINTER, length: CARDINAL, cb: IOCB] = { IF device # self THEN RETURN; cb _ FixAlignment[cb]; cb^ _ [ next: noIocb, mask: 0, spare: 0, completion: 0, used: 0, length: length, buffer: buffer]; IF csb.input # noIocb THEN csb.lastInput.next _ Shorten[cb]; IF csb.input = noIocb AND cb.completion = 0 THEN { csb.input _ Shorten[cb]; Output[eEnableRcv, eEICtl]}; csb.lastInput _ cb}; GetStatus: PUBLIC PROC [cb: IOCB] RETURNS [status: Status] = { completion: WORD; cb _ FixAlignment[cb]; IF (completion _ cb.completion) = 0 THEN RETURN[pending]; IF cb.spare = 0 THEN { IF cb.length = 177777B THEN RETURN[packetTooLong]; status _ SELECT PrincOpsUtils.BITAND[ completion, notGoodAlign + overRun + notGoodCRC + notEvenLen] FROM 0 => ok, notGoodAlign+notEvenLen => ok, -- dippled bit case - someday drippled should be returned notGoodAlign => badAlignmentButOkCrc, notGoodCRC => crc, notGoodCRC + notGoodAlign => crcAndBadAlignment, overRun, overRun + notGoodAlign, overRun + notGoodCRC, overRun + notGoodCRC + notGoodAlign => overrun, ENDCASE => otherError; IF status = ok THEN { count: CARDINAL _ cb.length; p: LONG POINTER _ cb.buffer; DO (p + count)^ _ (p + count)^; IF count < PrincOps.wordsPerPage THEN {p^ _ p^; EXIT}; count _ count - PrincOps.wordsPerPage; ENDLOOP}; RETURN[status]}; IF cb.spare = 1 THEN { IF cb.mask = 17777B THEN RETURN[tooManyCollisions]; RETURN[ SELECT PrincOpsUtils.BITAND[completion, collision + underRun] FROM 0 => ok, underRun, underRun + collision => underrun, ENDCASE => otherError]}; RETURN[otherError]}; GetRetries: PUBLIC PROC [cb: IOCB] RETURNS [CARDINAL] = { cb _ FixAlignment[cb]; RETURN[ SELECT cb.mask 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, ENDCASE => 16]}; GetPacketLength: PUBLIC PROC [cb: IOCB] RETURNS [CARDINAL] = { cb _ FixAlignment[cb]; RETURN[cb.used]}; GetPacketsMissed: PUBLIC PROC [device: DeviceHandle] RETURNS [CARDINAL] = { RETURN[IF device # self THEN 0 ELSE csb.missed]}; GetNextDevice: PUBLIC PROC [device: DeviceHandle] RETURNS [DeviceHandle] = { IF ~haveEther THEN RETURN[nullDeviceHandle]; IF device = nullDeviceHandle THEN RETURN[self] ELSE RETURN[nullDeviceHandle]}; TurnOn: PUBLIC PROC [ device: DeviceHandle, host: physical HostNumber, inInterrupt, outInterrupt: WORD, globalState: GlobalStatePtr] = { IF device # self THEN RETURN; MakeSureOff[]; csb^ _ [ host: host, input: noIocb, inputWakeups: inInterrupt, output: noIocb, outputWakeups: outInterrupt, missed: 0, lastInput: NIL, lastOutput: NIL]; Output[eEnableRcv, eEICtl]}; TurnOff: PUBLIC PROC [device: DeviceHandle] = { IF device # self THEN RETURN; MakeSureOff[]}; <> cleanupInitialized: BOOLEAN _ FALSE; savedCSB: ControllerStatusBlock; AddCleanup: PUBLIC PROC [device: DeviceHandle] = { OPEN DeviceCleanup; item: Item; oldHost: physical HostNumber; IF cleanupInitialized OR ~haveEther THEN RETURN; cleanupInitialized _ TRUE; DO SELECT Await[@item] FROM kill => MakeSureOff[]; turnOff => {MakeSureOff[]; savedCSB _ csb^; oldHost _ csb.host}; turnOn => { <> MakeSureOff[]; 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]; Output[eEnableRcv, eEICtl]}; ENDCASE; ENDLOOP}; RemoveCleanup: PUBLIC PROC [device: DeviceHandle] = {}; <> Start: PROC = { IF (haveEther _ Input[eHaveEther] = Data[1]) THEN controlBlockSize _ SIZE[IOControlBlock] + 4 ELSE controlBlockSize _ 0 }; Start[]; END. LOG Time: October 29, 1980 11:16 AM By: Sandman, Action: create file. Time: 18-Mar-81 17:20:25 By: Sandman, Action: Removed minimum packet length test, general cleanup.