<> <> <> <> <> DIRECTORY RoseTypes, Cache, RoseCreate, IO, BitOps, CacheOps, Cucumber, Dragon, Random, PrintTV, AMBridge, SwitchTypes; CacheImpl: CEDAR PROGRAM IMPORTS RoseCreate, BitOps, CacheOps, Cucumber, Dragon, Random, PrintTV, AMBridge, IO EXPORTS Cache = BEGIN OPEN RoseTypes, Cache; <> PBusCommands: TYPE = Dragon.PBusCommands; PBusFaults: TYPE = Dragon.PBusFaults; MBusCommands: TYPE = Dragon.MBusCommands; RegisterCells: PROC = BEGIN END; otherss: SymbolTable _ RoseCreate.GetOtherss["Cache.partsAssertions"]; OldCache: TYPE = RECORD [args: CacheArgs, ct: CellType]; oldCache: LIST OF OldCache _ NIL; Cache: PUBLIC PROC [args: CacheArgs] RETURNS [ct: CellType] = BEGIN FOR old: LIST OF OldCache _ oldCache, old.rest WHILE old # NIL DO IF old.first.args = args THEN RETURN [old.first.ct] ENDLOOP; ct _ RoseCreate.RegisterCellType[name: CacheName[args], expandProc: NIL, ioCreator: CreateCacheIO, driveCreator: CreateCacheDrive, initializer: InitializeCache, evals: [EvalSimple: CacheEvalSimple], tests: LIST[], ports: CreateCachePorts[args] , typeData: NEW [CacheArgs _ args]]; oldCache _ CONS[[args, ct], oldCache]; END; CacheName: PROC [args: CacheArgs] RETURNS [name: ROPE] = { to: IO.STREAM _ IO.ROS[]; to.PutRope["Cache"]; TRUSTED {PrintTV.Print[tv: AMBridge.TVForReferent[NEW [CacheArgs _ args]], put: to, depth: 2]}; name _ IO.RopeFromROS[to]}; CreateCachePorts: PROC [args: CacheArgs] RETURNS [ports: Ports] = {ports _ RoseCreate.PortsFromFile["Cache.Cache.rosePorts"]}; CacheSwitchIORef: TYPE = REF CacheSwitchIORec; CacheSwitchIORec: TYPE = RECORD [ PhA: SwitchTypes.SwitchVal ,PhB: SwitchTypes.SwitchVal ,PData: PACKED ARRAY [0 .. 32) OF SwitchTypes.SwitchVal ,PCmdA: PACKED ARRAY [0 .. 6) OF SwitchTypes.SwitchVal ,PRejectB: SwitchTypes.SwitchVal ,PFaultB: PACKED ARRAY [0 .. 4) OF SwitchTypes.SwitchVal ,MCmdAB: PACKED ARRAY [0 .. 4) OF SwitchTypes.SwitchVal ,MDataAB: PACKED ARRAY [0 .. 32) OF SwitchTypes.SwitchVal ,MParityAB: SwitchTypes.SwitchVal ,MNShared: SwitchTypes.SwitchVal ,MNError: SwitchTypes.SwitchVal ,MRq: SwitchTypes.SwitchVal ,MNewRq: SwitchTypes.SwitchVal ,MGnt: SwitchTypes.SwitchVal ,ResetAB: SwitchTypes.SwitchVal ,DHoldAB: SwitchTypes.SwitchVal ,DShiftAB: SwitchTypes.SwitchVal ,DExecuteAB: SwitchTypes.SwitchVal ,DNSelectAB: SwitchTypes.SwitchVal ,DDataInAB: SwitchTypes.SwitchVal ,DDataOutAB: SwitchTypes.SwitchVal ]; CacheSimpleIORef: TYPE = REF CacheSimpleIORec; CacheSimpleIORec: TYPE = RECORD [ fill0: [0 .. 32767], PhA: BOOLEAN ,fill1: [0 .. 32767], PhB: BOOLEAN ,PData: ARRAY [0..2) OF CARDINAL ,fill3: [0 .. 1023], PCmdA: PBusCommands ,fill4: [0 .. 32767], PRejectB: BOOLEAN ,fill5: [0 .. 4095], PFaultB: PBusFaults ,fill6: [0 .. 4095], MCmdAB: MBusCommands ,MDataAB: ARRAY [0..2) OF CARDINAL ,fill8: [0 .. 32767], MParityAB: BOOLEAN ,fill9: [0 .. 32767], MNShared: BOOLEAN ,fill10: [0 .. 32767], MNError: BOOLEAN ,fill11: [0 .. 32767], MRq: BOOLEAN ,fill12: [0 .. 32767], MNewRq: BOOLEAN ,fill13: [0 .. 32767], MGnt: BOOLEAN ,fill14: [0 .. 32767], ResetAB: BOOLEAN ,fill15: [0 .. 32767], DHoldAB: BOOLEAN ,fill16: [0 .. 32767], DShiftAB: BOOLEAN ,fill17: [0 .. 32767], DExecuteAB: BOOLEAN ,fill18: [0 .. 32767], DNSelectAB: BOOLEAN ,fill19: [0 .. 32767], DDataInAB: BOOLEAN ,fill20: [0 .. 32767], DDataOutAB: BOOLEAN ]; CacheDriveRef: TYPE = REF CacheDriveRec; CacheDriveRec: TYPE = RECORD [driveRecordInitialPadding: DriveTagType, drive: PACKED ARRAY CachePort OF DriveLevel]; CachePort: TYPE = { PhA, PhB, PData, PCmdA, PRejectB, PFaultB, MCmdAB, MDataAB, MParityAB, MNShared, MNError, MRq, MNewRq, MGnt, ResetAB, DHoldAB, DShiftAB, DExecuteAB, DNSelectAB, DDataInAB, DDataOutAB, CachePortTypePad21, CachePortTypePad22, CachePortTypePad23}; CreateCacheIO: PROC [ct: CellType, switch: BOOL] RETURNS [ioAsAny: REF ANY] --IOCreator-- = { args: REF CacheArgs _ NARROW[ct.typeData]; {OPEN args; ioAsAny _ IF switch THEN NEW[CacheSwitchIORec] ELSE NEW[CacheSimpleIORec]; }; }; CreateCacheDrive: PROC [ct: CellType] RETURNS [driveAsAny: REF ANY] --DriveCreator-- = { args: REF CacheArgs _ NARROW[ct.typeData]; {OPEN args; driveAsAny _ NEW[CacheDriveRec]; }; }; CacheStateRef: TYPE = REF CacheStateRec; CacheStateRec: TYPE = RECORD [ phALast: BOOL _ FALSE, -- hack to improve simulation performance cache: CacheOps.Cache, randomStream: Random.RandomStream, cycleNo: INT _ 0, skipRejects: BOOL _ FALSE, rejectCycles: NAT _ 0, cmdAB: PBusCommands _ NoOp, address, fetchData, storeDataBA: Dragon.HexWord _ 0, cmdType: {noOp, reset, fetch, store} _ noOp, pageFault, writeFault, firstBOfCmdBA: BOOL _ FALSE ]; InitializeCache: Initializer = { args: REF CacheArgs _ NARROW [cell.type.typeData]; {OPEN args; drive: CacheDriveRef _ NARROW[cell.realCellStuff.newDriveAsAny]; sw: CacheSwitchIORef _ NARROW[cell.realCellStuff.switchIO]; newIO: CacheSimpleIORef _ NARROW[cell.realCellStuff.newIO]; state: CacheStateRef _ NEW[CacheStateRec]; cell.realCellStuff.state _ state; BEGIN OPEN drive, newIO, state; cache _ cacheParm; skipRejects _ skipRejectsParm; END; }; }; CacheEvalSimple: SimpleEval = BEGIN args: REF CacheArgs _ NARROW[cell.type.typeData]; drive: CacheDriveRef _ NARROW[cell.realCellStuff.newDriveAsAny]; sw: CacheSwitchIORef _ NARROW[cell.realCellStuff.switchIO]; newIO: CacheSimpleIORef _ NARROW[cell.realCellStuff.newIO]; state: CacheStateRef _ NARROW[cell.realCellStuff.state]; BEGIN OPEN drive, newIO, args, state; IF PhA THEN BEGIN IF NOT phALast THEN BEGIN IF cmdType=store AND rejectCycles=0 AND NOT (pageFault OR writeFault) THEN CacheOps.Write[cache, address, storeDataBA]; phALast _ TRUE; END; IF rejectCycles=0 THEN address _ BitOps.ELFD[container: PData, containerWidth: 32, fieldPosition: 0, fieldWidth: 32]; cmdAB _ PCmdA; PRejectB _ FALSE; PFaultB _ none; END; IF PhB THEN BEGIN IF phALast THEN BEGIN IF ResetAB THEN BEGIN randomStream _ Random.Create[seed: randomSeed]; rejectCycles _ randomStream.ChooseInt[1, 5]; cmdType _ reset; cycleNo _ 0; cache _ CacheOps.NewCache[cache]; pageFault _ writeFault _ FALSE; END ELSE cycleNo _ cycleNo+1; IF rejectCycles=0 THEN BEGIN pageFault _ writeFault _ FALSE; SELECT cmdAB FROM Fetch, FetchHold => BEGIN cmdType _ fetch; [data: fetchData, rejectCycles: rejectCycles, pageFault: pageFault] _ CacheOps.Access[cache, address, read, cycleNo]; END; Store, StoreHold => BEGIN cmdType _ store; [rejectCycles: rejectCycles, pageFault: pageFault, writeProtect: writeFault] _ CacheOps.Access[cache, address, write, cycleNo]; END; IOFetch, IOStore, IOFetchHold, IOStoreHold => BEGIN Dragon.Assert[ FALSE, "Cache doesn't yet implement IO operations" ]; -- for now cmdType _ noOp; END; ENDCASE => cmdType _ noOp; rejectCycles _ (SELECT TRUE FROM skipRejects => INT[0], rejectCycles>0 => rejectCycles+randomStream.ChooseInt[0, 1], ENDCASE => rejectCycles); IF pageFault OR writeFault THEN rejectCycles _ MAX[1, rejectCycles]; firstBOfCmdBA _ TRUE; END ELSE BEGIN -- rejected on previous PhB Dragon.Assert[ (cmdAB = NoOp) ]; rejectCycles _ rejectCycles-1; firstBOfCmdBA _ FALSE; END; phALast _ FALSE; END; SELECT TRUE FROM cmdType=store AND firstBOfCmdBA => storeDataBA _ BitOps.ELFD[container: PData, containerWidth: 32, fieldPosition: 0, fieldWidth: 32]; cmdType=fetch AND rejectCycles=0 AND NOT pageFault => PData _ BitOps.ILID[source: fetchData, container: PData, containerWidth: 32, fieldPosition: 0, fieldWidth: 32]; ENDCASE => NULL; -- neither write nor read PData END; drive[PData] _ IF (PhB AND cmdType=fetch AND rejectCycles=0 AND NOT pageFault) THEN drive ELSE ignore; PFaultB _ (SELECT TRUE FROM NOT PhB => none, rejectCycles=1 AND pageFault => page, rejectCycles=1 AND writeFault => write, ENDCASE => none); PRejectB _ PhB AND rejectCycles>0; drive[PFaultB] _ drive[PRejectB] _ IF PhA OR (PhB AND cmdType#noOp) THEN drive ELSE ignore; END; END; <> <> <> <<>> <> <> CacheStateHandler: Cucumber.Handler = NEW[Cucumber.HandlerRep _ [ PrepareWhole: CacheStatePrepareProc, PartTransfer: CacheTransferProc ]]; CacheStatePrepareProc: PROC [ whole: REF ANY, where: IO.STREAM, direction: Cucumber.Direction, data: REF ANY ] RETURNS [ leaveTheseToMe: Cucumber.SelectorList ] -- Cucumber.Bracket -- = {leaveTheseToMe _ LIST[$cache]}; CacheTransferProc: PROC [ whole: REF ANY, part: Cucumber.Path, where: IO.STREAM, direction: Cucumber.Direction, data: REF ANY ] -- Cucumber.PartTransferProc -- = TRUSTED {Cucumber.Transfer[ what: NARROW[whole, REF CacheStateRec].cache, where: where, direction: direction ]}; randomSeed: INT _ -1; Cucumber.Register[CacheStateHandler, CODE[CacheStateRec]]; RegisterCells[]; END.