DIRECTORY AMBridge, AMTypes, Ascii, BitTwiddling, Cucumber, IO, OrderedSymbolTableRef, PrincOps, PrincOpsUtils, Rope, RoseClocks, RoseCreate, RoseRun, RoseStateIO, RoseTypes; RoseTestingImpl: CEDAR PROGRAM IMPORTS AMBridge, AMTypes, Ascii, BitTwiddling, Cucumber, IO, OrderedSymbolTableRef, PrincOpsUtils, 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, $tester, $testee, $testeeInitData, $switchInstructionsAsAny, $simpleInstructionsAsAny, $driveAsDrive => 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]; ENDCASE => ERROR; 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 _ cth.test; 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. Ü[Indigo]r>Rosemary.DF=>RoseTestingImpl.Mesa Last Edited by: Spreitzer, July 2, 1985 9:08:24 pm PDT Last Edited by: Barth, January 25, 1984 3:44 pm Last Edited by: Gasbarro, July 17, 1984 3:52:04 pm PDT Ê – "cedar" style˜JšœÏmœ"™5J™7J™/J™6Icode˜KšÏk œ3žœp˜®K˜šÐbxœžœž˜Kšžœ3žœe˜¡Kšžœ!˜(—K˜Kšžœžœ ˜*K˜šÐblœžœžœ ˜,Kšœžœ˜Kšœžœ˜ —K˜Kšžœžœ žœ˜Kšœžœ˜K˜š Ïnœžœžœžœ)žœžœ˜uKšž˜K˜Kšœ-˜-Kšœ[˜[Kšžœ˜—K˜š¡œžœžœžœ˜PKšž˜Kšœžœ!˜3K˜Kšžœ.žœžœžœ˜@Kšžœ$žœžœžœ+˜_šœ ˜ Kšœ˜K˜K˜ Kšœžœ˜Kšœ žœ$˜1—Kšžœ˜—K˜š œ žœžœžœžœ˜>K˜Kšœžœ˜—K˜š¡ œžœ)Ïcœ˜LKšž˜Kšœžœ˜.šžœ žœžœ˜Kšœ.˜.š¡œžœžœ˜-K˜$šžœžœž˜Kšœ'˜'Kšœ@˜@Kšžœžœ˜—Kšœk˜kK˜—Kšœ*˜*Kšœƒ˜ƒK˜—Kšœ=˜=K˜ŽKšžœ˜—K˜š ¡ œžœžœžœžœ˜0Kšžœžœžœ˜"K˜G—K˜š¡œžœžœ7˜UKšž˜šžœ žœžœž˜9K˜&Kšœ žœ%˜8Kšœ˜Kšœžœžœ˜Kšžœžœžœžœ˜Kšžœžœžœž˜BKšžœžœžœž˜BKš žœ žœžœ žœ ž˜5Kšžœ žœžœ žœ˜6Kš œ|žœžœžœžœžœ žœ˜¼Kšžœ˜—Kšžœ˜—K˜š¡ œžœžœžœžœžœžœžœ˜Kšžœžœžœ˜$KšœG˜GKšœ˜—Kšœžœ˜2Kšœ žœ˜3Kšžœ˜—Kšžœ˜—K˜š ¡ œžœžœ žœ8žœžœ˜‚Kšž˜Kšœ-˜-Kšœ˜Kšœ žœ ˜Kšœ žœ ˜K˜!Kšœžœ˜"Kšœ˜Kšœ˜Kšœ˜Kšžœžœžœžœ,˜JKšœ1˜1šœžœ˜Kšœ˜Kšœžœžœžœ˜PKšœ˜Kšœ˜Kšœ˜—šœžœ˜Kšœ˜Kšœ ˜ —Kšœžœžœžœ˜Wšžœ1ž˜6šžœ˜#Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ?žœ˜EKšœ ˜ Kšœ˜——šžœ.ž˜3šžœ˜#Kšœ˜Kšœ˜Kšœ ˜ Kšœžœ˜Kšœ˜——šžœžœ˜Kšœžœ%˜7Kšœ/˜/Kšœžœ"˜4šžœ žœžœ˜3Kšœ˜Kšœ˜Kšœ ˜ Kšœžœ˜Kšœ˜—Kšœ˜Kšœžœt˜}K˜—šžœ˜Kšœ˜Kšœžœx˜K˜—Kšœ˜KšœY˜Yšžœžœž˜˜Kšœžœ˜AKšœžœ˜AK˜—˜Kšœ"žœ#˜IKšœ"žœ#˜IKšœ"žœ#˜IKšœ"žœ#˜IK˜—Kšžœžœ˜—Kšžœ˜—K˜Kšœ žœžœ˜%šœžœžœ˜K˜Kšœ˜—K˜Kšœ žœžœ˜%šœžœžœ˜K˜Kšœ8žœ˜>—K˜Kšœ žœžœ ˜!šœ žœžœ˜Kšœžœ˜—K˜š¡œžœ)¢œ˜OKšž˜Kšœžœ˜0šžœžœžœ#ž˜2K˜!KšœP˜PKšžœ˜—Kšœ‚˜‚Kšœ‚˜‚Kšžœ˜—K˜š¡œžœ)¢œ˜OKšž˜Kšœžœ˜.Kšœx˜xKšœx˜xKšžœ˜—K˜šœ˜Kšœ˜Kšœ˜K˜K˜—K˜Kšœžœžœ˜-šœžœžœžœ˜)K˜Kšœžœ˜Kšœžœžœžœ˜'Kšœ"žœ˜&Kšœžœžœžœ˜'Kšœ"žœ˜&Kšœ žœžœžœ˜Kšœžœ˜K˜K˜!šœ žœ ž˜Kšœ"žœ˜'šœ ˜ Kš œžœ žœžœžœ˜2Kšœžœžœžœ˜*Kšœ%žœ˜)Kšœžœžœžœ˜*Kšœ%ž˜(Kšœ˜—Kšž˜—Kšœ˜—K˜Kšœ žœžœ˜/Kšœ žœžœ˜+K˜Kšœ žœ˜!K˜Kš¡œžœžœžœžœžœ žœ˜gK˜Kš¡œžœžœžœ%˜oK˜š¡œžœ žœžœžœžœ'žœžœ¢œž˜ªKšž˜Kšœžœ˜$šžœ ž˜Kšœnžœ˜sKšœQ˜QKšœƒ˜ƒKšœƒ˜ƒKšœ[˜[Kšžœžœ˜—Kšžœ˜—K˜š¡œžœžœžœ žœžœ¢ œ˜\Kšž˜Kšœžœ˜%Kšœ9˜9Kšžœ˜—K˜š ¡œžœžœ žœžœ¢œ˜TKšž˜Kšœžœ˜%Kšœ4˜4Kšžœ˜—K˜š¡ œžœ¢œ˜/Kšž˜Kšœžœ˜,Kšœ#˜#KšœEžœ˜KKšœžœ˜CKšœEžœ˜LKšœžœ˜CKšœžœ˜Kšœžœ˜šžœžœžœ˜&Kšœ žœžœ-˜@šžœžœžœ˜Kšœ žœ˜Kšœ žœ˜ Kšœ žœžœ#˜9Kšžœ2˜9Kšœ$˜$Kš žœžœžœžœ?žœ$˜Kšœ˜Kšžœžœ˜2šžœžœžœž˜/Kšœžœžœžœžœ'žœžœ'žœžœžœ˜¹Kšžœ˜—K˜—K˜—Kšœ˜Kšžœ˜—K˜š¡ œ ¢œ˜.Kšž˜Kšœžœ˜7Kšœzžœ žœ˜Kšžœ˜—K˜KšœžœG˜aK˜š¡œžœDžœžœ˜zKšžœžœ˜Kšœ$˜$Kšœ!˜!Kšžœ9˜@šžœ žœžœž˜.Kšœ˜Kšœ˜Kšœžœ˜Kšžœžœžœ˜'K˜EK˜Kšœžœžœ žœ ˜EK˜8K˜4šžœž˜šœžœ˜"šžœ˜šœžœž˜(Kšœ ˜ Kšœ˜Kšœ˜Kšœ¿˜¿Kšžœžœ˜—K˜—Kšžœžœ˜ —šœžœ˜!šžœ˜šœžœž˜(Kšœ˜Kšœ ˜ Kšœ˜Kšœ¼˜¼Kšžœžœ˜—K˜—Kšžœžœ˜ —šœ žœ˜šžœ˜šœžœž˜(Kšœ˜Kšœ ˜ Kšœ˜Kšœ¼˜¼Kšžœžœ˜—K˜—Kšžœžœ˜ —Kšœ,˜,Kšžœžœ˜—šžœž˜Kšœžœ˜ Kšœ3˜3Kšœ4˜4Kš œ žœžœ!žœžœ žœžœ2˜–Kšœžœ˜!Kšžœžœ˜—K˜Kšžœ˜—Kšžœ˜—K˜š¡œžœžœžœ˜4Kšœ1˜1Kšœ"˜"K˜—K˜š¡œžœžœ¢œ˜[Kšžœžœ˜Kšœžœ˜7šœžœžœž˜#šœžœž˜!Kšœ.˜.Kšœ1˜1Kšžœžœ˜—Kšœ/˜/Kšžœžœ˜—šžœ žœžœž˜6K˜(šžœžœžœ˜ Kšœžœ˜KšœA˜Ašœ˜Kšœ˜KšœP˜PKšœ1˜1K˜—K˜—Kšžœ˜—Kšžœ˜—K˜š¡ œžœžœ¢œ˜VKšž˜Kšœžœ˜7Kšœ*˜*Kšœ/˜/šžœžœž˜šœžœž˜!Kšœžœ˜šœ˜Kšœ%˜%K˜—Kšžœžœ˜—Kšœžœ˜Kšžœžœ˜—šžœžœž˜5Kšœžœžœ ˜;Kšžœ˜—Kšœdžœ˜ƒK˜ Kšžœ˜—K˜š¡œžœžœHžœ˜wKšž˜Kšœžœ˜Kšœžœ˜šžœžœž˜˜Kšœ˜Kšœ˜Kšœ)˜)Kšœ)˜)Kšœ€žœ˜ Kšœ€žœ˜¡K˜—šœž˜Kšœ˜Kšœ&˜&Kšœ˜—Kšžœžœ˜—Kšžœžœžœ˜=šž˜K˜Kšžœžœ žœžœžœžœžœžœ˜TKšžœ˜—šžœžœž˜˜Kšœ˜Kšœžœ*˜¯Kšœ~žœ*˜­K˜—šœ˜Kšœ˜Kšœ˜—Kšžœžœ˜—Kšœ&˜&Kšœmžœ,˜Kšžœžœžœ˜:Kšžœ˜—K˜š¡œžœ$˜