ArbRandReq:
CEDAR
PROGRAM
IMPORTS Commander, CommandTool, Convert, CoreClasses, CoreCreate, CoreFlat, CoreOps,
IO, Ports, Random, Rosemary
EXPORTS Arbiter
=
BEGIN OPEN Arbiter, CoreCreate;
logicCutSet: Rope.ROPE = "Logic"; -- should be Logic.logicCutSet, actually
ArbRandReqName: Rope.ROPE = Rosemary.Register[roseClassName: "ArbRandReq", init: ArbRandReqInit, evalSimple: ArbRandReqSimple];
ArbRandReqInterface: Wire = WireList[
LIST[
Seq["nDReq", 2], -- radial lines
"nDGrant",
"nBDLong", -- bussed lines
"nBDHi",
"nStartGrant",
"nDOwner",
"nSysOwner",
"nDShared",
"nSysShared",
"nDStop",
"nSysStop",
"nDReset",
Seq["DPriority", 9],
"nDynaBusBusy",
"nHolding",
"Ck", "Vdd", "Gnd"
]];
ArbRandReq:
PUBLIC
PROC
RETURNS [ ct: CoreCreate.CellType ] = {
ct ← CoreOps.CreateCellType[
class: CoreClasses.unspecifiedCellClass,
public: ArbRandReqInterface,
name: "ArbRandReq"
];
[] ← Rosemary.BindCellType[cellType: ct, roseClassName: ArbRandReqName];
[] ← CoreFlat.CellTypeCutLabels[ct, logicCutSet];
Ports.InitPorts[ct, c, drive, "nDReq"];
Ports.InitPorts[ct, b, none, "nDGrant", "nBDLong", "nBDHi", "nStartGrant"];
Ports.InitPorts[ct, b, driveWeak, "nDOwner", "nDShared", "nDStop"];
Ports.InitPorts[ct, b, none, "nSysOwner", "nSysShared", "nSysStop"];
Ports.InitPorts[ct, c, none, "DPriority"];
Ports.InitPorts[ct, b, none, "nDynaBusBusy", "nHolding"];
Ports.InitPorts[ct, b, none, "Ck", "Vdd", "Gnd"];
};
ArbRandReqState: TYPE = REF ArbRandReqStateRec ← NIL;
ArbRandReqStateRec:
TYPE =
RECORD [
nDReq, nDGrant, nBDLong, nBDHi, nStartGrant,
nDOwner, nSysOwner, nDShared, nSysShared, nDStop, nSysStop,
nDReset, DPriority, nDynaBusBusy, nHolding, Ck: NAT ← LAST[NAT],
random: Random.RandomStream,
m, s: ArbReqMSRec,
lastCk: BOOL ← FALSE
];
P a r a m e t e r s
probTable: ARRAY Arbiter.ReqCount OF INT ← [1, 4, 8, 16, 32, 64, 1];
maxCntLatency: INT ← 9; -- might be 8, certainly isn't 7
maxGrantLatency: INT ← 7; -- might be smaller
defaultProbs:
REF ProbabilitiesRec ←
NEW[ProbabilitiesRec ← [
request: ALL[30],
hold: 100
]];
lastGenSeed: INT ← 1354117939;
genRS: Random.RandomStream ← NIL;
SetupSeed:
PROC [ seed:
INT ← 0 ]
RETURNS [
IO.
ROPE ] = {
IF seed = 0 THEN seed ← lastGenSeed;
genRS ← Random.Create[seed: seed];
lastGenSeed ← genRS.seed;
RETURN[IO.PutFR["New random number seed is %d.\n", IO.int[lastGenSeed]]];
};
ArbRandReqInit:
PROC [ cellType: Core.CellType, p: Ports.Port, oldStateAny:
REF
ANY ←
NIL, steady:
BOOL ←
FALSE ]
RETURNS [ stateAny:
REF
ANY ←
NIL ]
-- Rosemary.InitProc -- = {
st: ArbRandReqState ←
NEW[ArbRandReqStateRec ← [
random: genRS
]];
[st.nDReq, st.nDGrant, st.nBDLong, st.nBDHi, st.nStartGrant ] ←
Ports.PortIndexes[cellType.public, "nDReq", "nDGrant", "nBDLong", "nBDHi", "nStartGrant"];
[st.nDOwner, st.nSysOwner, st.nDShared, st.nSysShared, st.nDStop, st.nSysStop] ←
Ports.PortIndexes[cellType.public, "nDOwner", "nSysOwner", "nDShared", "nSysShared", "nDStop", "nSysStop"];
[st.nDReset, st.DPriority, st.nDynaBusBusy, st.nHolding, st.Ck] ←
Ports.PortIndexes[cellType.public, "nDReset", "DPriority", "nDynaBusBusy", "nHolding", "Ck"];
stateAny ← NEW[RequesterStateRec ← [probs: defaultProbs, state: st]];
};
ArbRandReqSimple:
PROC [ p: Ports.Port, stateAny:
REF
ANY ]
-- Rosemary.EvalProc -- = {
rs: REF RequesterStateRec = NARROW[stateAny];
st: ArbRandReqState = NARROW[rs.state];
ArbReqMain[p, stateAny];
st.lastCk ← p[st.Ck].b;
};
ArbReqMSRec:
TYPE =
RECORD [
reset, grant, startGrant: BOOL ← FALSE,
long, prevLong: BOOL ← FALSE,
grantType, prevGrantType: DevReqType,
holding: BOOL ← FALSE,
drc: Arbiter.DevReqCode,
rqCnt: ARRAY DevReqType OF ReqCount ← ALL[0],
grantCycles: INT ← 0,
go: ARRAY DevReqType OF BOOL ← ALL[FALSE],
delayUntilDemand: INT ← 0,
busBusy, busWasBusy: BOOL ← TRUE,
cyclesSinceIdle: INT ← 0,
lenFIFO: ARRAY ReqCount OF PacketLength ← ALL[short2],
holdPipe: ARRAY [0..10) OF BOOL ← ALL[TRUE]
];
ArbReqMain: PROC [ p: Ports.Port, stateAny: REF ANY ] -- Rosemary.EvalProc -- = {
ProbBool:
PROC [ x:
INT ]
RETURNS [ b:
BOOL ] = {
b has an 1-in-x chance of being true, except if x >= 10000000
b ← (x < 10000000) AND (st.random.ChooseInt[1, x] <= 1);
};
rs: REF RequesterStateRec = NARROW[stateAny];
st: ArbRandReqState = NARROW[rs.state];
IF p[st.Ck].b
THEN {
IF NOT st.lastCk THEN st.s ← st.m -- positive clock edge
}
ELSE {
-- Clock is low, load master latches
dPriority: PriorityRec;
TRUSTED { dPriority ← LOOPHOLE[p[st.DPriority].c] };
st.m.reset ← NOT p[st.nDReset].b;
st.m.grant ← NOT p[st.nDGrant].b;
st.m.startGrant ← NOT p[st.nStartGrant].b;
st.m.long ← NOT p[st.nBDLong].b;
st.m.prevLong ← st.s.long;
st.m.grantType ← (IF NOT p[st.nBDHi].b THEN H ELSE L);
st.m.prevGrantType ← st.s.grantType;
st.m.busBusy ← NOT p[st.nDynaBusBusy].b;
st.m.busWasBusy ← st.s.busBusy;
st.m.holding ← NOT p[st.nHolding].b;
IF st.s.reset
THEN {
-- we're being reset
st.m.rqCnt ← ALL[0];
st.m.drc ← release;
st.m.grantCycles ← 0;
st.m.holdPipe ← ALL[FALSE];
}
ELSE {
st.m.delayUntilDemand ← (
SELECT
TRUE
FROM
st.s.rqCnt = ALL[0] => maxCntLatency,
st.s.startGrant => maxGrantLatency,
ENDCASE => MAX[0, st.s.delayUntilDemand-1]);
IF p[st.nDReset].b
AND
NOT st.s.reset
AND
NOT st.s.busBusy
AND NOT st.s.busWasBusy AND
NOT st.s.holding AND (st.s.delayUntilDemand = 0) THEN ERROR;
st.m.holdPipe[0] ← ProbBool[(
SELECT st.s.holdPipe[0]
FROM
FALSE => rs.probs.hold,
TRUE => 2,
ENDCASE => ERROR)];
FOR i:
NAT
IN [1..10)
DO
st.m.holdPipe[i] ← st.s.holdPipe[i-1];
ENDLOOP;
st.m.rqCnt ← st.s.rqCnt;
SELECT
TRUE
FROM
st.s.grantCycles > 1 => {
IF st.s.startGrant OR NOT st.s.grant THEN ERROR;
st.m.grantCycles ← st.s.grantCycles-1;
};
st.s.grant => {
IF NOT st.s.startGrant THEN ERROR;
IF st.m.rqCnt[st.s.prevGrantType] <= 0 THEN ERROR;
st.m.rqCnt[st.s.prevGrantType] ← st.s.rqCnt[st.s.prevGrantType]-1;
IF
NOT dPriority.nFIFOEna
THEN {
IF st.s.prevGrantType # L THEN ERROR;
IF st.s.prevLong # (st.s.lenFIFO[0] = long5) THEN ERROR;
}
ELSE {
expectedLong:
BOOL = (
SELECT
TRUE
FROM
st.s.prevGrantType = H AND dPriority.hiLong => TRUE,
st.s.prevGrantType = L AND dPriority.loLong => TRUE,
ENDCASE => FALSE);
IF st.s.prevLong # expectedLong THEN ERROR;
};
st.m.grantCycles ← IF st.s.prevLong THEN 5 ELSE 2;
};
ENDCASE =>
st.m.grantCycles ← 0;
FOR i: ReqCount
IN ReqCount
DO
st.m.lenFIFO[i] ← (
SELECT
TRUE
FROM
st.s.grant AND st.s.grantCycles <=1 AND i<LAST[ReqCount] => st.s.lenFIFO[i+1],
st.s.grant AND st.s.grantCycles <=1 => long5,
ENDCASE => st.s.lenFIFO[i]);
ENDLOOP;
st.m.cyclesSinceIdle ← (IF st.s.rqCnt = ALL[0] THEN 0 ELSE st.s.cyclesSinceIdle+1);
FOR rType: DevReqType
IN DevReqType
DO
st.m.go[rType] ←
ProbBool[probTable[st.m.rqCnt[rType]]*rs.probs.request[rType]];
ENDLOOP;
SELECT
TRUE
FROM
st.s.holdPipe[0] =>
st.m.drc ← seize;
st.s.holdPipe[1]
AND
NOT st.s.holdPipe[0] =>
st.m.drc ← release;
st.s.go[H]
AND dPriority.nFIFOEna
AND st.m.rqCnt[H] <
LAST[Arbiter.ReqCount]-1 => {
st.m.drc ← reqH;
st.m.rqCnt[H] ← st.m.rqCnt[H]+1;
};
st.s.go[H]
AND
NOT dPriority.nFIFOEna
AND st.m.rqCnt[L] <
LAST[Arbiter.ReqCount]-1 => {
st.m.drc ← reqH;
st.m.lenFIFO[st.m.rqCnt[L]] ← long5;
st.m.rqCnt[L] ← st.m.rqCnt[L]+1;
};
st.s.go[L]
AND st.m.rqCnt[L] <
LAST[Arbiter.ReqCount]-1 => {
st.m.drc ← reqL;
st.m.lenFIFO[st.m.rqCnt[L]] ← short2;
st.m.rqCnt[L] ← st.m.rqCnt[L]+1;
};
ENDCASE =>
st.m.drc ← release;
};
};
p[st.nDReq].c ← 3-ORD[st.s.drc]; -- inverts
p[st.nDOwner].b ← NOT FALSE;
p[st.nDOwner].d ← IF p[st.nDOwner].b THEN driveWeak ELSE drive;
p[st.nDShared].b ← NOT FALSE;
p[st.nDShared].d ← IF p[st.nDShared].b THEN driveWeak ELSE drive;
p[st.nDStop].b ← NOT FALSE;
p[st.nDStop].d ← IF p[st.nDStop].b THEN driveWeak ELSE drive;
p[st.nDynaBusBusy].d ← IF st.s.grantCycles > 0 THEN drive ELSE driveWeak;
p[st.nDynaBusBusy].b ← NOT (st.s.grantCycles > 0);
p[st.nHolding].d ← IF st.s.holdPipe[holdPipeLen] THEN drive ELSE driveWeak;
p[st.nHolding].b ← NOT st.s.holdPipe[holdPipeLen];
};
ArbRandReqSeedProc:
PROC [ cmd: Commander.Handle ]
RETURNS [ result:
REF ←
NIL, msg: Rope.
ROPE ←
NIL ]
-- Commander.CommandProc -- = {
seed: INT ← 0;
argv: CommandTool.ArgumentVector = CommandTool.Parse[cmd];
IF argv.argc > 1 THEN seed ← Convert.IntFromRope[ argv[1] ! Convert.Error => CONTINUE ];
cmd.out.PutRope[SetupSeed[seed]];
};
Commander.Register["ArbRandReqSeed", ArbRandReqSeedProc, "Reseeds the random number generator for the Arbiter simulation. Usage is\n ArbRandReqSeed n\n where n is an integer. 0 recovers the previous seed."];
END.