ArbRandReq.mesa
McCreight May 22, 1987 6:44:52 pm PDT
Last Edited by: McCreight December 28, 1987 4:33:23 pm PST
DIRECTORY
Arbiter, Atom, Commander, CommandTool, Convert, Core, CoreClasses, CoreCreate, CoreFlat, CoreOps, CoreProperties, IO, Ports, Random, Rope, Rosemary;
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: REFNIL ] 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: NATLAST[NAT],
pre: PRE,
random: Random.RandomStream,
m, s: ArbReqMSRec,
lastCk: BOOLFALSE
];
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 ANYNIL, steady: BOOLFALSE ] RETURNS [ stateAny: REF ANYNIL, 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]];
};
holdPipeLen: NAT ← 8;
ArbReqMSRec: TYPE = RECORD [
reset, grant, startGrant: BOOLFALSE,
long, prevLong: BOOLFALSE,
grantType, prevGrantType: DevReqType,
holding: BOOLFALSE,
drc: Arbiter.DevReqCode,
rqCnt: ARRAY DevReqType OF ReqCount ← ALL[0],
grantCycles: INT ← 0,
go: ARRAY DevReqType OF BOOLALL[FALSE],
delayUntilDemand: ARRAY DevReqType OF INTALL[0],
busBusy, busWasBusy: BOOLTRUE,
cyclesSinceIdle: INT ← 0,
lenFIFO: ARRAY ReqCount OF PacketLength ← ALL[short2],
stopping, owning, sharing: BOOLFALSE,
holdPipe: ARRAY [0..10) OF BOOLALL[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;
ENDLOOP;
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: REFNIL, msg: Rope.ROPENIL ] -- 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.