MapCacheCheckerImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Louis Monier December 22, 1987 11:42:06 am PST
DIRECTORY
BitOps, Core, CoreClasses, CoreCreate, CoreProperties, DynaBusInterface, FIFOQueue, Ports, MapCacheChecker, Rosemary, RosemaryUser;
MapCacheCheckerImpl:
CEDAR
PROGRAM
IMPORTS BitOps, CoreClasses, CoreCreate, DynaBusInterface, FIFOQueue, Ports, Rosemary
EXPORTS MapCacheChecker
= BEGIN OPEN MapCacheChecker;
Grant, Clock, Data, HeaderCycle: NAT ← LAST[NAT];
ROPE: TYPE = Core.ROPE;
Port: TYPE = Ports.Port;
Quad: TYPE = DynaBusInterface.Quad;
Cmd: TYPE = DynaBusInterface.Cmd;
qZero: Quad = BitOps.BitQWordZero;
mapCache: MC;
defaultFlags: [0..16)=12;
MC: TYPE = REF MCRec;
MCRec:
TYPE =
RECORD [
queue: FIFOQueue.Queue ← NIL,
regs: ARRAY Reg OF CARD,
table: ARRAY Byte OF Entry
];
Entry: TYPE = RECORD [valid: BOOL ← FALSE, vp, aid, rp, flags: CARD];
Byte: TYPE = [0..256);
WriteReg:
PUBLIC PROC [reg: Reg, data:
CARD] ~ {
mapCache.regs[reg] ← data;
};
ReadReg:
PUBLIC PROC [reg: Reg]
RETURNS [data:
CARD] ~ {
data ← mapCache.regs[reg];
};
WriteEntry:
PUBLIC
PROC [valid:
BOOL, vp, rp:
CARD, f: [0..16)]
RETURNS [ignored:
BOOL ←
FALSE] ~ {
h: Byte;
IF ~InSubset[vp] THEN RETURN[TRUE];
IF mapCache.regs[aidR]=0FFFFH OR InBypass[vp] THEN RETURN[];
h ← H[mapCache.regs[aidR], vp];
mapCache.table[h] ← [valid, vp, mapCache.regs[aidR], rp, f]; -- write in Cache
};
ReadEntry:
PUBLIC
PROC [vp:
CARD]
RETURNS [ignored, error:
BOOL ←
FALSE, rp:
CARD, f: [0..16)] ~ {
[ignored, error, rp, f] ← Map[vp, mapCache.regs[aidR]];
};
Map:
PUBLIC
PROC [vp, aid:
CARD]
RETURNS [ignored, error:
BOOL ←
FALSE, rp:
CARD, f: [0..16)] ~ {
h: Byte;
IF ~InSubset[vp] THEN RETURN[TRUE, FALSE, 0, 0];
SELECT
TRUE
FROM
aid=0FFFFH => RETURN[FALSE, FALSE, vp, defaultFlags];
InBypass[vp] => RETURN[FALSE, FALSE, Translated[vp], defaultFlags];
ENDCASE => {
entry: Entry;
aid ← IF InShared[vp] THEN 0 ELSE aid;
h ← H[aid, vp];
entry ← mapCache.table[h];
IF ~entry.valid OR aid#entry.aid THEN RETURN[FALSE, TRUE, 0, 0];
RETURN[FALSE, FALSE, entry.rp, entry.flags];
};
};
Translated:
PROC [vp:
CARD]
RETURNS [rp:
CARD] ~ {
RETURN[BitOps.
DOR[
BitOps.DAND[mapCache.regs[byB], mapCache.regs[byM]],
BitOps.DAND[vp, BitOps.DNOT[mapCache.regs[byM]]]]
];
};
InSubset:
PROC [vp:
CARD]
RETURNS [
BOOL] ~ {
RETURN[
BitOps.DAND[vp, mapCache.regs[vpM]]=
BitOps.DAND[mapCache.regs[vpP], mapCache.regs[vpM]]];
};
InBypass:
PROC [vp:
CARD]
RETURNS [
BOOL] ~ {
RETURN[
BitOps.DAND[vp, mapCache.regs[byM]]=
BitOps.DAND[mapCache.regs[byP], mapCache.regs[byM]]];
};
InShared:
PROC [vp:
CARD]
RETURNS [
BOOL] ~ {
RETURN[
BitOps.DAND[vp, mapCache.regs[shM]]=
BitOps.DAND[mapCache.regs[shP], mapCache.regs[shM]]];
};
H:
PROC [aid, vp:
CARD]
RETURNS [h: Byte] ~ {
w: CARD ← BitOps.DXOR[aid, vp];
h ← BitOps.WXOR[BitOps.ECFD[w, 16, 8], BitOps.ECFD[w, 24, 8]];
};
State: TYPE = REF StateRec;
StateRec:
TYPE =
RECORD [
thisCmd: Cmd,
thisResponse: ResponseRec,
cycleCount: CARDINAL ← 0,
grantM, grantS: BOOL,
alreadyChecked: BOOL
];
ResponseRec: TYPE = RECORD [header, data: Quad, ignoreData: BOOL ← FALSE];
checkerName:
ROPE = Rosemary.Register[roseClassName: "MapCacheChecker", init: Init, evalSimple: Simple, scheduleIfClockEval:
TRUE];
Create:
PUBLIC
PROC
RETURNS [ct: Core.CellType] = {
ct ← CoreClasses.CreateUnspecified[
name: checkerName,
public: CoreCreate.WireList[
name: "MapCacheChecker",
wrs: LIST["Grant", CoreCreate.Seq["Data", 64], "HeaderCycle", "Clock"]]
];
[] ← Rosemary.BindCellType[cellType: ct, roseClassName: checkerName];
[] ← Ports.InitPorts[ct, b, none, "Grant", "Clock"];
[] ← Ports.InitPorts[ct, l, none, "HeaderCycle"];
[] ← Ports.InitPorts[ct, ls, none, "Data"];
};
Init: Rosemary.InitProc = {
--PROC [cellType: Core.CellType, p: Ports.Port] RETURNS [stateAny: REF ANY ← NIL]--
state: State ← IF oldStateAny=NIL THEN NEW[StateRec] ELSE NARROW[oldStateAny];
InitPortIndicies[cellType];
mapCache ← NEW[MCRec];
mapCache.queue ← FIFOQueue.Create[];
state.cycleCount ← 0;
state.grantM ← FALSE;
state.grantS ← FALSE;
state.alreadyChecked ← FALSE;
stateAny ← state;
};
Simple: Rosemary.EvalProc = {
--PROC [p: Ports.Port, stateAny: REF ANY]--
state: State ← NARROW[stateAny];
header: BOOL ← p[HeaderCycle].l=H;
--delay Grant one clock cycle to make it easier to compare with header and data cycles
IF ~clockEval
THEN {
SELECT p[Clock].b
FROM
FALSE => state.grantM ← p[Grant].b;
TRUE => state.grantS ← state.grantM;
ENDCASE => ERROR;
};
IF clockEval THEN state.alreadyChecked ← FALSE;
IF clockEval OR p[Clock].b OR state.alreadyChecked THEN RETURN ELSE state.alreadyChecked ← TRUE;
IF state.cycleCount#0 AND ~state.grantS THEN ERROR; --Grant disappeared in middle of packet
IF header
AND state.grantS
THEN {
--begin new packet
IF state.cycleCount#0 THEN ERROR; --bogus HeaderCycle in middle of packet
state.thisResponse ← NARROW[FIFOQueue.Remove[mapCache.queue], REF ResponseRec]^;
state.thisCmd ← DynaBusInterface.ExtractCmd[LSToQ[p[Data].ls]];
state.cycleCount ← 2;
SELECT state.thisCmd
FROM
MapRply, IORRply, IOWRply => {
IF NOT QuadEqual[LSToQ[p[Data].ls], state.thisResponse.header] THEN ERROR;
};
ENDCASE => ERROR;
};
IF state.cycleCount#0
AND
NOT header
THEN {
SELECT state.thisCmd
FROM
MapRply, IORRply, IOWRply => {
IF ~(state.thisResponse.ignoreData OR QuadEqual[state.thisResponse.data, LSToQ[p[Data].ls]]) THEN ERROR;
};
ENDCASE => ERROR;
};
IF state.cycleCount#0 THEN state.cycleCount ← state.cycleCount-1;
};
LSToQ:
PROC [ls: Ports.LevelSequence]
RETURNS [q: Quad] ~ {
q ← IF Ports.HasX[ls] THEN qZero ELSE Ports.LSToQ[ls];
};
InitPortIndicies:
PROC [ct: Core.CellType] = {
[Grant, Data, HeaderCycle, Clock] ← Ports.PortIndexes[ct.public,
"Grant", "Data", "HeaderCycle", "Clock"];
};
ExpectReply:
PUBLIC
PROC [header, data: Quad, ignoreData:
BOOL ←
FALSE] ~ {
FIFOQueue.Include[mapCache.queue, NEW[ResponseRec ← [header, data, ignoreData]]];
};
IsEmpty:
PUBLIC
PROC
RETURNS [
BOOL] ~ {
RETURN[FIFOQueue.IsEmpty[mapCache.queue]];
};
QuadEqual:
PROC [q1, q2: Quad]
RETURNS [
BOOL ←
TRUE] ~ {
FOR i:
INT
IN[0..4)
DO
IF q1[i]#q2[i] THEN RETURN[FALSE];
ENDLOOP;
};
END.
PadRef: TYPE = REF PadRec;
PadRec: TYPE = RECORD [enableOut, enableIn, dataOut, dataIn, pad: NAT ← LAST[NAT]];
PadRoseClass: ROPE = RoseClass["Pad", PadInit, PadSimple];
Pad:
PUBLIC
PROC
RETURNS [ct: CellType] = {
ct ← Extract["PadAll.sch"];
-- bind to roseClass!!!
Ports.InitPorts[ct, l, none, "pad"]; -- bidirectionnal
Ports.InitPorts[ct, l, none, "enableOut", "enableIn", "dataIn"]; -- input
Ports.InitPorts[ct, l, none, "dataOut"]; -- output tristate
};
PadInit: Rosemary.InitProc = {
state: PadRef ← IF oldStateAny=NIL THEN NEW[PadRec] ELSE NARROW[oldStateAny];
[state.enableOut, state.enableIn, state.dataOut, state.dataIn, state.pad] ← Ports.PortIndexes[cellType.public, "enableOut", "enableIn", "dataOut", "dataIn", "pad"];
stateAny ← state;
};
PadSimple: Rosemary.EvalProc = {
state: PadRef ← NARROW[stateAny];
p[pad].d ← none;
SELECT p[enableOut].l
FROM
H => {p[pad].l ← p[dataOut].l; p[pad].d ← drive};
L => p[pad].d ← none;
ENDCASE => {p[pad].l ← X; p[pad].d ← drive};
SELECT p[enableIn].l
FROM
H => {p[dataIn].l ← p[pad].l; p[dataIn].d ← drive};
L => p[dataIn].d ← none;
ENDCASE => {p[dataIn].l ← X; p[dataIn].d ← drive};
};