Directory IO; Imports BitOps, CacheOps, Cucumber, Dragon, Random; Cache: LAMBDA [cacheParm: |CacheOps.Cache|, skipRejectsParm: |BOOL|] RETURN CELLTYPE AutoName PORTS [ PhA, PhB < BOOL, PData = INT[32], PCmdA < EnumType["Dragon.PBusCommands"], PRejectB = BOOL, PFaultB = EnumType["Dragon.PBusFaults"], MCmdAB = EnumType["Dragon.MBusCommands"], MDataAB = INT[32], MParityAB = BOOL, MNShared = BOOL, MNError > BOOL, MRq > BOOL, MNewRq > BOOL, MGnt < BOOL, ResetAB < BOOL, DHoldAB < BOOL, -- must be high before testing DShiftAB < BOOL, -- shift the shift register by 1 bit if ~DNSelect DExecuteAB < BOOL, -- interpret the content of the shift register if ~DNSelect DNSelectAB < BOOL, -- if high, hold but don't Execute or Shift DDataInAB < BOOL, -- sampled during each PhB following a PhB that DShift is asserted DDataOutAB > BOOL -- changes during each PhA following a PhB that DShift is asserted, continues to be driven through the PhB following the PhA it changes ] State 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 EvalSimple 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; Initializer cache _ cacheParm; skipRejects _ skipRejectsParm; ENDCELLTYPE; CEDAR 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]]; jCache.rose McCreight, September 9, 1985 4:18:38 pm PDT Curry, September 5, 1985 11:21:42 pm PDT Herrmann, September 6, 1985 5:09:36 pm PDT Last edited by: Barth, July 27, 1984 5:35:37 pm PDT Last edited by: McCreight, May 16, 1984 5:59:20 pm PDT Last edited by: Curry, February 1, 1985 5:05:34 pm PST Disabled Expansion (until rose files get updated to 2.7) Library CacheMInterface, CachePInterface, CacheEntries; Signal names obey the following convention: If a signal x is computed during PhA and remains valid throughout the following PhB, it is denoted as xAB. If x is computed during PhA and can change during the following PhB (as, for example, in precharged logic), it is denoted as xA. In this latter case, a client wanting to use x during PhB must receive it in his own latch open during PhA. xBA and xB are defined symmetrically. Positive logic is assumed (asserted = TRUE = 1 = more positive logic voltage); negative-logic signals have an extra "N" at or very near the beginning of the signal name (e.g., PNPError for PBus Negative-TRUE Parity Error). Timing and housekeeping interface Processor interface Main memory interface Serial debugging interface All the following signals change during PhA and propagate during the remainder of PhA and PhB, giving an entire clock cycle for them to propagate throughout the machine. Each user must receive them into a latch open during PhB. The effects of changes are intended to happen throughout the following PhA, PhB pair. Expand Buffered timing and housekeeping interface PhAb, nPhAb, PhBb, nPhBb:BOOL; Resetb:BOOL; CAM interface CAMPage, nCAMPage:SWITCH[24]; CAMBlock, nCAMBlock:SWITCH[4]; RAM access PBitsB, nPBitsB:SWITCH[132]; MBitsA, nMBitsA:SWITCH[132]; Cell control nVQMatchB, nQuadSharedB:BOOL; QValidA, nQValidA, QSharedA, nQSharedA, QMasterA, nQMasterA:BIT; MQSelBA, MatchQSelBA:INT[4]; nRQMatchA:BOOL; FinishSharedStoreAB:BOOL; nQDirtyB:INT[4]; PStoreAB, nPStoreAB:BOOL; PQSelAB:INT[4]; nPageDirtyB, nMapValidB:BOOL; RPValidBitA, nRPValidBitA, RPDirtyBitA, nRPDirtyBitA, VPValidBitA, nVPValidBitA:BIT; ForceAllDataSelectsBA:BOOL; nRealBlockMatchA, nVirtualBlockMatchB:BOOL; CellAdrBA, nCellAdrBA:INT[7]; SenseRMatchB, SenseVictimA, SelOrphanAdrBA, SelMapAdrBA, SelVPBA, SelRPVictimBA, SelRPDecoderBA, SelRealDataBA, SelPageFlagsBA, SelDecodeBA:BOOL; SenseVMatchA:BOOL; P control <=> M control, all change during PhA MDoneAB, MHeldAB:BOOL; MFaultAB:EnumType["Dragon.PBusFaults"]; PCmdToMAB:EnumType["Dragon.PBusCommands"]; PAdr2831AB:INT[4]; DriveVirtualPageAdrBA, DriveVirtualBlockAdrBA:BOOL; StartWordMachineBA:BOOL; pInterface: PInterface[]; mInterface: MInterface[]; cacheEntries: CacheEntries[] BlackBoxTest cacheTester[instructions, drive, handle]; CacheTester: TYPE = PROC[i: CacheIORef, d: REF CacheDrive, h: CellTestHandle]; cacheTester: CacheTester; RegisterCacheTester: PUBLIC PROC[ct: CacheTester]={ cacheTester _ ct}; Κ2˜šΠbl ™ Icode™+K™(K™*J™Jšœ3™3Jšœ6™6šœ6™6J™8——J˜Jšœ Οkœ˜ Jšœ3˜3J˜J™7J˜Jš œžœ1žœžœžœ ˜]˜JšΡbklœ˜˜Jšœ™J™šœ!™!Jšœ žœ˜—J˜šœ™Jšœžœ˜Jšœ(˜(Jšœ žœ˜Jšœ(˜(—J˜šœ™Jšœ)˜)Jšœ žœ˜Jšœ žœ˜Jšœ žœ˜Jšœ žœ˜Jšœžœ˜ Jšœ žœ˜Jšœžœ˜ —J˜šœ™Jšœ»™»Jšœ žœ˜Jšœ žœΟc˜.Jšœ žœ 1˜BJšœ žœ ;˜NJšœ žœ +˜>Jšœ žœ B˜UJšœ žœ ‡˜š—J˜—J˜š˜J˜Jšœ žœžœ )˜@J˜Jšœ"˜"Jšœ žœ˜Jšœ žœžœ˜Jšœžœ˜J˜Jšœ4˜4J˜,Jšœ&žœž˜2J˜—š ˜ J˜šžœž˜ Jšž˜J˜šžœžœ ž˜Jšž˜š žœžœžœžœ žœ ž˜JJšœ,˜,—Jšœ žœ˜Jšžœ˜J˜—šžœž˜JšœžœI˜^—Jšœ˜Jšœ žœ˜Jšœ˜Jšžœ˜J˜—šžœž˜ Jšž˜J˜šžœ ž˜Jšž˜šžœ ž˜Jšž˜Jšœ/˜/Jšœ,˜,Jšœ˜Jšœ ˜ Jšœ!˜!Jšœžœ˜Jšž˜—Jšžœ˜šžœž˜Jšž˜Jšœžœ˜šžœž˜šœ˜Jšž˜J˜Jšœu˜uJšžœ˜—šœ˜Jšž˜Jšœ˜Jšœ˜Jšžœ˜—šœ-˜-Jšž˜Jšœžœ2  ˜PJšœ˜Jšžœ˜—Jšžœ˜J˜—šœžœžœž˜ Jšœžœ˜Jšœ<˜