NewEthernetHeadDorado.mesa, HGM, 19-Sep-82 19:14:40
fix GetRetries and GetStatus for 16 retries, DLionInputOutput cleanup too,
NewEthernetHeadDLion.mesa, HGM, 15-Mar-82 17:47:31
EthernetHeadDLion.mesa (last edited by: Sandman on: 18-Mar-81 17:20:56)
EthernetHeadDLion.mesa (last edited by: Blyon on: 22-Apr-81 17:43:34)
Willie-Sue, January 9, 1986 6:21:27 pm PST
Last Edited by: Willie-Sue, July 12, 1984 1:09:54 pm PDT
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;
These are the data structures that the microcode knows about. If some other module (for example, a diagnostic) ever needs this info, it should probably get split out into a separate module. For now, it is lumped in here to avoid cluttering up the world with yet another file.
If the first word of the HostNumber is all ones then the input mode is to accept all packets!!
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
The NS Ethernet uses TIOA = 26b as NSControl when output and as NSStatus when it is read. The data reg is TIOA=25b.
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];
EtherNetOne uses 177600B for input and 177610B for output
csb: CSB← LOOPHOLE[LONG[177700B]];
Shorten:
PROCEDURE [iocb:
IOCB]
RETURNS [ShortIocb] =
INLINE {
Maybe we should check to be sure that the high half is zero
RETURN[LOOPHOLE[PrincOpsUtils.LowHalf[iocb]]]};
Reset10MBEther:
PROC =
MACHINE
CODE
Reset 10 MB Ethernet hardware and tasks (should be in DoradoInputOutput) Does NOT turn on either the transmittor or the receiver
{ PrincOps.zMISC, 250B};
EXPORTed TYPEs
DeviceHandle: PUBLIC TYPE = RECORD [CARDINAL];
ControlBlockRecord: PUBLIC TYPE = IOControlBlock;
EXPORTed variables
nullDeviceHandle: PUBLIC DeviceHandle ← [123456B];
self: DeviceHandle = [0];
globalStateSize: PUBLIC CARDINAL ← 0;
controlBlockSize: PUBLIC CARDINAL ← SIZE[IOControlBlock];
hearSelf: PUBLIC BOOLEAN ← FALSE;
private stuff
the following HWMode values match those in PilotNSEther.mc, for turning on the 10MB receiver in either regular or loopback mode
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;
-- *+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*
Question--Question--Question--Question--Question--Question
It would be best to talk to Hal about the bad alignmend and dribble wehn we are allowing odd number of bytes. These translations may need to be changed so that the odd byte user has no problems it doing it properly and the normal user still sees an odd byte packet as an error.
-- *+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*
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;
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[]};
There is no way to remove a cleanup procedure yet, so we have a flag to avoid duplicates.
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 => {
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.
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.