SmallCachePmCodeImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Created: Douady, Sindhu April 10, 1987 12:50:16 pm PDT
Pradeep Sindhu May 16, 1988 3:45:34 am PDT
Cesar Douady May 13, 1987 3:09:46 pm PDT
Don Curry June 7, 1988 9:26:26 pm PDT
This module defines the Processor-side microcode. Note that only the combinatorial part is modeled, and that the input, output, and feedback registers are within a higher level block defined by the schematic PCtl.sch.
In writing the microcode, we have made the following assumption about the speed of this combinatorial block: signals can go through the block in under one clock cycle, so that inputs need to come directly from a clocked register, and outputs need to go directly to a clocked register, with no intervening logic. This structure implies that the minimum delay between the microcode asserting a signal, and that signal having an effect on the input, is two cycles. This minimum delay is, in fact, used for the signal PCtlSetNonFBTIP -> NonFBTIP.
DIRECTORY
Core, CoreClasses, CoreCreate, CoreFlat, DynaBusInterface, FSM, IO, Ports, Rope, Rosemary, RosemaryUser, SmallCacheLogic, SmallCacheUtils, TerminalIO;
SmallCachePmCodeImpl: CEDAR PROGRAM
IMPORTS Ports, Rosemary, SmallCacheLogic, SmallCacheUtils, TerminalIO
EXPORTS SmallCacheLogic
~ BEGIN OPEN SmallCacheLogic;
Type Defs and Constants
IndexType: TYPE = {Label, ReturnAddress, IOAddr};
NumPCmdBits: NAT = 4;
Variable Defs
Microcode Labels
-- Begin Labels
Unused0PC: NAT = Next[Label]; -- for compatibility with FSM Impl
Init: NAT = Next[Label];
ChkPermPC: NAT = Next[Label];
CP1PC: NAT = Next[Label];
CP2PC: NAT = Next[Label];
CP3PC: NAT = Next[Label];
HandleMissPC: NAT = Next[Label];
HM1PC: NAT = Next[Label];
HM2PC: NAT = Next[Label];
HM3PPC: NAT = Next[Label];
HM3nPPC: NAT = Next[Label];
HMnMPC: NAT = Next[Label];
HMnM11PC: NAT = Next[Label];
HMnM12PC: NAT = Next[Label];
HMnM3PC: NAT = Next[Label];
HMnM4PC: NAT = Next[Label];
HMRCamReadyPC: NAT = Next[Label];
HMReadRamPC: NAT = Next[Label];
HMReturn1PC: NAT = Next[Label];
HMReturn2PC: NAT = Next[Label];
HMReturn3PC: NAT = Next[Label];
HMReturn4PC: NAT = Next[Label];
HMReturn5PC: NAT = Next[Label];
HMRR2PC: NAT = Next[Label];
HMRR3PC: NAT = Next[Label];
HMRR4PC: NAT = Next[Label];
HMRRCVct2PC: NAT = Next[Label];
HMRRCVct3PC: NAT = Next[Label];
HMRRCVct4PC: NAT = Next[Label];
HMRRCVM3PC: NAT = Next[Label];
HMRRCVM4PC: NAT = Next[Label];
IdlePC: NAT = Next[Label];
PCWS3PC: NAT = Next[Label];
PCWS4PC: NAT = Next[Label];
PCWS5PC: NAT = Next[Label];
PCWS6PC: NAT = Next[Label];
PCWS7PC: NAT = Next[Label];
PCWS8PC: NAT = Next[Label];
PCWS9PC: NAT = Next[Label];
PCWS10PC: NAT = Next[Label];
PCWS11PC: NAT = Next[Label];
PCWS12PC: NAT = Next[Label];
PCWS13PC: NAT = Next[Label];
PCWS14PC: NAT = Next[Label];
PCWS15PC: NAT = Next[Label];
PCWS15PrimePC: NAT = Next[Label];
PCWS16PC: NAT = Next[Label];
PCWS17PC: NAT = Next[Label];
PCWS18PC: NAT = Next[Label];
PCWSR2PC: NAT = Next[Label];
PCWSRetryPC: NAT = Next[Label];
PSR2PC: NAT = Next[Label];
PSR2PrimePC: NAT = Next[Label];
PSR3PC: NAT = Next[Label];
PSR4PC: NAT = Next[Label];
PSR5PC: NAT = Next[Label];
PSRetryPC: NAT = Next[Label];
PSReturn1PC: NAT = Next[Label];
PSReturn2PC: NAT = Next[Label];
PSRCamReadyPC: NAT = Next[Label];
PSRRCVM2PC: NAT = Next[Label];
PSRRCVM3PC: NAT = Next[Label];
PSRRCVM4PC: NAT = Next[Label];
PStorePC: NAT = Next[Label];
SBTOF2PC: NAT = Next[Label];
SBTOF3PC: NAT = Next[Label];
SIOAF2PC: NAT = Next[Label];
SIOAF3PC: NAT = Next[Label];
SMAF2PC: NAT = Next[Label];
SMAF3PC: NAT = Next[Label];
StoreBTimeOutFaultPC: NAT = Next[Label];
StoreMemAccessFaultPC: NAT = Next[Label];
StoreIOAccessFaultPC: NAT = Next[Label];
TestShiftVictimPC: NAT = Next[Label];
TestReadRamPC: NAT = Next[Label];
TestReadRCamPC: NAT = Next[Label];
TestReadVCamPC: NAT = Next[Label];
TestResetVictimPC: NAT = Next[Label];
TRR2PC: NAT = Next[Label];
TRR3PC: NAT = Next[Label];
TRV2PC: NAT = Next[Label];
TRRC2PC: NAT = Next[Label];
TRRC3PC: NAT = Next[Label];
TRRC4PC: NAT = Next[Label];
TRRC5PC: NAT = Next[Label];
TRRC6PC: NAT = Next[Label];
TRVC2PC: NAT = Next[Label];
TRVC3PC: NAT = Next[Label];
TRVC4PC: NAT = Next[Label];
TRVC5PC: NAT = Next[Label];
TRVC6PC: NAT = Next[Label];
TSV2PC: NAT = Next[Label];
TSV3PC: NAT = Next[Label];
-- End Labels
MaxPC: NAT = Next[Label];
NumPCBits: PUBLIC NAT ← 1+SmallCacheUtils.Log2[MaxPC-1];
Microcode Return Addresses
FromRead,
FromIORead:  NAT = 0;
FromWrite,
FromIOWrite:  NAT = 1;
FromCWS:   NAT = 2; -- FromCWS encoded as 2 or 3 in HMReturn2PC
NumStackBits: PUBLIC NAT ← 2;
ABus Source Codes
ABusPAdd: NAT = 0;
ABusRqstBuf: NAT = 1;
ABusVCam: NAT = 4;
  -- opCode 5 is forbidden by the hardware
