<> <> <> <> <> <<>> DIRECTORY DeviceCleanup USING [Item, Await], D0InputOutput USING [CSB, IOPage, ethernetIn, ethernetOut, ControllerNumber, GetNextController, nullControllerNumber], EthernetFace, PrincOps USING [zMISC, zSTARTIO], PrincOpsUtils USING [LowHalf]; EthernetHeadD0: PROGRAM IMPORTS D0InputOutput, DeviceCleanup, PrincOpsUtils EXPORTS EthernetFace = { OPEN EthernetFace; <> OCSB: TYPE = LONG POINTER TO OutputControllerStatusBlock; OutputControllerStatusBlock: TYPE = MACHINE DEPENDENT RECORD [ next: ShortIOCB, unused1: WORD, unused2: WORD, unused3: WORD, interruptBit: WORD, -- words after here are unused by microcode last: IOCB ]; -- last IOCB on output queue, valid if next#noIOCB ICSB: TYPE = LONG POINTER TO InputControllerStatusBlock; InputControllerStatusBlock: TYPE = MACHINE DEPENDENT RECORD [ next: ShortIOCB, host: HostNumber, interruptBit: WORD, missed: WORD, -- for debugging only spare1: WORD, spare2: WORD, buffer: ARRAY [0..4) OF CARDINAL, -- words after here are unused by microcode last: IOCB ]; -- last IOCB on input queue, valid if next#noIOCB IOCB: TYPE = LONG POINTER TO IOControlBlock; <> ShortIOCB: TYPE = POINTER TO IOControlBlock; IOControlBlock: TYPE = MACHINE DEPENDENT RECORD [ next: ShortIOCB, mask: WORD, spare: WORD, completion: WORD, used: CARDINAL, -- input only length: CARDINAL, buffer: LONG POINTER ]; -- NB: Must be QuadWord Aligned StartIO: PROC [SioParameter] = MACHINE CODE { PrincOps.zSTARTIO }; SioParameter: TYPE = RECORD [WORD]; firstFixupOutput: SioParameter = [20B]; firstFixupInput: SioParameter = [40B]; firstReset: SioParameter = [60B]; secondFixupOutput: SioParameter = [100B]; secondFixupInput: SioParameter = [200B]; secondReset: SioParameter = [300B]; <> Output: PROC [Command, Register] = MACHINE CODE { PrincOps.zMISC, 6; }; Input: PROC [Register] RETURNS [WORD] = MACHINE CODE { PrincOps.zMISC, 5; }; Command: TYPE = RECORD [WORD]; enableInput: Command = [220B]; enableOutput: Command = [103B]; Register: TYPE = MACHINE DEPENDENT RECORD [ zero: [0..377B] _ 0, controller: D0InputOutput.ControllerNumber, register: [0..17B]]; <> processed: WORD = 040000B; error: WORD = 020000B; hardwareError: WORD = 010000B; fragment, tooLong: WORD = 004000B; loadOverflow: WORD = 002000B; nothingYet: WORD = 0; <<001000 and 000400 are unused so far>> <> <<001: Memory Data Fault (OFault)>> <<002: Collision>> <<004: Output Underrrun>> <<010: Bad Parity (between mem and shifter)>> <<020: CRC>> <<040: Jam>> <<100: Input Overrun>> <<200: Bad Alignment>> noIOCB: ShortIOCB = LOOPHOLE[0]; Device: TYPE = RECORD [ board: Board, in, out: D0InputOutput.ControllerNumber]; Board: TYPE = [0..2); ICSBFronDevice: PROC [device: Device] RETURNS [ICSB] = INLINE { RETURN[LOOPHOLE[@D0InputOutput.IOPage[device.in]]]; }; OCSBFronDevice: PROC [device: Device] RETURNS [OCSB] = INLINE { RETURN[LOOPHOLE[@D0InputOutput.IOPage[device.out]]]; }; ControlRegister: PROC [c: D0InputOutput.ControllerNumber] RETURNS [Register] = INLINE { RETURN[[0,c,0]]; -- Register 0 is the control register }; Shorten: PROC [iocb: IOCB] RETURNS [ShortIOCB] = INLINE { <> RETURN[PrincOpsUtils.LowHalf[iocb]]; }; <> DeviceHandle: PUBLIC TYPE = Device; ControlBlockRecord: PUBLIC TYPE = IOControlBlock; <> nullDeviceHandle: PUBLIC DeviceHandle _ LOOPHOLE[123456B]; globalStateSize: PUBLIC CARDINAL _ 0; controlBlockSize: PUBLIC CARDINAL _ SIZE[IOControlBlock]; hearSelf: PUBLIC BOOL _ TRUE; <> fixupInputBits: ARRAY Board OF SioParameter = [firstFixupInput, secondFixupInput]; fixupOutputBits: ARRAY Board OF SioParameter = [firstFixupOutput, secondFixupOutput]; resetBits: ARRAY Board OF SioParameter = [firstReset, secondReset]; QueueOutput: PUBLIC PROC [device: Device, buffer: LONG POINTER, length: CARDINAL, cb: IOCB] = { out: OCSB = OCSBFronDevice[device]; cb^ _ [ next: noIOCB, mask: 0, spare: 0, completion: 0, used: 0, length: length, buffer: buffer ]; IF out.next=noIOCB THEN { <> out.next _ Shorten[cb]; Output[enableOutput,ControlRegister[device.out]]; -- poke hardware } ELSE { <> out.last.next _ Shorten[cb]; IF out.next=noIOCB AND cb.completion=0 THEN { <> out.next _ Shorten[cb]; Output[enableOutput,ControlRegister[device.out]]; -- poke hardware }; }; out.last _ cb; }; QueueInput: PUBLIC PROC [device: Device, buffer: LONG POINTER, length: CARDINAL, cb: IOCB] = { in: ICSB = ICSBFronDevice[device]; cb^ _ [ next: noIOCB, mask: 0, spare: 0, completion: 0, used: 0, length: length, buffer: buffer ]; IF in.next#noIOCB THEN in.last.next _ Shorten[cb]; IF in.next=noIOCB AND cb.completion=0 THEN { in.next _ Shorten[cb]; Output[enableInput,ControlRegister[device.in]]; }; in.last _ cb; }; GetStatus: PUBLIC PROC [cb: IOCB] RETURNS [status: Status] = { RETURN [ SELECT cb.completion FROM 0 => pending, 40000B => ok, 62000B => tooManyCollisions, 61000B => packetTooLong, 70200B => badAlignmentButOkCrc, 70020B => crc, 70220B => crcAndBadAlignment, 70100B, 70120B, 70300B, 70320B => overrun, 70004B, 70006B => underrun, ENDCASE => otherError ]; }; GetRetries: PUBLIC PROC [cb: IOCB] RETURNS [CARDINAL] = { 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, 17777B => 12, 37777B => 13, 77777B => 14, 177777B => 15, ENDCASE => 16 ]; }; GetPacketLength: PUBLIC PROC [cb: IOCB] RETURNS [CARDINAL] = { RETURN [cb.used]; }; GetPacketsMissed: PUBLIC PROC [device: Device] RETURNS [CARDINAL] = { RETURN [ICSBFronDevice[device].missed]; }; GetNextDevice: PUBLIC PROC [device: Device] RETURNS [Device] = { OPEN D0InputOutput; IF device=nullDeviceHandle THEN device _ [0,nullControllerNumber,nullControllerNumber] ELSE device.board _ device.board + 1; device.in _ GetNextController[ethernetIn,device.in]; device.out _ GetNextController[ethernetOut,device.out]; IF device.in=nullControllerNumber OR device.out=nullControllerNumber THEN RETURN[nullDeviceHandle]; RETURN[device]; }; TurnOn: PUBLIC PROC [device: Device, host: physical HostNumber, inInterrupt, outInterrupt: WORD, globalState: GlobalStatePtr] = { board: Board = device.board; out: OCSB = OCSBFronDevice[device]; in: ICSB = ICSBFronDevice[device]; StartIO[resetBits[board]]; out^ _ [ next: noIOCB, unused1: 0, unused2: 0, unused3: 0, interruptBit: outInterrupt, last: NIL ]; in^ _ [ next: noIOCB, host: host, interruptBit: inInterrupt, missed: 0, spare1: 0, spare2: 0, buffer: [0,0,0,0], last: NIL ]; StartIO[fixupInputBits[board]]; StartIO[fixupOutputBits[board]]; Output[enableInput,ControlRegister[device.in]]; }; TurnOff: PUBLIC PROC [device: Device] = { StartIO[resetBits[device.board]]; }; <> alreadyInitializedCleanup: ARRAY Board OF BOOL _ ALL[FALSE]; savedICSB: InputControllerStatusBlock; savedOCSB: OutputControllerStatusBlock; AddCleanup: PUBLIC PROC [device: Device] = { OPEN DeviceCleanup; item: Item; board: Board = device.board; out: OCSB = OCSBFronDevice[device]; in: ICSB = ICSBFronDevice[device]; oldHost: HostNumber; IF alreadyInitializedCleanup[device.board] THEN RETURN; alreadyInitializedCleanup[device.board] _ TRUE; DO SELECT Await[@item] FROM kill => { StartIO[resetBits[board]]; }; turnOff => { StartIO[resetBits[board]]; savedICSB _ in^; savedOCSB _ out^; oldHost _ in.host; }; turnOn => { <> StartIO[resetBits[board]]; out^ _ [ next: noIOCB, unused1: 0, unused2: 0, unused3: 0, interruptBit: 0, last: NIL ]; in^ _ [ next: noIOCB, host: oldHost, -- Ugh, it would be nice if we could do something better interruptBit: 0, missed: 0, spare1: 0, spare2: 0, buffer: [0,0,0,0], last: NIL ]; StartIO[fixupInputBits[board]]; StartIO[fixupOutputBits[board]]; Output[enableInput, ControlRegister[device.in]]; }; ENDCASE; ENDLOOP; }; RemoveCleanup: PUBLIC PROC [device: Device] = { }; }. LOG Time: September 4, 1980 11:02 PM By: HGM, Action: create file. Time: September 14, 1980 6:33 AM By: HGM, Action: buffer overflow bug. Time: November 3, 1983 11:14 am By: Birrell, Action: conversion to 5.0.