[Indigo]<Rosemary>®>Rosemary.DF=>RoseTestingImpl.Mesa
Last Edited by: Spreitzer, October 17, 1985 5:11:15 pm PDT
Last Edited by: Barth, September 16, 1985 3:53:42 pm PDT
Last Edited by: Gasbarro, July 17, 1984 3:52:04 pm PDT
DIRECTORY AMBridge, AMTypes, Ascii, BitTwiddling, Cucumber, IO, PrincOps, PrincOpsUtils, RedBlackTree, Rope, RoseClocks, RoseCreate, RoseRun, RoseStateIO, RoseTypes;
RoseTestingImpl:
CEDAR
PROGRAM
IMPORTS AMBridge, AMTypes, Ascii, BitTwiddling, Cucumber, IO, PrincOpsUtils, RedBlackTree, Rope, RoseClocks, RoseCreate, RoseRun, RoseStateIO, RoseTypes
EXPORTS RoseCreate, RoseRun, RoseTypes =
BEGIN OPEN RoseTypes, RoseRun, RoseCreate;
InterfaceMismatch:
PUBLIC
ERROR [cell: Cell,
index: CARDINAL,
expected, got: NodeType] = CODE;
TV: TYPE = AMTypes.TV;
Type: TYPE = AMTypes.Type;
WrapTop:
PUBLIC
PROC [rootName, typeName:
ROPE, decider: ExpandDeciderClosure, clocks:
ROPE ←
NIL, sim: Simulation] =
BEGIN
rootType: CellType;
rootType ← GetWrappingType[typeName, clocks];
CreateTopCell[instanceName: rootName, typeName: rootType.name, decider: decider, sim: sim];
END;
GetWrappingType:
PROC [subName, clocks:
ROPE]
RETURNS [wrappingType: CellType] =
BEGIN
wrappingName: ROPE = subName.Cat["-wrap-", clocks];
subType: CellType;
IF (wrappingType ← GetCellType[wrappingName]) # NIL THEN RETURN;
IF (subType ← GetCellType[subName]) = NIL THEN ERROR Error[msg: "No such type", data: subName];
wrappingType ← RegisterCellType[
name: wrappingName,
expandProc: ExpandWrapper,
evals: [],
ports: NEW [PortsRep[0]],
typeData: NEW [WrapTypeRep ← [subType, clocks]]];
END;
WrapType:
TYPE =
REF WrapTypeRep; WrapTypeRep:
TYPE =
RECORD [
subType: CellType,
clocks: ROPE];
ExpandWrapper:
PROC [thisCell: Cell, to: ExpansionReceiver]
--ExpandProc-- =
BEGIN
wc: WrapType ← NARROW[thisCell.type.typeData];
IF wc.clocks #
NIL
THEN {
clockType: CellType ← RoseClocks.ClockGen[[]];
PerClock:
PROC [key: Key, nodeName:
ROPE] = {
portIndex: PortIndex ← nilPortIndex;
WITH key
SELECT
FROM
x: Key.position => portIndex ← x.index;
x: Key.keyword => portIndex ← GetIndex[clockType.ports, x.name];
ENDCASE => ERROR;
[] ← to.class.NodeInstance[erInstance: to.instance, name: nodeName, type: clockType.ports[portIndex].type];
};
EnumerateConnections[wc.clocks, PerClock];
[] ← to.class.CellInstance[erInstance: to.instance, instanceName: "clockGen", typeName: clockType.name, interfaceNodes: wc.clocks];
};
EnsureEnvironment[in: thisCell, forType: wc.subType, to: to];
[] ← to.class.CellInstance[erInstance: to.instance, instanceName: LowerFirst[wc.subType.name], typeName: wc.subType.name, interfaceNodes: ""];
END;
LowerFirst:
PROC [u:
ROPE]
RETURNS [l:
ROPE] = {
IF u.Length[] = 0 THEN RETURN [u];
l ← Rope.FromChar[Ascii.Lower[u.Fetch[0]]].Concat[u.Substr[start: 1]]};
EnsureEnvironment:
PUBLIC
PROC [in: Cell, forType: CellType, to: ExpansionReceiver] =
BEGIN
FOR portIndex:
CARDINAL
IN [0 .. forType.ports.length)
DO
port: Port = forType.ports[portIndex];
node: Node ← NARROW[in.internalNodes.Lookup[port.name]];
s: Strength ← charge;
iv: ROPE ← NIL;
IF node # NIL THEN LOOP;
IF port.name.Equal["gnd", FALSE] THEN {s ← input; iv ← "gnd"} ELSE
IF port.name.Equal["vdd", FALSE] THEN {s ← input; iv ← "vdd"} ELSE
IF port.input AND NOT port.output THEN s ← input ELSE
IF port.output AND NOT port.input THEN s ← chargeWeak;
[] ← to.class.NodeInstance[erInstance: to.instance, name: port.name, type: port.type, initialValue: iv, initialValueFormat: IF iv # NIL THEN "init" ELSE NIL, initData: NEW [Strength ← s]];
ENDLOOP;
END;
ProcToInt:
PROC [p:
PROC
ANY
RETURNS
ANY]
RETURNS [i:
INT] =
TRUSTED {i ← LOOPHOLE[p, INTEGER]};
MakeTesterPorts:
PROC [testee: Ports, alwaysOutput, alwaysInput:
BOOL ←
FALSE]
RETURNS [tester: Ports] =
BEGIN
tester ← NEW [PortsRep[testee.length]];
FOR i:
CARDINAL
IN [0 .. testee.length)
DO
tester[i] ← testee[i];
IF testee[i].instructionsSimple # testee[i].type.simple
THEN {
IF testee[i].type.simple THEN ERROR;
tester[i].type ← testee[i].type.procs.SimpleEquivalent[testee[i].type];
};
tester[i].input ← alwaysInput OR testee[i].output;
tester[i].output ← alwaysOutput OR testee[i].input;
ENDLOOP;
END;
CreateTest:
PUBLIC
PROC [rootName, typeName, testName:
ROPE, decider: ExpandDeciderClosure, sim: Simulation, dual:
BOOL ←
FALSE] =
BEGIN
testeeType: CellType ← GetCellType[typeName];
test: CellTest;
testerName: ROPE = "tester";
testeeName: ROPE = "testee";
singleType, testerType: CellType;
singleTypeName, topTypeName: ROPE;
sd: SingleData;
td: TesterData;
cth: CellTestHandle;
IF testeeType = NIL THEN ERROR Error[msg: "No such type", data: typeName];
test ← GetTest[name: testName, from: testeeType];
sd ←
NEW [SingleDataRep ← [
testeeType: testeeType,
testerTypeName: IO.PutFR["%g-Tester(%g)", IO.rope[typeName], IO.rope[testName]],
testeeTypeName: typeName,
testerName: testerName,
testeeName: testeeName]];
td ←
NEW [TesterDataRep ← [
testeeType: testeeType,
test: test]];
singleTypeName ← IO.PutFR["%g-TesterSingle(%g)", IO.rope[typeName], IO.rope[testName]];
IF (testerType ← GetCellType[sd.testerTypeName]) =
NIL
THEN testerType ← RegisterCellType[
name: sd.testerTypeName,
ioCreator: CreateTesterIO,
initializer: InitTester,
evals: testerEvals,
ports: MakeTesterPorts[testee: testeeType.ports, alwaysOutput: TRUE],
driveCreator: CreateTesterDrive,
typeData: td];
IF (singleType ← GetCellType[singleTypeName]) =
NIL
THEN singleType ← RegisterCellType[
name: singleTypeName,
expandProc: ExpandTestSingle,
evals: [],
ports: NEW [PortsRep[0]],
typeData: sd];
IF dual
THEN {
dualTypeName: ROPE ← Rope.Cat[singleTypeName, "-Dual"];
dualType: CellType ← GetCellType[dualTypeName];
dd: DualData ← NEW [DualDataRep ← [singleTypeName]];
IF dualType =
NIL
THEN dualType ← RegisterCellType[
name: dualTypeName,
expandProc: ExpandDualTester,
evals: [],
ports: NEW [PortsRep[0]],
typeData: dd];
topTypeName ← dualTypeName;
cth ← NEW [CellTestHandleRep.dual ← [sim: sim, test: test, testerType: testerType, testeeType: testeeType, variant: dual[]]];
}
ELSE {
topTypeName ← singleTypeName;
cth ← NEW [CellTestHandleRep.single ← [sim: sim, test: test, testerType: testerType, testeeType: testeeType, variant: single[]]];
};
sim.cth ← cth;
CreateTopCell[instanceName: rootName, typeName: topTypeName, decider: decider, sim: sim];
WITH cth
SELECT
FROM
scth: SingleCTH => {
scth.testee ← LookupCell[path: LIST[testeeName], from: sim.root];
scth.tester ← LookupCell[path: LIST[testerName], from: sim.root];
};
dcth: DualCTH => {
dcth.testee[1] ← LookupCell[path: LIST["1", testeeName], from: sim.root];
dcth.tester[1] ← LookupCell[path: LIST["1", testerName], from: sim.root];
dcth.testee[2] ← LookupCell[path: LIST["2", testeeName], from: sim.root];
dcth.tester[2] ← LookupCell[path: LIST["2", testerName], from: sim.root];
};
ENDCASE => ERROR;
END;
TesterData: TYPE = REF TesterDataRep;
TesterDataRep:
TYPE =
RECORD [
testeeType: CellType,
test: CellTest];
SingleData: TYPE = REF SingleDataRep;
SingleDataRep:
TYPE =
RECORD [
testeeType: CellType,
testerTypeName, testeeTypeName, testerName, testeeName: ROPE];
DualData: TYPE = REF DualDataRep;
DualDataRep:
TYPE =
RECORD [
singleTypeName: ROPE];
ExpandTestSingle:
PROC [thisCell: Cell, to: ExpansionReceiver]
--ExpandProc-- =
BEGIN
sd: SingleData ← NARROW[thisCell.type.typeData];
FOR i:
INT
IN [0 .. sd.testeeType.ports.length)
DO
p: Port ← sd.testeeType.ports[i];
[] ← to.class.NodeInstance[erInstance: to.instance, name: p.name, type: p.type];
ENDLOOP;
[] ← to.class.CellInstance[erInstance: to.instance, instanceName: sd.testeeName, typeName: sd.testeeTypeName, interfaceNodes: ""];
[] ← to.class.CellInstance[erInstance: to.instance, instanceName: sd.testerName, typeName: sd.testerTypeName, interfaceNodes: ""];
END;
ExpandDualTester:
PROC [thisCell: Cell, to: ExpansionReceiver]
--ExpandProc-- =
BEGIN
dd: DualData ← NARROW[thisCell.type.typeData];
[] ← to.class.CellInstance[erInstance: to.instance, instanceName: "1", typeName: dd.singleTypeName, interfaceNodes: ""];
[] ← to.class.CellInstance[erInstance: to.instance, instanceName: "2", typeName: dd.singleTypeName, interfaceNodes: ""];
END;
testerEvals: EvalProcs ← [
PropQ: PropTesterQUD,
PropUD: PropTesterQUD,
ValsChanged: TesterValsChanged,
EvalSimple: TesterSimple];
CellTestHandle: TYPE = REF CellTestHandleRep;
CellTestHandleRep:
PUBLIC
TYPE =
RECORD [
sim: Simulation,
parms: RoseRun.TestParms ← NIL,
switchInstructionsAsAny: REF ANY ← NIL,
switchInstructionsAsWP: WordPtr ← NIL,
simpleInstructionsAsAny: REF ANY ← NIL,
simpleInstructionsAsWP: WordPtr ← NIL,
driveAsAny: REF ANY ← NIL,
driveAsDrive: Drive ← NIL,
test: CellTest,
testerType, testeeType: CellType,
variant:
SELECT kind: *
FROM
single => [tester, testee: Cell ← NIL],
dual => [
tester, testee: ARRAY [1 .. 2] OF Cell ← ALL[NIL],
altSwitchInstructionsAsAny: REF ANY ← NIL,
altSwitchInstructionsAsWP: WordPtr ← NIL,
altSimpleInstructionsAsAny: REF ANY ← NIL,
altSimpleInstructionsAsWP: WordPtr ← NIL
],
ENDCASE
];
SingleCTH: TYPE = REF CellTestHandleRep.single;
DualCTH: TYPE = REF CellTestHandleRep.dual;
Waiting: TYPE = {Tester, Testee};
NarrowToCellTestHandle: PUBLIC PROC [any: REF ANY] RETURNS [cth: CellTestHandle] = {cth ← NARROW[any]};
GetSimulationFromCellTestHandle: PUBLIC PROC [cth: CellTestHandle] RETURNS [sim: Simulation] = {sim ← cth.sim};
TransferCellTestHandle:
PROC [whole:
REF
ANY, part: Cucumber.Path, where:
IO.
STREAM, direction: Cucumber.Direction, data:
REF
ANY]
--Cucumber.PartTransferProc-- =
TRUSTED
BEGIN
cth: CellTestHandle ← NARROW[whole];
SELECT part.first
FROM
$sim, $switchInstructionsAsAny, $simpleInstructionsAsAny, $driveAsDrive, $test, $testerType, $testeeType, $kind => NULL;
$parms => Cucumber.Transfer[what: cth.parms, where: where, direction: direction];
$switchInstructionsAsWP => RoseStateIO.TransferWords[cth.switchInstructionsAsWP, cth.testerType.switchWordCount, where, direction];
$simpleInstructionsAsWP => RoseStateIO.TransferWords[cth.simpleInstructionsAsWP, cth.testerType.simpleWordCount, where, direction];
$driveAsAny => Cucumber.Transfer[what: cth.driveAsAny, where: where, direction: direction];
$variant =>
SELECT part.rest.first
FROM
$tester, $testee, $altSwitchInstructionsAsAny, $altSimpleInstructionsAsAny => NULL;
$altSwitchInstructionsAsWP => RoseStateIO.TransferWords[NARROW[cth, DualCTH].altSwitchInstructionsAsWP, cth.testerType.switchWordCount, where, direction];
$altSimpleInstructionsAsWP => RoseStateIO.TransferWords[NARROW[cth, DualCTH].altSimpleInstructionsAsWP, cth.testerType.simpleWordCount, where, direction];
ENDCASE => ERROR Cucumber.Error[IO.PutFR["I don't know how to save/restore the %g.%g field of a CellTestHandle --- tell Mike Spreitzer to fix me", [refAny[part.first]], [refAny[part.rest.first]] ]];
ENDCASE => ERROR Cucumber.Error[IO.PutFR["I don't know how to save/restore the %g field of a CellTestHandle --- tell Mike Spreitzer to fix me", [refAny[part.first]] ]];
END;
CreateTesterIO:
PROC [ct: CellType, switch:
BOOL]
RETURNS [ioAsAny:
REF
ANY]
--IOCreator-- =
BEGIN
td: TesterData ← NARROW[ct.typeData];
ioAsAny ← td.testeeType.ioCreator[td.testeeType, switch];
END;
CreateTesterDrive:
PROC [ct: CellType]
RETURNS [ioAsAny:
REF
ANY]
--DriveCreator-- =
BEGIN
td: TesterData ← NARROW[ct.typeData];
ioAsAny ← td.testeeType.driveCreator[td.testeeType];
END;
InitTester:
PROC [cell: Cell]
--Initializer-- =
BEGIN
td: TesterData ← NARROW[cell.type.typeData];
cth: CellTestHandle ← cell.sim.cth;
cth.switchInstructionsAsAny ← td.testeeType.ioCreator[td.testeeType, TRUE];
cth.switchInstructionsAsWP ← LOOPHOLE[cth.switchInstructionsAsAny];
cth.simpleInstructionsAsAny ← td.testeeType.ioCreator[td.testeeType, FALSE];
cth.simpleInstructionsAsWP ← LOOPHOLE[cth.simpleInstructionsAsAny];
cth.driveAsAny ← NIL;
cth.driveAsDrive ← NIL;
IF cell.type.driveCreator #
NIL
THEN {
driveAsAny: REF ANY ← td.testeeType.driveCreator[td.testeeType];
IF driveAsAny #
NIL
THEN {
driveAsTV: TV;
gotSize: INT;
neededSize: INT ← SIZE[DriveRep[cell.type.ports.length]];
TRUSTED {driveAsTV ← AMBridge.TVForReferent[driveAsAny]};
gotSize ← AMTypes.TVSize[driveAsTV];
IF gotSize < neededSize THEN ERROR Error[IO.PutFR["DriveCreator for cell type %g returned one too small", IO.rope[cell.type.name]], driveAsAny];
cth.driveAsAny ← driveAsAny;
TRUSTED {cth.driveAsDrive ← LOOPHOLE[driveAsAny]};
FOR pi:
NAT
IN [0 .. cell.type.ports.length)
DO
cth.driveAsDrive[pi] ← IF cell.type.ports[pi].input THEN test ELSE IF cell.type.ports[pi].name.Equal["vdd", FALSE] OR cell.type.ports[pi].name.Equal["gnd", FALSE] THEN input ELSE drive;
ENDLOOP;
};
};
cell.realCellStuff.state ← cth;
END;
PropTesterQUD: CellProc
--PROC [cell: Cell]-- =
BEGIN
cth: CellTestHandle ← NARROW[cell.realCellStuff.state];
CopyIO[from: cth.switchInstructionsAsWP, to: cell.realCellStuff.switchIOAsWP, by: cell.type.ports, what: forward, simple: FALSE, drive: NIL];
END;
DirectionInstruction: TYPE = {none, forward, backward, check, moveByDrive, checkTests, checkIns};
CopyIO:
PROC [from, to: WordPtr, by: Ports, what: DirectionInstruction, simple:
BOOLEAN, drive: Drive, cell: Cell ←
NIL] =
BEGIN OPEN BitTwiddling;
bbTableSpace: PrincOps.BBTableSpace;
bbTable: PrincOps.BitBltTablePtr;
TRUSTED {bbTable ← PrincOpsUtils.AlignedBBTable[@bbTableSpace]};
FOR portIndex:
CARDINAL
IN [0 .. by.length)
DO
port: Port ← by[portIndex];
di: DirectionInstruction;
bitCount, leftPad: INTEGER;
IF port.type.simple # simple THEN LOOP;
[data: bitCount, leftPad: leftPad] ← port.type.procs.Bits[port.type];
{
field: Field ← IF port.type.simple THEN port.simple ELSE port.switch;
fromPtr: Ptr ← OffsetPtr[WPField[from, field], leftPad];
toPtr: Ptr ← OffsetPtr[WPField[to, field], leftPad];
SELECT what
FROM
moveByDrive =>
IF port.type.simple
THEN {
di ←
SELECT drive.drives[portIndex]
FROM
test => none,
see => backward,
ignore => none,
chargeWeak, chargeMediumWeak, charge, chargeMediumStrong, chargeStrong, chargeVeryStrong, driveWeak, driveMediumWeak, drive, driveMediumStrong, driveStrong, driveVeryStrong, input => forward,
ENDCASE => ERROR;
}
ELSE ERROR;
checkTests =>
IF port.type.simple
THEN {
di ←
SELECT drive.drives[portIndex]
FROM
test => check,
see => none,
ignore => none,
chargeWeak, chargeMediumWeak, charge, chargeMediumStrong, chargeStrong, chargeVeryStrong, driveWeak, driveMediumWeak, drive, driveMediumStrong, driveStrong, driveVeryStrong, input => none,
ENDCASE => ERROR;
}
ELSE ERROR;
checkIns =>
IF port.type.simple
THEN {
di ←
SELECT drive.drives[portIndex]
FROM
test => check,
see => check,
ignore => none,
chargeWeak, chargeMediumWeak, charge, chargeMediumStrong, chargeStrong, chargeVeryStrong, driveWeak, driveMediumWeak, drive, driveMediumStrong, driveStrong, driveVeryStrong, input => none,
ENDCASE => ERROR;
}
ELSE ERROR;
none, forward, backward, check => di ← what;
ENDCASE => ERROR;
SELECT di
FROM
none => NULL;
forward => Copy[fromPtr, toPtr, bitCount, bbTable];
backward => Copy[toPtr, fromPtr, bitCount, bbTable];
check => IF NOT Equal[fromPtr, toPtr, bitCount] THEN SIGNAL Warning[IO.PutFR["test failed on %g", IO.rope[RoseCreate.LongPortName[cell, portIndex]]]];
moveByDrive, checkTests => ERROR;
ENDCASE => ERROR;
}
ENDLOOP;
END;
Fmt:
PROC [n: Node, p: Ptr]
RETURNS [rope:
ROPE] = {
fmt: Format ← n.type.procs.GetFormat[n.type, ""];
rope ← fmt.FormatValue[n, fmt, p];
};
TesterValsChanged:
PROC [cell: Cell, perturb:
PROC [portIndex: PortIndex]]
--SimpleEval-- =
BEGIN OPEN BitTwiddling;
cth: CellTestHandle ← NARROW[cell.realCellStuff.state];
swp: WordPtr ←
WITH cth
SELECT
FROM
dcth: DualCTH =>
SELECT cell
FROM
dcth.tester[1] => dcth.switchInstructionsAsWP,
dcth.tester[2] => dcth.altSwitchInstructionsAsWP,
ENDCASE => ERROR,
scth: SingleCTH => scth.switchInstructionsAsWP,
ENDCASE => ERROR;
FOR portIndex:
NAT
IN [0 .. cell.type.ports.length)
DO
port: Port ← cell.type.ports[portIndex];
IF (
NOT port.type.simple)
THEN {
leftPad, bits: INT;
[data: bits, leftPad: leftPad] ← port.type.procs.Bits[port.type];
port.type.procs.CopyVal[
nt: port.type,
from: OffsetPtr[WPField[cell.realCellStuff.switchIOAsWP, port.switch], leftPad],
to: OffsetPtr[WPField[swp, port.switch], leftPad]
];
};
ENDLOOP;
END;
TesterSimple:
PROC [cell: Cell, perturb:
PROC [portIndex: PortIndex]]
--SimpleEval-- =
BEGIN
cth: CellTestHandle ← NARROW[cell.realCellStuff.state];
swp: WordPtr ← cth.simpleInstructionsAsWP;
cellDrive: Drive ← cell.realCellStuff.newDrive;
WITH cth
SELECT
FROM
dcth: DualCTH =>
SELECT cell
FROM
dcth.tester[1] => NULL;
dcth.tester[2] => {
swp ← dcth.altSimpleInstructionsAsWP;
};
ENDCASE => ERROR;
scth: SingleCTH => NULL;
ENDCASE => ERROR;
FOR pi: PortIndex
IN [0 .. cell.type.ports.length)
DO
cellDrive[pi] ← MAX[cth.driveAsDrive[pi], FIRST[Strength]];
ENDLOOP;
CopyIO[from: swp, to: cell.realCellStuff.newIOAsWP, by: cell.type.ports, what: moveByDrive, simple: TRUE, drive: cth.driveAsDrive];
cell ← cell;
END;
Eval:
PUBLIC
PROC [handle: CellTestHandle, returnAfter: ReturnAfter ← returnWhenSettled]
RETURNS [happened: StepType] =
BEGIN
iowp: WordPtr ← NIL;
tester: Cell ← NIL;
WITH handle
SELECT
FROM
dcth: DualCTH => {
ScheduleCell[dcth.tester[1]];
ScheduleCell[dcth.tester[2]];
PerturbDifferences[dcth, dcth.tester[1]];
PerturbDifferences[dcth, dcth.tester[2]];
CopyIO[from: dcth.simpleInstructionsAsWP, to: dcth.altSimpleInstructionsAsWP, by: dcth.testerType.ports, what: forward, simple: TRUE, drive: dcth.driveAsDrive];
CopyIO[from: dcth.switchInstructionsAsWP, to: dcth.altSwitchInstructionsAsWP, by: dcth.testerType.ports, what: forward, simple: FALSE, drive: dcth.driveAsDrive];
};
scth: SingleCTH =>
{
ScheduleCell[scth.tester];
PerturbDifferences[scth, scth.tester];
};
ENDCASE => ERROR;
IF handle.parms.stopBefore THEN SIGNAL Stop["About to eval"];
DO
happened ← StepSim[handle.sim];
IF (IF happened IN MaskableStepType THEN returnAfter[happened] ELSE TRUE) THEN EXIT;
ENDLOOP;
WITH handle
SELECT
FROM
dcth: DualCTH => {
tester ← dcth.tester[1];
CopyIO[from: dcth.simpleInstructionsAsWP, to: dcth.altSimpleInstructionsAsWP, by: dcth.testerType.ports, what: checkIns, simple: TRUE, drive: dcth.driveAsDrive, cell: tester];
CopyIO[from: dcth.switchInstructionsAsWP, to: dcth.altSwitchInstructionsAsWP, by: dcth.testerType.ports, what: check, simple: FALSE, drive: dcth.driveAsDrive, cell: tester];
};
scth: SingleCTH => {
tester ← scth.tester;
};
ENDCASE => ERROR;
iowp ← tester.realCellStuff.newIOAsWP;
CopyIO[from: handle.simpleInstructionsAsWP, to: iowp, by: handle.testerType.ports, what: checkTests, simple: TRUE, drive: handle.driveAsDrive, cell: tester];
IF handle.parms.stopAfter THEN SIGNAL Stop["Just eval'd"];
END;
PerturbDifferences:
PROC [cth: CellTestHandle, cell: Cell] =
BEGIN OPEN BitTwiddling;
FOR portIndex: PortIndex
IN [0 .. cell.type.ports.length)
DO
port: Port ← cell.type.ports[portIndex];
different: BOOL ← FALSE;
leftPad: INT;
IF port.type.simple THEN LOOP;
leftPad ← port.type.procs.Bits[port.type].leftPad;
TRUSTED {different ← port.type.procs.CompareUD[
port.type,
OffsetPtr[WPField[cth.switchInstructionsAsWP, port.switch], leftPad],
OffsetPtr[WPField[cell.realCellStuff.switchIOAsWP, port.switch], leftPad]
]};
IF different THEN PerturbNode[node: cell.interfaceNodes[portIndex], agitator: nilSlot, evenIfInput: TRUE];
ENDLOOP;
END;
Test:
PUBLIC
PROC [sim: Simulation, parms: TestParms, testData:
REF
ANY ←
NIL] =
BEGIN
cth: CellTestHandle ← sim.cth;
test: CellTest ← NARROW[cth.testeeType.testers.Lookup[cth.test.name]];
state: REF ANY ← NIL;
IF test = NIL THEN ERROR Error["Type has no such test proc", cth];
cth.parms ← parms;
IF test.stateToo
THEN state ←
WITH cth
SELECT
FROM
scth: SingleCTH => scth.testee.realCellStuff.state,
dcth: DualCTH =>
IF dcth.testee[1].realCellStuff # NIL THEN dcth.testee[1].realCellStuff.state ELSE
IF dcth.testee[2].realCellStuff # NIL THEN dcth.testee[2].realCellStuff.state ELSE ERROR,
ENDCASE => ERROR;
test.proc[handle: cth, testeeType: cth.testeeType, testData: testData, switchInstructions: cth.switchInstructionsAsAny, simpleInstructions: cth.simpleInstructionsAsAny, driveAsAny: cth.driveAsAny, stateAsAny: state];
WHILE StepSim[sim] # noStep DO NULL ENDLOOP;
END;
cthHandler: Cucumber.Handler ← NEW [Cucumber.HandlerRep ← [TransferCellTestHandle]];
cthHandler.Register[CODE[CellTestHandleRep]];
END.