SmallCacheOutputSectionImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Created: Sindhu July 27, 1987 2:00:51 pm PDT
Pradeep Sindhu May 5, 1988 11:31:55 am PDT
Don Curry May 16, 1988 3:10:17 pm PDT
This module defines the cache's output section. The definition is parallel to the schematic-based definition contained in OutputSection.sch, and must be consistent with it. The consistency check should be performed by using OutputSection.oracle.
DIRECTORY
DynaBusInterface, IO, Ports, Rosemary, RosemaryUser, SmallCacheLogic, SCParms, Sisyph;
SmallCacheOutputSectionImpl: CEDAR PROGRAM
IMPORTS Ports, Rosemary, SmallCacheLogic, SCParms, Sisyph
EXPORTS SmallCacheLogic
~ BEGIN OPEN SmallCacheLogic;
Constants and Type Defs
outputSectionName: ROPE = Rosemary.Register[roseClassName: "OutputSection", init: Init, evalSimple: Simple, scheduleIfClockEval: TRUE];
MaxNumSignals: NAT = 30;
FIFOSize: NAT = 8;
SendStatus: TYPE = {h, d21, d51, d52, d53, d54}; -- output automaton states (see schematic)
FIFOIndex: TYPE = [0..FIFOSize);
Note: In both the fifo and the rqstbuffer, the header is stored non-interleaved
State: TYPE = REF StateRec;
StateRec: TYPE = RECORD [
sendStatus: SendStatus,
grantsPending: NAT,
cycleAdrs: LevelSequence ← NEW [LevelSequenceRec[2]],
rBuf: RECORD [
presence, ppresence: BOOL,
rqstPending: BOOL,
header: LevelSequence ← NEW [LevelSequenceRec[SCParms.numBitsPerCycle]],
dataHi: LevelSequence ← NEW [LevelSequenceRec[SCParms.numBitsPerWord]],
dataLo: LevelSequence ← NEW [LevelSequenceRec[SCParms.numBitsPerWord]]
],
fifo: RECORD [
count: [0..FIFOSize],
wtPtr, rdPtr: FIFOIndex,
header: ARRAY FIFOIndex OF LevelSequence,
data: ARRAY FIFOIndex OF LevelSequence
],
pClock: Level ← X,
ps: Signals -- holds values of signals just before positive going edge
];
Signal Defs
signals: Signals ← NEW [SignalsRec[MaxNumSignals]];
DataShiftEn: NAT = Declare[signals, "DataShiftEn", X, Input];
SerialIn: NAT = Declare[signals, "SerialIn", X, Input];
DataSerialOut: NAT = Declare[signals, "DataSerialOut", X, Output];
AOw: NAT = Declare[signals, "AOw", X, Input];
Grant: NAT = Declare[signals, "Grant", X, Input];
GLength: NAT = Declare[signals, "GLength", X, Input];
PCtlLdFIFO: NAT = Declare[signals, "PCtlLdFIFO", X, Input];
BCtlLdFIFO: NAT = Declare[signals, "BCtlLdFIFO", X, Input];
RplyStale34: NAT = Declare[signals, "RplyStale34", X, Input];
PCtlSetNonFBTIP: NAT = Declare[signals, "PCtlSetNonFBTIP", X, Input];
PCtlLdRBufHeader: NAT = Declare[signals, "PCtlLdRBufHeader", X, Input];
PCtlLdRBufDataHi: NAT = Declare[signals, "PCtlLdRBufDataHi", X, Input];
PCtlLdRBufDataLo: NAT = Declare[signals, "PCtlLdRBufDataLo", X, Input];
PCtlDrABusRqstBuf: NAT = Declare[signals, "PCtlDrABusRqstBuf", X, Input];
Reset: NAT = Declare[signals, "Reset", X, Input];
Clock: NAT = Declare[signals, "Clock", X, Input];
BCmd: NAT = DeclareS[signals, "BCmd", 4, Xs, Input];
PMode: NAT = Declare[signals, "PMode", X, Input];
DevId: NAT = DeclareS[signals, "DevId", SCParms.numDevIdBits, Xs, Input];
DBus: NAT = DeclareS[signals, "DBus", SCParms.numBitsPerWord, Xs, Input];
RplyHeader: NAT = DeclareS[signals, "RplyHeader", SCParms.numBitsPerCycle, Xs, Input];
FIFOData: NAT = DeclareS[signals, "FIFOData", SCParms.numBitsPerLine, Xs, Input];
ABus: NAT = DeclareS[signals, "ABus", SCParms.numBitsPerWord, Xs, InputOutput];
BDataOut: NAT = DeclareS[signals, "BDataOut", SCParms.numBitsPerCycle, Xs, Output];
HeaderCycleOut: NAT = Declare[signals, "HeaderCycleOut", L, Output];
FIFOOverflow: NAT = Declare[signals, "FIFOOverflow", L, Output];
Request: NAT = DeclareS[signals, "Request", 2, 0, Output];
Vdd: NAT = Declare[signals, "Vdd", X, Power];
Gnd: NAT = Declare[signals, "Gnd", X, Power];
Public Procs
OutputSection: PUBLIC PROC [cts: CellTypeSpec, cx: Context] RETURNS [ct: CellType] = {
SELECT cts FROM
Schematic => ct ← Sisyph.ES["OutputSection.sch", cx];
Procedure => ct ← Create[outputSectionName, signals];
CoreFile => ERROR
ENDCASE => ERROR
};
Internal Procs
Init: Rosemary.InitProc = {
state: State;
GetPortIndices[signals, cellType];
IF oldStateAny=NIL
THEN {
state ← NEW [StateRec];
FOR i: FIFOIndex IN FIFOIndex DO
state.fifo.header[i] ← NEW [LevelSequenceRec[SCParms.numBitsPerCycle]];
state.fifo.data[i] ← NEW [LevelSequenceRec[SCParms.numBitsPerLine]];
ENDLOOP;
state.ps ← NEW [SignalsRec[MaxNumSignals]];
CopySignals[state.ps, signals];
stateAny ← state;
}
ELSE state ← NARROW[oldStateAny];
IF steady THEN InitState[state];
stateAny ← state;
};
Simple: Rosemary.EvalProc = {
v: PROC [ix: NAT] RETURNS [BOOL] = {
RETURN[p[signals[ix].index].l=H]
};
pv: PROC [ix: NAT] RETURNS [BOOL] = {
RETURN[state.ps[ix].l=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];
};
LdHdrFromPSide: PROC [hdr: LevelSequence] = {
CopyLS[hdr, state.ps[BCmd].ls];
hdr[4] ← L;   -- rqst/rply bit
hdr[5] ← state.ps[PMode].l; -- pMode bit
hdr[6] ← L;   -- rplyShd bit
CopyLS[hdr, state.ps[DevId].ls, 7];
FOR i: NAT IN [7+SCParms.numDevIdBits..SCParms.numBitsPerWord) DO hdr[i] ← L; ENDLOOP;
CopyLS[hdr, state.ps[ABus].ls, SCParms.numBitsPerWord];
};
WtFIFO: PROC [] = {
wtPtr: FIFOIndex ← state.fifo.wtPtr;
IF state.fifo.count=FIFOSize THEN ERROR; -- FIFO Overflow
IF pv[BCtlLdFIFO]
THEN { -- load header from bside
Note that incoming header is interleaved, so we must unscramble:
numBitsPerWord: NAT ← SCParms.numBitsPerWord;
FOR i: NAT IN [0..numBitsPerWord) DO
state.fifo.header[wtPtr][i] ← state.ps[RplyHeader].ls[2*i];
state.fifo.header[wtPtr][i+numBitsPerWord] ← state.ps[RplyHeader].ls[2*i+1];
ENDLOOP;
}
ELSE { -- load header from pside
LdHdrFromPSide[state.fifo.header[wtPtr]]
};
CopyLS[state.fifo.data[wtPtr], state.ps[FIFOData].ls];
state.fifo.wtPtr ← IF wtPtr=FIFOSize-1 THEN 0 ELSE wtPtr+1;
state.fifo.count ← state.fifo.count+1;
state.grantsPending ← state.grantsPending+1;
};
state: State ← NARROW [stateAny];
OutputsToDefault[p, signals];
SELECT p[signals[Reset].index].l FROM
= X => OutputsToX[p, signals];
= H => {
InitState[state];
p[signals[ABus].index].d ← none;
ss[Request, 0];
s[FIFOOverflow, L];
s[HeaderCycleOut, L];
};
= L => {
First handle all the combinatorial signals; note, no state transitions allowed here!
s[DataSerialOut, state.rBuf.dataHi[0]];
IF v[PCtlDrABusRqstBuf]
THEN {p[signals[ABus].index].d ← drive;
CopyLS[p[signals[ABus].index].ls, state.rBuf.header, SCParms.numBitsPerWord];
}
ELSE p[signals[ABus].index].d ← none;
IF (v[PCtlLdFIFO] AND v[AOw]) OR v[BCtlLdFIFO]
THEN ss[Request, 3]
ELSE IF v[PCtlSetNonFBTIP] OR state.rBuf.rqstPending THEN ss[Request, 2];
IF state.grantsPending>0 THEN BEGIN
rdPtr: NAT ← state.fifo.rdPtr;
OutputH2: PROC [] = {
numBitsPerWord: NAT ← SCParms.numBitsPerWord;
IF state.rBuf.presence THEN s[HeaderCycleOut, H];
FOR i: NAT IN [0..numBitsPerWord) DO
p[signals[BDataOut].index].ls[2*i] ← state.rBuf.header[i];
p[signals[BDataOut].index].ls[2*i+1] ← state.rBuf.header[i+numBitsPerWord];
ENDLOOP;
};
OutputD2: PROC [] = {
numBitsPerWord: NAT ← SCParms.numBitsPerWord;
FOR i: NAT IN [0..numBitsPerWord) DO
p[signals[BDataOut].index].ls[2*i] ← state.rBuf.dataHi[i];
p[signals[BDataOut].index].ls[2*i+1] ← state.rBuf.dataLo[i];
ENDLOOP;
};
OutputH5: PROC [] = {
numBitsPerWord: NAT ← SCParms.numBitsPerWord;
IF state.fifo.count>0 AND NOT (v[RplyStale34] AND state.fifo.header[rdPtr][4]=L) THEN s[HeaderCycleOut, H];
CopyLS[state.cycleAdrs, state.fifo.header[rdPtr], SCParms.numBitsPerCycle-1-SCParms.logNumCyclesPerLine];
Output is interleaved, so we must rescramble:
FOR i: NAT IN [0..numBitsPerWord) DO
p[signals[BDataOut].index].ls[2*i] ← state.fifo.header[rdPtr][i];
p[signals[BDataOut].index].ls[2*i+1] ← state.fifo.header[rdPtr][i+numBitsPerWord];
ENDLOOP;
};
OutputD5: PROC [cycle: NAT] = {
cpl: NAT ← SCParms.numCyclesPerLine;
cix: NAT ← (Ports.LSToLC[state.cycleAdrs]+cycle) MOD cpl;
FOR i: NAT IN [0..SCParms.numBitsPerWord) DO
p[signals[BDataOut].index].ls[2*i] ← state.fifo.data[rdPtr][i*2*cpl+2*cix];
p[signals[BDataOut].index].ls[2*i+1] ← state.fifo.data[rdPtr][i*2*cpl+2*cix+1]
ENDLOOP;
};
SELECT state.sendStatus FROM
h => IF v[GLength] THEN OutputH5[] ELSE OutputH2[];
d21 => {
IF v[Grant]
THEN OutputD2[]
ELSE IF v[GLength] THEN OutputH5[] ELSE OutputH2[];
};
d51 => {
IF v[Grant]
THEN OutputD5[0]
ELSE IF v[GLength] THEN OutputH5[] ELSE OutputH2[];
};
d52 => OutputD5[1];
d53 => OutputD5[2];
d54 => OutputD5[3];
ENDCASE => ERROR;
END;
On clock low, copy all input signals to state
IF NOT v[Clock] AND NOT clockEval THEN CopyInputValues[state.ps, p];
On clock low to high change all clocked signals
IF state.pClock=L AND v[Clock] AND NOT clockEval THEN BEGIN
ldfifo: BOOL ← (pv[PCtlLdFIFO] AND pv[AOw]) OR pv[BCtlLdFIFO];
presenceCopy: BOOL ← state.rBuf.presence;
ppresenceCopy: BOOL ← state.rBuf.ppresence;
state.rBuf.ppresence ← presenceCopy;
IF pv[PCtlSetNonFBTIP] THEN state.rBuf.presence ← TRUE;
IF pv[PCtlSetNonFBTIP] AND ldfifo THEN state.rBuf.rqstPending ← TRUE;
IF (pv[PCtlSetNonFBTIP] OR state.rBuf.rqstPending) AND NOT ldfifo THEN state.grantsPending ← state.grantsPending+1;
IF pv[PCtlLdRBufHeader] THEN LdHdrFromPSide[state.rBuf.header];
IF pv[DataShiftEn]
THEN {
FOR i: NAT IN [0..SCParms.numBitsPerWord-1) DO state.rBuf.dataHi[i] ← state.rBuf.dataHi[i+1] ENDLOOP;
state.rBuf.dataHi[SCParms.numBitsPerWord-1] ← p[signals[SerialIn].index].l;
}
ELSE IF pv[PCtlLdRBufDataHi] THEN CopyLS[state.rBuf.dataHi, state.ps[DBus].ls];
IF pv[PCtlLdRBufDataLo] THEN CopyLS[state.rBuf.dataLo, state.ps[DBus].ls];
IF ldfifo THEN WtFIFO[] ELSE state.rBuf.rqstPending ← FALSE;
Update sendstatus:
SELECT state.sendStatus FROM
h => IF pv[GLength] THEN state.sendStatus ← d51 ELSE state.sendStatus ← d21;
d21 => {
IF pv[Grant]
THEN {
state.sendStatus ← h;
IF NOT pv[PCtlSetNonFBTIP] AND ppresenceCopy THEN {
state.rBuf.presence ← FALSE;
state.grantsPending ← state.grantsPending-1;
}
}
ELSE {IF pv[GLength] THEN state.sendStatus ← d51};
};
d51 => {
IF pv[Grant]
THEN state.sendStatus ← d52
ELSE {IF NOT pv[GLength] THEN state.sendStatus ← d21};
};
d52 => IF pv[Grant] THEN state.sendStatus ← d53;
d53 => IF pv[Grant] THEN state.sendStatus ← d54;
d54 => IF pv[Grant] THEN {
rdPtr: NAT ← state.fifo.rdPtr;
state.sendStatus ← h;
state.grantsPending ← state.grantsPending-1;
state.fifo.rdPtr ← IF rdPtr=FIFOSize-1 THEN 0 ELSE rdPtr+1;
state.fifo.count ← state.fifo.count-1;
};
ENDCASE => ERROR;
END;
};
ENDCASE;
Finally, copy Clock to pClock
IF NOT clockEval THEN state.pClock ← p[signals[Clock].index].l;
};
InitState: PROC [state: State] = {
state.sendStatus ← h;
state.grantsPending ← 0;
state.rBuf.presence ← FALSE;
state.fifo.wtPtr ← state.fifo.rdPtr ← state.fifo.count ← 0;
state.pClock ← X;
};
END.