<> <> <> <> 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: 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, 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: BOOL _ FALSE; 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] 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; Create: 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}; CacheCmdProc: PROC [cmd: Commander.Handle] -- Commander.CommandProc RETURNS [result: REF _ NIL, msg: Core.ROPE _ NIL] = {NULL}; Commander.Register["Cache", CacheCmdProc]; END.