-- ProcessorInterface.sak -- last edited by Suzuki: 10-Aug-81 8:32:23 CacheProcessor: MONITOR = { CacheSize: CARDINAL = 400B; DataSize: CARDINAL = 4; BusProtocol: TYPE = {Fetch, InvalidateVp, Noop, Store, SFetch, ReadMap, SetMapDirty, WriteMap, WriteMapFlags}; MemoryBusType: TYPE = RECORD[ body: SELECT OVERLAID * FROM Instruction => [Op: BusProtocol, Arg: [0..1777777777B]], Data => [Data: Word], Map => [Flags: MapFlags, Rp: [0..77777777B]], Exception => [ExceptionCode: Word] ENDCASE]; CacheIndex: TYPE = [0..CacheSize); CacheArray: TYPE = ARRAY CacheIndex OF RECORD [ data: RECORD [ body: SELECT OVERLAID * FROM Short => [short: ARRAY [0..DataSize) OF Word], Long => [long: ARRAY [0..DataSize/2) OF LONG CARDINAL ] ENDCASE ], vp: VirtualPage, b: PageOffset, rp: RealPage, flags: RECORD[ vaValid, raValid, ceDirty, shared, rpDirty: BOOLEAN]]; MapFlags: TYPE = MACHINE DEPENDENT RECORD [ reserved: [0..37B], protectd, dirty, referenced: BOOLEAN]; Instruction: TYPE = { Fetch1, Fetch2, Fetch4, Store1, Store2, Store4, Associate, SetF, GetF}; AddressType: TYPE = RECORD[ body: SELECT OVERLAID * FROM Fetch => [vp: VirtualPage, b: PageOffset, w: WordIndex], Store => [data: Word], SM => [mf: MapFlags, fill: [0..377B], rp: RealPage], SMF => [mf: MapFlags, vp: VirtualPage] ENDCASE ]; Word: TYPE = CARDINAL; VirtualPage: TYPE = [0..77777777B]; PageOffset: TYPE = [0..77B]; WordIndex: TYPE = [0..3]; RealPage: TYPE = [0..177777B]; ProcessorInterface: DEVICE = { IN -- From Processor Operation: Instruction, Hold, ReqFromProc: BOOLEAN, Address: AddressType, ProcParity, Tag: BOOLEAN, -- From Memory Bus AckFromBus, Shared, MemException: BOOLEAN, MemoryBus: MemoryBusType, -- From Slave Done, Exception, Start, MapEnd, ValidData: BOOLEAN OUT -- To Processor AckToProc: BOOLEAN, Address: AddressType, Data: DataType, CacheException, ProcParity, Tag: BOOLEAN, -- To Memory Bus ReqToBus, MemHold, Shared: BOOLEAN, MemoryBus: MemoryBusType, -- To slave Next: BOOLEAN GUARDIAN { } -- STATE Cache: CacheArray, held: BOOLEAN, entryLoc, victimLoc: CacheIndex DATAFLOW CONTROL { victimLoc _ 0; DO { ENABLE ExceptionAbort => CONTINUE; WHEN ReqFromProc CHANGE: CacheException _ FALSE; SELECT Operation FROM Fetch1 => Fetch1Proc[]; Fetch2 => Fetch2Proc[]; Fetch4 => Fetch4Proc[]; Store1 => Store1Proc[]; Store2 => Store2Proc[]; Store4 => Store4Proc[]; Associate => AssociateProc[]; SetF => SetFProc[]; GetF => GetFProc[] ENDCASE; held _ Hold; AckToProc _ NOT AckToProc} ENDLOOP; } }; --3) Processor Interface procedures Fetch1Proc: PROC = { OneWordAssign: PROC = { Address.data _ Cache[entryLoc].data.short[w]; ReleaseArbiter[entryLoc]}; FetchProc[OneWordAssign]}; Fetch2Proc: PROC = { TwoWordsAssign: PROC = { Address.data _ Cache[entryLoc].data.long[w/2]; ReleaseArbiter[entryLoc]}; FetchProc[TwoWordsAssign]}; Fetch4Proc: PROC = { FourWordsAssign: PROC = { Address.data _ Cache[entryLoc].data.long[0]; AckToProc _ NOT AckToProc; WHEN ReqFromProc CHANGE: Address.data _ Cache[entryLoc].data.long[1]; ReleaseArbiter[entryLoc]}; FetchProc[FourWordsAssign]}; FetchProc: PROC[WordsAssign: PROC] = { rp: RealPage; rpDirty, success: BOOLEAN; [vp: vp, b: b, w: w] _ Address; DO [success, entryLoc] _ VpBMatch[vp, b]; --This will acquire an arbiter at entryLoc IF success THEN GOTO CFinal; [success, rp, rpDirty] _ SelectVictimAndVpMatch[vp]; --This will acquire an arbiter at victimLoc IF success THEN Cache[entryLoc] _ [vp: vp, b: b, rp: rp, flags: [vaValid: TRUE, raValid: FALSE, ceDirty: FALSE, shared: FALSE, rpDirty: rpDirty]] ELSE { ReleaseArbiter[entryLoc]; [flags, rp] _ ReadMap[vp]; IF Vacant[flags] THEN GOTO PageFault; AcquireArbiter[entryLoc]; Cache[entryLoc] _ [vp: vp, b: b, rp: rp, flags: [vaValid: TRUE, raValid: FALSE, ceDirty: FALSE, shared: FALSE, rpDirty: flags.dirty]]}; ReleaseArbiter[entryLoc]; GetMasterCycle[]; -- If vp is valid then no map operations occurred in between IF Cache[entryLoc].flags.vaValid THEN GOTO Fetch; Abort[]; REPEAT Fetch => { MemoryBus _ [Op: Fetch, Arg: rp]; IF Hold THEN MemHold _ TRUE; BeginNewPhase[]; FetchFromBus[entryLoc]; WordsAssign[]; MemHold _ FALSE}; CFinal => { WordsAssign[]; Noop[]}; PageFault => { Address.exception _ PageFault; CacheException _ TRUE; Noop[]}; ENDLOOP}; VictimDirty: PROC RETURNS[BOOLEAN] = { RETURN[Cache[victimLoc].flags.vaValid AND Cache[victimLoc].flags.raValid AND Cache[victimLoc].flags.ceDirty]}; Vacant: PROC[flags: MapFlags] RETURNS[BOOLEAN] = { RETURN[flags.protectd AND flags.dirty AND ~flags.referenced]}; Noop: PROC = { IF NOT held OR Hold THEN RETURN; GetMasterCycle[]; MemoryBus _ [Op: Noop, Arg: 0]; BeginNewPhase[]}; Store1Proc: PROC = { OneWordStore: PROC[oldLevel:BOOLEAN] = { IF oldLevel=ReqFromProc THEN WHEN ReqFromProc CHANGE: NULL; Cache[entryLoc].data.short[w] _ Address.data}; StoreProc[OneWordStore]}; Store2Proc: PROC = { TwoWordsStore: PROC[oldLevel:BOOLEAN] = { IF oldLevel=ReqFromProc THEN WHEN ReqFromProc CHANGE: NULL; Cache[entryLoc].data.long[w/2] _ Address.data}; StoreProc[TwoWordsStore]}; Store4Proc: PROC = { FourWordsStore: PROC[oldLevel:BOOLEAN] = { IF oldLevel=ReqFromProc THEN WHEN ReqFromProc CHANGE: NULL; Cache[entryLoc].data.long[0] _ Address.data; AckToProc _ NOT AckToProc; WHEN ReqFromProc CHANGE: Cache[entryLoc].data.long[1] _ Address.data}; StoreProc[FourWordsStore]}; StoreProc: PROC[WordsStore: PROC] = { rp: RealPage; oldLevel, rpDirty, success: BOOLEAN; [vp: vp, b: b, w: w] _ Address; oldLevel _ ReqFromProc; AckToProc _ NOT AckToProc; DO [success, entryLoc] _ VpBMatch[vp, b]; IF ~success THEN { [success, rp, rpDirty] _ SelectVictimAndVpMatch[vp]; --This will acquire an arbiter at victimLoc IF success THEN Cache[entryLoc] _ [vp: vp, b: b, rp: rp, flags: [vaValid: TRUE, raValid: FALSE, ceDirty: FALSE, shared: FALSE, rpDirty: rpDirty]] ELSE { ReleaseArbiter[entryLoc]; [flags, rp] _ ReadMap[vp]; IF Vacant[flags] THEN GOTO PageFault; IF flags.protected THEN GOTO WriteProtectFault; AcquireArbiter[entryLoc]; Cache[entryLoc] _ [vp: vp, b: b, rp: rp, flags: [vaValid: TRUE, raValid: FALSE, ceDirty: FALSE, shared: FALSE, rpDirty: flags.dirty]]}; ReleaseArbiter[entryLoc]; GetMasterCycle[]; -- Obtains the memory bus -- Checks the validity of vp IF Cache[entryLoc].flags.vaValid THEN GOTO SFetch; Abort[]; LOOP}; IF ~Cache[entryLoc].flags.rpDirty THEN { ReleaseArbiter[entryLoc]; GetMasterCycle[]; IF ~Cache[entryLoc].flags.vaValid THEN {HeldNoop[]; LOOP}; MemoryBus _ [Op: SetMapDirty, vp: vp]; IF held THEN MemHold _ TRUE; AcquireArbiter[entryLoc]; --AcquireArbiter must come before Next so that --vaValid will not be invalidated from the back door BeginNewPhase[]; MemHold _ FALSE}; IF ~Cache[entryLoc].flags.shared THEN GOTO CacheStore; ReleaseArbiter[entryLoc]; GetMasterCycle[]; IF Cache[entryLoc].flags.vaValid THEN GOTO Store; HeldNoop[]; REPEAT CacheStore => { Cache[entryLoc].rpDirty _ Cache[entryLoc].ceDirty _ TRUE; WordsStore[oldLevel]}; Store => { WordsStore[oldLevel]; MemoryBus _ [Op: Store, Arg: vp]; IF Hold THEN MemHold _ TRUE; BeginNewPhase[]; StoreToBus[]; MemHold _ FALSE}; SFetch => SFetch[rp, oldLevel, WordsStore]; PageFault => { Address.exception _ PageFault; CacheException _ TRUE; Noop[]}; WriteProtectFault => { Address.exception _ WriteProtectFault; CacheException _ TRUE; Noop[]}; ENDLOOP; }; HeldNoop: PROC = { StartHeldInstruction[Op: Noop, Arg: 0]; MemHold _ FALSE}; Abort: PROC = { Cache[victimLoc].flags.vaValid _ FALSE; victimLoc _ (victimLoc - 1) MOD CacheSize; -- Send noop HeldNoop[]}; AssociateProc: PROC = { [vp: vp] _ Address; [mf: mf, rp: rp] _ Data; -- Invalidate Vp GetMasterCycle[]; MemoryBus _ [Op: SM, Arg: vp]; IF held THEN MemHold _ TRUE; BeginNewPhase[]; MemoryBus _ [Flag: mf, Rp: rp]; BeginNewPhase[]; MemHold _ FALSE}; GetFProc: PROC = { [vp: vp] _ Address; [mf, rp] _ ReadMap[vp]; Data _ [mf: mf, rp: rp]}; SetFProc: PROC = { [mf: newMf, vp: vp] _ Data; GetMasterCycle[]; MemoryBus _ [Op: SMF, Arg: vp]; IF held THEN MemHold _ TRUE; BeginNewPhase[]; MemoryBus _ [Flags: newMf]; BeginNewPhase[]; Address _ MemoryBus; MemHold _ FALSE}; --4) Processor Interface to Bus Interface communication VictimStore: PROC = { Cache[victimLoc].flags.vaValid _ FALSE; Cache[victimLoc].flags.raValid _ FALSE; ReleaseArbiter[victimLoc]; GetMasterCycle[]; StartHeldInstruction[Op: Store, Arg: vp]; StoreToBus[]; MemHold _ FALSE; AcquireArbiter[victimLoc]}; SFetch: PROC [rp: RealPage, oldLevel: BOOLEAN, WordsStore: PROC] = { MemoryBus _ [Op: SFetch, Arg: rp]; IF Hold THEN MemHold _ TRUE; BeginNewPhase[]; FetchFromBus[entryLoc]; WordsStore[oldLevel]; WHEN Done UP: IF Shared THEN StoreToBus[]; MemHold _ FALSE}; ReadMap: PROC[vp: VirtualPage] RETURNS [mf: Flags, rp: RealPage] = { GetMasterCycle[]; MemoryBus _ [Op: ReadMap, Arg: vp]; IF held THEN MemHold _ TRUE; BeginNewPhase[]; WHEN MapEnd UP: MemHold _ FALSE; WHEN ValidData UP: { MemoryBusSuccess _ TRUE; [mf: MapFlags, rp: MapRp] _ MemoryBus; BeginNewPhase[]; RETURN[MapFlags, MapRp]}}; --2) Bus Master procedures GetMasterCycle: PROC = { AcquireBus[]; WHEN Start UP: NULL}; StartHeldInstruction: PROC[Op: BusProtocol, Arg: [0..1777777777B]] = { MemoryBus _ [Op: Op, Arg: Arg]; IF held THEN MemHold _ TRUE; BeginNewPhase[]}; BeginNewPhase: PROC = { Next _ TRUE; WHEN Done UP: Next _ FALSE; IF Exception THEN {Noop[]; CacheException_ TRUE; SIGNAL ExceptionAbort}}; FetchFromBus: PROC[loc: CacheIndex] RETURNS[word: Word] = { WHEN ValidData UP: Cache[loc].data.long[0] _ MemoryBus.Data; BeginNewPhase[]; WHEN ValidData UP: Cache[loc].data.long[1] _ MemoryBus.Data; BeginNewPhase[]}; StoreToBus: PROC = { MemoryBus.Data _ Cache[loc].data[0]; BeginNewPhase[]; MemoryBus.Data _ Cache[loc].data[1]; BeginNewPhase[]}; -- Cache operations SelectVictimAndVpMatch: PROC[vp: VirtualPage] RETURNS[success: BOOLEAN, rp: RealPage, rpDirty: BOOLEAN] = { victimLoc _ (victimLoc + 1) MOD CacheSize; AcquireArbiter[victimLoc]; entryLoc _ victimLoc; IF VictimDirty[] THEN VictimStore[]; [success, rp, rpDirty] _ VpMatch[vp]}; }.