[Indigo]<Rosemary>2.6>Rosemary.DF=>RoseTesting.Mesa
Last Edited by: Spreitzer, October 9, 1984 10:41:22 pm PDT
Last Edited by: Barth, January 25, 1984 3:44 pm
Last Edited by: Gasbarro, July 17, 1984 3:52:04 pm PDT
DIRECTORY AMBridge, AMTypes, Ascii, Asserting, Cucumber, IO, OrderedSymbolTableRef, Rope, RoseClocks, RoseCreate, RoseIOHacks, RoseRun, RoseStateIO, RoseTypes;
RoseTesting: CEDAR PROGRAM
IMPORTS AMBridge, AMTypes, Ascii, Asserting, Cucumber, IO, OrderedSymbolTableRef, Rope, RoseClocks, RoseCreate, RoseRun, RoseStateIO, RoseTypes
EXPORTS RoseCreate, RoseIOHacks, RoseRun, RoseTypes =
BEGIN OPEN RoseTypes, RoseIOHacks, RoseRun, RoseCreate;
InterfaceMismatch: PUBLIC ERROR [cell: Cell,
index: CARDINAL,
expected, got: NodeType] = CODE;
TV: TYPE = AMTypes.TV;
Type: TYPE = AMTypes.Type;
MirrorPorts: PUBLIC PROC [fwd: Ports, alwaysOutput, alwaysInput: BOOLFALSE] RETURNS [bkwd: Ports] =
BEGIN
bkwd ← NEW [PortsRep[fwd.length]];
FOR i: CARDINAL IN [0 .. fwd.length) DO
bkwd[i] ← fwd[i];
bkwd[i].input ← alwaysInput OR fwd[i].output;
bkwd[i].output ← alwaysOutput OR fwd[i].input;
ENDLOOP;
END;
MakeMoreIO: PUBLIC PROC [cell: Cell, bToo: BOOL] RETURNS [a, b: REF ANY] = TRUSTED
BEGIN
org, aTV, bTV: AMTypes.TypedVariable;
type: AMTypes.Type;
IF cell.realCellStuff.newIO = NIL THEN RETURN [NIL, NIL];
org ← AMBridge.TVForReferent[cell.realCellStuff.newIO];
type ← AMTypes.TVType[org];
aTV ← AMTypes.New[type];
AMTypes.Assign[aTV, org];
aTV ← AMTypes.Copy[org];
a ← AMBridge.RefFromTV[aTV];
IF bToo THEN
{
bTV ← AMTypes.New[type];
AMTypes.Assign[bTV, org];
bTV ← AMTypes.Copy[org];
b ← AMBridge.RefFromTV[bTV];
};
END;
WrapTop: PUBLIC PROC [rootName, typeName: ROPE, decider: ExpandDeciderClosure, clocks: ROPENIL, sim: Simulation] RETURNS [root: Cell] =
BEGIN
rootType: CellType;
rootType ← GetWrappingType[typeName, clocks];
root ← 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];
EnsureEnvironment[in: thisCell, forType: wc.subType, to: to];
[] ← to.class.CellInstance[erInstance: to.instance, instanceName: LowerFirst[wc.subType.name], typeName: wc.subType.name, interfaceNodes: ""];
IF wc.clocks # NIL THEN [] ← to.class.CellInstance[erInstance: to.instance, instanceName: "clockGen", typeName: RoseClocks.ClockGen[[]].name, interfaceNodes: wc.clocks];
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]];
id: REF ANYNIL;
IF node # NIL THEN LOOP;
IF port.name.Equal["gnd", FALSE] THEN id ← $ZeroPower ELSE
IF port.name.Equal["vdd", FALSE] THEN id ← $PlusPower ELSE
IF port.input AND NOT port.output THEN id ← $Input ELSE
IF port.output AND NOT port.input THEN id ← $Output;
[] ← to.class.NodeInstance[erInstance: to.instance, name: port.name, type: port.type, initData: id];
ENDLOOP;
END;
CreateTest: PUBLIC PROC [rootName, testerName, testeeName, typeName: ROPE, stateToo: BOOLTRUE, decider: ExpandDeciderClosure, sim: Simulation] RETURNS [root: Cell, cth: CellTestHandle] =
BEGIN
rootType, testerType: CellType;
rootTypeName: ROPE;
rd: RootData ← NEW [RootDataRep ← [
testeeType: GetCellType[typeName],
testerTypeName: IO.PutFR["%g-Tester[%g]", IO.rope[typeName], IO.bool[stateToo]],
testeeTypeName: typeName,
testerName: testerName,
testeeName: testeeName]];
td: TesterData ← NEW [TesterDataRep ← [
testeeType: GetCellType[typeName],
stateToo: stateToo]];
IF rd.testeeType = NIL THEN ERROR Error[msg: "No such type", data: typeName];
rootTypeName ← IO.PutFR["%g-%g-%g-TesterRoot[%g]", IO.rope[testerName], IO.rope[testeeName], IO.rope[typeName], IO.bool[stateToo]];
IF (testerType ← GetCellType[rd.testerTypeName]) = NIL
THEN testerType ← RegisterCellType[
name: rd.testerTypeName,
ioCreator: CreateTesterIO,
initializer: InitTester,
evals: testerEvals,
ports: RoseCreate.MirrorPorts[fwd: rd.testeeType.ports, alwaysOutput: TRUE],
drivePrototype: rd.testeeType.drivePrototype,
typeData: td];
IF (rootType ← GetCellType[rootTypeName]) = NIL
THEN rootType ← RegisterCellType[
name: rootTypeName,
expandProc: ExpandTestRoot,
evals: [],
ports: NEW [PortsRep[0]],
typeData: rd];
cth ← NEW [CellTestHandleRep ← [sim: sim, stateToo: stateToo]];
sim.other ← Asserting.AssertFn1[fn: cthKey, val: cth, inAdditionTo: sim.other];
root ← CreateTopCell[instanceName: rootName, typeName: rootType.name, decider: decider, sim: sim];
cth.testee ← LookupCell[path: LIST[testeeName], from: root];
cth.tester ← LookupCell[path: LIST[testerName], from: root];
END;
cthKey: ATOM ← $cthKey;
TesterData: TYPE = REF TesterDataRep;
TesterDataRep: TYPE = RECORD [
testeeType: CellType,
stateToo: BOOL];
RootData: TYPE = REF RootDataRep;
RootDataRep: TYPE = RECORD [
testeeType: CellType,
testerTypeName, testeeTypeName, testerName, testeeName: ROPE];
ExpandTestRoot: PROC [thisCell: Cell, to: ExpansionReceiver] --ExpandProc-- =
BEGIN
rd: RootData ← NARROW[thisCell.type.typeData];
FOR i: INT IN [0 .. rd.testeeType.ports.length) DO
p: Port ← rd.testeeType.ports[i];
[] ← to.class.NodeInstance[erInstance: to.instance, name: p.name, type: p.type];
ENDLOOP;
[] ← to.class.CellInstance[erInstance: to.instance, instanceName: rd.testeeName, typeName: rd.testeeTypeName, interfaceNodes: ""];
[] ← to.class.CellInstance[erInstance: to.instance, instanceName: rd.testerName, typeName: rd.testerTypeName, interfaceNodes: ""];
END;
testerEvals: EvalProcs ← [
PropQ: PropTesterQUD,
PropUD: PropTesterQUD,
ValsChanged: TesterValsChanged,
EvalSimple: TesterSimple];
CellTestHandle: TYPE = REF CellTestHandleRep;
CellTestHandleRep: PUBLIC TYPE = RECORD [
sim: Simulation,
tester, testee: Cell ← NIL,
parms: RoseRun.TestParms ← NIL,
instructionsAsAny: REF ANYNIL,
instructionsAsWP: LONG POINTER TO CARDINALNIL,
driveAsAny: REF ANYNIL,
driveAsPtr: Drive ← NIL,
first: BOOLEANFALSE,
stateToo: BOOLEANTRUE
];
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, $tester, $testee, $testeeInitData, $instructionsAsAny, $driveAsPtr => NULL;
$parms => Cucumber.Transfer[what: cth.parms, where: where, direction: direction];
$instructionsAsWP => RoseStateIO.TransferWords[cth.instructionsAsWP, cth.tester.type.ioWordCount, where, direction];
$driveAsAny => Cucumber.Transfer[what: cth.driveAsAny, where: where, direction: direction];
ENDCASE => ERROR;
END;
CreateTesterIO: PROC [cell: Cell] --IOCreator-- =
BEGIN
td: TesterData ← NARROW[cell.type.typeData];
[cell.realCellStuff.newIO, cell.realCellStuff.oldIO] ← MakeMirrorIO[td.testee];
td.testeeType.ioCreator[cell];
END;
InitTester: PROC [cell: Cell, leafily: BOOLEAN] --Initializer-- =
BEGIN
IF leafily THEN
BEGIN
cth: CellTestHandle ← NARROW[Asserting.FnVal[fn: cthKey, from: cell.sim.other]];
cth.instructionsAsAny ← MakeMoreIO[cell: cell, bToo: FALSE].a;
cth.instructionsAsWP ← LOOPHOLE[cth.instructionsAsAny];
IF cell.type.drivePrototype # NIL THEN {
driveAsTV, driveProtoAsTV: TV;
TRUSTED {driveProtoAsTV ← AMBridge.TVForReferent[cell.type.drivePrototype]};
driveAsTV ← AMTypes.Copy[driveProtoAsTV];
TRUSTED {
cth.driveAsAny ← AMBridge.RefFromTV[driveAsTV];
cth.driveAsPtr ← LOOPHOLE[cth.driveAsAny];
cth.driveAsPtr ← LOOPHOLE[AMBridge.PointerFromTV[driveAsTV]];
};
}
ELSE {
cth.driveAsAny ← NIL;
cth.driveAsPtr ← NIL};
cell.realCellStuff.state ← cth;
END;
END;
PropTesterQUD: CellProc--PROC [cell: Cell]-- =
BEGIN
cth: CellTestHandle ← NARROW[cell.realCellStuff.state];
CopyIO[from: cth.instructionsAsWP, to: cell.realCellStuff.switchIOAsWP, by: cell.type.ports, what: forward, specials: FALSE, generals: TRUE, simples: FALSE, drive: NIL];
END;
CopyIO: PUBLIC PROC [from, to: WordPtr, by: Ports, what: DirectionInstruction, specials, generals, simples: BOOLEAN, drive: Drive] =
BEGIN
FOR portIndex: CARDINAL IN [0 .. by.length) DO
port: Port ← by[portIndex];
afterLast: CARDINAL;
di: DirectionInstruction;
IF NOT (IF port.type.simple THEN simples ELSE IF port.special THEN specials ELSE generals) THEN LOOP;
SELECT what FROM
firstFoo, restFoo => IF port.type.simple
THEN {
driven: BOOLEAN;
TRUSTED {driven ← drive[portIndex].bool};
di ← IF NOT driven THEN backward ELSE
IF what = firstFoo THEN forward ELSE
IF what = restFoo THEN check ELSE
ERROR;
}
ELSE IF port.special THEN {
di ← udFwdLBack;
}
ELSE ERROR;
none, forward, backward, check, udFwdLBack => di ← what;
ENDCASE => ERROR;
afterLast ← port.firstWord + port.wordCount;
SELECT di FROM
none => NULL;
forward => FOR c: CARDINAL IN [port.firstWord .. afterLast) DO
TRUSTED {(to + c)^ ← (from + c)^};
ENDLOOP;
backward => FOR c: CARDINAL IN [port.firstWord .. afterLast) DO
TRUSTED {(from + c)^ ← (to + c)^};
ENDLOOP;
udFwdLBack => TRUSTED {
port.type.procs.CopyUD[nt: port.type, from: from+port.firstWord, to: to+port.firstWord];
port.type.procs.CopyVal[nt: port.type, from: to+port.firstWord, to: from+port.firstWord];
};
check => FOR c: CARDINAL IN [port.firstWord .. afterLast) DO
TRUSTED {IF (from + c)^ # (to + c)^ THEN SIGNAL Warning["drive contradicted"]};
ENDLOOP;
ENDCASE => ERROR;
ENDLOOP;
END;
TesterValsChanged: PROC [cell: Cell] --CellProc-- =
BEGIN
cth: CellTestHandle ← NARROW[cell.realCellStuff.state];
FOR portIndex: NAT IN [0 .. cell.type.ports.length) DO
port: Port ← cell.type.ports[portIndex];
IF (NOT port.type.simple) AND (NOT port.special) THEN TRUSTED { port.type.procs.ValFromNode[cell.interfaceNodes[portIndex], cth.instructionsAsWP + port.firstWord]};
ENDLOOP;
END;
TesterSimple: PROC [cell: Cell] --CellProc-- =
BEGIN
cth: CellTestHandle ← NARROW[cell.realCellStuff.state];
bw: DirectionInstruction ← restFoo;
IF cth.first THEN {bw ← firstFoo; cth.first ← FALSE};
CopyIO[from: cth.instructionsAsWP, to: cell.realCellStuff.newIOAsWP, by: cell.type.ports, what: bw, specials: TRUE, generals: FALSE, simples: TRUE, drive: cth.driveAsPtr];
END;
Eval: PUBLIC PROC [handle: CellTestHandle, returnAfter: ReturnAfter ← returnWhenSettled] RETURNS [happened: StepType] =
BEGIN
ScheduleCell[handle.tester];
PerturbDifferences[handle];
handle.first ← TRUE;
IF handle.parms.stopBefore THEN SIGNAL Stop["About to eval", handle.testee];
DO
happened ← StepSim[handle.sim];
IF (IF happened IN MaskableStepType THEN returnAfter[happened] ELSE TRUE) THEN EXIT;
ENDLOOP;
IF handle.parms.stopAfter THEN SIGNAL Stop["Just eval'd", handle.testee];
END;
PerturbDifferences: PROC [cth: CellTestHandle] =
BEGIN
FOR portIndex: CARDINAL IN [0 .. cth.tester.type.ports.length) DO
port: Port ← cth.tester.type.ports[portIndex];
different: BOOLEANFALSE;
IF port.type.simple OR port.special THEN LOOP;
TRUSTED {different ← port.type.procs.CompareUD[nt: port.type, wp1: cth.instructionsAsWP + port.firstWord, wp2: cth.tester.realCellStuff.switchIOAsWP + port.firstWord]};
IF different THEN PerturbPort[cell: cth.tester, index: portIndex, evenIfInput: TRUE];
ENDLOOP;
END;
Test: PUBLIC PROC [sim: Simulation, cth: CellTestHandle, parms: TestParms, testData: REF ANYNIL] =
BEGIN
test: CellTestProc ← IF cth.stateToo THEN cth.testee.type.stateToo ELSE cth.testee.type.blackBox;
IF test = NIL THEN ERROR Error["Type has no such test proc", cth];
cth.parms ← parms;
test[handle: cth, testeeType: cth.testee.type, testData: testData, io: cth.instructionsAsAny, driveAsAny: cth.driveAsAny, stateAsAny: IF cth.stateToo THEN cth.testee.realCellStuff.state ELSE NIL];
WHILE StepSim[sim] # noStep DO NULL ENDLOOP;
END;
cthHandler: Cucumber.Handler ← NEW [Cucumber.HandlerRep ← [TransferCellTestHandle]];
cthHandler.Register[CODE[CellTestHandleRep]];
END.