SoftcardDataExchImpl.mesa
Copyright Ó 1987 by Xerox Corporation. All rights reserved.
written by Ch. Le Cocq, August 4, 1988
Christian Le Cocq November 22, 1988 10:51:21 am PST
Christophe Cuenod September 12, 1988 5:57:42 pm PDT
Packet exchange mechanism between CP (6085 mesa processor) and Sparc.
DIRECTORY
Basics USING [UnsafeBlock],
Process USING [Abort, Detach, PauseMsec, Milliseconds, InvalidProcess],
SoftcardBDVM,
SoftcardDataExch,
SoftcardUtil;
SoftcardDataExchImpl: CEDAR MONITOR
IMPORTS Process, SoftcardBDVM, SoftcardUtil
EXPORTS SoftcardDataExch
~ BEGIN
Types & Constants
Address: TYPE ~ SoftcardUtil.Address;
Block: TYPE ~ CARD32; -- local pointer to Block buffer
Header: TYPE ~ CARD32; -- local pointer to HeaderRec;
HeaderRec: TYPE ~ RECORD [
b: Block,
size: CARD32,
type: CARD32,
data1: CARD32,
data2: CARD32
];
Zone: TYPE ~ Address;
bufSize: CARD32 = 31096;
maxHeaders: CARD32 = 32;
IOZone: TYPE ~ LONG POINTER TO IOZoneRec;
IOZoneRec: TYPE ~ RECORD [
lastWrittenPacket,
lastRedPacket: Header,
headers: ARRAY[0..maxHeaders) OF HeaderRec,
buffer: PACKED ARRAY[0..bufSize) OF CHAR
];
lastWritten: CARD32 = 0;
lastRed: CARD32 = lastWritten+2;
headers: CARD32 = lastRed+2;
buffer: CARD32 = headers+SIZE[HeaderRec]*maxHeaders; --324
zoneSize: CARD32 = buffer+bufSize/2;
backDoorAddress: Address ← [1E2400h];
BiZone: TYPE ~ RECORD[hisZone, myZone: Zone];
data: BiZone ← [backDoorAddress, [backDoorAddress.a+zoneSize]];
watchingProcess: PROCESSNIL;
Utilities
Error: ERROR ~ CODE;
FillZones: PROC [w: UNSPECIFIED ← 0] ~ TRUSTED {
SoftcardUtil.FillZones[backDoorAddress, 2*zoneSize];
};
Restart: PUBLIC PROC ~ TRUSTED {
IF watchingProcess#NIL THEN Process.Abort[watchingProcess ! Process.InvalidProcess => CONTINUE];
FillZones[0];
watchingProcess ← FORK WatchPacketsIn[];
Process.Detach[watchingProcess];
};
GetLastRed: PROC [zone: Zone] RETURNS [h: Header] ~ TRUSTED INLINE {
RETURN[SoftcardUtil.GetCard32[[zone.a+lastRed]]];
};
GetLastWritten: PROC [zone: Zone] RETURNS [h: Header] ~ TRUSTED INLINE {
RETURN[SoftcardUtil.GetCard32[[zone.a+lastWritten]]];
};
PutLastRed: PROC [zone: Zone, h: Header] ~ TRUSTED INLINE {
SoftcardUtil.PutCard32[[zone.a+lastRed], h];
};
PutLastWritten: PROC [zone: Zone, h: Header] ~ TRUSTED INLINE {
SoftcardUtil.PutCard32[[zone.a+lastWritten], h];
};
GetHeaderRec: PROC [zone: Zone, h: Header] RETURNS [hr: HeaderRec] ~ TRUSTED {
base: CARD32 ← zone.a+headers+SIZE[HeaderRec]*h;
hr.b ← SoftcardUtil.GetCard32[[base]];
hr.size ← SoftcardUtil.GetCard32[[base+2]];
hr.type ← SoftcardUtil.GetCard32[[base+4]];
hr.data1 ← SoftcardUtil.GetCard32[[base+6]];
hr.data2 ← SoftcardUtil.GetCard32[[base+8]];
};
PutHeaderRec: PROC [zone: Zone, h: Header, b: Block, len, type, data1, data2: CARD32] ~ TRUSTED {
base: CARD32 ← zone.a+headers+SIZE[HeaderRec]*h;
SoftcardUtil.PutCard32[[base], b];
SoftcardUtil.PutCard32[[base+2], len];
SoftcardUtil.PutCard32[[base+4], type];
SoftcardUtil.PutCard32[[base+6], data1];
SoftcardUtil.PutCard32[[base+8], data2];
};
Packet out
outputWaitingTime: Process.Milliseconds ← 1; --ms
PutPacket: PUBLIC ENTRY PROC [type, data1, data2, len: CARD32 ← 0, pProc: SoftcardDataExch.PutProc] ~ {
h: Header;
done: CARD32 ← 0;
bufHead, bufTail: Block ← 0;
myLastWrittenPacket: Header ← GetLastWritten[data.myZone];
lastW: HeaderRec ← GetHeaderRec[data.myZone, myLastWrittenPacket];
prevSize: CARD32 ← lastW.size+(lastW.size MOD 2); -- round up to a word boundary
IF len>bufSize THEN Error; --oversized msg
h ← IF myLastWrittenPacket=maxHeaders-1 THEN 0 ELSE myLastWrittenPacket+1;
WHILE h=GetLastRed[data.hisZone] DO -- wait for a free header
Process.PauseMsec[ms: outputWaitingTime]
ENDLOOP;
bufHead ← IF lastW.b+prevSize>bufSize THEN lastW.b+prevSize-bufSize ELSE lastW.b+prevSize;
IF len>0 THEN {
bufTail ← IF bufHead+len>bufSize THEN bufHead+len-bufSize ELSE bufHead+len;
WHILE TouchSpace[data.myZone, GetLastRed[data.hisZone], myLastWrittenPacket, bufHead, bufTail] DO -- wait for some buffer space
Process.PauseMsec[ms: outputWaitingTime]
ENDLOOP;
};
PutHeaderRec[data.myZone, h, bufHead, len, type, data1, data2];
IF len>0 THEN {
DoAction: PROC [ub: Basics.UnsafeBlock] ~ {
IF pProc#NIL THEN done ← done+pProc[ub];
};
IF bufHead<=bufTail THEN {
realBase: CARD32 ← SoftcardBDVM.RealFromAddress[[data.myZone.a+buffer+bufHead/2]];
SoftcardBDVM.DoWithTranslation[realBase, len, DoAction]
}
ELSE {
realBase: CARD32 ← SoftcardBDVM.RealFromAddress[[data.myZone.a+buffer+bufHead/2]];
SoftcardBDVM.DoWithTranslation[realBase, bufSize-bufHead, DoAction];
realBase ← SoftcardBDVM.RealFromAddress[[data.myZone.a+buffer]];
SoftcardBDVM.DoWithTranslation[realBase, bufTail, DoAction];
};
};
PutLastWritten[data.myZone, h];
};
GetNextNonEmpty: PROC [z: Zone, h, hl: Header] RETURNS [findOne: BOOLEAN, nh: Header] ~ {
size: CARD32 ← 0;
WHILE size=0 DO
IF h=maxHeaders-1 THEN h ← 0 ELSE h ← h+1;
size ← GetHeaderRec[z, h].size;
IF h=hl THEN RETURN[FALSE, 0];
ENDLOOP;
RETURN [TRUE, h];
};
TouchSpace: PROC [z: Zone, h, hl: Header, head, tail: Block] RETURNS[OK: BOOLEAN] ~ {
checks that [head..tail) does not overlap target, with special care of the circularity
target: Block;
nh: Header;
findOne: BOOLEAN;
IF h=hl THEN RETURN[FALSE];
[findOne, nh] ← GetNextNonEmpty[z, h, hl];
IF NOT findOne THEN RETURN[FALSE];
target ← GetHeaderRec[z, nh].b;
IF tail<target THEN RETURN [FALSE]
ELSE RETURN [ head>tail];
};
Packets In
inputWaitingTime: Process.Milliseconds ← 1; --ms
WatchPacketsIn: PUBLIC PROC ~ {
Service daemon
DO
proc: SoftcardDataExch.ActionProc;
hVal: HeaderRec;
myLastRedPacket: Header ← GetLastRed[data.myZone];
h: Header ← IF myLastRedPacket=maxHeaders-1 THEN 0 ELSE myLastRedPacket+1;
WHILE GetLastWritten[data.hisZone]=myLastRedPacket DO Process.PauseMsec[ms: inputWaitingTime] ENDLOOP;
hVal ← GetHeaderRec[data.hisZone, h];
proc ← GetRegProc[hVal.type];
IF hVal.size #0 THEN {
DoAction: PROC [ub: Basics.UnsafeBlock] ~ {
IF proc#NIL THEN proc[ub, hVal.type, hVal.data1, hVal.data2];
};
bufHead: Block ← hVal.b;
bufTail: Block ← IF bufHead+hVal.size>bufSize THEN bufHead+hVal.size-bufSize ELSE bufHead+hVal.size;
IF bufHead<=bufTail THEN {
realBase: CARD32 ← SoftcardBDVM.RealFromAddress[[data.hisZone.a+buffer+bufHead/2]];
SoftcardBDVM.DoWithTranslation[realBase, hVal.size, DoAction];
}
ELSE {
realBase: CARD32 ← SoftcardBDVM.RealFromAddress[[data.hisZone.a+buffer+bufHead/2]];
SoftcardBDVM.DoWithTranslation[realBase, bufSize-bufHead, DoAction];
realBase ← SoftcardBDVM.RealFromAddress[[data.hisZone.a+buffer]];
SoftcardBDVM.DoWithTranslation[realBase, bufTail, DoAction];
};
}
ELSE IF proc#NIL THEN proc[[], hVal.type, hVal.data1, hVal.data2];
PutLastRed[data.myZone, h];
ENDLOOP;
};
typeMask: CARD32 = 31;
registration: ARRAY [0..typeMask] OF SoftcardDataExch.ActionProc;
GetRegProc: PROC [type: CARD32] RETURNS [a: SoftcardDataExch.ActionProc] ~ {
Description of the procedure.
a ← registration[type];
};
Register: PUBLIC PROC [type: CARD32, proc: SoftcardDataExch.ActionProc] ~ {
registration[type] ← proc;
};
END.