-- File: [Indigo]Dragon>DragonCacheImpl.sak -- Dragon Cache -- 23-Mar-82 13:02:29 DIRECTORY ConvertUnsafe, DragonCache, Inline, SakuraRT, SimIO; DragonCacheImpl: MONITOR IMPORTS ConvertUnsafe, Inline, SakuraRT, SimIO EXPORTS DragonCache = { -- The functionality of Dragon cache chip is described under the following --conventions: there are two main processes, a process to watch the processor bus --commands (PbusFetch), and a process to watch the memory bus commands --(BackDoor, backdoor operations). Furthermore, PbusFetch cooperates with --several other processes to allow overlapping of pipline operations: MProc is a --process that is invoked from PbusFetch and invokes Mbus operations directly. --Operations associated with Pbus commands are all split into two parts so that --they can be piplined. All the front parts of these operations are inside --PbusFetch, so they do not constitute independent processes. The latter parts --are all independent processes. They are FetchTransport, StoreTransport, and --DoMapOpTransport. -- Communications among processes: --Communication between PbusFetch and MProc is done through two global --variables: DoMProc and MProcDone. The communication between PbusFetch --and transport processes, FetchTransport, StoreTransport, and --DoMapOpTransport, is done by global variables, FetchTransportGo, --StoreTransportGo, and DoMapOpTransportGo, and ~Reject for the other --direction. Cell: TYPE = RECORD [ vp: LONG CARDINAL, rp: LONG CARDINAL, bl: [0..37B], D: ARRAY [0..3] OF LONG CARDINAL, VpValid, RpValid, RpDirty, CEDirty, Shared, TIP: BOOLEAN]; MProcType: TYPE = PROC; -- Constants DataArraySize: CARDINAL = 64; ProcessorNum: STRING = "Proc1: "; -- Global variables FetchTransportGo, StoreTransportGo, DoMapOpTransportGo, Holding, DoMProc, MProcDone, PRq, NewRq, MRq, Orph, MCMD: BOOLEAN; Instruction: DragonCache.PbusOp; DataIndex, VictimIndex: CARDINAL; RqBL, PBL, MBL: [0..37B]; PWord, MWord: [0..3]; RqVP, MVP, RqData, PResult, PRP, MRP, MOResult, MRdData, MWData: LONG CARDINAL; Data: ARRAY [0..DataArraySize) OF Cell; MOp: MProcType; MInst: DragonCache.MbusCommand; MapOp: DragonCache.MapOpKind; RpDirtyReg: BOOLEAN; -- This register is set by ReadMap or PartialMatch PageFault: SIGNAL = CODE; WriteViolation: SIGNAL = CODE; CheckVal: PUBLIC ENTRY PROC [vp: LONG CARDINAL, bl: [0..37B], word: [0..3], val: LONG CARDINAL] = { loc: CARDINAL; matched: BOOLEAN; [matched, loc] _ FullVpMatch[vp, bl]; IF ~ matched THEN ERROR; IF Data[loc].D[word]#val THEN ERROR}; Cache: PUBLIC DEVICE = { IN Op: DragonCache.PbusOp, PDataIn: DragonCache.PbusType, MDataIn: DragonCache.MbusType, ClockA, ClockB, CMDIn, RQ, SharedIn, Grant: BOOLEAN OUT Exception, Reject, SharedOut, CMDOut, Rq: BOOLEAN, PDataOut: DragonCache.PbusType, MDataOut: DragonCache.MbusType GUARDIAN {} CONTROL { -- PbusFetch process procedures PbusFetch: DEVICE = { IN OUT GUARDIAN {} CONTROL { success: BOOLEAN; DO WHEN ClockA UP: NULL; --A (Phase A) IF RQ AND ~Reject THEN { Exception _ FALSE; WITH b: PDataIn SELECT FROM Instruction => {RqVP _ b.vp; RqBL _ b.bl; PWord _ b.word}; ENDCASE => ERROR; Instruction _ Op; WHEN ClockB UP: [success, DataIndex] _ FullVpMatch[RqVP, RqBL]; --M (Phase B) { ENABLE { PageFault => {PDataOut _ [Data[-1]]; Exception _ TRUE}; WriteViolation => {PDataOut _ [Data[0]]; Exception _ TRUE}}; SELECT Instruction FROM Fetch => CallFetch[success]; FetchHold => CallFetchHold[success! PageFault => {PDataOut _ [Data[-1]]; Holding _ FALSE; Exception _ TRUE}; WriteViolation => {PDataOut _ [Data[0]]; Exception _ TRUE}]; Store => CallStore[success]; MapOp => CallMapOp[success]; ENDCASE} }; ENDLOOP} }; WaitForTIP: PROC = { Reject _ TRUE; DO SakuraRT.Delay[30]; IF Data[DataIndex].TIP THEN { WHEN ClockB UP: NULL; LOOP } ELSE EXIT; ENDLOOP}; CallFetch: PROC [success: BOOLEAN] = { -- Started at Phase B index: CARDINAL; IF success THEN { --hit WaitForTIP[]; Reject _ FALSE; FetchTransportGo _ TRUE; Holding _ FALSE} ELSE { Reject _ TRUE; Holding _ FALSE; WHEN ClockA UP: Holding _ TRUE; --R (Phase A) SakuraRT.Delay[10]; PRq _ TRUE; --T (Phase B) WaitForGrant[]; WriteBackVictimIfDirty[]; [success, index] _ PartialMatch[RqVP]; PRP _ Data[index].rp; WHEN ClockB UP: IF ~success THEN CallMProc[ReadMap, "ReadMap"]; IF success THEN CallMProc[ReadQuadMatch, "ReadQuad"] ELSE CallMProc[ReadQuad, "ReadQuad"]; PRq _ FALSE; Reject _ FALSE; [success, DataIndex] _ FullVpMatch[RqVP, RqBL]; IF ~success THEN ERROR; -- This is a description error FetchTransportGo _ TRUE} }; CallFetchHold: PROC [success: BOOLEAN] = { -- Started at Phase B IF ~Holding THEN { Reject _ TRUE; WHEN ClockA UP: NULL; SakuraRT.Delay[10]; PRq _ TRUE; WaitForGrant[]; WHEN ClockB UP: Holding _ TRUE}; CallFetch[success]}; CallStore: PROC [success: BOOLEAN] = { Reject _ TRUE; WHEN ClockA UP: WITH b: PDataIn SELECT FROM Data => RqData _ b.data; ENDCASE => ERROR; WaitForTIP[]; IF ~success THEN { SakuraRT.Delay[10]; PRq _ TRUE; WaitForGrant[]; WriteBackVictimIfDirty[]; WHEN ClockB UP: { [success, DataIndex] _ PartialMatch[RqVP]; PRP _ Data[DataIndex].rp; IF ~success THEN CallMProc[ReadMapAndSetRpDirty, "ReadMapAndSetRpDirty"]}; WHEN ClockB UP: IF success THEN CallMProc[ReadQuadMatch, "ReadQuad"] ELSE CallMProc[ReadQuad, "ReadQuad"]}; WHEN ClockB UP: [success, DataIndex] _ FullVpMatch[RqVP, RqBL]; Data[DataIndex].CEDirty _ TRUE; IF ~Data[DataIndex].RpDirty THEN { IF ~PRq THEN {PRq _ TRUE; WaitForGrant[]}; CallMProc[ReadMapAndSetRpDirty, "ReadMapAndSetRpDirty"]}; IF ~Data[DataIndex].Shared THEN StoreTransportGo _ TRUE ELSE { Data[DataIndex].D[PWord] _ RqData; IF ~PRq THEN {PRq _ TRUE; WaitForGrant[]}; CallMProc[WriteSingle, "WriteSingle"]}; Reject _ FALSE; PRq _ FALSE; }; -- CallStore CallMapOp: PROC [success: BOOLEAN] = { -- Started at Phase B Reject _ TRUE; WHEN ClockA UP: NULL; SakuraRT.Delay[10]; PRq _ TRUE; WaitForGrant[]; WHEN ClockA UP: WITH b: PDataIn SELECT FROM Data => RqData _ b.data; ENDCASE => ERROR; CallMProc[DoMapOp, "DoMapOp"]; PRq _ FALSE}; -- CallMapOp CallMProc: PROC [procedure: MProcType, name: REF TEXT] = { -- Starts in Phase B and finishes in Phase B st: LONG STRING _ [25]; ConvertUnsafe.AppendRefText[st, name]; WaitMProcReallyDone[]; SetMProcDone[FALSE]; SetDoMProc[TRUE]; MOp _ procedure; SimIO.WF2[" %sMbus op: %s started*n", ProcessorNum, st]; DO WHEN ClockB UP: IF IsMProcDone[] THEN EXIT; ENDLOOP; SimIO.WF2[" %sMbus op: %s finished*n", ProcessorNum, st]}; -- CallMProc WaitMProcReallyDone: PROC = { -- Starts in Phase B DO SakuraRT.Delay[30]; IF IsMProcReallyDone[] THEN EXIT; WHEN ClockB UP: NULL; ENDLOOP}; SetMProcReallyDone: ENTRY PROC [val: BOOLEAN] = { MProcReallyDone _ val}; IsMProcReallyDone: ENTRY PROC RETURNS [BOOLEAN] = { RETURN[MProcReallyDone]}; MProcReallyDone: BOOLEAN _ TRUE; WriteBackVictimIfDirty: PROC = { -- Starts at Phase A MRP _ Data[VictimIndex].rp; MBL _ Data[VictimIndex].bl; IF Data[VictimIndex].RpValid AND Data[VictimIndex].CEDirty THEN { CallMProc[WriteQuad, "WriteQuad"]; Data[VictimIndex].CEDirty _ FALSE}; }; -- WriteBackVictimIfNotClean WaitForGrant: PROC = { DO WHEN ClockA UP: IF Grant THEN EXIT ENDLOOP}; -- WaitForGrant -- FetchTransport process procedures FetchTransport: DEVICE = { IN OUT GUARDIAN {} CONTROL { -- Starts at Phase B DO WHEN ClockA UP: NULL; --R (Phase A) IF FetchTransportGo THEN { PResult _ Data[DataIndex].D[PWord]; FetchTransportGo _ FALSE; WHEN ClockB UP: PDataOut _ [Data[PResult]]}; ENDLOOP} }; StoreTransport: DEVICE = { IN OUT GUARDIAN {} CONTROL { -- Starts at Phase B index, pword: CARDINAL; success: BOOLEAN; DO WHEN ClockB UP: { pword _ PWord; [success, index] _ FullVpMatch[RqVP, RqBL]}; WHEN ClockA UP: IF StoreTransportGo THEN { IF ~success THEN ERROR; Data[index].D[pword] _ RqData; StoreTransportGo _ FALSE} ENDLOOP} }; -- StoreTransport DoMapOpTransport: DEVICE = { IN OUT GUARDIAN {} CONTROL { DO WHEN ClockB UP: NULL; -- (B) IF DoMapOpTransportGo THEN { NewRq _ TRUE; MOResult _ MRdData; Reject _ FALSE; WHEN ClockA UP: { PResult _ MOResult; NewRq _ FALSE}; WHEN ClockB UP: { IF Inline.BITAND[Inline.HighHalf[PResult],40000B]#0 THEN Exception _ TRUE; PDataOut _ [Data[PResult]]} } ENDLOOP} }; -- DoMapOpTransport -- MProc process procedures MProc: DEVICE = { IN OUT GUARDIAN {} CONTROL { SetMProcDone[FALSE]; DO WHEN ClockA UP: NULL; IF IsDoMProc[] THEN { SetDoMProc[FALSE]; CMDOut _ TRUE; MOp[]}; ENDLOOP} }; SetDoMProc: ENTRY PROC [val: BOOLEAN] = { DoMProc _ val}; IsDoMProc: ENTRY PROC RETURNS [BOOLEAN] = { RETURN[DoMProc]}; SetMProcDone: ENTRY PROC [val: BOOLEAN] = { MProcDone _ val}; IsMProcDone: ENTRY PROC RETURNS [BOOLEAN] = { RETURN[MProcDone]}; WriteQuad: PROC = { i: CARDINAL; WriteOneWord: PROC [pword: [0..3]] = { WHEN ClockB UP: MWData _ Data[VictimIndex].D[pword]; WHEN ClockA UP: MDataOut _ [Data[MWData]]}; -- WriteOneWord MDataOut _ [Instruction[WriteQuad, MRP, MBL, 0]]; WHEN ClockB UP: MWData _ Data[VictimIndex].D[0]; SakuraRT.Delay[20]; CMDOut _ FALSE; WHEN ClockA UP: MDataOut _ [Data[MWData]]; FOR i IN [1..3] DO WriteOneWord[i] ENDLOOP; WHEN ClockB UP: SetMProcDone[TRUE]; SetMProcReallyDone[TRUE]}; -- WriteQuad ReadMap: PROC = { fault: BOOLEAN; MVP _ RqVP; MDataOut _ [MapCommand[ReadMap, , , , MVP]]; WHEN ClockB UP: SakuraRT.Delay[20]; CMDOut _ FALSE; fault _ WaitMapOpDone[]; IF fault THEN SIGNAL PageFault; WITH b: MDataIn SELECT FROM MapCommand => {MRP _ b.vp; RpDirtyReg _ b.rpdirty}; ENDCASE => ERROR; SetMProcDone[TRUE]; SetMProcReallyDone[TRUE]}; ReadMapAndSetRpDirty: PROC = { fault: BOOLEAN; MVP _ RqVP; MDataOut _ [MapCommand[ReadMapAndSetRpDirty, , , , MVP]]; WHEN ClockB UP: SakuraRT.Delay[20]; CMDOut _ FALSE; fault _ WaitMapOpDone[]; IF fault THEN SIGNAL PageFault; WITH b: MDataIn SELECT FROM MapCommand => {MRP _ b.vp; RpDirtyReg _ b.rpdirty}; ENDCASE => ERROR; SetMProcDone[TRUE]; SetMProcReallyDone[TRUE]}; ReadQuadMatch: PROC = { MRP _ PRP; ReadQuad[]}; ReadQuad: PROC = { ReadOneWord: PROC = {IF ~Orph THEN ReadDataFromBus[@Data[index].D[pword]]}; success: BOOLEAN; pword: CARDINAL _ PWord; index: CARDINAL; PBL _ RqBL; MDataOut _ [Instruction[ReadQuad, MRP, PBL, pword]]; WITH b: MDataIn SELECT FROM Instruction => {MRP _ b.rp; MBL _ b.bl; MWord _ b.word}; ENDCASE => ERROR; WHEN ClockB UP: MRq _ TRUE; -- (Phase B, t2) SakuraRT.Delay[20]; CMDOut _ FALSE; WHEN ClockA UP: [success, index] _ FullRpMatch[MRP, MBL];-- (Phase A, t3) WHEN ClockB UP: { -- (Phase B, t4) Orph _ success; IF ~success THEN index _ VictimIndex}; WHEN ClockA UP: IF ~success THEN { -- (Phase A, t5) Data[index].rp _ MRP; Data[index].bl _ MBL; Data[index].RpValid _ TRUE; Data[index].Shared _ FALSE; Data[index].CEDirty _ FALSE; Data[index].RpDirty _ RpDirtyReg}; WHEN ClockB UP: -- (Phase B, t6) -- { Data[index].vp _ RqVP}; Data[index].VpValid _ TRUE; Data[index].Shared _ SharedIn; VictimIndex _ (VictimIndex+1) MOD DataArraySize; WHEN ClockA UP: MCMD _ CMDIn; -- (Phase A, t7) IF MCMD AND MInst=NotReady THEN WaitOneCycle[]; SetMProcDone[TRUE]; WHEN ClockB UP: ReadOneWord[]; -- (Phase B, t8) WHEN ClockA UP: pword _ (pword+1) MOD 4; -- (Phase A, t9) WHEN ClockB UP: -- (Phase B, t10) --{ Data[index].TIP _ TRUE; ReadOneWord[]; MRq _ FALSE; IF ~Holding THEN NewRq _ TRUE}; WHEN ClockA UP: pword _ (pword+1) MOD 4; -- (Phase A, t11) WHEN ClockB UP: { -- (Phase B, t12) ReadOneWord[]; IF ~Holding THEN NewRq _ FALSE}; WHEN ClockA UP: pword _ (pword+1) MOD 4; -- (Phase A, t13) WHEN ClockB UP: -- (Phase B, t14) --{ ReadOneWord[]; Data[index].TIP _ FALSE; SetMProcReallyDone[TRUE]}}; SetRpDirty: PROC = { -- Starts in A fault: BOOLEAN; PBL _ RqBL; MDataOut _ [Instruction[SetRpDirty, MRP, PBL, PWord]]; WITH b: MDataIn SELECT FROM Instruction => { MRP _ b.rp; MBL _ b.bl; MWord _ b.word}; ENDCASE => ERROR; WHEN ClockB UP: fault _ WaitMapOpDone[]; IF fault THEN SIGNAL WriteViolation; SetMProcDone[TRUE]; SetMProcReallyDone[TRUE]}; WriteSingle: PROC = { PBL _ RqBL; PRP _ RqVP; MDataOut _ [Instruction[WriteSingle, PRP, PBL, PWord]]; NewRq _ TRUE; WHEN ClockB UP: MWData _ RqData; SakuraRT.Delay[20]; CMDOut _ FALSE; WHEN ClockA UP: MDataOut _ [Data[MWData]]; WHEN ClockB UP: SetMProcDone[TRUE]; NewRq _ FALSE; SetMProcReallyDone[TRUE]}; DoMapOp: PROC = { fault: BOOLEAN; MVP _ RqVP; MDataOut _ [MapCommand[DoMapOp, MapOp, , , MVP]]; MCMD _ TRUE; WHEN ClockB UP: MWData _ RqData; SakuraRT.Delay[20]; CMDOut _ FALSE; WHEN ClockA UP: MDataOut _ [Data[MWData]]; fault _ WaitMapOpDone[]; IF fault THEN SIGNAL PageFault; SetMProcDone[TRUE]; ReadDataFromBus[@MRdData]; DoMapOpTransportGo _ TRUE; SetMProcReallyDone[TRUE]}; -- DoMapOp WaitMapOpDone: PROC RETURNS [fault: BOOLEAN] = { DO WHEN ClockB UP: SakuraRT.Delay[30]; MCMD _ CMDIn; [MInst, fault] _ DecodeMbusCommand[]; IF MCMD AND MInst=MapOpDone THEN EXIT; ENDLOOP; }; DecodeMbusCommand: PROC RETURNS [MInst: DragonCache.MbusCommand, fault: BOOLEAN] = { WITH b: MDataIn SELECT FROM Instruction => {MInst _ b.command; MRP _ b.rp; MBL _ b.bl; MWord _ b.word; fault _ FALSE}; MapCommand => {MInst _ b.command; fault _ b.fault}; ENDCASE => ERROR}; WaitOneCycle: PROC = { WHEN ClockB UP: NULL; WHEN ClockA UP: NULL; }; ReadDataFromBus: PROC [data: POINTER TO LONG CARDINAL] = { WITH b: MDataIn SELECT FROM Data => data^ _ b.data; ENDCASE => ERROR}; ArbiterInterface: DEVICE = { IN OUT GUARDIAN {} CONTROL { arbiterHolding: BOOLEAN _ FALSE; DO WHEN ClockA UP: NULL; SakuraRT.Delay[15]; IF (~ arbiterHolding) AND (PRq OR MRq) THEN { arbiterHolding _ TRUE; Rq _ TRUE} ELSE IF arbiterHolding AND ~PRq AND ~MRq THEN { arbiterHolding _ FALSE; Rq _ FALSE}; ENDLOOP} }; -- Back door operations BackDoor: DEVICE = { IN OUT GUARDIAN {} CONTROL { MInst: DragonCache.MbusCommand; DO WHEN ClockB UP: NULL; MCMD _ CMDIn; IF MCMD THEN { [MInst, ] _ DecodeMbusCommand[]; SELECT MInst FROM ReadQuad => BDReadQuad[]; WriteQuad => NULL; WriteSingle => BDWriteSingle[]; ReadMap => NULL; ReadMapAndSetRpDirty => BDReadMapAndSetRpDirty[]; SetRpDirty => BDSetRpDirty[]; DoMapOp => NULL; ENDCASE}; ENDLOOP} }; BDReadQuad: PROC = { -- Starts in B index: CARDINAL; success: BOOLEAN; ReadOneWord: PROC = { WHEN ClockB UP: IF success THEN MWData _ Data[index].D[MWord]; WHEN ClockA UP: { IF success THEN MDataOut _ [Data[MWData]]; MWord _ (MWord+1) MOD 4}; }; WHEN ClockA UP: [success, index] _ FullRpMatch[MRP, MBL]; IF success THEN { Data[index].Shared _ TRUE; SharedOut _ TRUE}; WHEN ClockB UP: NULL; THROUGH [1..4] DO ReadOneWord[] ENDLOOP; WHEN ClockB UP: SharedOut _ FALSE}; -- BDReadQuad BDWriteSingle: PROC = { index: CARDINAL; success: BOOLEAN; WHEN ClockA UP: [success, index] _ FullRpMatch[MRP, MBL]; SakuraRT.Delay[30]; ReadDataFromBus[@MRdData]; -- (A) WHEN ClockB UP: IF success THEN { Data[index].D[MWord] _ MRdData}};-- BDWriteSingle BDReadMapAndSetRpDirty: PROC = { index: CARDINAL; success: BOOLEAN; WHEN ClockA UP: [success, index] _ FullRpMatch[MRP, MBL]; WHEN ClockB UP: IF success THEN Data[index].RpDirty _ TRUE}; -- BDReadMapAndSetRpDirty BDSetRpDirty: PROC = { index: CARDINAL; success: BOOLEAN; WHEN ClockA UP: [success, index] _ FullRpMatch[MRP, MBL]; WHEN ClockB UP: IF success THEN Data[index].RpDirty _ TRUE}; -- BDSetRpDirty Reject _ FALSE; SharedOut _ FALSE; CMDOut _ FALSE; FOR i: CARDINAL IN [0..DataArraySize) DO Data[i].VpValid _ Data[i].RpValid _ FALSE ENDLOOP; WHEN ClockA UP: NULL; CIRCUIT { COMPONENTS pbus: PbusFetch, fetch: FetchTransport, store: StoreTransport, domapop: DoMapOpTransport, mproc: MProc, backdoor: BackDoor, arbinterface: ArbiterInterface NODES REPRESENTATION CONNECTIONS pbus[], fetch[], store[], domapop[], mproc[], backdoor[], arbinterface[]} } }; -- Data array access procedures FullVpMatch: PROC [vp: LONG CARDINAL, bl: CARDINAL] RETURNS [BOOLEAN, CARDINAL] = { FOR i: CARDINAL IN [0..DataArraySize) DO IF Data[i].VpValid AND Data[i].vp=vp AND Data[i].bl=bl THEN RETURN [TRUE, i] ENDLOOP; RETURN[FALSE, 0]}; FullRpMatch: PROC [rp: LONG CARDINAL, bl: CARDINAL] RETURNS [BOOLEAN, CARDINAL] = { FOR i: CARDINAL IN [0..DataArraySize) DO IF Data[i].RpValid AND Data[i].rp=rp AND Data[i].bl=bl THEN RETURN [TRUE, i] ENDLOOP; RETURN[FALSE, 0]}; PartialMatch: ENTRY PROC [vp: LONG CARDINAL] RETURNS [BOOLEAN, CARDINAL] = { FOR i: CARDINAL IN [0..DataArraySize) DO IF Data[i].VpValid AND Data[i].vp=vp THEN { RpDirtyReg _ Data[i].RpDirty; RETURN [TRUE, i] } ENDLOOP; RETURN[FALSE, 0]}; }.