<> <> <> 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: BOOL _ FALSE ]; CacheInit: PROC [ cellType: Core.CellType, p: Ports.Port ] RETURNS [ stateAny: REF ANY _ NIL ] -- 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: BOOL _ FALSE ] RETURNS [ ct: CellType ] = BEGIN 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], initType: (SELECT pITypes[wireId].width FROM 1 => b, <=16 => c, <=32 => lc, ENDCASE => ERROR) ]; ENDLOOP; END; Cache2CmdProc: PROC [cmd: Commander.Handle] RETURNS [result: REF _ NIL, msg: Core.ROPE _ NIL] -- Commander.CommandProc -- = {NULL}; Commander.Register["Cache2", Cache2CmdProc]; END.