Cache2Impl.mesa
Copyright c 1986 by Xerox Corporation. All rights reserved.
McCreight, September 10, 1986 6:57:34 pm PDT
Curry, September 27, 1986 1:11:45 pm PDT
Don Curry October 30, 1986 5:09:53 pm PST
Cache2Impl:
CEDAR
PROGRAM
IMPORTS CacheOps, Commander, CoreClasses, CoreCreate, CoreOps, CoreProperties, DragonRosemary, Ports, Random, Rosemary
EXPORTS Cache2 =
BEGIN
CacheName: ROPE = Rosemary.Register[roseClassName: "Cache", init: CacheInit, evalSimple: CacheSimple];
ROPE: TYPE = Core.ROPE;
CellType: TYPE = Core.CellType;
PI: TYPE = Cache2.PI;
CacheState: TYPE = Cache2.CacheState;
PortData: TYPE = RECORD [ name: Core.ROPE, width: NAT ← 1 ];
CacheParm:
TYPE =
RECORD [
vm: CacheOps.VirtualMemory,
nLines: NAT,
skipRejects: BOOL ← FALSE ];
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
ANY ←
NIL, steady:
BOOL ←
FALSE ]
RETURNS [stateAny: REF ANY ← 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:
PROC [ p: Ports.Port, stateAny:
REF
ANY ] = {
-- 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 {
pageFault, writeFault: BOOL ← FALSE;
state.fault ← none;
SELECT state.cmdAB
FROM
NoOp => state.cmdType ← noOp;
Fetch => {
state.cmdType ← fetch;
[data: state.fetchData, rejectCycles: state.rejectCycles, pageFault: pageFault]
← CacheOps.Access[state.cache, state.address, read, state.cycleNo];
IF pageFault THEN state.fault ← page };
FetchSpecial => {
state.cmdType ← specialFetch;
[data: state.fetchData, rejectCycles: state.rejectCycles, pageFault: pageFault]
← CacheOps.Access[state.cache, state.address, read, state.cycleNo];
SELECT
TRUE
FROM
pageFault => state.fault ← page;
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, pageFault: pageFault, writeProtect: writeFault]
← CacheOps.Access[state.cache, state.address, write, state.cycleNo];
state.rejectCycles ← state.rejectCycles+rc;
IF writeFault THEN state.fault ← write } };
Store => {
state.cmdType ← store;
IF p[
PI[PUserMode].
ORD].b
AND KernelMemoryRange[state.address]
THEN state.fault ← memAccess
ELSE {
[rejectCycles: state.rejectCycles, pageFault: pageFault, writeProtect: writeFault]
← CacheOps.Access[state.cache, state.address, write, state.cycleNo];
state.fault ← (
SELECT
TRUE
FROM
pageFault => page,
writeFault => write,
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]
THEN NULL -- 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;
Cache:
PUBLIC
PROC [ vm: CacheOps.VirtualMemory, nLines:
NAT ← CacheOps.StdLinesPerCache, skipRejects:
BOOL ←
FALSE ]
RETURNS [ ct: CellType ] = {
PIGet: PROC [ wireId: PI ] RETURNS [ w: Core.Wire ] = {w ← ct.public[wireId.ORD]};
wireList: LIST OF CoreCreate.WR ← NIL;
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};
Cache2CmdProc:
PROC [cmd: Commander.Handle]
-- Commander.CommandProc
RETURNS [result: REF ← NIL, msg: Core.ROPE ← NIL] = {NULL};
Commander.Register["Cache2", Cache2CmdProc];
END.