Cache2Impl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
McCreight, April 10, 1986 11:40:24 am PST
DIRECTORY Cache2, CacheOps, Commander, Core, CoreClasses, CoreCreate, CoreOps, CoreProperties, Dragon, DragonRosemary, Ports, Random, Rosemary;
Cache2Impl: CEDAR PROGRAM
IMPORTS CacheOps, Commander, CoreClasses, CoreCreate, CoreOps, CoreProperties, DragonRosemary, Ports, Random, Rosemary
EXPORTS Cache2
= BEGIN OPEN Cache2, Core;
randomSeed: INT ← -1;
CacheName: ROPE = Rosemary.Register[roseClassName: "Cache", init: CacheInit, evalSimple: CacheSimple];
PortData: TYPE = RECORD [ name: Core.ROPE, width: NAT ← 1 ];
pITypes: ARRAY PI OF PortData ← [
PhA: ["PhA"],
PhB: ["PhB"],
PData: ["PData", 32],
PCmdA: ["PCmdA", 8],
PRejectB: ["PRejectB"],
PFaultB: ["PFaultB", 5],
ResetAB: ["ResetAB"]
];
CacheParm: TYPE = RECORD [
vm: CacheOps.VirtualMemory,
nLines: NAT,
skipRejects: BOOLFALSE
];
CacheInit: PROC [ cellType: Core.CellType, p: Ports.Port ] RETURNS [ stateAny: REF ANYNIL ] -- Rosemary.InitProc -- =
BEGIN
cp: REF CacheParm = NARROW[CoreProperties.GetCellTypeProp[cellType, $ClusterInfo]];
stateAny ← NEW[CacheState ← [
cache: CacheOps.NewCache[cp.vm, cp.nLines],
skipRejects: cp.skipRejects
]];
END;
CacheSimple: PROC [ p: Ports.Port, stateAny: REF ANY ] -- Rosemary.EvalProc -- =
BEGIN
state: REF CacheState = NARROW[stateAny];
PhA: BOOL = p[PI[PhA].ORD].b;
PhB: BOOL = p[PI[PhB].ORD].b;
IF PhA THEN
BEGIN
IF NOT state.phALast THEN
BEGIN
IF state.cmdType=store AND state.rejectCycles=0 AND NOT (state.pageFault OR state.writeFault) THEN
CacheOps.Write[state.cache, state.address, state.storeDataBA];
state.phALast ← TRUE;
END;
IF state.rejectCycles=0 THEN state.address ← p[PI[PData].ORD].lc;
state.cmdAB ← VAL[p[PI[PCmdA].ORD].c];
END;
IF PhB THEN
BEGIN
IF state.phALast THEN
BEGIN
IF p[PI[ResetAB].ORD].b THEN
BEGIN
state.randomStream ← Random.Create[seed: randomSeed];
state.rejectCycles ← state.randomStream.ChooseInt[1, 5];
state.cmdType ← reset;
state.cycleNo ← 0;
state.cache ← CacheOps.NewCache[state.cache];
state.pageFault ← state.writeFault ← FALSE;
END
ELSE state.cycleNo ← state.cycleNo+1;
IF state.rejectCycles=0 THEN
BEGIN
state.pageFault ← state.writeFault ← FALSE;
SELECT state.cmdAB FROM
Fetch, FetchHold =>
BEGIN
state.cmdType ← fetch;
[data: state.fetchData, rejectCycles: state.rejectCycles, pageFault: state.pageFault] ← CacheOps.Access[state.cache, state.address, read, state.cycleNo];
END;
Store, StoreHold =>
BEGIN
state.cmdType ← store;
[rejectCycles: state.rejectCycles, pageFault: state.pageFault, writeProtect: state.writeFault] ← CacheOps.Access[state.cache, state.address, write, state.cycleNo];
END;
IOFetch, IOStore, IOFetchHold, IOStoreHold =>
BEGIN
DragonRosemary.Assert[ FALSE, "Cache doesn't yet implement IO operations" ]; -- for now
state.cmdType ← noOp;
END;
ENDCASE => state.cmdType ← noOp;
state.rejectCycles ← (SELECT TRUE FROM
state.skipRejects => INT[0],
state.rejectCycles>0 => state.rejectCycles+state.randomStream.ChooseInt[0, 1],
ENDCASE => state.rejectCycles);
IF state.pageFault OR state.writeFault THEN state.rejectCycles ← MAX[1, state.rejectCycles];
state.firstBOfCmdBA ← TRUE;
END
ELSE
BEGIN -- rejected on previous PhB
DragonRosemary.Assert[ (state.cmdAB = NoOp) ];
state.rejectCycles ← state.rejectCycles-1;
state.firstBOfCmdBA ← FALSE;
END;
state.phALast ← FALSE;
END;
SELECT TRUE FROM
state.cmdType=store AND state.firstBOfCmdBA =>
state.storeDataBA ← p[PI[PData].ORD].lc;
state.cmdType=fetch AND state.rejectCycles=0 AND NOT state.pageFault =>
p[PI[PData].ORD].lc ← state.fetchData;
ENDCASE => NULL; -- neither write nor read PData
END;
p[PI[PData].ORD].d ←
IF (PhB AND state.cmdType=fetch AND state.rejectCycles=0 AND NOT state.pageFault) THEN drive ELSE none;
p[PI[PFaultB].ORD].c ← Dragon.PBusFaults[(SELECT TRUE FROM
NOT PhB => none,
state.rejectCycles=1 AND state.pageFault => page,
state.rejectCycles=1 AND state.writeFault => write,
ENDCASE => none)].ORD;
p[PI[PRejectB].ORD].b ← PhB AND state.rejectCycles>0;
p[PI[PFaultB].ORD].d ← p[PI[PRejectB].ORD].d ←
IF PhA OR (PhB AND state.cmdType#noOp) THEN drive ELSE none;
END;
Cache: PUBLIC PROC [ vm: CacheOps.VirtualMemory, nLines: NAT ← CacheOps.StdLinesPerCache, skipRejects: BOOLFALSE ] RETURNS [ ct: CellType ] =
BEGIN
PIGet: PROC [ wireId: PI ] RETURNS [ w: Core.Wire ] = {
w ← ct.public[wireId.ORD];
};
wireList: LIST OF CoreCreate.WRNIL;
FOR wireId: PI DECREASING IN PI DO
wr: CoreCreate.WR ← (SELECT pITypes[wireId].width FROM
1 => pITypes[wireId].name,
ENDCASE => CoreCreate.Seq[name: pITypes[wireId].name, size: pITypes[wireId].width]
);
wireList ← CONS[wr, wireList];
ENDLOOP;
ct ← CoreOps.CreateCellType[
class: CoreClasses.unspecifiedCellClass,
public: CoreCreate.WireList[wireList],
props: CoreProperties.Props[[$ClusterInfo, NEW[CacheParm ← [
vm: vm,
nLines: nLines,
skipRejects: skipRejects
]]]],
name: "Cache"
];
[] ← Rosemary.BindCellType[cellType: ct, roseClassName: CacheName];
FOR wireId: PI IN PI DO
[] ← Ports.InitPort[wire: ct.public[wireId.ORD],
initType: (SELECT pITypes[wireId].width FROM
1 => b,
<=16 => c,
<=32 => lc,
ENDCASE => ERROR)
];
ENDLOOP;
END;
Cache2CmdProc: PROC [cmd: Commander.Handle] RETURNS [result: REFNIL, msg: Core.ROPENIL] -- Commander.CommandProc -- =
{NULL};
Commander.Register["Cache2", Cache2CmdProc];
END.