ABusCam: NAT = 6;
ABusRCam: NAT = 7;
ABusIOOld: NAT = 8;
ABusIONew: NAT = 9;
ABusIOAId: NAT = 12;
ABusIOFault: NAT = 13;
ABusFault: NAT = 8;
DBus Source Codes
DBusWdRdData: NAT = 0; -- This is the default
DBusPWtLatch: NAT = 1;
DBusRRLatch: NAT = 2;
DBusABus: NAT = 3;
Array Multiplexer Select Codes
SCmdNoOp: NAT = 0;
SCmdLRM: NAT = 1;
SCmdLVM: NAT = 2;
SCmdVictim: NAT = 3;
PCmd Defs
PCmdNoOp: NAT = 7;
PCmdRead: NAT = 8;
PCmdWrite: NAT = 9;
PCmdCWS: NAT = 10;
PCmdDeMap: NAT = 11;
PCmdIORead: NAT = 12;
PCmdIOWrite: NAT = 13;
PCmdClrAllVPV: NAT = 14;
PCmdBIOWrite: NAT = 15;
BCmd Defs
BCmdBIOW: NAT = ORD[DynaBusInterface.Cmd.BIOWRqst]/2;
BCmdCWS: NAT = ORD[DynaBusInterface.Cmd.CWSRqst]/2;
BCmdDeMap: NAT = ORD[DynaBusInterface.Cmd.DeMapRqst]/2;
BCmdFB: NAT = ORD[DynaBusInterface.Cmd.FBRqst]/2;
BCmdIOR: NAT = ORD[DynaBusInterface.Cmd.IORRqst]/2;
BCmdIOW: NAT = ORD[DynaBusInterface.Cmd.IOWRqst]/2;
BCmdMap: NAT = ORD[DynaBusInterface.Cmd.MapRqst]/2;
BCmdRB: NAT = ORD[DynaBusInterface.Cmd.RBRqst]/2;
BCmdWB: NAT = ORD[DynaBusInterface.Cmd.WBRqst]/2;
BCmdWS: NAT = ORD[DynaBusInterface.Cmd.WSRqst]/2;
Fault Code Defs
Note: the microcode only generates the two most significant bits of fault code (the least significant bit is always 1 for faults generated by the cache--see PInterfaceSpecs).
MemAccessFault: NAT = 0;
IOAccessFault: NAT = 1;
DynaBusTimeOut: NAT = 2;
Signal Defs
signals: Signals ← NEW [SignalsRec[100]];
ASh: NAT = Declare[signals, "ASh", X, Input];
AVM: NAT = Declare[signals, "AVM", X, Input];
MyBFault: NAT = Declare[signals, "MyBFault", X, Input];
NonFBTIP: NAT = Declare[signals, "NonFBTIP", X, Input];
PAccessPermission: NAT = Declare[signals, "PAccessPermission", X, Input];
PCmd: NAT = DeclareS[signals, "PCmd", NumPCmdBits, Xs, Input];
PCWSEq: NAT = Declare[signals, "PCWSEq", X, Input];
RamForP: NAT = Declare[signals, "RamForP", X, Input];
RCamForP: NAT = Declare[signals, "RCamForP", X, Input];
RPValid: NAT = Declare[signals, "RPValid", X, Input];
TimeOut: NAT = Declare[signals, "TimeOut", X, Input];
PC: NAT = DeclareS[signals, "PC", NumPCBits, Xs, Input];
Stack: NAT = DeclareS[signals, "Stack", NumStackBits, Xs, Input];
Reset: NAT = Declare[signals, "Reset", X, Input];
PCtlABusCmd: NAT = DeclareS[signals, "PCtlABusCmd", 4, ABusPAdd, Output];
PCtlBCmd: NAT = DeclareS[signals, "PCtlBCmd", 4, 0, Output];
PCtlBusy: NAT = Declare[signals, "PCtlBusy", H, Output];
PCtlClrAllVPV: NAT = Declare[signals, "PCtlClrAllVPV", L, Output];
PCtlCSCmd: NAT = DeclareS[signals, "PCtlCSCmd", 2, SCmdNoOp, Output];
PCtlDBusCmd: NAT = DeclareS[signals, "PCtlDBusCmd", 2, DBusWdRdData, Output];
PCtlEnCamSel: NAT = Declare[signals, "PCtlEnCamSel", L, Output];
PCtlEnCamSelExt: NAT = Declare[signals, "PCtlEnCamSelExt", L, Output];
PCtlFault: NAT = Declare[signals, "PCtlFault", L, Output];
PCtlFaultCode: NAT = DeclareS[signals, "PCtlFaultCode", 2, 0, Output];
PCtlLdFlagsReg: NAT = Declare[signals, "PCtlLdFlagsReg", L, Output];
PCtlForceWordAddress: NAT = Declare[signals, "PCtlForceWordAddress", L, Output];
PCtlPartFMch: NAT = Declare[signals, "PCtlPartFMch", L, Output];
PCtlFrzVictim: NAT = Declare[signals, "PCtlFrzVictim", L, Output];
PCtlLdFIFOIfAOw: NAT = Declare[signals, "PCtlLdFIFOIfAOw", L, Output];
PCtlLdRBufDataLo: NAT = Declare[signals, "PCtlLdRBufDataLo", L, Output];
PCtlLdRBufDataHi: NAT = Declare[signals, "PCtlLdRBufDataHi", L, Output];
PCtlLdRBufHeader: NAT = Declare[signals, "PCtlLdRBufHeader", L, Output];
PCtlLdSnooper: NAT = Declare[signals, "PCtlLdSnooper", L, Output];
PCtlPartVMch: NAT = Declare[signals, "PCtlPartVMch", L, Output];
PCtlRdRam: NAT = Declare[signals, "PCtlRdRam", L, Output];
PCtlRdRCam: NAT = Declare[signals, "PCtlRdRCam", L, Output];
PCtlRdVCam: NAT = Declare[signals, "PCtlRdVCam", L, Output];
PCtlReleaseP: NAT = Declare[signals, "PCtlReleaseP", L, Output];
PCtlResetVictim: NAT = Declare[signals, "PCtlResetVictim", L, Output];
PCtlRSCmd: NAT = DeclareS[signals, "PCtlRSCmd", 2, SCmdNoOp, Output];
PCtlSelBFC: NAT = Declare[signals, "PCtlSelBFC", L, Output];
PCtlSelRplyData: NAT = Declare[signals, "PCtlSelRplyData", L, Output];
PCtlSetFBTIP: NAT = Declare[signals, "PCtlSetFBTIP", L, Output];
PCtlSetNonFBTIP: NAT = Declare[signals, "PCtlSetNonFBTIP", L, Output];
PCtlSetSnooperValid: NAT = Declare[signals, "PCtlSetSnooperValid", L, Output];
PCtlShftVictim: NAT = Declare[signals, "PCtlShftVictim", L, Output];
PCtlWtMchVCam: NAT = Declare[signals, "PCtlWtMchVCam", L, Output];
PCtlWtRam: NAT = Declare[signals, "PCtlWtRam", L, Output];
NxtPC: NAT = DeclareS[signals, "NxtPC", NumPCBits, 0, Output ];
NxtStack: NAT = DeclareS[signals, "NxtStack", NumStackBits, 0, Output];
Push: NAT = Declare[signals, "Push", L, Output];
Vdd: NAT = Declare[signals, "Vdd", X, Power];
Gnd: NAT = Declare[signals, "Gnd", X, Power];
Public Procs
PmCode: PUBLIC PROC [] RETURNS [ct: CellType] = {
ct ← Create[pmCodeName, signals]
};
Internal Procs
InitPmCode: Rosemary.InitProc = {
GetPortIndices[signals, cellType]
};
Simple: Rosemary.EvalProc = {
v: PROC [ix: NAT] RETURNS [BOOL] = {
level: Level ← p[signals[ix].index].l;
IF level=X THEN ERROR ELSE RETURN[level=H]
};
vs: PROC [ix: NAT] RETURNS [NAT] = {
RETURN[Ports.LSToLC[p[signals[ix].index].ls]]
};
s: PROC [ix: NAT, l: Level] = {
p[signals[ix].index].l ← l
};
ss: PROC [ix: NAT, c: CARD] = {
IF c=Xs
THEN Ports.SetLS[p[signals[ix].index].ls, X]
ELSE Ports.LCToLS[c, p[signals[ix].index].ls];
};
This corresponds to the ReadRCam command cycle
ReadRCam1: PROC [enExt: Level ← L] = {
s[PCtlRdRCam, H];
s[PCtlEnCamSel, H];
s[PCtlEnCamSelExt, enExt];
};
This corresponds to the first cycle of RCam use
ReadRCam2: PROC [sCmd: NAT, enExt: Level ← L] = {
s[PCtlRdRCam, H];
s[PCtlEnCamSel, H];
s[PCtlEnCamSelExt, enExt];
ss[PCtlCSCmd, sCmd];
};
This corresponds to the second and third cycles of RCam use (note they are the same)
ReadRCam34: PROC [sCmd: NAT] = {
ss[PCtlCSCmd, sCmd];
};
This corresponds to the ReadVCam command cycle
ReadVCam1: PROC [sCmd: NAT] = {
s[PCtlRdVCam, H];
s[PCtlEnCamSel, H];
s[PCtlEnCamSelExt, H];
};
This corresponds to the first cycle of VCam use
ReadVCam2: PROC [sCmd: NAT] = {
s[PCtlRdVCam, H];
s[PCtlEnCamSel, H];
s[PCtlEnCamSelExt, H];
ss[PCtlCSCmd, sCmd];
};
This corresponds to the second and third cycles of VCam use (note they are the same)
ReadVCam34: PROC [sCmd: NAT] = {
ss[PCtlCSCmd, sCmd];
};
This corresponds to the ReadRam command cycle
ReadRam1: PROC [sCmd: NAT, drDBus: {DBus, NoDBus} ← DBus] = {
ss[PCtlRSCmd, sCmd];
s[PCtlRdRam, H];
};
This corresponds to the first cycle of Ram use (note that ReadRam2 must follow ReadRam1
ReadRam2: PROC [sCmd: NAT, drDBus: {DBus, NoDBus} ← DBus] = {
ss[PCtlRSCmd, sCmd];
IF drDBus = DBus THEN ss[PCtlDBusCmd, DBusWdRdData];
};
This corresponds to the second cycle of Ram use
ReadRam3: PROC [sCmd: NAT, drDBus: {DBus, NoDBus} ← DBus] = {
IF drDBus = DBus THEN ss[PCtlDBusCmd, DBusWdRdData];
};
This corresponds to the WriteRam command cycle
WriteRam1: PROC [sCmd: NAT, data: NAT] = {
ss[PCtlRSCmd, sCmd];
s[PCtlWtRam, H];
};
This corresponds to the first cycle of Ram use (note that WriteRam2 must follow ReadRam1
WriteRam2: PROC [sCmd: NAT, data: NAT] = {
ss[PCtlRSCmd, sCmd];
ss[PCtlDBusCmd, data];
};
This corresponds to the second cycle of Ram use
WriteRam3: PROC [sCmd: NAT, data: NAT] = {
ss[PCtlDBusCmd, data];
};
Jmp: PROC [dest: NAT] = {
IF dest=StoreBTimeOutFaultPC OR
dest=StoreMemAccessFaultPC OR
dest=StoreIOAccessFaultPC THEN {
ss[PCtlABusCmd, ABusIOFault];
s[PCtlWtMchVCam, H];
};
IF dest=IdlePC THEN {
s[PCtlBusy, L];
s[PCtlLdRBufDataLo, H];  -- to make WriteSingle (shared) go faster
};
ss[NxtPC, dest];
};
OutputsToDefault[p, signals];
The microcode
SELECT p[signals[Reset].index].l FROM
= X => {OutputsToX[p, signals]; RETURN};
= H => {
s[Push, H]; ss[NxtStack, FromRead]; Jmp[Init]
};
= L => {
SELECT vs[PC] FROM -- Begin Transitions
= Init  => {
IF TRUE THEN {
Initiate Reset sequence:
s[PCtlClrAllVPV, H];
Jmp[IdlePC];
};
};
= IdlePC  => {
SELECT vs[PCmd] FROM
<= PCmdNoOp => {
Wait for something to happen
Jmp[IdlePC];
};
= PCmdRead => {
IF v[AVM] THEN {
A hit: Everything is done automatically
Jmp[IdlePC];
};
IF NOT v[AVM] THEN {
A miss: Do partial virtual match to find translation
s[PCtlPartVMch, H];
s[PCtlPartFMch, H];
s[PCtlWtMchVCam, H];
s[Push, H];
ss[NxtStack, FromRead];
Jmp[HandleMissPC];
};
};
= PCmdWrite => {
IF v[AVM] THEN {
A hit: Check if shared bit is set; Wait for ASh to be available
s[PCtlBusy, L];
Jmp[PStorePC];
};
IF NOT v[AVM] THEN {
A miss: Do partial virtual match to find translation
s[PCtlPartVMch, H];
s[PCtlPartFMch, H];
s[PCtlWtMchVCam, H];
s[Push, H];
ss[NxtStack, FromWrite];
Jmp[HandleMissPC];
};
};
= PCmdCWS => {
IF v[AVM] THEN {
A hit: Good, get the old value
ss[PCtlABusCmd, ABusIOOld];
s[PCtlWtMchVCam, H];
Jmp[PCWS3PC];
};
IF NOT v[AVM] THEN {
A miss: Do partial virtual match to find translation
s[PCtlPartVMch, H];
s[PCtlPartFMch, H];
s[PCtlWtMchVCam, H];
s[Push, H];
ss[NxtStack, FromCWS];
Jmp[HandleMissPC];
};
};
= PCmdDeMap => {
IF TRUE THEN {
This operation always misses: Load RqstBuf header with address; Send ArbRequest; Set NonFBTIP (continuation is the same as IOWrite)
s[PCtlLdRBufHeader, H];
s[PCtlSetNonFBTIP, H];
ss[PCtlBCmd, BCmdDeMap];
ss[PCtlABusCmd, ABusPAdd];
Jmp[PSReturn1PC];
};
};
= PCmdIORead => {
IF v[AVM] THEN {
A hit: Everything is done automatically
Jmp[IdlePC];
};
IF NOT v[AVM] THEN {
A miss: Check if we have access permission; First match without flags
s[PCtlPartFMch , H];
s[PCtlWtMchVCam, H];
s[Push, H];
ss[NxtStack, FromIORead];
Jmp[ChkPermPC];
};
};
= PCmdIOWrite => {
IF v[AVM] THEN {
A hit: Everything is done automatically
Jmp[IdlePC];
};
IF NOT v[AVM] THEN {
A miss: Check if we have access permission; First match without flags
s[PCtlPartFMch, H];
s[PCtlWtMchVCam, H];
s[Push, H];
ss[NxtStack, FromIOWrite];
Jmp[ChkPermPC];
};
};
= PCmdClrAllVPV => {
IF TRUE THEN {
This operation always misses: Just pulse PCtlClrAllVPV and releaseP
s[PCtlClrAllVPV, H];
s[PCtlReleaseP, H];
Jmp[IdlePC];
};
};
= PCmdBIOWrite => {
IF TRUE THEN {
This operation always misses: Load RqstBuf header with IO address; Send ArbRequest; Set NonFBTIP (continuation is the same as IOWrite)
s[PCtlLdRBufHeader, H];
s[PCtlSetNonFBTIP, H];
ss[PCtlBCmd, BCmdBIOW];
ss[PCtlABusCmd, ABusPAdd];
Jmp[PSReturn1PC];
};
};
ENDCASE => ERROR;
};
= ChkPermPC => {
IF TRUE THEN {
Wait virtual match w/o flags to complete, 1 of 3
s[PCtlPartFMch, H];
Jmp[CP1PC];
};
};
= CP1PC => {
IF TRUE THEN {
Wait virtual match w/o flags to complete, 2 of 3
Jmp[CP2PC];
};
};
= CP2PC => {
IF TRUE THEN {
Wait virtual match w/o flags to complete, 3 of 3
Jmp[CP3PC];
};
};
= CP3PC => {
IF v[AVM] THEN {
Partial match successful: an IO access permission fault, store it and return
Jmp[StoreIOAccessFaultPC];
};
IF NOT v[AVM] THEN {
A miss. Generate IO(Read/Write) Rqst packet: Load RqstBuf header with IO address; Load RqstBuf data with PData (doesn't hurt for read); Send ArbRqst; Set NonFBTIP; Return when transaction completes (same as PS)
ss[PCtlABusCmd, ABusPAdd];
s[PCtlLdRBufHeader, H];
ss[PCtlDBusCmd, DBusPWtLatch];
s[PCtlLdRBufDataLo, H];
s[PCtlLdRBufDataHi, H];
s[PCtlSetNonFBTIP, H];
Jmp[PSReturn1PC];
SELECT vs[Stack] FROM
= FromIORead => {
Generate IOReadRqst
ss[PCtlBCmd, BCmdIOR]};
= FromIOWrite => {
Generate IOWriteRqst
ss[PCtlBCmd, BCmdIOW]};
= FromCWS => { -- do as FromIORead
TerminalIO.PutRope
["***Stack Value 2 is not valid for state: CP3PC\n"];
ss[PCtlBCmd, BCmdIOR]};
ENDCASE => { -- do as FromIOWrite
TerminalIO.PutRope
["***Stack Value 3 is not valid for state: CP3PC\n"];
ss[PCtlBCmd, BCmdIOW]};
};
};
= PCWSRetryPC => {
IF TRUE THEN {
Wait for AVM, 1 of 3: Don't need Ram value, just want to verify a hit
Jmp[PCWSR2PC];
};
};
= PCWSR2PC => {
IF TRUE THEN {
Wait for AVM, 2 of 3
ss[PCtlABusCmd, ABusIOOld];
s[PCtlWtMchVCam, H];
Jmp[PCWS3PC];
};
};
= PCWS3PC => {
IF TRUE THEN {
Wait for AVM, 3 of 3: Read Ram to get the old value
ReadRam1[SCmdLVM];
Jmp[PCWS4PC];
};
};
= PCWS4PC => {
IF v[AVM] THEN {
A hit: Wait for PCWSEq, 1 of 3; (Can't let the processor go, sample value may be wrong)
ReadRam2[SCmdLVM];
Jmp[PCWS5PC];
};
IF NOT v[AVM] THEN {
A miss: Do partial virtual match to find translation
ReadRam2[SCmdLVM];
s[PCtlPartVMch, H];
s[PCtlPartFMch, H];
s[PCtlWtMchVCam, H];
s[Push, H];
ss[NxtStack, FromCWS];
Jmp[HandleMissPC];
};
};
= PCWS5PC => {
IF v[RamForP] THEN {
Wait for PCWSEq, 2 of 3: Compare old and sample; Put old in RqstBuf in case shared is set
s[PCtlLdRBufDataHi, H];
ReadRam3[SCmdLVM];
Jmp[PCWS6PC];
};
IF NOT v[RamForP] THEN {
Ratted! Just redo it: Read Ram to get the old value
ReadRam1[SCmdLVM];
Jmp[PCWS4PC];
};
};
= PCWS6PC => {
IF TRUE THEN {
Wait for PCWSEq, 3 of 3
Jmp[PCWS7PC];
};
};
= PCWS7PC => {
IF v[PCWSEq] THEN {
Read new value from the Ram, present IOAddress to VCam
ss[PCtlABusCmd, ABusIONew];
s[PCtlWtMchVCam, H];
Jmp[PCWS8PC];
};
IF NOT v[PCWSEq] THEN {
Not equal: Don't need to do anything
s[PCtlReleaseP, H];
Jmp[IdlePC];
};
};
= PCWS8PC => {
IF TRUE THEN {
Read new value from the Ram, send ReadRam pulse
ReadRam1[SCmdLVM];
Jmp[PCWS9PC];
};
};
= PCWS9PC => {
IF TRUE THEN {
Wait for data to appear on DBus, 1 of 2; (note that we can't start the match for PAdr here because this will disturb the contents of LVM which is being used to read the new value)
ReadRam2[SCmdLVM];
Jmp[PCWS10PC];
};
};
= PCWS10PC => {
IF v[RamForP] THEN {
Wait for data to appear on DBus, 2 of 2: Start writing new data back; Load Rqst Buffer with new value in case shared bit is set; match PAdr to prepare the write
ReadRam3[SCmdLVM];
s[PCtlLdRBufDataLo, H];
ss[PCtlABusCmd, ABusPAdd];
s[PCtlWtMchVCam, H];
Jmp[PCWS11PC];
};
IF NOT v[RamForP] THEN {
Ratted! Re-read new value from scrtach; Present IOAddress to VCam
ss[PCtlABusCmd, ABusIONew];
s[PCtlWtMchVCam, H];
Jmp[PCWS8PC];
};
};
= PCWS11PC => {
IF TRUE THEN {
Start to write the new value
WriteRam1[SCmdLVM, DBusRRLatch];
Jmp[PCWS12PC];
};
};
= PCWS12PC => {
IF TRUE THEN {
Select RamReadLatch to go to the Ram, 1 of 2
Wait for Ash, 1 of 3
WriteRam2[SCmdLVM, DBusRRLatch];
Jmp[PCWS13PC];
};
};
= PCWS13PC => {
IF v[RamForP] THEN {
Select RamReadLatch to go to the Ram, 2 of 2; Wait for Ash, 2 of 3; Start RCam read in case of ASh
WriteRam3[SCmdLVM, DBusRRLatch];
s[PCtlWtMchVCam, H];
ss[PCtlABusCmd, ABusPAdd];
Jmp[PCWS14PC];
};
IF NOT v[RamForP] THEN {
Ratted! Re-read the new value from scratch; Present IOAddress to VCam
ss[PCtlABusCmd, ABusIONew];
s[PCtlWtMchVCam, H];
Jmp[PCWS8PC];
};
};
= PCWS14PC => {
IF TRUE THEN {
Wait for Ash, 3 of 3; Read RCam, cycle 1
ReadRCam1[];
Jmp[PCWS15PC];
};
};
= PCWS15PC => {
IF v[ASh] AND v[RCamForP] THEN {
Data is shared, generate CWSRqst; Read RCam to get real address, cycle 2
ReadRCam2[SCmdLVM];
Jmp[PCWS16PC];
};
IF v[ASh] AND NOT v[RCamForP] THEN {
Don't have RCam; Read RCam to get real address, cycle 1
ReadRCam1[];
Jmp[PCWS15PrimePC];
};
IF NOT v[ASh] THEN {
Data is not shared, we are done
s[PCtlReleaseP, H];
Jmp[IdlePC];
};
};
= PCWS15PrimePC => {
IF v[RCamForP] THEN {
First, read RCamPage|VCamBlock to get the real address, cycle 2
ReadRCam2[SCmdLVM];
Jmp[PCWS16PC];
};
IF NOT v[RCamForP] THEN {
First, read RCam to get the real address, cycle 1
ReadRCam1[];
Jmp[PCWS15PrimePC];
};
};
= PCWS16PC => {
IF v[RCamForP] THEN {
Read RCam, cycle 3; We have the RCam, go to next cycle
ReadRCam34[SCmdLVM];
Jmp[PCWS17PC];
};
IF NOT v[RCamForP] THEN {
Read RCam, cycle 1; We don't have the RCam, return to cycle 2
ReadRCam1[];
Jmp[PCWS15PrimePC];
};
};
= PCWS17PC => {
IF v[RCamForP] THEN {
Read RCam, cycle 4; RCamPage|VCamBlock has been read; Send ArbRqst; Set NonFBTIP
s[PCtlSetNonFBTIP, H];
ReadRCam34[SCmdLVM];
Jmp[PCWS18PC];
};
IF NOT v[RCamForP] THEN {
Read RCam, cycle 1; We don't have the RCam, return to cycle 2
ReadRCam1[];
Jmp[PCWS15PrimePC];
};
};
= PCWS18PC => {
IF TRUE THEN {
Load RqstBuf header with real address
s[PCtlLdRBufHeader, H];
ss[PCtlBCmd, BCmdCWS];
ss[PCtlABusCmd, ABusCam];
Jmp[PSReturn2PC];
};
};
= PSRetryPC => {
IF TRUE THEN {
Wait for AVM, 1 of 3; Write Ram in case of a match
WriteRam1[SCmdLVM, DBusPWtLatch];
Jmp[PSR2PC];
};
};
= PSR2PrimePC => {
IF v[AVM] THEN {
Wait for time to pass
WriteRam2[SCmdLVM, DBusPWtLatch];
Jmp[PSR3PC];
};
IF NOT v[AVM] THEN {
A miss: Do partial virtual match to find translation
s[PCtlPartVMch, H];
s[PCtlPartFMch, H];
s[PCtlWtMchVCam, H];
s[Push, H];
ss[NxtStack, FromWrite];
Jmp[HandleMissPC];
};
};
= PSR2PC => {
IF TRUE THEN {
Wait for AVM, 2 of 3
WriteRam2[SCmdLVM, DBusPWtLatch];
Jmp[PSR3PC];
};
};
= PSR3PC => {
IF v[RamForP] THEN {
Wait for AVM, 3 of 3
WriteRam3[SCmdLVM, DBusPWtLatch];
Jmp[PSR4PC];
};
IF NOT v[RamForP] THEN {
Ratted! Just redo it; Write the Ram in case of a match
WriteRam1[SCmdLVM, DBusPWtLatch];
Jmp[PSR2PrimePC];
};
};
= PSR4PC => {
IF v[AVM] THEN {
A hit: Check for shared bit; Wait for ASh to be available
Jmp[PSR5PC];
};
IF NOT v[AVM] THEN {
A miss: Do partial virtual match to find translation
s[PCtlPartVMch, H];
s[PCtlPartFMch, H];
s[PCtlWtMchVCam, H];
s[Push, H];
ss[NxtStack, FromWrite];
Jmp[HandleMissPC];
};
};
= PSR5PC => {
IF v[ASh] THEN {
Data is shared, generate WSRqst; Read RCam to get the real address
ReadRCam1[];
Jmp[PSRRCVM2PC];
};
IF NOT v[ASh] THEN {
Data is not shared, everything is done automatically: Release processor
s[PCtlReleaseP, H];
Jmp[IdlePC];
};
};
= PStorePC => {
IF v[ASh] THEN {
Data is shared, generate WSRqst; Read RCam to get the real address
ReadRCam1[];
Jmp[PSRRCVM2PC];
};
IF NOT v[ASh] THEN {
Data is not shared, everything is done automatically
Jmp[IdlePC];
};
};
= PSRRCVM2PC => {
IF v[RCamForP] THEN {
Read RCam, cycle 2: We have RCam, go to next cycle
ReadRCam2[SCmdLVM];
Jmp[PSRRCVM3PC];
};
IF NOT v[RCamForP] THEN {
Read RCam, cycle 1: We don't have RCam, return to cycle 2
ReadRCam1[];
Jmp[PSRRCVM2PC];
};
};
= PSRRCVM3PC => {
IF v[RCamForP] THEN {
Read RCam, cycle 3: We have RCam, go to next cycle
ReadRCam34[SCmdLVM];
Jmp[PSRRCVM4PC];
};
IF NOT v[RCamForP] THEN {
Read RCam, cycle 1: We don't have RCam, return to cycle 2
ReadRCam1[];
Jmp[PSRRCVM2PC];
};
};
= PSRRCVM4PC => {
IF v[RCamForP] THEN {
Read RCam, cycle 4: RCam has been read; Send ArbRqst; Set NonFBTIP
s[PCtlSetNonFBTIP, H];
ReadRCam34[SCmdLVM];
Jmp[PSRCamReadyPC];
};
IF NOT v[RCamForP] THEN {
Read RCam, cycle 1: We don't have RCam, return to cycle 2
ReadRCam1[];
Jmp[PSRRCVM2PC];
};
};
= PSRCamReadyPC => {
IF TRUE THEN {
Load Rqst buffer header with real address
s[PCtlLdRBufHeader, H];
ss[PCtlBCmd, BCmdWS];
ss[PCtlABusCmd, ABusCam];
Jmp[PSReturn2PC];
};
};
= PSReturn1PC => {
Blow one cycle to give NonFBTIP time to be set
IF TRUE THEN {
Jmp[PSReturn2PC];
};
};
= PSReturn2PC => {
IF v[NonFBTIP] AND NOT v[TimeOut] THEN {
Wait for WSRply, IOWRply, IORRply, BIOWRply, DeMapRply
s[PCtlSelRplyData, H];
Jmp[PSReturn2PC];
};
IF v[NonFBTIP] AND v[TimeOut] THEN {
A timeOut: Signal and return
s[PCtlSelRplyData, H];
Jmp[StoreBTimeOutFaultPC];
};
IF NOT v[NonFBTIP] AND v[MyBFault] THEN {
WSRply has come back with a fault, release processor and return
s[PCtlFault, H];
s[PCtlSelBFC, H];
s[PCtlReleaseP, H];
s[PCtlSelRplyData, H];
Jmp[IdlePC];
};
IF NOT v[NonFBTIP] AND NOT v[MyBFault] THEN {
Reply has come back, release processor and return
s[PCtlReleaseP, H];
s[PCtlSelRplyData, H];
Jmp[IdlePC];
};
};
= HandleMissPC => {
IF TRUE THEN {
Wait for partial virtual match, 1 of 3: (Could begin the RCam read here at the expense of (~6) more lines) Freeze victim, Cycle 1 of 2
s[PCtlPartVMch, H];
s[PCtlPartFMch, H];
s[PCtlFrzVictim, H];
Jmp[HM1PC];
};
};
Note: The index i in HMiPC refers to time, not cycle number
= HM1PC => {
IF TRUE THEN {
Wait for partial virtual match, 2 of 3: Initiate RCam read in case partial match succeeds, Read RCam cycle 1; Freeze victim, Cycle 2 of 2
ReadRCam1[];
s[PCtlFrzVictim, H];
Jmp[HM2PC];
};
};
= HM2PC => {
IF v[RCamForP] THEN {
Wait for partial virtual match, 3 of 3; Read RCam, cycle 2
ReadRCam2[SCmdLVM];
Jmp[HM3PPC];
};
IF NOT v[RCamForP] THEN {
Wait for partial virtual match, 3 of 3; Don't have RCam, Read RCam, cycle 1
ReadRCam1[];
Jmp[HM3nPPC];
};
};
= HM3PPC => {
IF v[AVM] AND v[RCamForP] THEN {
Partial virtual match is successful; Read RCam, cycle 3
ReadRCam34[SCmdLVM];
Jmp[HMRRCVM4PC];
};
IF v[AVM] AND NOT v[RCamForP] THEN {
Partial virtual match is successful; Don't have RCam, Read RCam, cycle 1
ReadRCam1[];
Jmp[HM3nPPC];
};
IF NOT v[AVM] THEN {
Read AId from the Ram, first do a match in the VCam. Note that this destroys the old contents of the vCamWtReg, which will be restored automatically by the hardwired control when the MapRply comes back (see VCamInterlockCtl).
ss[PCtlABusCmd, ABusIOAId];
s[PCtlWtMchVCam, H];
Jmp[HMnMPC];
};
};
= HMnMPC => {
IF TRUE THEN {
Read AId from Ram, cycle 1; Load RqstBuf with MapRqst|myId|PAdd; Set NonFBTIP
s[PCtlLdRBufHeader, H];
ss[PCtlBCmd, BCmdMap];
ss[PCtlABusCmd, ABusPAdd];
ReadRam1[SCmdLVM];
Jmp[HMnM11PC];
};
};
= HMnM11PC => {
IF TRUE THEN {
Read AId from Ram, cycle 2; Wait for AId to appear in the RRdLatch, 1 of 1
ReadRam2[SCmdLVM];
Jmp[HMnM12PC];
};
};
= HMnM12PC => {
IF v[RamForP] THEN {
Load RBufLo with AId, RBufHi with garbage; Send ArbRqst
s[PCtlSetNonFBTIP, H];
s[PCtlLdRBufDataLo, H];
s[PCtlLdRBufDataHi, H];
ReadRam3[SCmdLVM];
Jmp[HMnM3PC];
};
IF NOT v[RamForP] THEN {
Ratted, didn't have Ram! Just redo it
ReadRam1[SCmdLVM];
Jmp[HMnM11PC];
};
};
= HMnM3PC => {
Blow one cycle to let NonFBTIP get set; drive PAdrs onto ABus and load VCamWtReg with PAdrs (remember that it got clobbered when we read AID)
IF TRUE THEN {
ss[PCtlABusCmd, ABusPAdd];
s[PCtlWtMchVCam, H];
Jmp[HMnM4PC];
};
};
= HMnM4PC => {
IF v[NonFBTIP] AND NOT v[TimeOut] THEN {
Wait for MapRply to come back; Set CSCmd to select Victim so we can drive the cam (rcampage+vcamblock) onto the ABus
ss[PCtlCSCmd, SCmdVictim];
Jmp[HMnM4PC];
};
IF v[NonFBTIP] AND v[TimeOut] THEN {
TimeOut : Signal and store the fault in the array
Jmp[StoreBTimeOutFaultPC];
};
IF NOT v[NonFBTIP] AND v[MyBFault] THEN {
MapCache fault: abort access
s[PCtlFault, H];
s[PCtlSelBFC, H];
s[PCtlReleaseP, H];
Jmp[IdlePC];
};
IF NOT v[NonFBTIP] AND NOT v[MyBFault] THEN {
Load Rqst buffer header with RealAddress; Read RCam using victim, cycle 1; Set CSCmd to select Victim so we can drive the cam (rcampage+vcamblock) onto the ABus (note that ReadRCam1 does not set the CSCmd).
s[PCtlLdRBufHeader, H];
ss[PCtlBCmd, BCmdRB];
ss[PCtlCSCmd, SCmdVictim];
ss[PCtlABusCmd, ABusCam];
ReadRCam1[enExt: H];
Jmp[HMRRCVct2PC];
};
};
For all jumps to this location except the one from HM2PC, we know that the AVM check will succeed since match is latched, and AVM was high earlier. Doing the check in all cases allows us to share this instruction, thereby eliminating waste.
= HM3nPPC => {
IF v[AVM] AND v[RCamForP] THEN {
Partial virtual match is successful; Read RCam, cycle 2
ReadRCam2[SCmdLVM];
Jmp[HMRRCVM3PC];
};
IF v[AVM] AND NOT v[RCamForP] THEN {
Partial virtual match is successful; Didn't have RCam, Read RCam, cycle 1
ReadRCam1[];
Jmp[HM3nPPC];
};
IF NOT v[AVM] THEN {
Read AId from the Ram, first find it in the VCam
ss[PCtlABusCmd, ABusIOAId];
s[PCtlWtMchVCam, H];
Jmp[HMnMPC];
};
};
= HMRRCVM3PC => {
IF v[RCamForP] THEN {
Read RCam, cycle 3
ReadRCam34[SCmdLVM];
Jmp[HMRRCVM4PC];
};
IF NOT v[RCamForP] THEN {
Read RCam, cycle 1; Didn't have RCam, redo read
ReadRCam1[];
Jmp[HM3nPPC];
};
};
= HMRRCVM4PC => {
IF v[RCamForP] THEN {
Read RCam, cycle 4; RCam has been read
ReadRCam34[SCmdLVM];
Jmp[HMRCamReadyPC];
};
IF NOT v[RCamForP] THEN {
Read RCam, cycle 1; Didn't have RCam, redo read
ReadRCam1[];
Jmp[HM3nPPC];
};
};
We've read RPage from the RCam successfully
= HMRCamReadyPC => {
IF TRUE THEN {
Load RqstBuf header with RealAddress; Load FlagsReg; Read RCam using victim, cycle 1.
s[PCtlLdRBufHeader, H];
ss[PCtlBCmd, BCmdRB];
ss[PCtlABusCmd, ABusCam];
s[PCtlLdFlagsReg, H];
ReadRCam1[enExt: H];
Jmp[HMRRCVct2PC];
};
};
= HMRRCVct2PC => {
IF v[RCamForP] THEN {
Read RCam using victim, cycle 2
ReadRCam2[sCmd: SCmdVictim, enExt: H];
Jmp[HMRRCVct3PC];
};
IF NOT v[RCamForP] THEN {
Read RCam, cycle 1; Didn't have RCam, return to cycle 2
ReadRCam1[enExt: H];
Jmp[HMRRCVct2PC];
};
};
= HMRRCVct3PC => {
IF v[RCamForP] THEN {
Read RCam using victim, cycle 3
ReadRCam34[SCmdVictim];
Jmp[HMRRCVct4PC];
};
IF NOT v[RCamForP] THEN {
Read RCam, cycle 1; Didn't have RCam, return to cycle 2
ReadRCam1[enExt: H];
Jmp[HMRRCVct2PC];
};
};
= HMRRCVct4PC => {
IF v[PAccessPermission] AND v[RCamForP] THEN {
Read RCam using victim, cycle 4
ReadRCam34[SCmdVictim];
Jmp[HMReadRamPC];
};
IF v[PAccessPermission] AND NOT v[RCamForP] THEN {
Read RCam, cycle 1; Didn't have RCam, return to cycle 2
ReadRCam1[enExt: H];
Jmp[HMRRCVct2PC];
};
IF NOT v[PAccessPermission] THEN {
Fault: Signal and store in the array (can be done after releasing processor). Note that we must keep asserting SCmdVictim so as not to change xCSCmd while enCamSel is high.
ReadRCam34[SCmdVictim];
Jmp[StoreMemAccessFaultPC];
};
};
= HMReadRamPC => {
IF TRUE THEN {
ABus ← VictimAddress (note ABus ← AToDPipe Reg automatically); Load Snooper in case of FlushBlock; Set snooper valid to begin snooping;
ReadRam1[SCmdVictim, NoDBus];
ss[PCtlABusCmd, ABusRCam];
s[PCtlLdSnooper, H];
s[PCtlSetSnooperValid, H];
Jmp[HMRR2PC];
};
};
= HMRR2PC => {
IF TRUE THEN {
RqstBufLo ← AToDPipe; RqstBufHi ← garbage; ReadRam cycle 2
ReadRam2[SCmdVictim, NoDBus];
ss[PCtlDBusCmd, DBusABus];
s[PCtlLdRBufDataLo, H];
s[PCtlLdRBufDataHi, H];
Jmp[HMRR3PC];
};
};
= HMRR3PC => {
IF v[RPValid] AND v[RamForP] THEN {
Read Ram, cycle 3; LoadFIFOIfAOw; Generate FBRqst
ReadRam3[SCmdVictim, NoDBus];
s[PCtlLdFIFOIfAOw, H];
ss[PCtlBCmd, BCmdFB];
ss[PCtlABusCmd, ABusRCam];
s[PCtlSetFBTIP, H];
Jmp[HMRR4PC];
};
IF v[RPValid] AND NOT v[RamForP] THEN {
Redo Ram Read; Also redrive victim address onto ABus
ReadRam1[SCmdVictim, NoDBus];
ss[PCtlABusCmd, ABusRCam];
Jmp[HMRR2PC];
};
IF NOT v[RPValid] THEN {
Victim is not valid, don't flush it.
Send RBRqst; Set NonFBTIP;
s[PCtlSetNonFBTIP, H];
Jmp[HMReturn1PC];
};
};
= HMRR4PC => {
IF TRUE THEN {
Send RBRqst; Set NonFBTIP;
s[PCtlSetNonFBTIP, H];
Jmp[HMReturn1PC];
};
};
= HMReturn1PC => {
Wait a cycle to let NonFBTIP get set; ABus←RealAddress to load Snooper on MyRBRqst
IF TRUE THEN {
ss[PCtlABusCmd, ABusRqstBuf];
Jmp[HMReturn2PC];
}
};
= HMReturn2PC => {
IF v[NonFBTIP] AND NOT v[TimeOut] THEN {
Wait for RBRply; ABus←RealAddress to load Snooper on MyRBRqst
ss[PCtlABusCmd, ABusRqstBuf];
s[PCtlSelRplyData, H];
Jmp[HMReturn2PC];
};
IF v[NonFBTIP] AND v[TimeOut] THEN {
TimeOut: Signal and store the fault in the array
s[PCtlSelRplyData, H];
Jmp[StoreBTimeOutFaultPC];
};
IF NOT v[NonFBTIP] AND v[MyBFault] THEN {
Reply has come back with a fault, release processor and return
s[PCtlFault, H];
s[PCtlSelBFC, H];
s[PCtlReleaseP, H];
s[PCtlSelRplyData, H];
Jmp[IdlePC]; -- check that fault code gets written automatically; if not, just do it in ucode by copying one of the store fault routines
};
IF NOT v[NonFBTIP] AND NOT v[MyBFault] THEN {
Unfreeze victim and shift it to avoid victimizing the line just brought in
s[PCtlShftVictim, H];
s[PCtlSelRplyData, H];
Jmp[HMReturn3PC];
};
};
= HMReturn3PC => {
IF TRUE THEN {
Produce the pulse to write the VCam and Flags (recall that VCamWtReg may have been overwritten with the address of IOAID).
s[PCtlWtMchVCam, H];
ss[PCtlABusCmd, ABusPAdd];
SELECT vs[Stack] FROM
= FromRead => {
Release processor and go to idle
s[PCtlReleaseP, H];
s[PCtlSelRplyData, H];
Jmp[IdlePC]};
= FromWrite => {
Wait two cycles because we can't use the VCam to do a match yet
Jmp[HMReturn4PC]};
= FromCWS => {
Wait two cycles because we can't use the VCam to do a match yet
Jmp[HMReturn4PC]};
ENDCASE => { -- do as FromCWS
TerminalIO.PutRope
["***Stack Value 3 is not valid for state: HMReturn3PC\n"];
Jmp[HMReturn4PC]};
};
};
= HMReturn4PC => {
IF TRUE THEN {
Wait one cycle because we can't use the VCam to do a match yet
Jmp[HMReturn5PC];
};
};
= HMReturn5PC => {
SELECT vs[Stack] FROM
= FromWrite => {
Do a Match to check if address is in array
s[PCtlWtMchVCam, H];
Jmp[PSRetryPC]};
= FromCWS => {
Do a Match to check if address is in array
s[PCtlWtMchVCam, H];
Jmp[PCWSRetryPC]};
= FromRead => { -- do as FromWrite
TerminalIO.PutRope
["***Stack Value 0 is not valid for state: HMReturn5PC\n"];
s[PCtlWtMchVCam, H];
Jmp[PSRetryPC]};
ENDCASE => { -- do as FromCWS
TerminalIO.PutRope
["***Stack Value 3 is not valid for state: HMReturn5PC\n"];
s[PCtlWtMchVCam, H];
Jmp[PCWSRetryPC]};
};
= StoreMemAccessFaultPC => {
IF TRUE THEN {
Write fault code into the RAM, cycle 1
WriteRam1[SCmdLVM, DBusABus];
ss[PCtlABusCmd, ABusFault+MemAccessFault];
Jmp[SMAF2PC];
};
};
= SMAF2PC => {
IF TRUE THEN {
Write fault code into the RAM, cycle 2
WriteRam2[SCmdLVM, DBusABus];
ss[PCtlABusCmd, ABusFault+MemAccessFault];
Jmp[SMAF3PC];
};
};
= SMAF3PC => {
IF v[RamForP] THEN {
Write completed successfully. Go back to Idle loop
WriteRam3[SCmdLVM, DBusABus];
s[PCtlFault, H];
ss[PCtlFaultCode, MemAccessFault];
s[PCtlReleaseP, H];
Jmp[IdlePC];
};
IF NOT v[RamForP] THEN {
Ratted! Redo the access
ss[PCtlDBusCmd, DBusABus];
WriteRam1[SCmdLVM, DBusABus];
ss[PCtlABusCmd, ABusFault+MemAccessFault];
Jmp[SMAF2PC];
};
};
= StoreBTimeOutFaultPC => {
IF TRUE THEN {
Write fault code into the RAM, cycle 1
WriteRam1[SCmdLVM, DBusABus];
ss[PCtlABusCmd, ABusFault+DynaBusTimeOut];
Jmp[SBTOF2PC];
};
};
= SBTOF2PC => {
IF TRUE THEN {
Write fault code into the RAM, cycle 2
WriteRam2[SCmdLVM, DBusABus];
ss[PCtlABusCmd, ABusFault+DynaBusTimeOut];
Jmp[SBTOF3PC];
};
};
= SBTOF3PC => {
IF v[RamForP] THEN {
Write completed successfully. Go back to Idle loop
WriteRam3[SCmdLVM, DBusABus];
s[PCtlFault, H];
ss[PCtlFaultCode, DynaBusTimeOut];
s[PCtlReleaseP, H];
Jmp[IdlePC];
};
IF NOT v[RamForP] THEN {
Ratted! Redo the access
WriteRam1[SCmdLVM, DBusABus];
ss[PCtlABusCmd, ABusFault+DynaBusTimeOut];
Jmp[SBTOF2PC];
};
};
= StoreIOAccessFaultPC => {
IF TRUE THEN {
Write fault code into the RAM, cycle 1
WriteRam1[SCmdLVM, DBusABus];
ss[PCtlABusCmd, ABusFault+IOAccessFault];
Jmp[SIOAF2PC];
};
};
= SIOAF2PC => {
IF TRUE THEN {
Write fault code into the RAM, cycle 2
WriteRam2[SCmdLVM, DBusABus];
ss[PCtlABusCmd, ABusFault+IOAccessFault];
Jmp[SIOAF3PC];
};
};
= SIOAF3PC => {
IF v[RamForP] THEN {
Write completed successfully. Go back to Idle loop
WriteRam3[SCmdLVM, DBusABus];
s[PCtlFault, H];
ss[PCtlFaultCode, IOAccessFault];
s[PCtlReleaseP, H];
Jmp[IdlePC];
};
IF NOT v[RamForP] THEN {
Ratted! Redo the access
ss[PCtlDBusCmd, DBusABus];
WriteRam1[SCmdLVM, DBusABus];
ss[PCtlABusCmd, ABusFault+IOAccessFault];
Jmp[SIOAF2PC];
};
};
Here begins the tests subroutines. They cannot be executed during normal operations. They are reached only by the mean of a PC forced by the DebugBus. It is assumed that the DynaBus is stopped during these operations.
= TestReadRamPC => {
IF TRUE THEN {
s[PCtlForceWordAddress, H];
ReadRam1[SCmdVictim];
Jmp[TRR2PC];
};
};
= TRR2PC => {
IF TRUE THEN {
s[PCtlForceWordAddress, H];
ReadRam2[SCmdVictim];
Jmp[TRR3PC];
};
};
= TRR3PC => {
IF TRUE THEN {
s[PCtlForceWordAddress, H];
ReadRam3[SCmdVictim];
s[PCtlLdRBufDataHi, H];
Jmp[IdlePC];
};
};
= TestReadRCamPC => {
IF TRUE THEN {
Read RCam using Victim, cycle 1
ReadRCam1[enExt: H];
Jmp[TRRC2PC];
};
};
= TRRC2PC => {
IF TRUE THEN {
Read RCam using Victim, cycle 2
ReadRCam2[sCmd: SCmdVictim, enExt: H];
Jmp[TRRC3PC];
};
};
= TRRC3PC => {
IF TRUE THEN {
Read RCam using Victim, cycle 3
ReadRCam34[SCmdVictim];
Jmp[TRRC4PC];
};
};
= TRRC4PC => {
IF TRUE THEN {
Read RCam using Victim, cycle 4
ReadRCam34[SCmdVictim];
Jmp[TRRC5PC];
};
};
= TRRC5PC => {
IF TRUE THEN {
Put Victim into the ABus to DBus pipe (automatic) through the ABus
ss[PCtlABusCmd, ABusRCam];
Jmp[TRRC6PC];
};
};
= TRRC6PC => {
IF TRUE THEN {
Load RBufDataHi with the content of the RCam
ss[PCtlDBusCmd, DBusABus];
s[PCtlLdRBufDataHi, H];
Jmp[IdlePC];
};
};
= TestReadVCamPC => {
IF TRUE THEN {
Read VCam using Victim, cycle 1
ReadVCam1[SCmdVictim];
Jmp[TRVC2PC];
};
};
= TRVC2PC => {
IF TRUE THEN {
Read VCam using Victim, cycle 2
ReadVCam2[SCmdVictim];
Jmp[TRVC3PC];
};
};
= TRVC3PC => {
IF TRUE THEN {
Read VCam using Victim, cycle 3
ReadVCam34[SCmdVictim];
Jmp[TRVC4PC];
};
};
= TRVC4PC => {
IF TRUE THEN {
Read VCam using Victim, cycle 4
ReadVCam34[SCmdVictim];
Jmp[TRVC5PC];
};
};
= TRVC5PC => {
IF TRUE THEN {
Put Victim into the ABus to DBus pipe (automatic) through the ABus
ss[PCtlABusCmd, ABusVCam];
Jmp[TRVC6PC];
};
};
= TRVC6PC => {
IF TRUE THEN {
Load RBufDataHi with the content of the VCam
ss[PCtlDBusCmd, DBusABus];
s[PCtlLdRBufDataHi, H];
Jmp[IdlePC];
};
};
= TestShiftVictimPC => {
IF TRUE THEN {
The victim is assumed to be waiting at some place
s[PCtlShftVictim, H];
Jmp[TSV2PC];
};
};
= TSV2PC => {
IF TRUE THEN {
The victim may point to a place where it wants to get out of
Force it to stay there. Cycle 1 of 2
s[PCtlFrzVictim, H];
Jmp[TSV3PC];
};
};
= TSV3PC => {
IF TRUE THEN {
The victim may point to a place where it wants to get out of
Force it to stay there. Cycle 2 of 2
s[PCtlFrzVictim, H];
Jmp[IdlePC];
};
};
= TestResetVictimPC => {
IF TRUE THEN {
Force the victim to point at the initial place. Cycle 1 of 2
s[PCtlResetVictim, H];
Jmp[TRV2PC];
};
};
= TRV2PC => {
IF TRUE THEN {
Force the victim to point at the initial place. Cycle 2 of 2
The victim will not get out now that the used bit has been cleared
s[PCtlResetVictim, H];
Jmp[IdlePC];
};
};
ENDCASE; -- End Transitions
};
ENDCASE => ERROR;
};
Next: PROC [it: IndexType] RETURNS [ix: NAT] = {
ix ← index[it];
index[it] ← index[it]+1;
};
index: ARRAY IndexType OF NATALL [0];
pmCodeName: ROPE = Rosemary.Register[roseClassName: "PmCode", init: InitPmCode, evalSimple: Simple];
END.