ALS652:
CEDAR
PROGRAM
IMPORTS Commander, CommandTool, Convert, IO, Ports, Random, Rosemary, RosemaryUser, MTSVector
=
BEGIN
controlledClocks: BOOL ← FALSE;
ALS652Wires: TYPE = {A, B, nGBA, GAB, CBA, CAB, SBA, SAB};
ALS652WireNames: ARRAY ALS652Wires OF IO.ROPE = ["A", "B", "nGBA", "GAB", "CBA", "CAB", "SBA", "SAB"];
State: TYPE = REF StateRec ← NIL;
StateRec:
TYPE =
RECORD [
cellType: Core.CellType ← NIL,
p: Ports.Port ← NIL,
pi: ARRAY ALS652Wires OF NAT ← ALL[0], -- indexes in cellType.public
Vdd, Gnd: NAT ← 0,
AVal, BVal: ARRAY [0..8) OF Ports.Level ← ALL[X]
];
CreateState:
PROC [cellType: Core.CellType, p: Ports.Port]
RETURNS [ st: State ] = {
st ← NEW[StateRec ← [cellType: cellType, p: p]];
[st.Vdd, st.Gnd] ← Ports.PortIndexes[st.cellType.public, "Vdd", "Gnd"];
FOR aw: ALS652Wires
IN ALS652Wires
DO
[st.pi[aw]] ← Ports.PortIndexes[st.cellType.public, ALS652WireNames[aw]];
ENDLOOP;
};
RunTest:
PROC [st: State, eval: RosemaryUser.TestEvalProc, mts: MTSVector.Capture ] = {
ENABLE UNWIND => MTSVector.CloseCapture[mts];
Eval:
PROC = {
MTSVector.EvalAndCapture[capture: mts, Eval: eval, memory: FALSE];
};
EvalIgnoreX:
PROC = {
Eval[ ! Rosemary.Stop => IF reason = $BoolWireHasX THEN RESUME ELSE REJECT ];
};
st.p[st.Vdd].d ← st.p[st.Gnd].d ← inspect;
st.p[st.Vdd].b ← TRUE;
st.p[st.Gnd].b ← FALSE;
st.p[st.pi[CAB]].d ← st.p[st.pi[CBA]].d ← drive;
st.p[st.pi[CAB]].b ← st.p[st.pi[CBA]].b ← FALSE;
st.p[st.pi[nGBA]].d ← st.p[st.pi[GAB]].d ← drive;
st.p[st.pi[nGBA]].b ← TRUE;
st.p[st.pi[GAB]].b ← FALSE;
st.p[st.pi[SAB]].d ← st.p[st.pi[SBA]].d ← drive;
st.p[st.pi[SAB]].b ← st.p[st.pi[SBA]].b ← FALSE;
st.p[st.pi[A]].d ← st.p[st.pi[B]].d ← drive;
FOR i:
NAT
IN [0..8)
DO
st.p[st.pi[A]].ls[i] ← st.p[st.pi[B]].ls[i] ← st.AVal[i] ← st.BVal[i] ← L;
ENDLOOP;
EvalIgnoreX[];
--
st.p[st.pi[CAB]].b ← st.p[st.pi[CBA]].b ← TRUE; -- clear internal flipflops
EvalIgnoreX[];
--
st.p[st.pi[CAB]].b ← st.p[st.pi[CBA]].b ← FALSE;
EvalIgnoreX[];
--
st.p[st.pi[A]].d ← st.p[st.pi[B]].d ← force;
Eval[];
--
FOR i:
NAT
IN [0..8)
DO
st.p[st.pi[A]].ls[i] ← st.p[st.pi[B]].ls[i] ← st.AVal[i] ← st.BVal[i] ← H;
ENDLOOP;
Eval[];
--
FOR i:
NAT
IN [0..8)
DO
st.p[st.pi[A]].ls[i] ← st.p[st.pi[B]].ls[i] ← st.AVal[i] ← st.BVal[i] ← L;
ENDLOOP;
st.p[st.pi[A]].d ← st.p[st.pi[B]].d ← drive;
Eval[];
--
FOR i:
NAT
IN [0..2000)
DO
SimulateALS652Data:
PROC = {
FOR i:
NAT
IN [0..8)
DO
baMux: Ports.Level ← (
SELECT
TRUE
FROM
st.p[st.pi[SBA]].b => st.BVal[i],
NOT st.p[st.pi[GAB]].b => st.p[st.pi[B]].ls[i],
st.p[st.pi[SAB]].b => st.AVal[i],
st.p[st.pi[nGBA]].b => st.p[st.pi[A]].ls[i],
ENDCASE => ERROR -- logical loop -- );
abMux: Ports.Level ← (
SELECT
TRUE
FROM
st.p[st.pi[SAB]].b => st.AVal[i],
st.p[st.pi[nGBA]].b => st.p[st.pi[A]].ls[i],
st.p[st.pi[SBA]].b => st.BVal[i],
NOT st.p[st.pi[GAB]].b => st.p[st.pi[B]].ls[i],
ENDCASE => ERROR -- logical loop -- );
IF st.p[st.pi[GAB]].b THEN st.p[st.pi[B]].ls[i] ← abMux;
IF NOT st.p[st.pi[nGBA]].b THEN st.p[st.pi[A]].ls[i] ← baMux;
ENDLOOP;
};
gba, gab, sba, sab, cba, cab: BOOL;
didEval: BOOL ← FALSE;
Choose at most one random thing to do next....
DO
gba ← NOT st.p[st.pi[nGBA]].b;
gab ← st.p[st.pi[GAB]].b;
sba ← st.p[st.pi[SBA]].b;
sab ← st.p[st.pi[SAB]].b;
cba ← st.p[st.pi[CBA]].b;
cab ← st.p[st.pi[CAB]].b;
SELECT genRS.ChooseInt[max: 8]
FROM
0 => gba ← NOT gba;
1 => gab ← NOT gab;
2 => sba ← NOT sba;
3 => sab ← NOT sab;
4 => cba ← NOT cba;
5 => cab ← NOT cab;
ENDCASE => NULL;
Check that it's legal...
IF NOT gba OR NOT gab OR sba OR sab THEN EXIT; -- it's OK
ENDLOOP;
To avoid complications of high-impedance buses oscillating, we overlap drive of tester and DUT by one test vector.
SELECT
TRUE
FROM
st.p[st.pi[
GAB]].b
AND
NOT gab => {
-- device port B turning off, tester drives the same value for one vector
st.p[st.pi[GAB]].b ← FALSE;
st.p[st.pi[B]].d ← drive;
Eval[];
};
NOT st.p[st.pi[
GAB]].b
AND gab => {
-- device port B turning on
st.p[st.pi[GAB]].b ← TRUE;
SimulateALS652Data[];
figure out what device port B would be saying if it were on now, and drive that from the tester before turning device port B on.
st.p[st.pi[GAB]].b ← FALSE;
Eval[];
st.p[st.pi[GAB]].b ← TRUE; -- now turn device port B on
Eval[];
st.p[st.pi[B]].d ← expect; -- now disable tester drive
};
NOT st.p[st.pi[nGBA]].b
AND
NOT gba => {
-- device port A turning off, tester drives the same value for one vector
st.p[st.pi[nGBA]].b ← NOT FALSE;
st.p[st.pi[A]].d ← drive;
Eval[];
};
st.p[st.pi[nGBA]].b
AND gba => {
-- device port A turning on
st.p[st.pi[nGBA]].b ← NOT TRUE;
SimulateALS652Data[];
figure out what device port A would be saying if it were on now, and drive that from the tester before turning device port A on.
st.p[st.pi[nGBA]].b ← NOT FALSE;
Eval[];
st.p[st.pi[nGBA]].b ← NOT TRUE; -- now turn device port A on
Eval[];
st.p[st.pi[A]].d ← expect; -- now disable tester drive
};
NOT st.p[st.pi[
CAB]].b
AND cab => {
-- clock A->B rising
st.p[st.pi[CAB]].b ← TRUE;
FOR i:
NAT
IN [0..8)
DO
st.AVal[i] ← st.p[st.pi[A]].ls[i];
ENDLOOP;
SimulateALS652Data[];
Eval[];
IF controlledClocks
THEN {
st.p[st.pi[CAB]].b ← FALSE; -- for clock edge noise immunity
Eval[];
};
};
NOT st.p[st.pi[
CBA]].b
AND cba => {
-- clock B->A rising
st.p[st.pi[CBA]].b ← TRUE;
FOR i:
NAT
IN [0..8)
DO
st.BVal[i] ← st.p[st.pi[B]].ls[i];
ENDLOOP;
SimulateALS652Data[];
Eval[];
IF controlledClocks
THEN {
st.p[st.pi[CBA]].b ← FALSE; -- for clock edge noise immunity
Eval[];
};
};
ENDCASE => {
st.p[st.pi[SAB]].b ← sab;
st.p[st.pi[SBA]].b ← sba;
st.p[st.pi[CAB]].b ← cab;
st.p[st.pi[CBA]].b ← cba;
FOR i:
NAT
IN [0..8)
DO
IF st.p[st.pi[A]].d = drive
THEN
-- tester is driving port A
st.p[st.pi[A]].ls[i] ← (IF genRS.ChooseInt[max: 1] < 1 THEN H ELSE L);
IF st.p[st.pi[B]].d = drive
THEN
-- tester is driving port B
st.p[st.pi[B]].ls[i] ← (IF genRS.ChooseInt[max: 1] < 1 THEN H ELSE L);
ENDLOOP;
SimulateALS652Data[];
Eval[];
};
ENDLOOP;
MTSVector.CloseCapture[mts];
};
RandomCapture: RosemaryUser.TestProc ~ {
RunTest[CreateState[cellType, p], Eval, MTSVector.CreateCapture[cellType]];
};
RandomTest: RosemaryUser.TestProc ~ {
RunTest[CreateState[cellType, p], Eval, NIL];
};
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 ALS652 random number seed is %d.\n", IO.int[lastGenSeed]]];
};
ALS652RandSeedProc:
PROC [ cmd: Commander.Handle ]
RETURNS [ result:
REF ←
NIL, msg:
IO.
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["ALS652RandSeed", ALS652RandSeedProc, "Reseeds the random number generator for the ALS652 simulation. Usage is\n ALS652RandSeed n\n where n is an integer. 0 recovers the previous seed."];
RosemaryUser.RegisterTestProc["ALS652Random", RandomTest];
RosemaryUser.RegisterTestProc["ALS652RandomCapture", RandomCapture];
END.