Cache.rose
McCreight, March 10, 1986 7:20:54 pm PST
Curry, September 5, 1985 11:21:42 pm PDT
Herrmann, September 6, 1985 5:09:36 pm PDT
Last edited by: Barth, July 27, 1984 5:35:37 pm PDT
Last edited by: McCreight, May 16, 1984 5:59:20 pm PDT
Last edited by: Curry, February 1, 1985 5:05:34 pm PST
Disabled Expansion (until rose files get updated to 2.7)
Directory IO;
TranslationNeeds Dragon;
Imports BitOps, CacheOps, Cucumber, DragonRosemary, Random;
Library CacheMInterface, CachePInterface, CacheEntries;
Cache: LAMBDA [cacheParm: |CacheOps.Cache|, skipRejectsParm: |BOOL|] RETURN CELLTYPE AutoName
PORTS [
Signal names obey the following convention: If a signal x is computed during PhA and remains valid throughout the following PhB, it is denoted as xAB. If x is computed during PhA and can change during the following PhB (as, for example, in precharged logic), it is denoted as xA. In this latter case, a client wanting to use x during PhB must receive it in his own latch open during PhA. xBA and xB are defined symmetrically. Positive logic is assumed (asserted = TRUE = 1 = more positive logic voltage); negative-logic signals have an extra "N" at or very near the beginning of the signal name (e.g., PNPError for PBus Negative-TRUE Parity Error).
Timing and housekeeping interface
PhA, PhB < BOOL,
Processor interface
PData = INT[32],
PCmdA < EnumType["Dragon.PBusCommands"],
PRejectB = BOOL,
PFaultB = EnumType["Dragon.PBusFaults"],
Main memory interface
MCmdAB = EnumType["Dragon.MBusCommands"],
MDataAB = INT[32],
MParityAB = BOOL,
MNShared = BOOL,
MNError > BOOL,
MRq > BOOL,
MNewRq > BOOL,
MGnt < BOOL,
Serial debugging interface
All the following signals change during PhA and propagate during the remainder of PhA and PhB, giving an entire clock cycle for them to propagate throughout the machine. Each user must receive them into a latch open during PhB. The effects of changes are intended to happen throughout the following PhA, PhB pair.
ResetAB < BOOL,
DHoldAB < BOOL, -- must be high before testing
DShiftAB < BOOL, -- shift the shift register by 1 bit if ~DNSelect
DExecuteAB < BOOL, -- interpret the content of the shift register if ~DNSelect
DNSelectAB < BOOL, -- if high, hold but don't Execute or Shift
DDataInAB < BOOL, -- sampled during each PhB following a PhB that DShift is asserted
DDataOutAB > BOOL -- changes during each PhA following a PhB that DShift is asserted, continues to be driven through the PhB following the PhA it changes
]
State
phALast: BOOLFALSE, -- hack to improve simulation performance
cache: CacheOps.Cache,
randomStream: Random.RandomStream,
cycleNo: INT ← 0,
skipRejects: BOOLFALSE,
rejectCycles: NAT ← 0,
cmdAB: PBusCommands ← NoOp,
address, fetchData, storeDataBA: Dragon.HexWord ← 0,
cmdType: {noOp, reset, fetch, store} ← noOp,
pageFault, writeFault, firstBOfCmdBA: BOOLFALSE
EvalSimple
IF PhA THEN
BEGIN
IF NOT phALast THEN
BEGIN
IF cmdType=store AND rejectCycles=0 AND NOT (pageFault OR writeFault) THEN
CacheOps.Write[cache, address, storeDataBA];
phALast ← TRUE;
END;
IF rejectCycles=0 THEN
address ← BitOps.ELFD[container: PData, containerWidth: 32, fieldPosition: 0, fieldWidth: 32];
cmdAB ← PCmdA;
PRejectB ← FALSE;
PFaultB ← none;
END;
IF PhB THEN
BEGIN
IF phALast THEN
BEGIN
IF ResetAB THEN
BEGIN
randomStream ← Random.Create[seed: randomSeed];
rejectCycles ← randomStream.ChooseInt[1, 5];
cmdType ← reset;
cycleNo ← 0;
cache ← CacheOps.NewCache[cache];
pageFault ← writeFault ← FALSE;
END
ELSE cycleNo ← cycleNo+1;
IF rejectCycles=0 THEN
BEGIN
pageFault ← writeFault ← FALSE;
SELECT cmdAB FROM
Fetch, FetchHold =>
BEGIN
cmdType ← fetch;
[data: fetchData, rejectCycles: rejectCycles, pageFault: pageFault] ← CacheOps.Access[cache, address, read, cycleNo];
END;
Store, StoreHold =>
BEGIN
cmdType ← store;
[rejectCycles: rejectCycles, pageFault: pageFault, writeProtect: writeFault] ← CacheOps.Access[cache, address, write, cycleNo];
END;
IOFetch, IOStore, IOFetchHold, IOStoreHold =>
BEGIN
DragonRosemary.Assert[ FALSE, "Cache doesn't yet implement IO operations" ]; -- for now
cmdType ← noOp;
END;
ENDCASE => cmdType ← noOp;
rejectCycles ← (SELECT TRUE FROM
skipRejects => INT[0],
rejectCycles>0 => rejectCycles+randomStream.ChooseInt[0, 1],
ENDCASE => rejectCycles);
IF pageFault OR writeFault THEN rejectCycles ← MAX[1, rejectCycles];
firstBOfCmdBA ← TRUE;
END
ELSE
BEGIN -- rejected on previous PhB
DragonRosemary.Assert[ (cmdAB = NoOp) ];
rejectCycles ← rejectCycles-1;
firstBOfCmdBA ← FALSE;
END;
phALast ← FALSE;
END;
SELECT TRUE FROM
cmdType=store AND firstBOfCmdBA =>
storeDataBA ← BitOps.ELFD[container: PData, containerWidth: 32, fieldPosition: 0, fieldWidth: 32];
cmdType=fetch AND rejectCycles=0 AND NOT pageFault =>
PData ← BitOps.ILID[source: fetchData, container: PData, containerWidth: 32, fieldPosition: 0, fieldWidth: 32];
ENDCASE => NULL; -- neither write nor read PData
END;
drive[PData] ←
IF (PhB AND cmdType=fetch AND rejectCycles=0 AND NOT pageFault) THEN drive ELSE ignore;
PFaultB ← (SELECT TRUE FROM
NOT PhB => none,
rejectCycles=1 AND pageFault => page,
rejectCycles=1 AND writeFault => write,
ENDCASE => none);
PRejectB ← PhB AND rejectCycles>0;
drive[PFaultB] ← drive[PRejectB] ←
IF PhA OR (PhB AND cmdType#noOp) THEN drive ELSE ignore;
Initializer
cache ← cacheParm;
skipRejects ← skipRejectsParm;
Expand
Buffered timing and housekeeping interface
PhAb, nPhAb, PhBb, nPhBb:BOOL;
Resetb:BOOL;
CAM interface
CAMPage, nCAMPage:SWITCH[24];
CAMBlock, nCAMBlock:SWITCH[4];
RAM access
PBitsB, nPBitsB:SWITCH[132];
MBitsA, nMBitsA:SWITCH[132];
Cell control
nVQMatchB, nQuadSharedB:BOOL;
QValidA, nQValidA, QSharedA, nQSharedA, QMasterA, nQMasterA:BIT;
MQSelBA, MatchQSelBA:INT[4];
nRQMatchA:BOOL;
FinishSharedStoreAB:BOOL;
nQDirtyB:INT[4];
PStoreAB, nPStoreAB:BOOL;
PQSelAB:INT[4];
nPageDirtyB, nMapValidB:BOOL;
RPValidBitA, nRPValidBitA, RPDirtyBitA, nRPDirtyBitA, VPValidBitA, nVPValidBitA:BIT;
ForceAllDataSelectsBA:BOOL;
nRealBlockMatchA, nVirtualBlockMatchB:BOOL;
CellAdrBA, nCellAdrBA:INT[7];
SenseRMatchB, SenseVictimA, SelOrphanAdrBA, SelMapAdrBA, SelVPBA, SelRPVictimBA, SelRPDecoderBA, SelRealDataBA, SelPageFlagsBA, SelDecodeBA:BOOL;
SenseVMatchA:BOOL;
P control <=> M control, all change during PhA
MDoneAB, MHeldAB:BOOL;
MFaultAB:EnumType["Dragon.PBusFaults"];
PCmdToMAB:EnumType["Dragon.PBusCommands"];
PAdr2831AB:INT[4];
DriveVirtualPageAdrBA, DriveVirtualBlockAdrBA:BOOL;
StartWordMachineBA:BOOL;
pInterface: PInterface[];
mInterface: MInterface[];
cacheEntries: CacheEntries[]
BlackBoxTest
cacheTester[instructions, drive, handle];
ENDCELLTYPE;
CEDAR
CacheTester: TYPE = PROC[i: CacheIORef, d: REF CacheDrive, h: CellTestHandle];
cacheTester: CacheTester;
RegisterCacheTester: PUBLIC PROC[ct: CacheTester]={
cacheTester ← ct};
CacheStateHandler: Cucumber.Handler = NEW[Cucumber.HandlerRep ← [
PrepareWhole: CacheStatePrepareProc,
PartTransfer: CacheTransferProc
]];
CacheStatePrepareProc: PROC [ whole: REF ANY, where: IO.STREAM, direction: Cucumber.Direction, data: REF ANY ] RETURNS [ leaveTheseToMe: Cucumber.SelectorList ] -- Cucumber.Bracket -- =
{leaveTheseToMe ← LIST[$cache]};
CacheTransferProc: PROC [ whole: REF ANY, part: Cucumber.Path, where: IO.STREAM, direction: Cucumber.Direction, data: REF ANY ] -- Cucumber.PartTransferProc -- =
TRUSTED {Cucumber.Transfer[ what: NARROW[whole, REF CacheStateRec].cache, where: where, direction: direction ]};
randomSeed: INT ← -1;
Cucumber.Register[CacheStateHandler, CODE[CacheStateRec]];