EUSim.mesa
Copyright © 1985 by Xerox Corporation. All rights reversed.
Created by Bertrand Serlet July 31, 1985 3:03:17 pm PDT
Last edited by Bertrand Serlet June 8, 1986 5:21:11 pm PDT
Barth, April 16, 1986 3:05:40 pm PST
Louis Monier June 19, 1986 11:54:42 pm PDT
Last Edited by: Louis Monier April 24, 1987 1:49:58 pm PDT
DIRECTORY
BitOps, Core, CoreFlat, Dragon, DragOpsCross, EUArith, ICTest, IO, Rope, Rosemary, RosemaryUser, Ports, TerminalIO;
EUSim: CEDAR PROGRAM
IMPORTS BitOps, CoreFlat, EUArith, ICTest, IO, Rosemary, RosemaryUser, Ports, TerminalIO =
BEGIN
Test of EU
ROPE: TYPE = Rope.ROPE;
nbPhases: INT ← 0;
Vdd, Gnd, PadVdd, PadGnd, PhA, PhB,
DPRejectB, DPData,  -- 32 bits
KBus,    -- 32 bits
EURdFromPBus3AB, EUWriteToPBus3AB,
EUAluOp2AB,  -- 4 bits
EUCondSel2AB,  -- 4 bits
EUCondition2B,
DShA, DShB, DShRd, DShWt, DShIn, DShOut, DHold, DStAd: NATLAST[NAT];
REProc: TYPE = PROC [memory: BOOLTRUE];
Initialize: PROC [p: Ports.Port, public: Core.Wire] = {
InitializePublic[public];
p[DPRejectB].b ← FALSE;
p[DShA].b ← p[DShB].b ← FALSE;
p[DShRd].b ← p[DShWt].b ← p[DShIn].b ← p[DHold].b ← FALSE;
p[DStAd].c ← 0;
p[EUCondSel2AB].c ← 0;    -- false
p[EUAluOp2AB].c ← ORD[Dragon.ALUOps[Or]];  -- 0
p[EURdFromPBus3AB].b ← FALSE; -- don't read data from PBus
p[EUWriteToPBus3AB].b ← FALSE; -- and don't write onto PBus during PhB
p[DShOut].b ← FALSE;
p[DShOut].d ← none;
p[EUCondition2B].b ← FALSE;
p[EUCondition2B].d ← none;
p[KBus].d ← none;
p[DPData].d ← none;
};
InitializePublic: PROC [public: Core.Wire] = {
[Vdd, Gnd, PadVdd, PadGnd, PhA, PhB, DPRejectB, DPData] ← Ports.PortIndexes[public, "Vdd", "Gnd", "PadVdd", "PadGnd", "PhA", "PhB", "DPRejectB", "DPData"];
[KBus, EURdFromPBus3AB, EUWriteToPBus3AB, EUAluOp2AB, EUCondSel2AB, EUCondition2B] ← Ports.PortIndexes[public, "KBus", "EURdFromPBus3AB", "EUWriteToPBus3AB", "EUAluOp2AB", "EUCondSel2AB", "EUCondition2B"];
[DShA, DShB, DShRd, DShWt, DShIn, DShOut, DHold, DStAd] ←
Ports.PortIndexes[public, "DShA", "DShB", "DShRd", "DShWt", "DShIn", "DShOut", "DHold", "DStAd"];
[] ← Rosemary.SetFixedWire[public[Vdd], H];
[] ← Rosemary.SetFixedWire[public[Gnd], L];
[] ← Rosemary.SetFixedWire[public[PadVdd], H];
[] ← Rosemary.SetFixedWire[public[PadGnd], L];
[] ← Ports.InitTesterDrive[public[PhA], force];
[] ← Ports.InitTesterDrive[public[PhB], force];
[] ← Ports.InitTesterDrive[public[DPRejectB], force];
[] ← Ports.InitPort[public[DPData], lc];
[] ← Ports.InitTesterDrive[public[DPData], expect];
[] ← Ports.InitPort[public[KBus], lc];
[] ← Ports.InitTesterDrive[public[KBus], force];
[] ← Ports.InitTesterDrive[public[EURdFromPBus3AB], force];
[] ← Ports.InitTesterDrive[public[EUWriteToPBus3AB], force];
[] ← Ports.InitPort[public[EUAluOp2AB], c];
[] ← Ports.InitTesterDrive[public[EUAluOp2AB], force];
[] ← Ports.InitPort[public[EUCondSel2AB], c];
[] ← Ports.InitTesterDrive[public[EUCondSel2AB], force];
[] ← Ports.InitTesterDrive[public[EUCondition2B], expect];
[] ← Ports.InitTesterDrive[public[DShA], force];
[] ← Ports.InitTesterDrive[public[DShB], force];
[] ← Ports.InitTesterDrive[public[DShRd], force];
[] ← Ports.InitTesterDrive[public[DShWt], force];
[] ← Ports.InitTesterDrive[public[DShIn], force];
[] ← Ports.InitTesterDrive[public[DHold], force];
[] ← Ports.InitPort[public[DStAd], c];
[] ← Ports.InitTesterDrive[public[DStAd], force];
[] ← Ports.InitTesterDrive[public[DShOut], none];
};
ExerciseRose: PUBLIC PROC [ct: Core.CellType, cutSets: LIST OF ROPENIL] RETURNS [tester: RosemaryUser.Tester] = {
InitializePublic[ct.public];
tester ← RosemaryUser.TestProcedureViewer[
cellType: ct,
testButtons: LIST["AllTests", "ZeroAndOne", "Sanity Check", "RamTest", "ALUTest", "FUTest", "WiresTest", "DBusTest"],
name: "EUTest",
displayWires: RosemaryUser.DisplayPortLeafWires[ct],
cutSet: CoreFlat.CreateCutSet[labels: cutSets],
steady: FALSE];
};
stackAdr: NAT = ORD[DragOpsCross.ProcessorRegister[euStack]];
junkAdr: NAT = ORD[DragOpsCross.ProcessorRegister[euJunk]];
ifuAdr: NAT = ORD[DragOpsCross.ProcessorRegister[euToKBus]];
marAdr: NAT = ORD[DragOpsCross.ProcessorRegister[euMAR]];
fieldAdr: NAT = ORD[DragOpsCross.ProcessorRegister[euField]];
constAdr: NAT = ORD[DragOpsCross.ProcessorRegister[euConstant]];
bogusAdr: NAT = ORD[DragOpsCross.ProcessorRegister[euBogus]];
Phase: TYPE = {A, B};
DoPh: PROC [p: Ports.Port, Eval: REProc, ph: Phase] = {
nbPhases ← nbPhases+1;
-- Invariants
IF PhA=0 AND PhB=0 THEN ERROR;  -- port indexes not initialized
-- On PhA the chip always drives the PBus, so we check that the tester is not driving
IF ph=A AND p[DPData].d=force THEN ERROR;
-- appropriate clock up
p[PhA].b ← ph=A; p[PhB].b ← ph=B; Eval[FALSE];
-- both clocks down
p[PhA].b ← FALSE; p[PhB].b ← FALSE; Eval[FALSE ! Ports.CheckError =>RESUME];
};
Ignore: PROC [p: Ports.Port, port: NAT] ~ {p[port].d ← none};
Force: PROC [p: Ports.Port, port: NAT, val: CARD] ~ {p[port].d ← force; p[port].lc ← val};
Expect: PROC [p: Ports.Port, port: NAT, val: CARD] ~ {p[port].d ← expect; p[port].lc ← val};
ReadPBus: PROC [p: Ports.Port] ~ {
p[EURdFromPBus3AB].b ← TRUE; 
p[EUWriteToPBus3AB].b ← FALSE;
};
WritePBus: PROC [p: Ports.Port] ~ {
p[EURdFromPBus3AB].b ← FALSE; 
p[EUWriteToPBus3AB].b ← TRUE;
};
IgnorePBus: PROC [p: Ports.Port] ~ {
p[EURdFromPBus3AB].b ← FALSE; 
p[EUWriteToPBus3AB].b ← FALSE;
};
PackK: PROC [a, b: NAT ← constAdr, c: NAT ← junkAdr, st3AisC: BOOLFALSE,
aluL, aluR, st2A: NAT ← 0] RETURNS [k: CARD] ~ {
k ← (((((LONG[a]*256+LONG[b])*256+LONG[c])*2+(IF st3AisC THEN 1 ELSE 0))*4+aluL)*8+aluR)*4+st2A;
};
WriteInRam: PROC [p: Ports.Port, Eval: REProc, ad: NAT, val: CARD] ~ {
Force[p, KBus, PackK[c: ad]]; -- load c address in kReg
ReadPBus[p];
Force[p, DPData, val];
DoPh[p, Eval, B];         -- 0B: kReg ← ad; dataIn ← val
Ignore[p, KBus];
IgnorePBus[p];
Ignore[p, DPData];
DoPh[p, Eval, A];         -- 1A: ram[ad] ← val
};
ReadFromRam: PROC [p: Ports.Port, Eval: REProc, ad: NAT, val: CARD, m: CARD ← 01234567H] ~ {
Force[p, KBus, PackK[b: ad, st2A: 0]]; -- load b address in kReg
ReadPBus[p];
Force[p, DPData, m];  -- to detect no drive on PBus
DoPh[p, Eval, B];         -- 0B: kReg ← ad
Ignore[p, KBus];
IgnorePBus[p];
Ignore[p, DPData];
DoPh[p, Eval, A];         -- 1A: st2A ← ram[ad]
CheckSt2A[p, Eval, val];  -- 4 more phases
};
-- Utility, not a test in itself
-- Gets value through the KBus and computes OR[ct0, val]
PutValInR2B: PROC [p: Ports.Port, Eval: REProc, val, k: CARD] ~ {
Force[p, KBus, PackK[a: constAdr, aluR: 3]]; -- load addresses in kReg
IgnorePBus[p];
Force[p, DPData, 0];   -- to detect no drive on PBus
DoPh[p, Eval, B];         -- 0B: kReg ← ad
Force[p, KBus, val];
IgnorePBus[p];
Ignore[p, DPData];
DoPh[p, Eval, A];         -- 1A: left ← ram[ad], right ← kBus
p[EUAluOp2AB].c ← 0; -- ORD[Or]
Force[p, KBus, k];
Ignore[p, DPData];
DoPh[p, Eval, B];         -- 1B: r2B ← right
};
-- Gets value through the KBus and computes OR[ct0, val], then moves it down by two latches
-- k is the value on the kBus in the last PhB
PutValInR3B: PROC [p: Ports.Port, Eval: REProc, val, k: CARD, reject: BOOLFALSE] ~ {
PutValInR2B[p, Eval, val, PackK[]];  -- 1B: r2B ← val
Ignore[p, KBus];
Ignore[p, DPData];
DoPh[p, Eval, A];         -- 2A: r3A ← val
IF reject THEN p[DPRejectB].b ← TRUE;
Force[p, KBus, k];
Ignore[p, DPData];
DoPh[p, Eval, B];         -- 2B: r3B ← val
p[DPRejectB].b ← FALSE;
};
-- Checks whether st2A=val
CheckSt2A: PROC [p: Ports.Port, Eval: REProc, val: CARD] ~ {
Force[p, KBus, PackK[]];
Ignore[p, DPData];
DoPh[p, Eval, B];         -- 0B: st2B ← val
Ignore[p, KBus];
Ignore[p, DPData];
DoPh[p, Eval, A];         -- 1A: st3A ← val
Force[p, KBus, PackK[]];
WritePBus[p];
Expect[p, DPData, val];
DoPh[p, Eval, B];         -- 1B: PBus ← st3A = val ???
Ignore[p, KBus];
IgnorePBus[p];
Ignore[p, DPData];
DoPh[p, Eval, A];         -- 2A: just for sync.
};
-- Computes OP(left, right) and checks that the result is equal to val
OpAndCheck: PROC [p: Ports.Port, Eval: REProc, val: CARD, op: NAT] ~ {
p[EUAluOp2AB].c ← op; -- ORD[alu opcode]
Force[p, KBus, PackK[]];
Ignore[p, DPData];
DoPh[p, Eval, B];         -- 0B: r2B ← val
Ignore[p, KBus];
Expect[p, DPData, val];
DoPh[p, Eval, A];         -- 1A: PBus ← r2B = val ???.
};
-- From PBus to dataIn to cBus to KBus
FromPtoK: PROC [p: Ports.Port, Eval: REProc, val: CARD] ~ {
Force[p, KBus, PackK[c: ifuAdr]]; -- cBus->IFU on next PhA
ReadPBus[p];
Force[p, DPData, val];
DoPh[p, Eval, B];         -- Cycle 0: dataIn ← val
Expect[p, KBus, val];
IgnorePBus[p];
Ignore[p, DPData];
DoPh[p, Eval, A];         -- Cycle 1: KBus ← cBus ← val
IgnorePBus[p];
};
ALUOp: PROC [p: Ports.Port, Eval: REProc, op: Dragon.ALUOps, opL, opR, res: CARD, cc: Dragon.CondSelects ← False, cond: BOOLFALSE] ~ {
lAd: NAT = 1;
rAd: NAT = 3;
TerminalIO.PutF["ALU, phase %g: %g (%g) %g -> %g", IO.card[nbPhases], IO.card[opL], IO.rope[opName[op]], IO.card[opR], IO.card[res]];
TerminalIO.PutF[" cc: %g\n", IO.int[ORD[cc]]];
WriteInRam[p, Eval, lAd, opL];
WriteInRam[p, Eval, rAd, opR];
p[EURdFromPBus3AB].b ← FALSE;
Force[p, KBus, PackK[a: lAd, b: rAd]];
Ignore[p, DPData];
DoPh[p, Eval, B];         -- 0B: aAdr ← lAd, bAdr ← rAd
p[EUAluOp2AB].c ← ORD[op];
Ignore[p, KBus];
Ignore[p, DPData];
DoPh[p, Eval, A];         -- 1A: opL ← ram[lAd]; opR ← ram[rAd]
p[EUCondSel2AB].c ← ORD[cc];
p[EUCondition2B].b ← cond;
p[EUCondition2B].d ← expect;
p[DShOut].b ← FALSE;
p[DShOut].d ← expect;
Force[p, KBus, PackK[]];
Ignore[p, DPData];
DoPh[p, Eval, B];         -- 1B: r2B ← opL op opR
p[EUCondSel2AB].c ← 0;
p[EUCondition2B].b ← FALSE;
p[EUCondition2B].d ← none;
p[DShOut].d ← none;
Ignore[p, KBus];
Expect[p, DPData, res];
DoPh[p, Eval, A];         -- 2A: PBus ← r2B
p[EUAluOp2AB].c ← 0;
};
-- This test uses the field register to hold the field descriptor
FUOp: PROC [p: Ports.Port, Eval: REProc, leftW, rightW, mask, shift: CARD, insert: BOOLFALSE] ~ {
fd: NAT ← ((IF insert THEN 1 ELSE 0)*64+mask)*64+shift;
res: CARD ← EUArith.FieldOp[leftW, rightW, fd];
TerminalIO.PutF["FU, phase %g, mask: %g, shift: %g, insert: %g\n", IO.card[nbPhases], IO.card[mask], IO.card[shift], IO.bool[insert]];
WriteInRam[p, Eval, fieldAdr, LONG[fd]]; -- field�
WriteInRam[p, Eval, 1, leftW];  -- ram[0]←leftW
WriteInRam[p, Eval, 2, rightW];  -- ram[1]←rightW
Force[p, KBus, PackK[a: 1, b: 2, aluR: 4]]; -- right𡤏ield; left←leftW; st2A←rightW
Ignore[p, DPData];
DoPh[p, Eval, B];       -- 0B: load operand addresses
p[EUAluOp2AB].c ← ORD[Dragon.ALUOps[FOP]];
Ignore[p, KBus];
Ignore[p, DPData];
DoPh[p, Eval, A];       -- 1A: read ram
Force[p, KBus, PackK[]];
Ignore[p, DPData];
DoPh[p, Eval, B];       -- 1B: field unit is active
Ignore[p, KBus];
Expect[p, DPData, res];
DoPh[p, Eval, A];       -- 2A: PBus ← r2B
};
-- Test procs
-- The combination of all the test procs
AllTests: RosemaryUser.TestProc = {
[cellType: Core.CellType, p: Ports.Port, Eval: PROC [...]]
TerminalIO.PutRope["Starting AllTests"];
ZeroAndOne[cellType, p, Eval];
SanityCheck[cellType, p, Eval];
WiresTest[cellType, p, Eval];
DBusTest[cellType, p, Eval];
ALUTest[cellType, p, Eval];
FUTest[cellType, p, Eval];
RamTest[cellType, p, Eval];
TerminalIO.PutRope["Finished with AllTests"];
};
-- The absolute minimum expected from a chip
ZeroAndOne: RosemaryUser.TestProc = {
TerminalIO.PutRope["Starting ZeroAndOne"];
Initialize[p, cellType.public];
FromPtoK[p, Eval,000000000H];
FromPtoK[p, Eval,0FFFFFFFFH];
FromPtoK[p, Eval,05555AAAAH];
TerminalIO.PutRope["Finished with ZeroAndOne"];
};
-- The minimum expected from a chip
SanityCheck: RosemaryUser.TestProc = {
FromPtoP2: PROC [val: CARD] ~ {
Force[p, KBus, PackK[st3AisC: TRUE]]; -- st3A ← cBus on next PhA
ReadPBus[p];
Force[p, DPData, val];
DoPh[p, Eval, B];         -- 0B: dataIn ← val
Ignore[p, KBus];
IgnorePBus[p];
Ignore[p, DPData];
DoPh[p, Eval, A];         -- 1A: st3A ← cBus ← dataIn (val)
Force[p, KBus, PackK[]];
WritePBus[p];
Expect[p, DPData, val];
DoPh[p, Eval, B];         -- 1B: PBus ← st3A = val ???
Ignore[p, KBus];
IgnorePBus[p];
Ignore[p, DPData];
DoPh[p, Eval, A];         -- 2A: just for sync.
};
FromPtoP4: PROC [val: CARD] ~ {
Force[p, KBus, PackK[st2A: 2]]; -- st2A ← cBus on next PhA
ReadPBus[p];
Force[p, DPData, val];
DoPh[p, Eval, B];         -- 0B: dataIn ← val
Ignore[p, KBus];
IgnorePBus[p];
Ignore[p, DPData];
DoPh[p, Eval, A];         -- 1A: st2A ← cBus ← val
Force[p, KBus, PackK[]];
IgnorePBus[p];
Force[p, DPData, 01234567H]; -- to eliminate old (good) value on PBus
DoPh[p, Eval, B];         -- 1B: st2B ← st2A
Ignore[p, KBus];
IgnorePBus[p];
Ignore[p, DPData];
DoPh[p, Eval, A];         -- 2A: st3A ← st2B
Force[p, KBus, PackK[]];
WritePBus[p];
Expect[p, DPData, val];
DoPh[p, Eval, B];         -- 2B: PBus ← st3A = val ???
Ignore[p, KBus];
IgnorePBus[p];
Ignore[p, DPData];
DoPh[p, Eval, A];         -- 3A: just for sync.
};
TerminalIO.PutRope["Starting SanityCheck"];
Initialize[p, cellType.public];
FromPtoP4[000000000H]; FromPtoP4[0AAAAAAAAH]; FromPtoP4[055555555H];
FromPtoP4[0FFFFFFFFH]; FromPtoP4[02BAD2BADH];
FromPtoP2[000000000H]; FromPtoP2[0AAAAAAAAH]; FromPtoP2[055555555H];
FromPtoP2[0FFFFFFFFH]; FromPtoP2[02BAD2BADH];
FromPtoK[p, Eval,000000000H]; FromPtoK[p, Eval,0AAAAAAAAH];
FromPtoK[p, Eval,055555555H]; FromPtoK[p, Eval,0FFFFFFFFH];
FromPtoK[p, Eval,02BAD2BADH];
TerminalIO.PutRope["Finished with SanityCheck"];
};
-- Test the entire RAM
RamTest: RosemaryUser.TestProc = {
Val: PROC [i: NAT] RETURNS [val: CARD] ~ {
val ← 0137FA00H+i;
};
CheckRamBlock: PROC [from, to: NAT] ~ {
FOR i: NAT IN [from..to) DO
WriteInRam[p, Eval, i, 0137FA00H+i];
ENDLOOP;
FOR i: NAT IN [from..to) DO
ReadFromRam[p, Eval, i, 0137FA00H+i];
WriteInRam[p, Eval, i, 0FEC8500H+0FFH-i];
ENDLOOP;
FOR i: NAT IN [from..to) DO
ReadFromRam[p, Eval, i, 0FEC8500H+0FFH-i];
ENDLOOP;
};
TerminalIO.PutRope["Starting RamTest"];
Initialize[p, cellType.public];
CheckRamBlock[stackAdr, junkAdr];
CheckRamBlock[junkAdr+1, constAdr]; -- avoid euJunk, since it should not exist
CheckRamBlock[constAdr+4, bogusAdr];
-- Read constants in ROM
ReadFromRam[p, Eval, constAdr, 0];
ReadFromRam[p, Eval, constAdr+1, 1];
ReadFromRam[p, Eval, constAdr+2, 2];
ReadFromRam[p, Eval, constAdr+3, 3];
TerminalIO.PutRope["Finished with RamTest"];
};
ALUTest: RosemaryUser.TestProc = {
ResetCarry: PROC ~ {TestALU[LAdd, 0, 0, 0]};
SetCarry: PROC ~ {TestALU[UAdd, 0FFFFFFFFH, 000000001H, 0]};
TestALU: PROC [op: Dragon.ALUOps, opL, opR, res: CARD, cc: Dragon.CondSelects ← False, cond: BOOLFALSE] ~ {
ALUOp[p, Eval, op, opL, opR, res, cc, cond];
};
TestAdd: PROC [op: Dragon.ALUOps] ~ {
IF op#SAdd AND op#UAdd AND op#VAdd AND op#LAdd AND op#VAdd2 THEN ERROR;
ResetCarry[];
TestALU[op, 000000000H,000000000H,000000000H];
TestALU[op, 000000001H,000000002H,000000003H];
TestALU[op, 00FFFFFFFH,000000001H,010000000H];
TestALU[op, 012345678H,087654321H,099999999H];
TestALU[op, 0FFFFFFFFH,000000000H,0FFFFFFFFH];
TestALU[op, 000000000H,0FFFFFFFFH,0FFFFFFFFH];
-- may generates a carry
TestALU[op, 000000001H,0FFFFFFFFH,000000000H];
ResetCarry[];
};
TestSub: PROC [op: Dragon.ALUOps] ~ {
IF op#SSub AND op#USub AND op#VSub AND op#LSub THEN ERROR;
TestALU[op, 000000000H,000000000H,000000000H];
TestALU[op, 000000003H,000000002H,000000001H];
TestALU[op, 010000000H,000000001H,00FFFFFFFH];
TestALU[op, 099999999H,087654321H,012345678H];
TestALU[op, 0FFFFFFFFH,000000000H,0FFFFFFFFH];
TestALU[op, 0FFFFFFFFH,0FFFFFFFFH,000000000H];
-- may generates a carry
TestALU[op, 000000000H,0FFFFFFFFH,000000001H];
ResetCarry[];
};
TerminalIO.PutRope["Starting ALUTest"];
Initialize[p, cellType.public];
TerminalIO.PutF["New Test\n"];
-- OvFl ← (Cout XOR opL[0] XOR opR[0]) XOR res[0], so we need a carry out;
ResetCarry[];
TestALU[UAdd, 07FFFFFFFH, 000000001H, 080000000H, OvFl, TRUE];
ResetCarry[];
TestALU[UAdd, 07FFFFFFFH, 000000000H, 07FFFFFFFH, OvFl, FALSE];
BC ← ~Cout
ResetCarry[];
TestALU[BndChk, 000000000H, 000000001H, 000000000H, BC, FALSE];
ResetCarry[];
TestALU[BndChk, 000000002H, 000000001H, 000000002H, BC, TRUE];
ResetCarry[];
TestALU[BndChk, 000000000H, 000000001H, 000000000H, NotBC, TRUE];
ResetCarry[];
TestALU[BndChk, 000000002H, 000000001H, 000000002H, NotBC, FALSE];
-- LZ ← Cout XOR opL[0] XOR opR[0], so we need a carry out; GE ← ~ LZ
ResetCarry[];
TestALU[USub, 000000000H, 000000001H, 0FFFFFFFFH, LZ, TRUE];
ResetCarry[];
TestALU[UAdd, 000000000H, 000000000H, 000000000H, LZ, FALSE];
ResetCarry[];
TestALU[UAdd, 000000000H, 000000000H, 000000000H, GE, TRUE];
ResetCarry[];
TestALU[USub, 000000000H, 000000001H, 0FFFFFFFFH, GE, FALSE];
-- LE ← EZ OR LZ
ResetCarry[];
TestALU[USub, 000000000H, 000000000H, 000000000H, LE, TRUE];
TestALU[USub, 000000001H, 000000000H, 000000001H, LE, FALSE];
TestALU[USub, 000000001H, 000000000H, 000000001H, NE, TRUE];
TestALU[USub, 000000001H, 000000001H, 000000000H, NE, FALSE];
TestALU[USub, 000000001H, 000000000H, 000000001H, GZ, TRUE];
TestALU[USub, 000000000H, 000000000H, 000000000H, GZ, FALSE];
IL ← all 3 high-order bits equal
TestALU[LAdd, 07FFFFFFFH, 000000001H, 080000000H, IL, TRUE]; -- opL=011
TestALU[LAdd, 000000000H, 0FFFFFFFFH, 0FFFFFFFFH, IL, FALSE]; -- all 0 or 1
TestALU[LAdd, 010000000H, 010000000H, 020000000H, IL, TRUE]; -- res=001
TestALU[LAdd, 000000001H, 000000001H, 000000002H, IL, FALSE]; -- all 0
TestALU[LAdd, 07FFFFFFFH, 000000001H, 080000000H, NotIL, FALSE]; -- opL=011
TestALU[LAdd, 000000000H, 0FFFFFFFFH, 0FFFFFFFFH, NotIL, TRUE]; -- all 0 or 1
TestALU[LAdd, 010000000H, 010000000H, 020000000H, NotIL, FALSE]; -- res=001
TestALU[LAdd, 000000001H, 000000001H, 000000002H, NotIL, TRUE]; -- all 0
EZ ← zero, found after a sub at the top of the CLA tree
ResetCarry[];
TestALU[USub, 000000000H, 000000000H, 000000000H, EZ, TRUE];
TestALU[USub, 02BAD2BADH, 02BAD2BADH, 000000000H, EZ, TRUE];
TestALU[USub, 0FFFFFFFFH, 0FFFFFFFFH, 000000000H, EZ, TRUE];
TestALU[USub, 000000001H, 000000000H, 000000001H, EZ, FALSE];
TestALU[USub, 02BAD2BADH, 000000001H, 02BAD2BACH, EZ, FALSE];
TestALU[USub, 000000001H, 000000002H, 0FFFFFFFFH, EZ, FALSE];
Check integrity of aluLeft-> r2B-> pDriver path
TestALU[BndChk,  000000000H,000000000H,000000000H];
TestALU[BndChk,  055555555H,000000000H,055555555H];
TestALU[BndChk,  0AAAAAAAAH,000000000H,0AAAAAAAAH];
TestALU[BndChk,  0FFFFFFFFH,000000000H,0FFFFFFFFH];
Logic operations
TestALU[Or, 000FF00FFH,00F0F0F0FH,00FFF0FFFH];
TestALU[And,  000FF00FFH,00F0F0F0FH,0000F000FH];
TestALU[Xor,  000FF00FFH,00F0F0F0FH,00FF00FF0H];
All additions
TestAdd[SAdd];
TestAdd[UAdd];
TestAdd[VAdd];
TestAdd[LAdd];
TestAdd[VAdd2];
All subtractions
TestSub[SSub];
TestSub[USub];
TestSub[VSub];
TestSub[LSub];
Constant Conditions
TestALU[LAdd, 000000000H, 000000000H, 000000000H, False, FALSE];
TestALU[LAdd, 000000000H, 000000000H, 000000000H, ModeFault, TRUE];
TerminalIO.PutRope["Finished with ALUTest"];
};
FUTest: RosemaryUser.TestProc = {
TestFU: PROC [leftW, rightW, mask, shift: CARD, insert: BOOLFALSE] ~ {
FUOp[p, Eval, leftW, rightW, mask, shift, insert];
};
TerminalIO.PutRope["Starting FUTest"];
Initialize[p, cellType.public];
-- Testing the shifter (no masking)
FOR shift: NAT IN [0..32] DO
TestFU[leftW: 0F0402010H, rightW: 0AAAAAAAAH, mask: 32, shift: shift];
ENDLOOP;
-- Testing the mask generator (no shifting)
FOR shift: NAT IN [0..32] DO
TestFU[leftW: 0F0402010H, rightW: 0AAAAAAAAH, mask: shift, shift: 0];
ENDLOOP;
-- General Shift and Mask test
FOR i: NAT IN [0..32] DO
TestFU[leftW: 0F0402010H, rightW: 0AAAAAAAAH, mask: (4*i+19) MOD 33, shift: (3*i+5) MOD 33];
ENDLOOP;
-- With insert
TestFU[leftW: 0F0402010H, rightW: 02BAD2BADH, mask: 0, shift: 0, insert: TRUE];
TestFU[leftW: 0F0402010H, rightW: 02BAD2BADH, mask: 32, shift: 0, insert: TRUE];
TestFU[leftW: 0F0402010H, rightW: 02BAD2BADH, mask: 32, shift: 32, insert: TRUE];
TestFU[leftW: 0F0402010H, rightW: 0AAAAAAAAH, mask: 18, shift: 4, insert: TRUE];
TestFU[leftW: 0F0402010H, rightW: 02BAD2BADH, mask: 21, shift: 12, insert: TRUE];
TerminalIO.PutRope["Finished with FUTest"];
};
EUTest: RosemaryUser.TestProc = {
}; 
-- Try to put a zero and a 1 through every path in the EU
-- I use an asymetric pattern to detect flips in buses
-- I use the bus names defined in the schematics of the datapath
c1: CARD = 00137FFFFH;
c2: CARD = 0FEC80000H;
-- Test the tristate driver r3B on the cBus; normal case
R3BNormal: PROC [p: Ports.Port, Eval: REProc, val: CARD] ~ {
PutValInR3B[p, Eval, val, PackK[st3AisC: TRUE]];-- 2B: r3B ← val
Ignore[p, KBus];
Ignore[p, DPData];
DoPh[p, Eval, A];         -- 3A: st3A ← val
Force[p, KBus, PackK[]];
WritePBus[p];
Expect[p, DPData, val];
DoPh[p, Eval, B];         -- 3B: PBus ← st3A = val ???
Ignore[p, KBus];
IgnorePBus[p];
Ignore[p, DPData];
DoPh[p, Eval, A];         -- 4A: just for sync.
};
-- Test the tristate driver r3B on the cBus; reject case
R3BReject: PROC [p: Ports.Port, Eval: REProc, val: CARD] ~ {
PutValInR3B[p, Eval, val, PackK[], TRUE];-- 2B: r3B ← val
Ignore[p, KBus];
Ignore[p, DPData];
DoPh[p, Eval, A];         -- 3A: ram[marAdr] ← cBus ← val (reject)
ReadFromRam[p, Eval, marAdr, val];   -- check marAdr
};
-- Bypass from r2B to left
R2BtoLeft: PROC [p: Ports.Port, Eval: REProc, val: CARD] ~ {
PutValInR2B[p, Eval, val, PackK[b: constAdr, aluL: 1]]; -- 1B: r2B ← val
Ignore[p, KBus];
Ignore[p, DPData];
DoPh[p, Eval, A];         -- 2A: left ← r2B ← val; right ← 0
OpAndCheck[p, Eval, val, 0];
};
-- Bypass from r2B to right
R2BtoRight: PROC [p: Ports.Port, Eval: REProc, val: CARD] ~ {
PutValInR2B[p, Eval, val, PackK[a: constAdr, aluR: 1]]; -- 1B: r2B ← val
Ignore[p, KBus];
Ignore[p, DPData];
DoPh[p, Eval, A];         -- 2A: right ← r2B ← val; left ← 0
OpAndCheck[p, Eval, val, 0];
};
-- Bypass from r2B to st2A
R2BtoSt2A: PROC [p: Ports.Port, Eval: REProc, val: CARD] ~ {
PutValInR2B[p, Eval, val, PackK[a: constAdr, st2A: 1]]; -- 1B: r2B ← val
Ignore[p, KBus];
Ignore[p, DPData];
DoPh[p, Eval, A];         -- 2A: st2A ← r2B ← val
CheckSt2A[p, Eval, val];
};
-- Bypass from r3B to left
CBustoLeft: PROC [p: Ports.Port, Eval: REProc, val: CARD] ~ {
PutValInR3B[p, Eval, val, PackK[b: constAdr, aluL: 2]]; -- 1B: r3B ← val
Ignore[p, KBus];
Ignore[p, DPData];
DoPh[p, Eval, A];         -- 2A: left ← r2B ← val; right ← 0
OpAndCheck[p, Eval, val, 0];
};
CBustoRight: PROC [p: Ports.Port, Eval: REProc, val: CARD] ~ {
PutValInR3B[p, Eval, val, PackK[a: constAdr, aluR: 2]]; -- 1B: r3B ← val
Ignore[p, KBus];
Ignore[p, DPData];
DoPh[p, Eval, A];         -- 2A: right ← r2B ← val; left ← 0
OpAndCheck[p, Eval, val, 0];
};
WiresTest: RosemaryUser.TestProc = {
TryAllPaths: PROC [p: Ports.Port, Eval: REProc, val: CARD] ~ {
FromPtoK[p, Eval, val];  -- 4 evals
R3BNormal[p, Eval, val];  -- 24 evals
R3BReject[p, Eval, val];  -- 24 evals
R2BtoLeft[p, Eval, val];  -- 12 evals
R2BtoRight[p, Eval, val]; -- 12 evals
R2BtoSt2A[p, Eval, val];  -- 16 evals
CBustoLeft[p, Eval, val];  -- 16 evals
CBustoRight[p, Eval, val]; -- 16 evals
};
TerminalIO.PutRope["Starting WiresTest"];
TryAllPaths[p, Eval, c1];
TryAllPaths[p, Eval, c2];
TerminalIO.PutRope["Finished with WiresTest"];
};
DBusTest: RosemaryUser.TestProc = {
TerminalIO.PutRope["Starting DBusTest"];
Initialize[p, cellType.public];
ReadR2BWithDBus[p, Eval, 0A123456FH];
TerminalIO.PutRope["Finished with DBusTest"];
};
ReadR2BWithDBus: PROC [p: Ports.Port, Eval: REProc, val: CARD] ~ {
PutValInR2B[p, Eval, val, PackK[a: constAdr, aluR: 2]]; -- 1B: r2B ← val
Ignore[p, KBus];
Ignore[p, DPData];
p[DStAd].c ← 7;   -- EUUtils.r2BRow
p[DShRd].b ← TRUE;
p[DShWt].b ← FALSE;
Eval[];      -- read the register: shiftReg ← reg[regAd]
p[DShRd].b ← FALSE;
p[DShWt].b ← FALSE;
FOR i: NAT IN [0..32) DO
bitOut: BOOL ← BitOps.EBFD[val, i];
p[DShOut].d ← expect;
p[DShOut].b ← bitOut;
p[DShB].b ← TRUE;
Eval[];      -- <b> ← <a>; shOut ← new value
p[DShOut].d ← none;
p[DShB].b ← FALSE;
Eval[];      -- <b> latched; shOut tristate
p[DShIn].b ← FALSE;
p[DShA].b ← TRUE;
Eval[];      -- <a> ← <in>; shIn is sampled
p[DShA].b ← FALSE;
p[DShB].b ← FALSE;
Eval[];      -- <a> latched
ENDLOOP;
p[DShRd].b ← FALSE;
p[DShWt].b ← FALSE;
p[DHold].b ← FALSE;
p[DStAd].c ← 0;
Eval[];
DoPh[p, Eval, A];         -- A: for synch
};
Register: PROC [usingTester: BOOL] ~ {
IF usingTester THEN { -- for IMS tester
ICTest.RegisterTestProc[euTest, "ZeroAndOne", ZeroAndOne];
ICTest.RegisterTestProc[euTest, "Sanity Check", SanityCheck];
ICTest.RegisterTestProc[euTest, "RamTest", RamTest];
ICTest.RegisterTestProc[euTest, "ALUTest", ALUTest];
ICTest.RegisterTestProc[euTest, "FUTest", FUTest];
}
ELSE { -- for Rosemary simulation
RosemaryUser.RegisterTestProc["AllTests",  AllTests];
RosemaryUser.RegisterTestProc["ZeroAndOne",  ZeroAndOne];
RosemaryUser.RegisterTestProc["Sanity Check",  SanityCheck];
RosemaryUser.RegisterTestProc["RamTest",  RamTest];
RosemaryUser.RegisterTestProc["ALUTest",  ALUTest];
RosemaryUser.RegisterTestProc["FUTest",  FUTest];
RosemaryUser.RegisterTestProc["WiresTest",  WiresTest];
RosemaryUser.RegisterTestProc["DBusTest",  DBusTest];
};
};
euTest: ROPE = "EU4 Test";
opName: ARRAY Dragon.ALUOps OF Rope.ROPE;
opName[Or] ← "Or";   opName[And] ← "And"; 
opName[VAdd2] ← "VAdd2";  opName[BndChk] ← "BndChk";
opName[SAdd] ← "SAdd"; opName[SSub] ← "SSub";
opName[LAdd] ← "LAdd"; opName[LSub] ← "LSub";
opName[Xor] ← "Xor";  opName[res9] ← "res9";
opName[FOP] ← "FOP";  opName[res11] ← "res11";
opName[VAdd] ← "VAdd"; opName[VSub] ← "VSub"; 
opName[UAdd] ← "UAdd"; opName[USub] ← "USub";
END.