-- File: [Indigo]<Sakura>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]};
}.