CacheTester.mesa
Last Edited by: Barth, May 31, 1984 5:09:34 pm PDT
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);
PhaseLetter: TYPE = {A, B, N};
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,
WQ, WQNoOp: BOOLFALSE, wqNotReadyCount: NAT ← 0, WQAddress, WQData0, WQData1, WQData2, WQData3: Dragon.Word ← 0,
IOR, IOW, IONoOp: BOOLFALSE, IOAddress, IOData: Dragon.Word ← 0, IOTraffic: IOTrafficProc ← NIL, IOTrafficData: REF ANYNIL,
RQ, RQNoOp, shared: BOOLFALSE, rqNotReadyCount: NAT ← 0, RQAddress, RQData0, RQData1, RQData2, RQData3: Dragon.Word ← 0,
WS, WSNoOp: 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 ← 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, checkMParityBA, checkDDataOutAB, checkPData, checkMNShared: BOOL;
killThreads, clocksSkewed: BOOL;
ignoreWarnings: BOOL;
EtuBrute: ERROR = CODE;
CacheTest: Cache.CacheTester = {
priority: Process.Priority ← Process.GetPriority[];
clocksSkewed ← FALSE;
{
Process.SetPriority[Process.priorityBackground];
ReallyCacheTest[i, d, h
! UNWIND => Process.SetPriority[priority];
EtuBrute => GOTO quit];
EXITS
quit => NULL;
};
Process.SetPriority[priority];
IF clocksSkewed THEN Complain["clocks out of sync"];
};
ReallyCacheTest: Cache.CacheTester = {
OPEN value;
clockPhase ← 3;
cycleNumber ← 0;
pushWaitCount ← 0;
evalWaitCount ← 0;
evalCount ← 0;
drive ← d;
instructions ← i;
handle ← h;
killThreads ← FALSE;
ignoreWarnings ← FALSE;
Invariant: Each thread always calls P before changing anything in value or drive. All threads must have called P before P actually advances the clock and lets the evaluation procede. E only executes when all threads are hung on P or E.
UNTIL threadCount=0 DO
Process.Yield[];
ENDLOOP;
PhA ← FALSE;
PhB ← FALSE;
ThreadStart[MainThread];
UNTIL threadCount=0 DO
EntryEval[];
ENDLOOP;
};
MainThread: ThreadProc = {
OPEN value;
DoAReset[];
R[A]; R[];
ThreadStart[MCommand, NEW[MCommandRec ← [slave: TRUE, WQ: TRUE, WQAddress: 0, WQData0: 1, WQData1: 2, WQData2: 3, WQData3: 4]]];
THROUGH [0..5) DO R[B]; R[]; R[A]; R[]; ENDLOOP;
ThreadStart[MCommand, NEW[MCommandRec ← [slave: TRUE, RQ: TRUE, RQAddress: 5, RQData0: 6, RQData1: 7, RQData2: 8, RQData3: 9]]];
THROUGH [0..6) DO R[B]; R[]; R[A]; R[]; ENDLOOP;
ThreadStart[MCommand, NEW[MCommandRec ← [slave: TRUE, WS: TRUE, WSAddress: 10, WSData: 11]]];
THROUGH [0..2) DO R[B]; R[]; R[A]; R[]; ENDLOOP;
ThreadStart[MCommand, NEW[MCommandRec ← [slave: TRUE, CF: TRUE, CFData: 12]]];
THROUGH [0..2) DO R[B]; R[]; R[A]; R[]; ENDLOOP;
R[B]; R[];
ThreadStart[PReference, NEW[PReferenceRec ← [command: IOFetchHold, address: 2, data: 00060001H, rejects: 5]]]; R[A]; R[];
ThreadStart[MCommand, NEW[MCommandRec ← [arb: TRUE, releaseBus: FALSE, IOR: TRUE, IOAddress: 2, IOData: 00060001H]]];
R[B]; R[]; R[A]; R[]; R[B]; R[]; R[A]; R[]; -- arbitrate
R[B]; R[]; R[A]; R[]; R[B]; R[]; R[A]; R[]; -- io
R[B]; R[]; R[A]; R[]; R[B]; R[];
ThreadStart[PReference, NEW[PReferenceRec ← [command: IOStoreHold, address: 3, data: 00070001H, rejects: 4]]]; R[A]; R[]; R[B]; R[]; R[A]; R[];
ThreadStart[MCommand, NEW[MCommandRec ← [releaseBus: FALSE, IOW: TRUE, IOAddress: 3, IOData: 00070001H]]];
R[B]; R[]; R[A]; R[]; R[B]; R[]; R[A]; R[]; -- io
R[B]; R[]; R[A]; R[]; R[B]; R[];
ThreadStart[PReference, NEW[PReferenceRec ← [command: IOFetch, address: 4, data: 00080001H, rejects: 4]]]; R[A]; R[]; R[B]; R[]; R[A]; R[];
ThreadStart[MCommand, NEW[MCommandRec ← [IOR: TRUE, IOAddress: 4, IOData: 00080001H]]];
R[B]; R[]; R[A]; R[]; R[B]; R[]; R[A]; R[]; -- io
R[B]; R[]; R[A]; R[]; R[B]; R[]; R[A]; R[]; R[B]; R[]; -- release bus
ThreadStart[PReference, NEW[PReferenceRec ← [command: Store, address: 1, data: 2, rejects: 15]]];
R[A];
R[];
ThreadStart[MCommand, NEW[MCommandRec ← [arb: TRUE, IOR: TRUE, IOAddress: 0C0H, IOData:00010000H, RQ: TRUE, rqNotReadyCount: 2, shared: TRUE, RQAddress:00010001H, RQData0: 00020001H, RQData1: 00020002H, RQData2: 00020003H, RQData3: 00020004H, WS: TRUE, WSAddress:00010001H, WSData:02H]]];
THROUGH [0..16) DO R[B]; R[]; R[A]; R[]; ENDLOOP;
P[B]; drive.MCmdBA ← TRUE; MCmdBA ← NoOp; MNShared ← TRUE; F[]; drive.MCmdBA ← FALSE;
R[B]; R[];
ThreadStart[PReference, NEW[PReferenceRec ← [command: Fetch, address: 1, data: 2]]]; R[A]; R[]; R[B]; R[];
ThreadStart[PReference, NEW[PReferenceRec ← [command: Fetch, address: 0, data: 00020004H]]]; R[A]; R[]; R[B]; R[];
ThreadStart[PReference, NEW[PReferenceRec ← [command: Fetch, address: 2, data: 00020002H]]]; R[A]; R[]; R[B]; R[];
ThreadStart[PReference, NEW[PReferenceRec ← [command: Fetch, address: 3, data: 00020003H]]]; R[A]; R[]; R[B]; R[];
ThreadStart[PReference, NEW[PReferenceRec ← [command: Fetch, address: 4, data: 00040000H, rejects: 5]]]; R[A]; R[];
ThreadStart[MCommand, NEW[MCommandRec ← [arb: TRUE, RQ: TRUE, RQAddress:00010004H, RQData0: 00040000H, RQData1: 00040001H, RQData2: 00040002H, RQData3: 00040003H]]];
THROUGH [0..8) DO R[B]; R[]; R[A]; R[]; ENDLOOP;
P[B]; drive.MCmdBA ← TRUE; MCmdBA ← NoOp; E[]; R[]; drive.MCmdBA ← FALSE;
ThreadStart[PReference, NEW[PReferenceRec ← [command: FetchHold, address: 6, data: 00040002H, rejects: 3]]]; R[A]; R[];
ThreadStart[MCommand, NEW[MCommandRec ← [arb: TRUE, releaseBus: FALSE]]];
R[B]; R[]; R[A]; R[]; R[B]; R[]; R[A]; R[];
drive.MCmdBA ← TRUE; MCmdBA ← Reserve14; E[]; drive.MCmdBA ← FALSE;
P[B]; MCmdBA ← NoOp; E[]; R[]; R[A]; R[]; R[B]; R[];
ThreadStart[PReference, NEW[PReferenceRec ← [command: Store, address: 6, data: 00040012H]]]; R[A]; R[]; R[B]; R[];
ThreadStart[PReference, NEW[PReferenceRec ← [command: StoreHold, address: 6, data: 00040112H, rejects: 3]]]; R[A]; R[];
ThreadStart[MCommand, NEW[MCommandRec ← [arb: TRUE, newRequest: TRUE, releaseBus: FALSE]]];
R[B]; R[]; R[A]; R[]; R[B]; R[]; R[A]; R[];
drive.MCmdBA ← TRUE; MCmdBA ← Reserve14; E[]; drive.MCmdBA ← FALSE;
P[B]; MCmdBA ← NoOp; E[]; R[]; R[A]; R[]; R[B]; R[];
ThreadStart[PReference, NEW[PReferenceRec ← [command: Fetch, address: 6, data: 00040112H]]]; R[A]; R[]; R[B]; R[];
R[A]; R[]; ThreadStart[MCommand, NEW[MCommandRec ← []]];
R[B]; R[]; R[A]; R[]; R[B]; R[]; R[A]; R[];
P[B]; drive.MCmdBA ← TRUE; MCmdBA ← NoOp; MNShared ← TRUE; E[]; drive.MCmdBA ← FALSE; R[];
ThreadStart[PReference, NEW[PReferenceRec ← [command: Fetch, address: 8, data: 00080000H, rejects: 5]]]; R[A]; R[];
ThreadStart[MCommand, NEW[MCommandRec ← [arb: TRUE, RQ: TRUE, RQAddress:00010008H, RQData0: 00080000H, RQData1: 00080001H, RQData2: 00080002H, RQData3: 00080003H]]];
THROUGH [0..8) DO R[B]; R[]; R[A]; R[]; ENDLOOP;
P[B]; drive.MCmdBA ← TRUE; MCmdBA ← NoOp; E[]; R[]; drive.MCmdBA ← FALSE;
ThreadStart[PReference, NEW[PReferenceRec ← [command: Fetch, address: 0CH, data: 000C0000H, rejects: 5]]]; R[A]; R[];
ThreadStart[MCommand, NEW[MCommandRec ← [arb: TRUE, RQ: TRUE, RQAddress:0001000CH, RQData0: 000C0000H, RQData1: 000C0001H, RQData2: 000C0002H, RQData3: 000C0003H]]];
THROUGH [0..8) DO R[B]; R[]; R[A]; R[]; ENDLOOP;
P[B]; drive.MCmdBA ← TRUE; MCmdBA ← NoOp; E[]; R[]; drive.MCmdBA ← FALSE;
ThreadStart[PReference, NEW[PReferenceRec ← [command: Fetch, address: 10H, data: 00100000H, rejects: 13]]]; R[A]; R[];
ThreadStart[MCommand, NEW[MCommandRec ← [arb: TRUE, WQ: TRUE, wqNotReadyCount: 3, WQAddress: 00010000H, WQData0: 00020004H, WQData1: 00000002H, WQData2: 00020002H, WQData3: 00020003H, RQ: TRUE, RQAddress:00010010H, RQData0: 00100000H, RQData1: 00100001H, RQData2: 00100002H, RQData3: 00100003H]]];
THROUGH [0..16) DO R[B]; R[]; R[A]; R[]; ENDLOOP;
P[B]; drive.MCmdBA ← TRUE; MCmdBA ← NoOp; E[]; R[]; drive.MCmdBA ← FALSE;
ThreadStart[PReference, NEW[PReferenceRec ← [command: Fetch, address: 14H, data: 00140000H, rejects: 10]]]; R[A]; R[];
ThreadStart[MCommand, NEW[MCommandRec ← [arb: TRUE, WQ: TRUE, WQAddress: 00010004H, WQData0: 00040000H, WQData1: 00040001H, WQData2: 00040112H, WQData3: 00040003H, RQ: TRUE, RQAddress:00010014H, RQData0: 00140000H, RQData1: 00140001H, RQData2: 00140002H, RQData3: 00140003H]]];
THROUGH [0..13) DO R[B]; R[]; R[A]; R[]; ENDLOOP;
P[B]; drive.MCmdBA ← TRUE; MCmdBA ← NoOp; E[]; R[]; drive.MCmdBA ← FALSE;
ThreadStart[PReference, NEW[PReferenceRec ← [command: Fetch, address: 18H, data: 00180000H, rejects: 5]]]; R[A]; R[];
ThreadStart[MCommand, NEW[MCommandRec ← [arb: TRUE, RQ: TRUE, RQAddress:00010018H, RQData0: 00180000H, RQData1: 00180001H, RQData2: 00180002H, RQData3: 00180003H]]];
THROUGH [0..8) DO R[B]; R[]; R[A]; R[]; ENDLOOP;
P[B]; drive.MCmdBA ← TRUE; MCmdBA ← NoOp; E[]; R[]; drive.MCmdBA ← FALSE;
R[A]; R[];
ThreadStart[MCommand, NEW[MCommandRec ← [slave: TRUE, WQ: TRUE, WQAddress: 00010018H, WQData0: 00190001H, WQData1: 00190002H, WQData2: 00190003H, WQData3: 00190004H]]];
THROUGH [0..5) DO R[B]; R[]; R[A]; R[]; ENDLOOP;
ThreadStart[MCommand, NEW[MCommandRec ← [slave: TRUE, RQ: TRUE, shared: TRUE, RQAddress: 00010018H, RQData0: 00190001H, RQData1: 00190002H, RQData2: 00190003H, RQData3: 00190004H]]];
THROUGH [0..6) DO R[B]; R[]; R[A]; R[]; ENDLOOP;
ThreadStart[MCommand, NEW[MCommandRec ← [slave: TRUE, WS: TRUE, WSAddress: 00010018H, WSData: 00200001H]]];
THROUGH [0..2) DO R[B]; R[]; R[A]; R[]; ENDLOOP;
ThreadStart[MCommand, NEW[MCommandRec ← [slave: TRUE, RQ: TRUE, shared: TRUE, RQAddress: 00010018H, RQData0: 00200001H, RQData1: 00190002H, RQData2: 00190003H, RQData3: 00190004H]]];
THROUGH [0..6) DO R[B]; R[]; R[A]; R[]; ENDLOOP;
ThreadStart[MCommand, NEW[MCommandRec ← [slave: TRUE, CF: TRUE, CFData: 00010000H]]];
THROUGH [0..2) DO R[B]; R[]; R[A]; R[]; ENDLOOP;
R[B]; R[];
ThreadStart[PReference, NEW[PReferenceRec ← [command: Store, address: 1, data: 2, rejects: 6, fault: WriteProtectFault]]];
R[A]; R[];
ThreadStart[MCommand, NEW[MCommandRec ← [arb: TRUE, IOR: TRUE, IOAddress: 0C0H, IOData:00000002H]]];
THROUGH [0..6) DO R[B]; R[]; R[A]; R[]; ENDLOOP;
R[B]; R[];
ThreadStart[PReference, NEW[PReferenceRec ← [command: IOFetch, address: 0, data: 00050000H, rejects: 5]]]; R[A]; R[];
ThreadStart[MCommand, NEW[MCommandRec ← [arb: TRUE, IOR: TRUE, IOAddress: 0, IOData: 00050000H]]];
R[B]; R[]; R[A]; R[]; R[B]; R[]; R[A]; R[]; -- arbitrate
R[B]; R[]; R[A]; R[]; R[B]; R[]; R[A]; R[]; -- io
R[B]; R[]; R[A]; R[]; R[B]; R[]; R[A]; R[]; -- release bus
R[B]; R[];
ThreadStart[PReference, NEW[PReferenceRec ← [command: IOStore, address: 2, data: 00050001H, rejects: 5]]]; R[A]; R[];
ThreadStart[MCommand, NEW[MCommandRec ← [arb: TRUE, IOW: TRUE, IOAddress: 2, IOData: 00050001H]]];
R[B]; R[]; R[A]; R[]; R[B]; R[]; R[A]; R[]; -- arbitrate
R[B]; R[]; R[A]; R[]; R[B]; R[]; R[A]; R[]; -- io
R[B]; R[]; R[A]; R[]; R[B]; R[]; R[A]; R[]; -- release bus
R[B]; R[];
DoAReset[];
Check that a write single causes master to be reset.
ThreadStart[PReference, NEW[PReferenceRec ← [command: Store, address: 00010000H, data: 00000011H, rejects: 9]]]; R[A]; R[];
ThreadStart[MCommand, NEW[MCommandRec ← [arb: TRUE, IOR: TRUE, IOAddress: 00010080H, IOData:00020000H, RQ: TRUE, RQAddress:00020000H, RQData0: 00000001H, RQData1: 00000002H, RQData2: 00000003H, RQData3: 00000004H]]];
THROUGH [0..12) DO R[B]; R[]; R[A]; R[]; ENDLOOP;
R[B]; R[];
ThreadStart[PReference, NEW[PReferenceRec ← [command: Fetch, address: 00010004H, data: 00000005H, rejects: 5]]]; R[A]; R[];
ThreadStart[MCommand, NEW[MCommandRec ← [arb: TRUE, RQ: TRUE, RQAddress:00020004H, RQData0: 00000005H, RQData1: 00000006H, RQData2: 00000007H, RQData3: 00000008H]]];
THROUGH [0..8) DO R[B]; R[]; R[A]; R[]; ENDLOOP;
R[B]; R[];
ThreadStart[PReference, NEW[PReferenceRec ← [command: Fetch, address: 00010008H, data: 00000009H, rejects: 5]]]; R[A]; R[];
ThreadStart[MCommand, NEW[MCommandRec ← [arb: TRUE, RQ: TRUE, RQAddress:00020008H, RQData0: 00000009H, RQData1: 0000000AH, RQData2: 0000000BH, RQData3: 0000000CH]]];
THROUGH [0..8) DO R[B]; R[]; R[A]; R[]; ENDLOOP;
R[B]; R[];
ThreadStart[PReference, NEW[PReferenceRec ← [command: Fetch, address: 0001000CH, data: 0000000DH, rejects: 5]]]; R[A]; R[];
ThreadStart[MCommand, NEW[MCommandRec ← [arb: TRUE, RQ: TRUE, RQAddress:0002000CH, RQData0: 0000000DH, RQData1: 0000000EH, RQData2: 0000000FH, RQData3: 00000010H]]];
THROUGH [0..8) DO R[B]; R[]; R[A]; R[]; ENDLOOP;
ThreadStart[MCommand, NEW[MCommandRec ← [slave: TRUE, RQ: TRUE, shared: TRUE, RQAddress: 00020000H, RQData0: 00000011H, RQData1: 00000002H, RQData2: 00000003H, RQData3: 00000004H]]];
THROUGH [0..6) DO R[B]; R[]; R[A]; R[]; ENDLOOP;
ThreadStart[MCommand, NEW[MCommandRec ← [slave: TRUE, WS: TRUE, WSAddress: 00010000H, WSData: 00200001H]]];
THROUGH [0..2) DO R[B]; R[]; R[A]; R[]; ENDLOOP;
R[B]; R[];
ThreadStart[PReference, NEW[PReferenceRec ← [command: Fetch, address: 00010010H, data: 00000011H, rejects: 5]]]; R[A]; R[];
ThreadStart[MCommand, NEW[MCommandRec ← [arb: TRUE, RQ: TRUE, RQAddress:00020010H, RQData0: 00000011H, RQData1: 00000012H, RQData2: 00000013H, RQData3: 00000014H]]];
THROUGH [0..8) DO R[B]; R[]; R[A]; R[]; ENDLOOP;
};
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 ← None;
drive.PNPError ← TRUE; PNPError ← TRUE;
drive.MDataBA ← TRUE; MDataBA ← [0,0];
drive.MCmdBA ← TRUE; MCmdBA ← NoOp;
drive.MNShared ← TRUE; MNShared ← TRUE; checkMNShared ← FALSE;
drive.MParityBA ← TRUE; MParityBA ← FALSE;
drive.MNError ← TRUE; MNError ← TRUE;
MReadyBA ← 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.MDataBA ← FALSE;
drive.MCmdBA ← FALSE;
drive.MNShared ← FALSE;
drive.MParityBA ← FALSE;
checkMParityBA ← 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[WQ, IOR, RQ, WS])) OR (NOT slave AND CF) THEN ERROR;
IF arb THEN {
P[B]; MRq ← TRUE; IF newRequest THEN MNewRq ← TRUE; E[];
R[];
P[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[];
};
IF WQ THEN {
IF slave THEN {drive.MCmdBA ← TRUE; drive.MDataBA ← TRUE; drive.MParityBA ← TRUE};
IF WQNoOp THEN {P[B]; MCmdBA ← NoOp; F[]};
P[B]; MCmdBA ← WriteQuad; SetMData[WQAddress]; F[];
THROUGH [0..wqNotReadyCount) DO
P[B]; MReadyBA ← FALSE; MCmdBA ← DataTransport; SetMData[WQData0]; checkMParityBA ← TRUE; F[];
ENDLOOP;
P[B]; MReadyBA ← TRUE; MCmdBA ← DataTransport; SetMData[WQData0]; checkMParityBA ← TRUE; F[];
P[B]; MCmdBA ← DataTransport; SetMData[WQData1]; F[];
P[B]; MCmdBA ← DataTransport; SetMData[WQData2]; F[];
P[B]; MCmdBA ← DataTransport; SetMData[WQData3]; F[]; checkMParityBA ← FALSE;
IF slave THEN {MCmdBA ← NoOp; E[]; drive.MCmdBA ← FALSE; drive.MDataBA ← FALSE; drive.MParityBA ← FALSE};
};
IF IOR THEN {
dropGrant: BOOLNOT slave AND NOT RQ AND NOT WS AND releaseBus;
IF IONoOp THEN {P[B]; MCmdBA ← NoOp; F[]};
P[B]; MCmdBA ← IORead; SetMData[IOAddress]; F[];
IF IOTraffic#NIL THEN IOTraffic[IOTrafficData];
P[B]; drive.MCmdBA ← TRUE; MCmdBA ← IOReadDone; drive.MDataBA ← TRUE; SetMData[IOData]; F[]; drive.MCmdBA ← FALSE; drive.MDataBA ← FALSE;
P[B]; MCmdBA ← NoOp; IF dropGrant THEN MRq ← FALSE; F[];
P[B]; MCmdBA ← NoOp; E[]; R[]; R[A]; IF dropGrant THEN {MGnt ← FALSE; E[]}; R[];
};
IF RQ THEN {
dropGrant: BOOLNOT slave AND NOT WS AND releaseBus;
IF RQNoOp THEN {P[B]; MCmdBA ← NoOp; F[]};
P[B]; IF slave THEN {drive.MCmdBA ← TRUE; drive.MDataBA ← TRUE}; MCmdBA ← ReadQuad; SetMData[RQAddress]; MNShared ← TRUE; checkMNShared ← TRUE; F[];
P[B]; MCmdBA ← NoOp; IF slave THEN MNShared ← NOT shared; E[];
R[];
P[A]; E[]; IF NOT slave AND shared THEN {drive.MNShared ← TRUE; MNShared ← FALSE}; E[];
R[]; drive.MNShared ← FALSE; checkMNShared ← FALSE;
P[B]; IF slave AND shared THEN drive.MDataBA ← FALSE ELSE {drive.MDataBA ← TRUE; drive.MParityBA ← TRUE}; MCmdBA ← DataTransport; IF rqNotReadyCount=0 THEN {SetMData[RQData0]; checkMParityBA ← TRUE} ELSE MReadyBA ← FALSE; F[];
IF rqNotReadyCount>0 THEN {
THROUGH [0..rqNotReadyCount-1) DO
P[B]; F[];
ENDLOOP;
P[B]; SetMData[RQData0]; checkMParityBA ← TRUE; MReadyBA ← TRUE; F[];
};
P[B]; SetMData[RQData1]; F[];
P[B]; IF dropGrant THEN MRq ← FALSE; SetMData[RQData2]; F[];
P[B]; SetMData[RQData3]; E[]; R[]; R[A]; IF dropGrant THEN MGnt ← FALSE; E[]; R[]; IF slave THEN {MCmdBA ← NoOp; E[]}; drive.MDataBA ← FALSE; drive.MCmdBA ← FALSE; drive.MParityBA ← FALSE; checkMParityBA ← FALSE;
};
IF WS THEN {
dropGrant: BOOLNOT slave AND releaseBus;
IF WSNoOp THEN {P[B]; MCmdBA ← NoOp; F[]};
P[B]; IF slave THEN {drive.MCmdBA ← TRUE; drive.MDataBA ← TRUE; drive.MParityBA ← TRUE}; MCmdBA ← WriteSingle; SetMData[WSAddress]; IF dropGrant THEN MRq ← FALSE; F[];
P[B]; MCmdBA ← DataTransport; SetMData[WSData]; checkMParityBA ← TRUE; E[]; R[]; R[A]; IF dropGrant THEN {MGnt ← FALSE; E[]}; R[]; IF slave THEN {MCmdBA ← NoOp; E[]}; drive.MDataBA ← FALSE; drive.MCmdBA ← FALSE; drive.MParityBA ← FALSE; checkMParityBA ← FALSE;
};
IF IOW THEN {
IF IONoOp THEN {P[B]; MCmdBA ← NoOp; F[]};
P[B]; MCmdBA ← IOWrite; SetMData[IOAddress]; F[];
IF IOTraffic#NIL THEN {
P[B]; drive.MCmdBA ← TRUE; MCmdBA ← NoOp; SetMData[IOData]; F[]; drive.MCmdBA ← FALSE;
IOTraffic[IOTrafficData];
P[B]; drive.MCmdBA ← TRUE; MCmdBA ← IOWriteDone; F[]; drive.MCmdBA ← FALSE;
}
ELSE {
P[B]; drive.MCmdBA ← TRUE; MCmdBA ← IOWriteDone; SetMData[IOData]; F[]; drive.MCmdBA ← FALSE;
};
P[B]; MCmdBA ← NoOp; IF releaseBus THEN MRq ← FALSE; F[];
P[B]; MCmdBA ← NoOp; E[]; R[]; R[A]; IF releaseBus THEN {MGnt ← FALSE; E[]}; R[];
};
IF NOT (slave OR IOR OR RQ OR WS OR IOW) AND releaseBus THEN {
P[B]; MRq ← FALSE; F[];
R[B]; R[]; R[A]; MGnt ← FALSE; E[]; R[]; drive.MCmdBA ← TRUE; MCmdBA ← NoOp; E[]; drive.MCmdBA ← FALSE;
};
IF CF THEN {
P[B]; drive.MCmdBA ← TRUE; drive.MDataBA ← TRUE; MCmdBA ← ChangeFlags; SetMData[CFData]; F[]; IF slave THEN {MCmdBA ← NoOp; E[]}; drive.MDataBA ← FALSE; drive.MCmdBA ← FALSE;
P[B]; MCmdBA ← 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 ← 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 ← None; E[];
IF fault#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.MDataBA THEN instructions.MDataBA ← MDataBA;
IF drive.MCmdBA THEN instructions.MCmdBA ← MCmdBA;
IF drive.MNShared THEN instructions.MNShared ← MNShared;
IF drive.MParityBA THEN instructions.MParityBA ← MParityBA;
IF drive.MNError THEN instructions.MNError ← MNError;
instructions.MReadyBA ← MReadyBA;
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.MDataBA#MDataBA THEN Complain["MDataBA"];
IF instructions.MCmdBA#MCmdBA THEN Complain["MCmdBA"];
IF checkMNShared AND instructions.MNShared#MNShared THEN Complain["MNShared"];
IF checkMParityBA AND instructions.MParityBA#MParityBA THEN Complain["MParityBA"];
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[A];R[]};
R: PROC [phase: PhaseLetter ← N] = {P[phase];E[]};
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.MDataBA ← ILID[dw, value.MDataBA, 32, 0, 32];
value.MParityBA ← 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;
};
Cache.RegisterCacheTester[CacheTest];
END.
The following note is not up to date !!!
Bits in the debug shift register in order of appearance. Put them in and read them out backwards! Multiple bit quantities within CacheMx appear low order bit first, within CachePx appear high order bit first. There is currently a total of 33+1+8+26+12+0+30+30+12+33+1 or 186 bits.
CacheMRAMDriver 33
shiftDataParity
shiftData[32]
CacheMCtlRAMCtl 1
shiftHighAddress
CacheMCtlFlagCtl 8
sVPValid
sRPValid
sRPDirty
sMaster
sShared
sVictim
sTIP
sBroken
CacheMCtlSequencer 26
cycleShifterAB[7]
currentSequenceAB[7]
currentPDemandsBA[7]
slaveAB
forceSlaveBA
wonArbitrationAB
mWantsMBA
samplePDemandsBA
CacheMCtlEntryCtl 12
sMAdrLow
sMAdrHigh
sReadEntry
sWriteEntry
sCellAdr[8]
CacheMCtlCAMCtl 0
CacheMCAMDriver 30
shiftData[30]
CachePCAMDriver 30
shiftData[30]
CachePCtl 12
loadEnable
loadMustBeOne
pCmdShift[4]
rejectShift
parityShift
requestShift
readVA
pAdrLowShift
pAdrHighShift
CachePRAMDriver 33
shiftData[32]
parityShift
CacheMPads 1
shiftAB