DIRECTORY BitOps, Commander, CommandTool, Convert, Core, CoreOps, FS, IO, Ports, Random, Rosemary, RosemaryUser, MTSVector; ALS652Tests: CEDAR PROGRAM IMPORTS BitOps, Commander, CommandTool, Convert, CoreOps, FS, IO, Ports, Random, Rosemary, RosemaryUser, MTSVector = BEGIN makeMTSVectors: BOOL _ TRUE; makeOtherVectors: BOOL _ FALSE; 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, eval: RosemaryUser.TestEvalProc _ 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] ]; lastState: State _ NIL; GetAllState: PROC [cellType: Core.CellType, p: Ports.Port, eval: RosemaryUser.TestEvalProc] RETURNS [ st: State ] = { lastState _ st _ NEW[StateRec _ []]; st.cellType _ cellType; st.p _ p; TRUSTED { st.eval _ eval }; [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; }; PortToStream: PROC [ p: Ports.Port, s: IO.STREAM ] = { PutBool: PROC [ b: BOOL, d: Ports.Drive ] = { s.PutRope[(SELECT d FROM < none => (IF b THEN "H" ELSE "L"), none => "X", <= force => (IF b THEN "T" ELSE "F"), ENDCASE => (IF b THEN "1" ELSE "0") )]; }; PutLevel: PROC [ l: Ports.Level, d: Ports.Drive ] = { s.PutRope[(SELECT d FROM < none => (SELECT l FROM H => "H", L => "L", ENDCASE => "X"), none => "X", <= force => (SELECT l FROM H => "T", L => "F", ENDCASE => "X"), ENDCASE => (SELECT l FROM H => "1", L => "0", ENDCASE => "X") )]; }; IF p.levelType=composite THEN FOR i: NAT IN [0..p.size) DO PortToStream[p[i], s]; ENDLOOP ELSE { SELECT p.levelType FROM l => PutLevel[p.l, p.d]; ls => FOR i: NAT IN [0..p.ls.size) DO PutLevel[p.ls[i], (IF p.driveType=aggregate THEN p.d ELSE p.ds[i])]; ENDLOOP; b => PutBool[p.b, p.d]; bs => FOR i: NAT IN [0..p.bs.size) DO PutBool[p.bs[i], (IF p.driveType=aggregate THEN p.d ELSE p.ds[i])]; ENDLOOP; c => FOR i: NAT IN [p.fieldStart..16) DO PutBool[BitOps.EBFW[p.c, i], p.d]; ENDLOOP; lc => FOR i: NAT IN [p.fieldStart..32) DO PutBool[BitOps.EBFW[p.lc, i], p.d]; ENDLOOP; q => FOR i: NAT IN [p.fieldStart..64) DO PutBool[BitOps.EBFW[p.q[i/16], (i MOD 16)], p.d]; ENDLOOP; ENDCASE => ERROR; }; }; Closem: PROC [mts: MTSVector.File, ascii: IO.STREAM] ~ { IF mts # NIL THEN MTSVector.Close[mts]; IF ascii # NIL THEN ascii.Close[]; }; RunTest: PROC [st: State, mts: MTSVector.File, ascii: IO.STREAM, initializeAll: BOOL _ FALSE ] = { ENABLE UNWIND => Closem[mts, ascii]; Eval: PROC = { st.eval[memory: FALSE, clockEval: TRUE, checkPorts: FALSE]; st.eval[memory: FALSE, clockEval: FALSE, checkPorts: TRUE]; IF mts # NIL THEN MTSVector.WriteVectorFromPort[mts, st.p]; IF ascii # NIL THEN { FOR aw: ALS652Wires IN ALS652Wires DO PortToStream[st.p[st.pi[aw]], ascii]; ENDLOOP; ascii.PutF["\n"]; }; }; EvalIgnoreX: PROC = { Eval[ ! Rosemary.Stop => IF reason = $BoolWireHasX THEN RESUME ELSE REJECT ]; }; 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; 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; IF NOT gba OR NOT gab OR sba OR sab THEN EXIT; -- it's OK ENDLOOP; 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[]; 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[]; 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; Closem[mts, ascii]; }; ALS652Test: RosemaryUser.TestProc ~ { st: State = GetAllState[cellType, p, Eval]; mts: MTSVector.File _ NIL; -- MTS vector file handle ascii: IO.STREAM _ NIL; -- readable vector format stream IF makeMTSVectors THEN mts _ MTSVector.Create[ct: st.cellType, fileBase: "ALS652Tests"]; IF makeOtherVectors THEN { ascii _ FS.StreamOpen[fileName: "ALS652T.av", accessOptions: $create]; ascii.PutF[" %g\n", IO.time[]]; FOR aw: ALS652Wires IN ALS652Wires DO ascii.PutF[" %g [%g]\n", IO.rope[ALS652WireNames[aw]], IO.int[CoreOps.WireBits[st.cellType.public[st.pi[aw]]]]]; ENDLOOP; ascii.PutRope["\n\n"]; }; RunTest[st, mts, ascii, TRUE]; }; 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["ALS652Test", ALS652Test]; END. ALS652Tests.mesa Copyright c 1986 by Xerox Corporation. All rights reserved. E. McCreight, May 15, 1987 4:28:01 pm PDT Last Edited by: McCreight January 13, 1988 12:06:05 pm PST Jean-Marc Frailong January 25, 1988 1:27:13 pm PST st.p[st.Vdd].d _ st.p[st.Gnd].d _ inspect; st.p[st.Vdd].b _ TRUE; st.p[st.Gnd].b _ FALSE; -- -- -- -- -- -- Choose at most one random thing to do next.... Check that it's legal... To avoid complications of high-impedance buses oscillating, we overlap drive of tester and DUT by one test vector. 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. 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. Κ α– "cedar" style˜šœ™Jšœ<™