CacheTester.mesa
Last Edited by: Barth, July 30, 1984 5:22:55 pm PDT
Last Edited by: Curry, February 1, 1985 9:15:04 am PST
DIRECTORY BitOps, Cache, CacheOps, Dragon, IO, Process, Rope, RoseEventsImpl, RoseRun, RoseTypes;
CacheTester: CEDAR MONITOR
IMPORTS BitOps, Cache, CacheOps, Dragon, IO, Process, Rope, RoseEventsImpl, RoseRun, RoseTypes
SHARES Cache =
BEGIN OPEN BitOps, IO;
BitsInDRegister: NAT = 186;
Phase: TYPE = [0..4);
QuadsPerEntry: NAT = 4;
QuadIndex: TYPE = [0..QuadsPerEntry);
QuadCount: TYPE = [0..QuadsPerEntry];
PhaseLetter: TYPE = {A, B, N};
QuadData: TYPE = ARRAY [0..4) OF Dragon.Word ← ALL[0];
WQData: TYPE = RECORD[
shared, match: BOOLFALSE,
wqNotReadyCount: NAT ← 0,
WQAddress: Dragon.Word ← 0,
WQData0, WQData1, WQData2, WQData3: Dragon.Word ← 0];
IOTrafficProc: TYPE = PROC[data: REF ANY];
ThreadProc: TYPE = PROC[data: REF ANY];
MCommandRef: TYPE = REF MCommandRec;
MCommandRec: TYPE = RECORD[
slave: BOOLFALSE,
arb, newRequest: BOOLFALSE, releaseBus: BOOLTRUE, refuseGrantCount: NAT ← 0,
wqCount: QuadCount ← 0, wqData: ARRAY QuadIndex OF WQData,
IOR, IOW: BOOLFALSE, IOAddress, IOData: Dragon.Word ← 0, IOTraffic: IOTrafficProc ← NIL, IOTrafficData: REF ANYNIL,
RQ, rqShared, rqMatch: BOOLFALSE, rqNotReadyCount: NAT ← 0, RQAddress, RQData0, RQData1, RQData2, RQData3: Dragon.Word ← 0,
WS: BOOLFALSE, WSAddress, WSData: Dragon.Word ← 0,
CF: BOOLFALSE, CFData: Dragon.Word ← 0];
PReferenceRef: TYPE = REF PReferenceRec;
PReferenceRec: TYPE = RECORD[
command: Dragon.PBusCommands,
address, data: Dragon.Word,
rejects: INT ← 0,
fault: Dragon.PBusFaults ← Dragon.None];
clockPhase: Phase;
cycleNumber: NAT;
pushWaitCount: NAT;
evalWaitCount: NAT;
evalCount: NAT;
threadCount: NAT ← 0;
pushWait: CONDITION;
evalWait: CONDITION;
entryEvalWait: CONDITION;
drive: REF Cache.CacheDrive;
instructions: Cache.CacheIORef;
handle: RoseTypes.CellTestHandle;
value: Cache.CacheIORef ← NEW[Cache.CacheIORec];
checkPParityB, checkMParityAB, checkDDataOutAB, checkPData, checkMNShared: BOOL;
killThreads, clocksSkewed: BOOL;
ignoreWarnings: BOOL;
EtuBrute: ERROR = CODE;
DoAReset: PROC = {
OPEN value;
Vdd ← TRUE;
Gnd ← FALSE;
PadVdd ← TRUE;
PadGnd ← FALSE;
drive.PData ← TRUE; PData ← [0,0]; checkPData ← TRUE;
drive.PParityB ← TRUE; PParityB ← FALSE;
PCmdA ← NoOp;
drive.PRejectB ← TRUE; PRejectB ← FALSE;
drive.PFaultB ← TRUE; PFaultB ← Dragon.None;
drive.PNPError ← TRUE; PNPError ← TRUE;
drive.MCmdAB ← TRUE; MCmdAB ← NoOp;
drive.MDataAB ← TRUE; MDataAB ← [0,0];
drive.MParityAB ← TRUE; MParityAB ← FALSE;
drive.MNShared ← TRUE; MNShared ← TRUE; checkMNShared ← FALSE;
drive.MNError ← TRUE; MNError ← TRUE;
MRq ← FALSE;
drive.MNewRq ← TRUE; MNewRq ← FALSE;
MGnt ← FALSE;
ResetAB ← TRUE;
DHoldAB ← FALSE;
DShiftAB ← FALSE;
DExecuteAB ← FALSE;
DNSelectAB ← TRUE;
DDataInAB ← FALSE;
checkDDataOutAB ← FALSE;
ignoreWarnings ← TRUE;
THROUGH [0..2) DO R[A]; R[]; R[B]; R[]; ENDLOOP;
ignoreWarnings ← FALSE;
drive.PData ← FALSE;
checkPParityB ← FALSE;
drive.PParityB ← FALSE;
drive.PRejectB ← FALSE;
drive.PFaultB ← FALSE;
drive.PNPError ← FALSE;
drive.MDataAB ← FALSE;
drive.MCmdAB ← FALSE;
drive.MNShared ← FALSE;
drive.MParityAB ← FALSE;
checkMParityAB ← FALSE;
drive.MNError ← FALSE;
drive.MNewRq ← FALSE;
ResetAB ← FALSE;
THROUGH [0..2) DO R[A]; R[]; R[B]; R[]; ENDLOOP;
};
MCommand: ThreadProc = {
masterCtl: MCommandRef ← NARROW [data];
{
OPEN value, masterCtl;
IF (slave AND (arb OR Dragon.MoreThanOneOf[wqCount>0, IOR, RQ, WS] OR wqCount>1)) OR (NOT slave AND CF) THEN ERROR;
IF arb THEN {
R[A];
R[];
P[B]; MRq ← TRUE; IF newRequest THEN MNewRq ← TRUE; E[];
R[];
R[A];
R[];
P[B]; MNewRq ← FALSE; E[];
R[];
THROUGH [0..refuseGrantCount) DO
P[A]; MGnt ← FALSE; E[];
R[];
R[B];
R[];
ENDLOOP;
P[A]; MGnt ← TRUE; E[];
R[];
P[B]; IF wqCount=0 AND NOT IOR AND NOT RQ AND WS AND NOT slave AND releaseBus THEN MRq ← FALSE; E[];
R[];
};
FOR i:QuadIndex IN [0..wqCount) DO
OPEN wqData[i];
IF slave THEN {drive.MCmdAB ← TRUE; drive.MDataAB ← TRUE; drive.MParityAB ← TRUE};
P[A]; MNShared ← TRUE; MCmdAB ← WriteQuad; SetMData[WQAddress]; checkMNShared ← TRUE; F[];
P[A]; MCmdAB ← DataTransport; SetMData[WQData0]; checkMParityAB ← TRUE; MNShared ← NOT shared; IF slave AND match THEN drive.MCmdAB ← FALSE ELSE {drive.MNShared ← TRUE; drive.MCmdAB ← TRUE}; F[];
drive.MNShared ← FALSE; checkMNShared ← FALSE;
THROUGH [0..wqNotReadyCount) DO
P[A]; MCmdAB ← NoOp; SetMData[WQData1]; checkMParityAB ← TRUE; F[];
ENDLOOP;
P[A]; MCmdAB ← DataTransport; SetMData[WQData1]; F[];
P[A]; SetMData[WQData2]; F[];
P[A]; SetMData[WQData3]; F[]; checkMParityAB ← FALSE;
IF slave THEN {drive.MCmdAB ← TRUE; MCmdAB ← NoOp; E[]; drive.MCmdAB ← FALSE; drive.MDataAB ← FALSE; drive.MParityAB ← FALSE};
ENDLOOP;
IF IOR THEN {
dropGrant: BOOLNOT slave AND NOT RQ AND NOT WS AND releaseBus;
P[A]; MCmdAB ← IORead; SetMData[IOAddress]; F[];
IF IOTraffic#NIL THEN IOTraffic[IOTrafficData];
P[A]; drive.MCmdAB ← TRUE; MCmdAB ← IOReadDone; drive.MDataAB ← TRUE; SetMData[IOData]; F[]; drive.MCmdAB ← FALSE; drive.MDataAB ← FALSE;
P[A]; MCmdAB ← NoOp; E[]; R[]; P[B]; IF dropGrant THEN MRq ← FALSE; E[]; R[];
P[A]; F[];
P[A]; IF dropGrant THEN MGnt ← FALSE; E[]; R[]; P[B]; IF NOT RQ AND WS AND NOT slave AND releaseBus THEN MRq ← FALSE; E[]; R[];
};
IF RQ THEN {
dropGrant: BOOLNOT slave AND NOT WS AND releaseBus;
P[A]; IF slave THEN {drive.MCmdAB ← TRUE; drive.MDataAB ← TRUE}; MCmdAB ← ReadQuad; SetMData[RQAddress]; MNShared ← TRUE; checkMNShared ← TRUE; F[];
P[A]; MCmdAB ← NoOp; MNShared ← NOT rqShared; IF slave AND rqMatch THEN drive.MCmdAB ← FALSE ELSE {drive.MNShared ← TRUE; drive.MCmdAB ← TRUE}; F[];
drive.MNShared ← FALSE; checkMNShared ← FALSE;
THROUGH [0..rqNotReadyCount) DO
P[A]; MCmdAB ← NoOp; F[];
ENDLOOP;
P[A]; IF slave AND rqShared THEN drive.MDataAB ← FALSE ELSE {drive.MDataAB ← TRUE; drive.MParityAB ← TRUE}; MCmdAB ← DataTransport; SetMData[RQData0]; checkMParityAB ← TRUE; F[];
P[A]; SetMData[RQData1]; E[]; R[]; P[B]; IF dropGrant THEN MRq ← FALSE; E[]; R[];
P[A]; SetMData[RQData2]; F[];
P[A]; SetMData[RQData3]; IF dropGrant THEN MGnt ← FALSE; E[]; R[]; P[B]; IF WS AND NOT slave AND releaseBus THEN MRq ← FALSE; E[]; R[]; IF slave THEN {drive.MCmdAB ← TRUE; MCmdAB ← NoOp; E[]}; drive.MDataAB ← FALSE; drive.MCmdAB ← FALSE; drive.MParityAB ← FALSE; checkMParityAB ← FALSE;
};
IF WS THEN {
dropGrant: BOOLNOT slave AND releaseBus;
P[A]; IF slave THEN {drive.MCmdAB ← TRUE; drive.MDataAB ← TRUE; drive.MParityAB ← TRUE}; MCmdAB ← WriteSingle; SetMData[WSAddress]; F[];
P[A]; MCmdAB ← DataTransport; SetMData[WSData]; checkMParityAB ← TRUE; IF dropGrant THEN MGnt ← FALSE; F[]; IF slave THEN {MCmdAB ← NoOp; E[]}; drive.MDataAB ← FALSE; drive.MCmdAB ← FALSE; drive.MParityAB ← FALSE; checkMParityAB ← FALSE;
};
IF IOW THEN {
P[A]; MCmdAB ← IOWrite; SetMData[IOAddress]; F[];
IF IOTraffic#NIL THEN {
P[A]; drive.MCmdAB ← TRUE; MCmdAB ← NoOp; SetMData[IOData]; F[]; drive.MCmdAB ← FALSE;
IOTraffic[IOTrafficData];
P[A]; drive.MCmdAB ← TRUE; MCmdAB ← IOWriteDone; F[]; drive.MCmdAB ← FALSE;
}
ELSE {
P[A]; drive.MCmdAB ← TRUE; MCmdAB ← IOWriteDone; SetMData[IOData]; F[]; drive.MCmdAB ← FALSE;
};
P[A]; MCmdAB ← NoOp; E[]; R[]; P[B]; IF releaseBus THEN MRq ← FALSE; E[]; R[];
P[A]; F[];
P[A]; IF releaseBus THEN MGnt ← FALSE; E[]; R[]; R[B]; R[];
};
IF NOT (slave OR IOR OR RQ OR WS OR IOW) AND releaseBus THEN {
R[A]; R[]; P[B]; MRq ← FALSE; E[]; R[];
R[A]; R[]; R[B]; R[];
P[A]; MGnt ← FALSE; F[]; drive.MCmdAB ← TRUE; MCmdAB ← NoOp; E[]; drive.MCmdAB ← FALSE;
};
IF CF THEN {
P[A]; drive.MCmdAB ← TRUE; drive.MDataAB ← TRUE; MCmdAB ← ChangeFlags; SetMData[CFData]; F[]; IF slave THEN {MCmdAB ← NoOp; E[]}; drive.MDataAB ← FALSE; drive.MCmdAB ← FALSE;
P[A]; MCmdAB ← NoOp; F[];
};
};
};
PReference: ThreadProc = {
pRefCtl: PReferenceRef ← NARROW [data];
{
OPEN value, pRefCtl;
fetch: BOOL ← command=Fetch OR command=FetchHold OR command=IOFetch OR command=IOFetchHold;
store: BOOL ← command=Store OR command=StoreHold OR command=IOStore OR command=IOStoreHold;
P[A]; PNPError ← TRUE; PRejectB ← FALSE; PFaultB ← Dragon.None; E[]; PData ← ILID[address, PData, 32, 0, 32]; drive.PData ← TRUE; checkPData ← TRUE; PCmdA ← command; E[];
R[]; IF fetch THEN drive.PData ← FALSE; PCmdA ← NoOp; E[];
P[B]; IF rejects>0 THEN {PRejectB ← TRUE; IF fetch THEN checkPData ← FALSE} ELSE {PRejectB ← FALSE; IF fetch THEN {checkPParityB ← TRUE; SetPData[data]}}; E[]; IF store THEN {checkPParityB ← TRUE; drive.PParityB ← TRUE; SetPData[data]}; E[];
R[]; checkPParityB ← FALSE; IF store THEN {drive.PData ← FALSE; drive.PParityB ← FALSE};
IF rejects=0 THEN RETURN;
THROUGH [0..rejects-2) DO
P[A]; PRejectB ← FALSE; E[];
R[];
P[B]; PRejectB ← TRUE; E[];
R[];
ENDLOOP;
P[A]; PRejectB ← FALSE; E[];
R[];
P[B]; PRejectB ← TRUE; PFaultB ← fault; E[];
R[];
P[A]; PRejectB ← FALSE; PFaultB ← Dragon.None; E[];
IF fault#Dragon.None THEN RETURN;
R[];
P[B]; IF fetch THEN {checkPData ← TRUE; SetPData[data]; IF command=Fetch THEN checkPParityB ← TRUE}; E[];
R[]; checkPParityB ← FALSE;
};
};
ThreadStart: PROC[thread:ThreadProc, data: REF ANYNIL] = TRUSTED {
ThreadUp[];
Process.Detach[FORK ThreadFork[thread, data]];
};
ThreadFork: PROC[thread:ThreadProc, data: REF ANY] = {
{
thread[data
! UNWIND, EtuBrute => GOTO quit]
EXITS
quit => NULL;
};
ThreadDown[];
};
ThreadUp: ENTRY PROC = {
threadCount ← threadCount + 1;
};
ThreadDown: ENTRY PROC = {
threadCount ← threadCount - 1;
NOTIFY pushWait;
NOTIFY entryEvalWait;
};
P: ENTRY PROC [phase: PhaseLetter ← N] = {
OPEN value;
waitPhase: Phase ← clockPhase;
newPhase: Phase ← (clockPhase + 1) MOD 4;
IF (phase=A AND newPhase#0) OR (phase=B AND newPhase#2) OR (phase=N AND (newPhase#1 AND newPhase#3)) THEN {
clocksSkewed ← TRUE;
Kick[];
RETURN WITH ERROR EtuBrute;
};
pushWaitCount ← pushWaitCount + 1;
NOTIFY entryEvalWait;
WHILE waitPhase=clockPhase DO
IF pushWaitCount=threadCount THEN {
clockPhase ← (clockPhase + 1) MOD 4;
SELECT clockPhase FROM
0 => {PhA ← TRUE; cycleNumber ← cycleNumber + 1};
1 => PhA ← FALSE;
2 => PhB ← TRUE;
3 => PhB ← FALSE;
ENDCASE => ERROR;
pushWaitCount ← 0;
BROADCAST pushWait;
RETURN;
};
WAIT pushWait;
IF killThreads THEN RETURN WITH ERROR EtuBrute;
ENDLOOP;
};
E: ENTRY PROC = {
waitCount: NAT ← evalCount;
evalWaitCount ← evalWaitCount + 1;
NOTIFY entryEvalWait;
WHILE waitCount=evalCount DO
WAIT evalWait;
IF killThreads THEN RETURN WITH ERROR EtuBrute;
ENDLOOP;
};
EntryEval: ENTRY PROC = {
UNTIL evalWaitCount+pushWaitCount=threadCount AND evalWaitCount>0 DO
IF threadCount=0 THEN RETURN;
WAIT entryEvalWait;
IF killThreads THEN RETURN WITH ERROR EtuBrute;
ENDLOOP;
ReallyEval[!UNWIND => Kick[]];
};
ReallyEval: INTERNAL PROC = {
OPEN value;
instructions.PhA ← PhA;
instructions.PhB ← PhB;
instructions.Vdd ← Vdd;
instructions.Gnd ← Gnd;
instructions.PadVdd ← PadVdd;
instructions.PadGnd ← PadGnd;
IF drive.PData THEN instructions.PData ← PData;
IF drive.PParityB THEN instructions.PParityB ← PParityB;
instructions.PCmdA ← PCmdA;
IF drive.PRejectB THEN instructions.PRejectB ← PRejectB;
IF drive.PFaultB THEN instructions.PFaultB ← PFaultB;
IF drive.PNPError THEN instructions.PNPError ← PNPError;
IF drive.MDataAB THEN instructions.MDataAB ← MDataAB;
IF drive.MCmdAB THEN instructions.MCmdAB ← MCmdAB;
IF drive.MNShared THEN instructions.MNShared ← MNShared;
IF drive.MParityAB THEN instructions.MParityAB ← MParityAB;
IF drive.MNError THEN instructions.MNError ← MNError;
IF drive.MNewRq THEN instructions.MNewRq ← MNewRq;
instructions.MGnt ← MGnt;
instructions.ResetAB ← ResetAB;
instructions.DHoldAB ← DHoldAB;
instructions.DShiftAB ← DShiftAB;
instructions.DExecuteAB ← DExecuteAB;
instructions.DNSelectAB ← DNSelectAB;
instructions.DDataInAB ← DDataInAB;
[] ← RoseRun.Eval[handle
! Dragon.AssertionFailed => IF ignoreWarnings THEN RESUME ELSE REJECT;
RoseTypes.Stop => IF data = $FailedAssertion AND ignoreWarnings THEN RESUME ELSE REJECT;
RoseEventsImpl.Warning => IF ignoreWarnings THEN RESUME ELSE REJECT];
IF checkPData AND instructions.PData#PData THEN Complain["PData"];
IF checkPParityB AND instructions.PParityB#PParityB THEN Complain["PParityB"];
IF instructions.PRejectB#PRejectB THEN Complain["PRejectB"];
IF instructions.PFaultB#PFaultB THEN Complain["PFaultB"];
IF instructions.PNPError#PNPError THEN Complain["PNPError"];
IF instructions.MDataAB#MDataAB THEN Complain["MDataAB"];
IF instructions.MCmdAB#MCmdAB THEN Complain["MCmdAB"];
IF checkMNShared AND instructions.MNShared#MNShared THEN Complain["MNShared"];
IF checkMParityAB AND instructions.MParityAB#MParityAB THEN Complain["MParityAB"];
IF instructions.MNError#MNError THEN Complain["MNError"];
IF instructions.MRq#MRq THEN Complain["MRq"];
IF instructions.MNewRq#MNewRq THEN Complain["MNewRq"];
IF checkDDataOutAB AND instructions.DDataOutAB#DDataOutAB THEN Complain["DDataOutAB"];
evalWaitCount ← 0;
evalCount ← evalCount + 1;
BROADCAST evalWait;
};
F: PROC={E[];R[];R[B];R[]};
R: PROC [phase: PhaseLetter ← N] = {P[phase];E[]};
C: PROC [cycleCount: NAT ← 1] = {
THROUGH [0..cycleCount) DO R[A]; R[]; R[B]; R[]; ENDLOOP};
Complain: PROC [r: ROPE] = {IF NOT ignoreWarnings THEN RoseTypes.Stop[Rope.Concat[r, PutFR[" in cycle %g phase %g", int[cycleNumber], int[clockPhase]]], $FailedAssertion]};
SetMData: PROC[dw: Dragon.Word] = {
value.MDataAB ← ILID[dw, value.MDataAB, 32, 0, 32];
value.MParityAB ← CacheOps.Parity32[dw];
};
SetPData: PROC[dw: Dragon.Word] = {
value.PData ← ILID[dw, value.PData, 32, 0, 32];
value.PParityB ← CacheOps.Parity32[dw];
};
Kick: INTERNAL PROC = {
killThreads ← TRUE;
BROADCAST pushWait;
BROADCAST evalWait;
BROADCAST entryEvalWait;
};
END.