CacheImpl.mesa
Copyright c 1986 by Xerox Corporation. All rights reserved.
McCreight, February 12, 1987 2:47:28 pm PST
Don Curry May 1, 1987 2:43:54 pm PDT
DIRECTORY Cache, CacheOps, Commander, Core, CoreClasses, CoreCreate, CoreOps, CoreProperties, Dragon, DragOpsCross, DragonRosemary, Ports, Random, Rosemary;
CacheImpl: CEDAR PROGRAM
IMPORTS CacheOps, Commander, CoreClasses, CoreCreate, CoreOps, CoreProperties, DragonRosemary, Ports, Random, Rosemary
EXPORTS Cache =
BEGIN
CacheName: ROPE = Rosemary.Register[roseClassName: "Cache", init: CacheInit, evalSimple: CacheSimple];
ROPE:   TYPE = Core.ROPE;
CellType:  TYPE = Core.CellType;
PI:    TYPE = Cache.PI;
CacheState: TYPE = Cache.CacheState;
PortData:  TYPE = RECORD [ name: Core.ROPE, width: NAT ← 1 ];
CacheParm: TYPE = RECORD [
vm:   CacheOps.VirtualMemory,
nLines:  NAT,
skipRejects: BOOLFALSE ];
randomSeed: INT ← -1;
pITypes: ARRAY PI OF PortData ← [
PhA:   ["PhA"],
PhB:   ["PhB"],
PData:   ["PData", 32],
PCmdA:  ["PCmdA", 8],
PRejectB:  ["PRejectB"],
PUserMode: ["PUserMode"],
PFaultB:  ["PFaultB", 4],
ResetAB:  ["ResetAB"] ];
CacheInit: PROC -- Rosemary.InitProc
[cellType: Core.CellType, p: Ports.Port, oldStateAny: REF ANYNIL, steady: BOOLFALSE ]
RETURNS [stateAny: REF ANYNIL, stateValue: Ports.LevelSequence ← NIL ] = {
cp: REF CacheParm = NARROW[CoreProperties.GetCellTypeProp[cellType, $ClusterInfo]];
stateAny ← NEW[CacheState ← [
cache: CacheOps.NewCache[cp.vm, cp.nLines],
skipRejects: cp.skipRejects ]]};
KernelMemoryRange: PROC [addr: Dragon.HexWord] RETURNS [inRange: BOOL] =
{inRange ← addr IN [Dragon.HexWord[0]..DragOpsCross.KernalLimit)};
KernelIORange: PROC [addr: Dragon.HexWord] RETURNS [inRange: BOOL] =
{inRange ← addr IN [Dragon.HexWord[0]..DragOpsCross.KernalLimit)};
CacheSimple: Rosemary.EvalProc = {
state: REF CacheState = NARROW[stateAny];
PhA: BOOL = p[PI[PhA].ORD].b;
PhB: BOOL = p[PI[PhB].ORD].b;
IF PhA THEN {
IF NOT state.phALast AND state.rejectCycles=0 AND state.fault = none THEN
SELECT state.cmdType FROM
store   => CacheOps.Write[state.cache, state.address, state.storeDataBA];
specialFetch => CacheOps.Write[state.cache, state.address, state.csNew];
ioStore  => SELECT state.address FROM
0    => state.csPredicted ← state.storeDataBA;
1    => state.csNew  ← state.storeDataBA;
ENDCASE  => ERROR;
ENDCASE;
state.phALast ← TRUE;
IF state.rejectCycles=0 THEN state.address ← p[PI[PData].ORD].lc;
state.cmdAB ← VAL[p[PI[PCmdA].ORD].c]};
IF PhB THEN {
IF state.phALast THEN {
IF p[PI[ResetAB].ORD].b
THEN {
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.fault ← none }
ELSE state.cycleNo ← state.cycleNo+1;
IF state.rejectCycles=0
THEN {
mapFault, memAccessFault: BOOLFALSE;
state.fault ← none;
SELECT state.cmdAB FROM
NoOp => state.cmdType ← noOp;
Fetch => {
state.cmdType ← fetch;
[data: state.fetchData, rejectCycles: state.rejectCycles, mapFault: mapFault]
← CacheOps.Access[state.cache, state.address, read, state.cycleNo];
IF mapFault THEN state.fault ← map };
FetchSpecial => {
state.cmdType ← specialFetch;
[data: state.fetchData, rejectCycles: state.rejectCycles, mapFault: mapFault]
← CacheOps.Access[state.cache, state.address, read, state.cycleNo];
SELECT TRUE FROM
mapFault         => state.fault ← map;
state.fetchData # state.csPredicted  => state.cmdType ← fetch; -- no write
p[PI[PUserMode].ORD].b AND
KernelMemoryRange[state.address] => state.fault ← memAccess;
ENDCASE => {
rc: INT;
[data: state.fetchData, rejectCycles: rc, mapFault: mapFault, memAccessProtect: memAccessFault]
← CacheOps.Access[state.cache, state.address, write, state.cycleNo];
state.rejectCycles ← state.rejectCycles+rc;
IF memAccessFault THEN state.fault ← memAccess } };
Store => {
state.cmdType ← store;
IF p[PI[PUserMode].ORD].b AND KernelMemoryRange[state.address]
THEN state.fault ← memAccess
ELSE {
[rejectCycles: state.rejectCycles, mapFault: mapFault, memAccessProtect: memAccessFault]
← CacheOps.Access[state.cache, state.address, write, state.cycleNo];
state.fault ← (SELECT TRUE FROM
mapFault  => map,
memAccessFault => memAccess,
ENDCASE  => none) } };
IOFetch => {
state.cmdType ← fetch;
SELECT state.address FROM
0 => state.fetchData ← state.csPredicted;
1 => state.fetchData ← state.csNew;
ENDCASE => DragonRosemary.Assert
[FALSE, "Cache doesn't yet implement IO operations" ]};
IOStore, IOStoreSpecial => {
state.cmdType ← ioStore;
IF state.address IN [0..1]
THENNULL -- store done above in next PhA
ELSE IF p[PI[PUserMode].ORD].b AND KernelIORange[state.address]
THEN state.fault ← ioAccess
ELSE {
DragonRosemary.Assert[FALSE, "IO addr not yet implemented" ];
state.fault ← ioAccess}};
ENDCASE => DragonRosemary.Assert[FALSE, "Cache doesn't implement this operation" ];
state.rejectCycles ← (SELECT TRUE FROM
state.skipRejects => INT[0],
state.rejectCycles>0 => state.rejectCycles+state.randomStream.ChooseInt[0, 1],
ENDCASE => state.rejectCycles);
IF state.fault#none THEN state.rejectCycles ← MAX[1, state.rejectCycles];
state.firstBOfCmdBA ← TRUE }
ELSE { -- rejected on previous PhB
DragonRosemary.Assert[ (state.cmdAB = NoOp) ];
state.rejectCycles ← state.rejectCycles-1;
state.firstBOfCmdBA ← FALSE };
state.phALast ← FALSE };
SELECT state.cmdType FROM
store,
ioStore => IF state.firstBOfCmdBA THEN state.storeDataBA ← p[PI[PData].ORD].lc;
specialFetch,
fetch  => IF state.rejectCycles=0 AND state.fault=none THEN p[PI[PData].ORD].lc←state.fetchData;
ENDCASE => NULL}; -- neither write nor read PData
p[PI[PData].ORD].d ←
IF (PhB AND (state.cmdType=fetch OR state.cmdType=specialFetch) AND state.rejectCycles=0 AND state.fault = none) THEN drive ELSE none;
p[PI[PFaultB].ORD].c ← Dragon.PBusFaults[(SELECT TRUE FROM
NOT PhB    => none,
state.rejectCycles=1 => state.fault,
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 };
Signal: SIGNAL = CODE;
Create: PUBLIC PROC [ vm: CacheOps.VirtualMemory, nLines: NAT ← CacheOps.StdLinesPerCache, skipRejects: BOOLFALSE ] RETURNS [ ct: CellType ] = {
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],
levelType: (SELECT pITypes[wireId].width FROM
1   => b,
<=16  => c,
<=32  => lc,
ENDCASE => ERROR) ];
ENDLOOP};
CacheCmdProc: PROC [cmd: Commander.Handle] -- Commander.CommandProc
RETURNS [result: REFNIL, msg: Core.ROPENIL] = {NULL};
Commander.Register["Cache", CacheCmdProc];
END.