ArbRandReq:
CEDAR
PROGRAM
IMPORTS Atom, Commander, CommandTool, Convert, CoreClasses, CoreCreate, CoreFlat, CoreOps, CoreProperties,
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, scheduleIfClockEval: TRUE];
ArbRandReqInterface: Wire = WireList[
LIST[
Seq["nRequestOut", 2], -- radial lines
"nGrant",
"nLongGrant", -- bussed lines
"nHiPGrant",
"nStartGrant",
"nOwnerOut",
"nOwnerIn",
"nSharedOut",
"nSharedIn",
"nSStopOut",
"nSStopIn",
"nDReset",
"nDynaBusBusy",
"nHolding",
"Ck", "Vdd", "Gnd"
]];
ArbRandReq:
PUBLIC
PROC [ pre:
PRE ← DefaultPriority, prob:
REF ←
NIL ]
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, "nRequestOut"];
Ports.InitPorts[ct, b, none, "nGrant", "nLongGrant", "nHiPGrant", "nStartGrant"];
Ports.InitPorts[ct, b, driveWeak, "nOwnerOut", "nSharedOut", "nSStopOut"];
Ports.InitPorts[ct, b, none, "nOwnerIn", "nSharedIn", "nSStopIn"];
Ports.InitPorts[ct, b, none, "nDynaBusBusy", "nHolding"];
Ports.InitPorts[ct, b, none, "Ck", "Vdd", "Gnd"];
ct.properties ← CoreProperties.PutProp[ct.properties, $ArbRandReqProb, prob];
ct.properties ← CoreProperties.PutProp[ct.properties, $ArbRandReqPRE, NEW[PRE ← pre]];
};
ArbRandReqState: TYPE = REF ArbRandReqStateRec ← NIL;
ArbRandReqStateRec:
TYPE =
RECORD [
nRequestOut, nGrant, nLongGrant, nHiPGrant, nStartGrant,
nOwnerOut, nOwnerIn, nSharedOut, nSharedIn, nSStopOut, nSStopIn,
nDReset, nDynaBusBusy, nHolding, Ck: NAT ← LAST[NAT],
pre: PRE,
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, stateValue: Ports.LevelSequence ←
NIL ]
-- Rosemary.InitProc -- = {
st: ArbRandReqState ←
NEW[ArbRandReqStateRec ← [
random: genRS
]];
[st.nRequestOut, st.nGrant, st.nLongGrant, st.nHiPGrant, st.nStartGrant ] ←
Ports.PortIndexes[cellType.public, "nRequestOut", "nGrant", "nLongGrant", "nHiPGrant", "nStartGrant"];
[st.nOwnerOut, st.nOwnerIn, st.nSharedOut, st.nSharedIn, st.nSStopOut, st.nSStopIn] ←
Ports.PortIndexes[cellType.public, "nOwnerOut", "nOwnerIn", "nSharedOut", "nSharedIn", "nSStopOut", "nSStopIn"];
[st.nDReset, st.nDynaBusBusy, st.nHolding, st.Ck] ←
Ports.PortIndexes[cellType.public, "nDReset", "nDynaBusBusy", "nHolding", "Ck"];
st.pre ← NARROW[CoreProperties.GetProp[cellType.properties, $ArbRandReqPRE], REF PRE]^;
stateAny ←
NEW[RequesterStateRec ← [
probs: CoreProperties.GetProp[cellType.properties, $ArbRandReqProb], state: st]];
};
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: ARRAY DevReqType OF INT ← ALL[0],
busBusy, busWasBusy: BOOL ← TRUE,
cyclesSinceIdle: INT ← 0,
lenFIFO: ARRAY ReqCount OF PacketLength ← ALL[short2],
stopping, owning, sharing: BOOL ← FALSE,
holdPipe: ARRAY [0..10) OF BOOL ← ALL[TRUE]
];
ArbRandReqSimple: PROC [ p: Ports.Port, stateAny: REF ANY, clockEval: BOOL ] RETURNS [ stateValue: Ports.LevelSequence ← NIL ] -- Rosemary.EvalProc -- = {
ProbBool:
PROC [ x:
INT ]
RETURNS [ b:
BOOL ] = {
b has an 1-in-x chance of being true, except if x >= never
b ← (x < never) AND (st.random.ChooseInt[1, x] <= 1);
};
rs: REF RequesterStateRec = NARROW[stateAny];
st: ArbRandReqState = NARROW[rs.state];
SELECT
TRUE
FROM
clockEval => NULL;
p[st.Ck].b
AND
NOT st.lastCk => {
-- positive clock edge
st.lastCk ← TRUE;
st.s ← st.m;
};
NOT p[st.Ck].b => {
-- Clock is low, load master latches
prob: REF ProbabilitiesRec;
dPriority: PriorityRec;
st.lastCk ← FALSE;
WITH rs.probs
SELECT
FROM
rp: REF ProbabilitiesRec => prob ← rp;
atom: ATOM => prob ← NARROW[Atom.GetProp[atom, $ArbRandReqProb]];
ENDCASE => prob ← defaultProbs;
TRUSTED { dPriority ← LOOPHOLE[CARDINAL[st.pre]] };
st.m.reset ← NOT p[st.nDReset].b;
st.m.grant ← NOT p[st.nGrant].b;
st.m.startGrant ← NOT p[st.nStartGrant].b;
st.m.long ← NOT p[st.nLongGrant].b;
st.m.prevLong ← st.s.long;
st.m.grantType ← (IF NOT p[st.nHiPGrant].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 {
FOR drt: DevReqType
IN DevReqType
DO
st.m.delayUntilDemand[drt] ← (
SELECT
TRUE
FROM
st.s.rqCnt[drt] = 0 => maxCntLatency,
st.s.startGrant => maxGrantLatency,
ENDCASE => MAX[0, st.s.delayUntilDemand[drt]-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
OR ((
SELECT drt
FROM
H => dPriority.hiP,
L => dPriority.loP,
ENDCASE => ERROR) < HoldPriority))
AND (st.s.delayUntilDemand[drt] = 0) THEN ERROR;
st.m.holdPipe[0] ← ProbBool[(
SELECT st.s.holdPipe[0]
FROM
FALSE => prob.hold,
TRUE => 2,
ENDCASE => ERROR)];
FOR i:
NAT
IN [1..10)
DO
st.m.holdPipe[i] ← st.s.holdPipe[i-1];
ENDLOOP;
st.m.stopping ← ProbBool[prob.stop];
st.m.owning ← ProbBool[prob.owner];
st.m.sharing ← ProbBool[prob.shared];
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]]*prob.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;
};
}; -- clock low
ENDCASE => NULL;
p[st.nRequestOut].c ← 3-ORD[st.s.drc]; -- inverts
p[st.nOwnerOut].b ← NOT st.s.owning;
p[st.nOwnerOut].d ← IF p[st.nOwnerOut].b THEN driveWeak ELSE drive;
p[st.nSharedOut].b ← NOT st.s.owning;
p[st.nSharedOut].d ← IF p[st.nSharedOut].b THEN driveWeak ELSE drive;
p[st.nSStopOut].b ← NOT st.s.stopping;
p[st.nSStopOut].d ← IF p[st.nSStopOut].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.