ALS652.mesa
Copyright Ó 1987, 1988 by Xerox Corporation. All rights reserved.
E. McCreight, May 15, 1987 4:28:01 pm PDT
Jean-Marc Frailong September 30, 1988 11:26:48 am PDT
DIRECTORY
Commander, CommandTool, Convert, Core, IO, Ports, Random, Rosemary, RosemaryUser, MTSVector;
ALS652: CEDAR PROGRAM
IMPORTS Commander, CommandTool, Convert, IO, Ports, Random, Rosemary, RosemaryUser, MTSVector
=
BEGIN
controlledClocks: BOOLFALSE;
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 NATALL[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: BOOLFALSE;
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: REFNIL, msg: IO.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["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.