<> <> <> 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: BOOL _ FALSE, 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: BOOL _ FALSE, arb, newRequest: BOOL _ FALSE, releaseBus: BOOL _ TRUE, refuseGrantCount: NAT _ 0, wqCount: QuadCount _ 0, wqData: ARRAY QuadIndex OF WQData, IOR, IOW: BOOL _ FALSE, IOAddress, IOData: Dragon.Word _ 0, IOTraffic: IOTrafficProc _ NIL, IOTrafficData: REF ANY _ NIL, RQ, rqShared, rqMatch: BOOL _ FALSE, rqNotReadyCount: NAT _ 0, RQAddress, RQData0, RQData1, RQData2, RQData3: Dragon.Word _ 0, WS: BOOL _ FALSE, WSAddress, WSData: Dragon.Word _ 0, CF: BOOL _ FALSE, 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: BOOL _ NOT 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: BOOL _ NOT 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: BOOL _ NOT 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 ANY _ NIL] = 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.