<> <> <> <> <> <> <> DIRECTORY Basics USING [HighByte], DeviceCleanup USING [Item, Await], DoradoInputOutput USING [Input, IOAddress, Output, ResetEther], EthernetOneFace, PrincOpsUtils USING [BITAND, LowHalf], MPCodes USING [Code, ethernetHostChanged], ProcessorFace USING [SetMP]; EthernetOneHeadDorado: PROGRAM IMPORTS Basics, DeviceCleanup, DoradoInputOutput, PrincOpsUtils, ProcessorFace EXPORTS EthernetOneFace = BEGIN OPEN EthernetOneFace; OCSB: TYPE = LONG POINTER TO OutputControllerStatusBlock; OutputControllerStatusBlock: TYPE = MACHINE DEPENDENT RECORD [ next: ShortIOCB, interruptBit: WORD, minPacketSpacing: CARDINAL, <> last: IOCB]; -- last IOCB on output queue, valid if next#noIOCB ICSB: TYPE = LONG POINTER TO InputControllerStatusBlock; InputControllerStatusBlock: TYPE = MACHINE DEPENDENT RECORD [ next: ShortIOCB, interruptBit: WORD, host: WORD, -- if >=0, old-style single-host receive microcode will be used. missed: CARDINAL, <> last: IOCB, -- last IOCB on input queue, valid if next#noIOCB interstices: ARRAY [6..30B) OF WORD_NULL, -- hosts start 30B beyond next <> hosts: HostArray]; -- current set of hosts to which receiver code responds IOCB: TYPE = LONG POINTER TO IOControlBlock; ShortIOCB: TYPE = POINTER TO IOControlBlock; IOControlBlock: TYPE = MACHINE DEPENDENT RECORD [ next: ShortIOCB, completion: CompletionStatus, used: CARDINAL, -- input only load: CARDINAL, -- output only length: CARDINAL, buffer: LONG POINTER, <> direction: {input, output}, fill: [0..77777B] _ NULL]; CompletionStatus: TYPE = MACHINE DEPENDENT RECORD [ microcode (0: 0..7): {pending (0), done (1), bufferOverflow (2), loadOverflow (3)}, 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]; multiHosts: CARDINAL = 177777B; 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; noIOCB: ShortIOCB = LOOPHOLE[0]; <> <> Device: TYPE = RECORD [WORD]; Shorten: PROCEDURE [iocb: IOCB] RETURNS [ShortIOCB] = INLINE BEGIN <> RETURN[PrincOpsUtils.LowHalf[iocb]]; END; <> DeviceHandle: PUBLIC TYPE = Device; ControlBlockRecord: PUBLIC TYPE = IOControlBlock; <> nullDeviceHandle: PUBLIC DeviceHandle _ LOOPHOLE[123456B]; globalStateSize: PUBLIC CARDINAL _ 0; controlBlockSize: PUBLIC CARDINAL _ SIZE[IOControlBlock]; hearSelf: PUBLIC BOOLEAN _ TRUE; <> oCSB: OCSB = LOOPHOLE[LONG[177610B]]; iCSB: ICSB = LOOPHOLE[LONG[177600B]]; QueueOutput: PUBLIC PROCEDURE [ device: Device, buffer: LONG POINTER, length: CARDINAL, cb: IOCB] = BEGIN cb^ _ [next: noIOCB, completion: nullCompletion, used: 0, load: 0, length: length, buffer: buffer, direction: output]; IF oCSB.next # noIOCB THEN oCSB.last.next _ Shorten[cb]; IF oCSB.next = noIOCB AND cb.completion = nullCompletion THEN BEGIN oCSB.next _ Shorten[cb]; DoradoInputOutput.Output[enableOutput, control]; END; oCSB.last _ cb; END; QueueInput: PUBLIC PROCEDURE [ device: Device, buffer: LONG POINTER, length: CARDINAL, cb: IOCB] = BEGIN cb^ _ [next: noIOCB, completion: nullCompletion, used: 0, load: 0, length: length, buffer: buffer, direction: input]; IF iCSB.next # noIOCB THEN iCSB.last.next _ Shorten[cb]; IF iCSB.next = noIOCB AND cb.completion = nullCompletion THEN iCSB.next _ Shorten[cb]; iCSB.last _ cb; END; GetStatus: PUBLIC PROCEDURE [cb: IOCB] RETURNS [status: Status] = BEGIN OPEN cb.completion; RETURN[ SELECT microcode FROM pending => pending, done => SELECT cb.direction FROM input => IF PrincOpsUtils.BITAND[ LOOPHOLE[cb.completion], LOOPHOLE[inputErrorMask] ]=0 THEN ok ELSE SELECT TRUE FROM rxCollision => otherError, rxDataLate => overrun, rxCRCError => IF rxIncTrans THEN crcAndBadAlignment ELSE crc, rxIncTrans => badAlignmentButOkCrc, ENDCASE => otherError, output => IF PrincOpsUtils.BITAND[ LOOPHOLE[cb.completion], LOOPHOLE[outputErrorMask] ]=0 THEN ok ELSE SELECT TRUE FROM txCollision => tooManyCollisions, txDataLate => underrun, txFifoPE => otherError, ENDCASE => otherError, ENDCASE => otherError, bufferOverflow => packetTooLong, loadOverflow => tooManyCollisions, ENDCASE => otherError]; END; GetRetries: PUBLIC PROCEDURE [cb: IOCB] RETURNS [CARDINAL] = BEGIN RETURN[ SELECT cb.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]; END; GetPacketLength: PUBLIC PROCEDURE [cb: IOCB] RETURNS [CARDINAL] = BEGIN RETURN[cb.used]; END; GetPacketsMissed: PUBLIC PROCEDURE [device: Device] RETURNS [CARDINAL] = BEGIN RETURN[iCSB.missed]; END; nonNullDeviceHandle: DeviceHandle = LOOPHOLE[22334]; -- # nullDeviceHandle GetNextDevice: PUBLIC PROCEDURE [device: Device] RETURNS [Device] = BEGIN RETURN[IF device=nullDeviceHandle THEN nonNullDeviceHandle ELSE nullDeviceHandle]; END; GetEthernet1Address: PUBLIC PROCEDURE [device: Device] RETURNS [net: [0..256), host: HostAddress] = BEGIN RETURN[net: 0, host: Basics.HighByte[DoradoInputOutput.Input[control]]]; END; TurnOn: PUBLIC PROCEDURE [ device: Device, host: HostAddress, inInterrupt, outInterrupt: WORD, globalState: GlobalStatePtr] = BEGIN DoradoInputOutput.ResetEther[]; iCSB.next _ noIOCB; iCSB.interruptBit_inInterrupt; iCSB.missed_0; iCSB.last_NIL; <> <> IF iCSB.host#multiHosts THEN iCSB.host_host ELSE IF host = 0 THEN iCSB.hosts_ALL[TRUE] ELSE iCSB.hosts[host]_TRUE; oCSB^ _ [next: noIOCB, interruptBit: outInterrupt, last: NIL, <> minPacketSpacing: 500/32]; DoradoInputOutput.Output[enableInput, control]; END; TurnOff: PUBLIC PROCEDURE [device: Device] = BEGIN DoradoInputOutput.ResetEther[]; END; <> <> <> <> InputHosts: PUBLIC PROCEDURE [device: DeviceHandle, inputHosts: LONG POINTER TO HostArray] = { iCSB.hosts_inputHosts^; iCSB.host_multiHosts; }; -- enable multicast host array InputHost: PUBLIC PROCEDURE[device: DeviceHandle, host: HostAddress] = { iCSB.host_host; }; -- disable multicast host array, specify host. MulticastCapabilities: PUBLIC PROCEDURE[device: DeviceHandle] RETURNS [ canDo: BOOLEAN, multicastsEnabled: BOOLEAN] = { RETURN [ canDo: TRUE, multicastsEnabled: iCSB.host = multiHosts]; }; <> alreadyInitializedCleanup: BOOLEAN _ FALSE; savedICSB: InputControllerStatusBlock; savedOCSB: OutputControllerStatusBlock; AddCleanup: PUBLIC PROCEDURE [device: Device] = BEGIN OPEN DeviceCleanup; item: Item; originalHost: HostAddress _ GetEthernet1Address[device].host; IF alreadyInitializedCleanup THEN RETURN; alreadyInitializedCleanup _ TRUE; DO SELECT Await[@item] FROM kill => BEGIN DoradoInputOutput.ResetEther[]; END; turnOff => BEGIN DoradoInputOutput.ResetEther[]; savedICSB _ iCSB^; savedOCSB _ oCSB^; END; turnOn => BEGIN <> <> <> <> <> DoradoInputOutput.ResetEther[]; IF GetEthernet1Address[device].host#originalHost THEN ErrorHalt[MPCodes.ethernetHostChanged]; -- InLoaded on another machine? iCSB^ _ [ next: noIOCB, interruptBit: 0, host: savedICSB.host, hosts: savedICSB.hosts, <> missed: 0, last: NIL]; oCSB^ _ [ next: noIOCB, interruptBit: 0, minPacketSpacing: savedOCSB.minPacketSpacing, last: NIL]; DoradoInputOutput.Output[enableInput, control]; END; ENDCASE; ENDLOOP; END; RemoveCleanup: PUBLIC PROCEDURE [device: Device] = BEGIN END; ErrorHalt: PROC [code: MPCodes.Code] = INLINE { ProcessorFace.SetMP[code]; DO ENDLOOP }; <> ethernetHostChanged: MPCodes.Code = 933; <> END. -- EthernetOneHeadDorado. LOG Time: August 20, 1980 2:01 PM By: BLyon, Action: renamed EthernetFace and EthernetHeadD0 to EthernetOneFace and EthernetOneHeadD0, resp. Time: August 25, 1980 5:36 PM By: BLyon, Action: added [ ELSE h.board _ h.board + 1] clause to GetNextDevice. Time: September 4, 1980 11:02 PM By: HGM, Action: add hearSelf, use exported types. Time: September 14, 1980 6:36 AM By: HGM, Action: bug in bufferOverflow. Time: December 5, 1980 9:50 PM By: Taft, Action: convert for Dorado. 8-Jul-82 14:19:21 Taft Cleanup routine checks for Ethernet address changing at turnOn time. Time: September 17, 1982 1:08 pm By: Swinehart, Action: add multicast input Requires PilotEther microcode that knows about multicast as well.