DIRECTORY CD, CDEnvironment, CDSequencer, CDSequencerExtras, Core, CoreCDUser, CoreClasses, CoreCreate, CoreFlat, CoreOps, CoreProperties, FileNames, FileViewerOps, FS, IO, Logic, LogicUtils, Ports, RopeList, Rosemary, RosemaryUser, Sisyph, Static, SymTab, TerminalIO; LogicRosemaryImpl: CEDAR PROGRAM IMPORTS CDEnvironment, CDSequencerExtras, CoreCDUser, CoreClasses, CoreCreate, CoreFlat, CoreOps, CoreProperties, FileNames, FileViewerOps, FS, IO, LogicUtils, Ports, RopeList, Rosemary, RosemaryUser, Sisyph, Static, SymTab, TerminalIO EXPORTS Logic = BEGIN OPEN LogicUtils, CoreCreate; oracleBindings: SymTab.Ref _ SymTab.Create[]; -- oracle name -> file name; default is oracle name=file name SetOracleFileName: PUBLIC PROC [id, fileName: ROPE] ~ { [] _ SymTab.Store[oracleBindings, id, fileName]; }; GetOracleFileName: PUBLIC PROC [id: ROPE] RETURNS [fileName: ROPE]~ { ref: REF _ SymTab.Fetch[oracleBindings, id].val; RETURN[IF ref=NIL THEN id ELSE NARROW[ref]]; }; OracleRoseClass: ROPE = RoseClass["Oracle", OracleInit, OracleSimple]; Oracle: PUBLIC PROC [in, out, name: ROPE, log: BOOL _ FALSE] RETURNS [ct: CellType] = { WireFromRope: PROC [descr, name: ROPE, driveLevel: Ports.Drive] RETURNS [wire: Wire] = { s: IO.STREAM = IO.RIS[IO.PutFR["(%s)", IO.rope[descr]]]; ref: REF ANY = IO.GetRefAny[s]; IO.Close[s]; wire _ WireFromRef[ref, driveLevel]; IF name#NIL THEN wire _ CoreOps.SetShortWireName[wire, name]; }; WireFromRef: PROC [ref: REF, driveLevel: Ports.Drive] RETURNS [wire: Wire] = { WireListFromRefList: PROC [lora: LIST OF REF ANY] RETURNS [wl: LIST OF WR] = { wl _ IF lora=NIL THEN NIL ELSE CONS[WireFromRef[lora.first, driveLevel], WireListFromRefList[lora.rest]]; }; WITH ref SELECT FROM refSize: REF INT => { size: INT = refSize^; wire _ CoreCreate.Seq[size: size]; IF size=0 THEN [] _ Ports.InitPort[wire: wire, levelType: l, driveType: aggregate, initDrive: driveLevel] ELSE [] _ Ports.InitPort[wire: wire, levelType: ls, driveType: separate, initDrive: driveLevel]; CoreProperties.PutWireProp[wire, oracleValueProp, oracleValueProp]; --non-NIL }; lora: LIST OF REF ANY => wire _ CoreCreate.WireList[wrs: WireListFromRefList[lora]]; -- no l or ls ENDCASE => ERROR; }; oracleName: ROPE = "Oracle"; inWire, outWire: Wire; IF out=NIL OR in=NIL OR name=NIL THEN Error["Missing parameter on oracle"]; inWire _ WireFromRope[in, "In", none]; -- also sets the ports outWire _ WireFromRope[out, "Out", force]; -- also sets the ports ct _ CoreClasses.CreateUnspecified[name: "Oracle", public: Wires["CK", inWire, outWire]]; CoreProperties.PutCellTypeProp[ct, $oracle, name]; CoreProperties.PutCellTypeProp[ct, $log, NEW[BOOL _ log]]; SimulateGate[ct, OracleRoseClass]; Ports.InitPorts[ct, l, none, "CK"]; }; OracleState: TYPE = REF OracleStateRec; OracleStateRec: TYPE = RECORD [ oracleName: ROPE _ NIL, -- entry in `oracleBindings' table clk, in, out: NAT _ LAST[NAT], inWire, outWire: Wire, stopAfterOneRun: BOOL _ FALSE, maxNbCycle: INT _ 0, log: BOOL, prevClk: Ports.Level _ L, sLog: IO.STREAM _ NIL, cycle: INT _ -1 ]; OracleInit: Rosemary.InitProc = { state: OracleState _ IF oldStateAny=NIL THEN NEW[OracleStateRec] ELSE NARROW[oldStateAny]; clk, in, out: NAT _ LAST[NAT]; id: ROPE _ NARROW[CoreProperties.GetCellTypeProp[cellType, $oracle]]; log: BOOL _ NARROW[CoreProperties.GetCellTypeProp[cellType, $log], REF BOOL]^; path: LIST OF ROPE = LIST [CDEnvironment.GetWorkingDirectory[]]; state.oracleName _ FileNames.FileWithSearchRules[root: GetOracleFileName[id], defaultExtension: ".oracle", requireExtension: FALSE, requireExact: TRUE, searchRules: path].fullPath; [state.clk, state.in, state.out] _ Ports.PortIndexes[cellType.public, "CK", "In", "Out"]; state.inWire _ cellType.public[state.in]; state.outWire _ cellType.public[state.out]; [state.stopAfterOneRun, state.maxNbCycle] _ ParseFileAndDecorateWires[state.oracleName, state.inWire, state.outWire]; state.log _ log; state.prevClk _ L; IF log THEN state.sLog _ FS.StreamOpen[IO.PutFR["///Temp/%g.bugs", IO.rope[id]], $create]; state.cycle _ -1; stateAny _ state; }; OracleSimple: Rosemary.EvalProc = { Mismatch: PROC [shouldBe, is: ROPE, index: CARD] ~ { msg: ROPE = IO.PutFR["At %g expected %g but received %g", IO.int[index], IO.rope[shouldBe], IO.rope[is]]; IF state.log THEN IO.PutF[state.sLog, "%g\n", IO.rope[msg]] ELSE { TerminalIO.PutF["Oracle %g : %g\n", IO.rope[state.oracleName], IO.rope[msg]]; PointAt[state.oracleName, index]; SIGNAL Ports.CheckError[msg]; }; }; Compare: PROC [wire: Wire, cycle: CARD, p: Ports.Port] ~ { LevelToRope: PROC [level: Ports.Level] RETURNS [r: ROPE] ~ { r _ SELECT level FROM L => "L", H => "H", ENDCASE => "X"; }; ref: REF _ CoreProperties.GetWireProp[wire, oracleValueProp]; IF ref=NIL THEN FOR i: NAT IN [0..wire.size) DO Compare[wire[i], cycle, p[i]] ENDLOOP ELSE { value: Value _ NARROW[ref, Values][cycle]; IF wire.size=0 THEN { -- atomic wire check IF value.ls[0]#X AND value.ls[0]#p.l THEN Mismatch[LevelToRope[value.ls[0]], LevelToRope[p.l], value.filePosition]; } ELSE FOR i: NAT IN [0..value.ls.size) DO -- level sequence check IF value.ls[i]=X OR value.ls[i]=p.ls[i] THEN LOOP; Mismatch[Ports.LSToRope[value.ls], Ports.LSToRope[p.ls], value.filePosition]; EXIT; -- to catch error at most once per level sequence ENDLOOP; }; }; SetPort: PROC [wire: Wire, cycle: NAT, p: Ports.Port] ~ { ref: REF _ CoreProperties.GetWireProp[wire, oracleValueProp]; IF ref=NIL THEN FOR i: NAT IN [0..wire.size) DO SetPort[wire[i], cycle, p[i]] ENDLOOP ELSE { value: Value _ NARROW[ref, Values][cycle]; IF wire.size=0 THEN { -- special case for atomic p.l _ value.ls[0]; p.d _ IF p.l=X THEN none ELSE drive; } ELSE { Ports.CopyLS[from: value.ls, to: p.ls]; FOR i: NAT IN [0..p.ls.size) DO p.ds[i] _ IF p.ls[i]=X THEN none ELSE drive; ENDLOOP; }; }; }; state: OracleState _ NARROW[stateAny]; curClk: Ports.Level = p[state.clk].l; IF state.prevClk=L AND curClk=H THEN { -- up-going transition state.cycle _ (state.cycle+1) MOD state.maxNbCycle; }; IF state.cycle=-1 THEN RETURN; FOR i: NAT IN [0..state.outWire.size) DO SetPort[state.outWire[i], state.cycle, p[state.out][i]]; ENDLOOP; IF state.prevClk=H AND curClk=L THEN { -- down-transition: check inputs FOR i: NAT IN [0..state.inWire.size) DO Compare[state.inWire[i], state.cycle, p[state.in][i]]; ENDLOOP; IF state.cycle=state.maxNbCycle-1 THEN SELECT TRUE FROM state.log AND state.stopAfterOneRun => { IO.Close[state.sLog]; Rosemary.Stop[msg: "Oracle completed; look at ///Temp/*.bugs"]; }; state.log AND ~state.stopAfterOneRun => IO.PutF[state.sLog, "Processed the file entirely at cycle %g\n", IO.int[state.cycle]]; ~state.log AND state.stopAfterOneRun => Rosemary.Stop[msg: "Oracle completed successfully", reason: $Oracle]; ENDCASE => NULL; }; IF curClk#X THEN state.prevClk _ curClk; }; PointAt: PROC [oracleName: ROPE, index: CARD] = { FileViewerOps.OpenSource[fileName: oracleName, index: index, chars: 1]; }; Bug: ERROR [msg: ROPE] = CODE; CrashAndPointTo: PROC [oracleName, msg: ROPE, index: CARD] = { PointAt[oracleName, index]; Bug[msg]; }; oracleValueProp: ATOM = $OracleValueProp; -- of type Values Values: TYPE = REF ValuesRec; ValuesRec: TYPE = RECORD[seq: SEQUENCE size: NAT OF Value]; Value: TYPE = REF ValueRec; ValueRec: TYPE = RECORD[ ls: Ports.LevelSequence _ NIL, -- if atomic wire, use ls[0] filePosition: CARD _ 0 ]; ParseFileAndDecorateWires: PROC [oracleName: ROPE, in, out: Wire] RETURNS [stopAfterOneRun: BOOL _ FALSE, numberOfCycles: NAT _ 0] ~ { Absorb: PROC [source: IO.STREAM, c: CHAR, msg: ROPE] ~ { [] _ IO.SkipWhitespace[source]; IF IO.GetChar[source] # c THEN CrashAndPointTo[oracleName, msg, IO.GetIndex[source]-1]; }; CountBars: PROC [source: IO.STREAM] RETURNS [length: NAT _ 0] ~ { [] _ IO.SkipWhitespace[source]; -- important if there is a | in initial comments DO IF IO.GetChar[source ! IO.EndOfStream => GOTO Done] = '| THEN length _ length+1; REPEAT Done => NULL; ENDLOOP; }; GetLevel: PROC [] RETURNS [level: Ports.Level] ~ { SELECT IO.GetChar[source] FROM '0 => level _ L; '1 => level _ H; 'X, 'x => level _ X; ENDCASE => CrashAndPointTo[oracleName, "Not a valid level", IO.GetIndex[source]-1]; }; GetHexDigit: PROC [] RETURNS [h: Ports.LevelSequence] ~ { h _ NEW[Ports.LevelSequenceRec[4]]; SELECT IO.PeekChar[source] FROM '( => { [] _ IO.GetChar[source]; -- absorb the '( h[0] _ GetLevel[]; h[1] _ GetLevel[]; h[2] _ GetLevel[]; h[3] _ GetLevel[]; Absorb[source, '), "Missing )"]; }; ENDCASE => { c: CHAR; SELECT c _ IO.GetChar[source] FROM IN ['0 .. '9] => Ports.LCToLS[ORD[c]-ORD['0], h]; IN ['A .. 'F] => Ports.LCToLS[ORD[c]-ORD['A]+10, h]; IN ['a .. 'f] => Ports.LCToLS[ORD[c]-ORD['a]+10, h]; 'X, 'x => Ports.SetLS[h, X]; ENDCASE => CrashAndPointTo[oracleName, "not a hex digit", IO.GetIndex[source]]; }; }; IsTerminator: PROC [c: CHAR] RETURNS [BOOL] ~ { RETURN [c IN [IO.NUL .. IO.SP] OR c='|]}; GetToken: PROC [nbBits: NAT] RETURNS [ls: Ports.LevelSequence]= { digitIndex: NAT _ 100; -- we can extend on the left with 100 zeros lsSize: NAT _ MAX[nbBits, 1]; -- atomic => 0, but represented as ls ls _ NEW[Ports.LevelSequenceRec[lsSize]]; [] _ IO.SkipWhitespace[source]; IF IsTerminator[IO.PeekChar[source]] THEN CrashAndPointTo[oracleName, "not a value", IO.GetIndex[source]]; WHILE NOT IsTerminator[IO.PeekChar[source]] DO h: Ports.LevelSequence _ GetHexDigit[]; FOR i: NAT IN [0..4) DO bigValue[digitIndex+i] _ h[i]; ENDLOOP; digitIndex _ digitIndex+4; ENDLOOP; FOR i: NAT IN [0..lsSize) DO ls[i] _ bigValue[digitIndex-lsSize+i]; ENDLOOP; Ports.SetLS[bigValue, L]; -- clean-up }; ParseOneLine: PROC [cycle: NAT] ~ { values: Values; val: Value; PutValuesOnLeavesLtoR: PROC [wire: Wire, level: NAT] ~ { ref: REF _ CoreProperties.GetWireProp[wire, oracleValueProp]; IF ref#NIL THEN { values _ NARROW[ref]; val _ NEW[ValueRec _ [ ls: GetToken[nbBits: wire.size], filePosition: IO.GetIndex[source]-1]]; values[cycle] _ val; } ELSE { IF level>0 THEN Absorb[source, '(, "Missing ("]; -- get the "(" FOR i: NAT IN [0..wire.size) DO PutValuesOnLeavesLtoR[wire[i], level+1] ENDLOOP; IF level>0 THEN Absorb[source, '), "Missing )"]; -- get the ")" }; }; PutValuesOnLeavesLtoR[out, 0]; -- read left side (stimuli) Absorb[source, '|, "Missing |"]; PutValuesOnLeavesLtoR[in, 0]; -- read right side (correct answers) }; InitValueSequences: PROC [wire: Wire, nb: NAT] ~ { IF CoreProperties.GetWireProp[wire, oracleValueProp]#NIL THEN CoreProperties.PutWireProp[wire, oracleValueProp, NEW[ValuesRec[nb]]] ELSE FOR i: NAT IN [0..wire.size) DO InitValueSequences[wire[i], nb] ENDLOOP; }; source: IO.STREAM _ FS.StreamOpen[oracleName]; bigValue: Ports.LevelSequence _ NEW[Ports.LevelSequenceRec[300]]; -- for parser numberOfCycles _ CountBars[source]; Ports.SetLS[bigValue, L]; IO.SetIndex[source, 0]; -- return to beginning of test InitValueSequences[in, numberOfCycles]; InitValueSequences[out, numberOfCycles]; FOR cycle: NAT IN [0..numberOfCycles) DO ParseOneLine[cycle] ENDLOOP; [] _ IO.SkipWhitespace[source]; SELECT TRUE FROM IO.EndOf[source] => stopAfterOneRun _ FALSE; IO.PeekChar[source]='. => stopAfterOneRun _ TRUE; ENDCASE => CrashAndPointTo[oracleName, "What is this???", IO.GetIndex[source]]; }; ClockGenRoseClass: ROPE = RoseClass["ClockGen", ClockGenInit, ClockGenSimple]; ClockGen: PUBLIC PROC [up, dn, firstEdge: INT, initLow: BOOL] RETURNS [ct: CellType] ~ { ct _ CoreClasses.CreateUnspecified[name: "ClockGen", public: Wires["Clock", "RosemaryLogicTime"]]; CoreProperties.PutCellTypeProp[ct, $up, NEW[INT _ up]]; CoreProperties.PutCellTypeProp[ct, $dn, NEW[INT _ dn]]; CoreProperties.PutCellTypeProp[ct, $firstEdge, NEW[INT _ firstEdge]]; CoreProperties.PutCellTypeProp[ct, $initLow, NEW[BOOL _ initLow]]; CoreProperties.PutCellTypeProp[ct, $DAUserIgnoreForSelection, $Exists]; SimulateGate[ct, ClockGenRoseClass]; Ports.InitPorts[ct, l, none, "RosemaryLogicTime"]; Ports.InitPorts[ct, l, drive, "Clock"]; }; ClockState: TYPE = REF ClockStateRec; ClockStateRec: TYPE = RECORD [ ck, time: NAT _ LAST[NAT], up, dn, firstEdge: INT, initLow: BOOL, counter: INT _ 0, lastTime: Ports.Level _ X]; ClockGenInit: Rosemary.InitProc = { state: ClockState _ IF oldStateAny=NIL THEN NEW[ClockStateRec] ELSE NARROW[oldStateAny]; infinity: INT _ LAST[INT]/4; -- to avoid overflow [state.ck, state.time] _ Ports.PortIndexes[cellType.public, "Clock", "RosemaryLogicTime"]; state.initLow _ NARROW[CoreProperties.GetCellTypeProp[cellType, $initLow], REF BOOL]^; state.up _ NARROW[CoreProperties.GetCellTypeProp[cellType, $up], REF INT]^; state.dn _ NARROW[CoreProperties.GetCellTypeProp[cellType, $dn], REF INT]^; state.firstEdge _ NARROW[CoreProperties.GetCellTypeProp[cellType, $firstEdge], REF INT]^; state.counter _ 0; IF state.up=-1 THEN state.up _ infinity; IF state.dn=-1 THEN state.dn _ infinity; IF state.firstEdge=-1 THEN state.firstEdge _ infinity; state.lastTime _ X; stateAny _ state; }; ClockGenSimple: Rosemary.EvalProc = { state: ClockState _ NARROW[stateAny]; {OPEN state; t0, normTime: INT; pt: Ports.Level = p[time].l; state: ClockState _ NARROW[stateAny]; IF pt=X THEN {p[ck].l _ X; RETURN}; IF pt#state.lastTime THEN state.counter _ state.counter+1; t0 _ IF state.initLow THEN state.firstEdge+state.up ELSE state.firstEdge; normTime _ (state.counter-t0+state.up+state.dn) MOD (state.up+state.dn); p[ck].l _ SELECT TRUE FROM state.counter IF state.initLow THEN L ELSE H, normTime< state.dn => L, ENDCASE => H; state.lastTime _ p[time].l; }}; StopRoseClass: ROPE = RoseClass["Stop", StopInit, StopSimple]; Stop: PUBLIC PROC [] RETURNS [ct: CellType] ~ { ct _ CoreClasses.CreateUnspecified[name: "Stop", public: Wires["ShouldBeFalse", "RosemaryLogicTime"]]; SimulateGate[ct, StopRoseClass]; Ports.InitPorts[ct, l, none, "ShouldBeFalse", "RosemaryLogicTime"]; }; StopState: TYPE = REF StopStateRec; StopStateRec: TYPE = RECORD [ in, time: NAT _ LAST[NAT], lastTime: Ports.Level _ H]; StopInit: Rosemary.InitProc = { state: StopState _ IF oldStateAny=NIL THEN NEW[StopStateRec] ELSE NARROW[oldStateAny]; [state.in, state.time] _ Ports.PortIndexes[cellType.public, "ShouldBeFalse", "RosemaryLogicTime"]; state.lastTime _ p[state.time].l; stateAny _ state; }; StopSimple: Rosemary.EvalProc = { state: StopState _ NARROW[stateAny]; {OPEN state; IF p[in].l=H AND p[time].l#lastTime THEN Rosemary.Stop[msg: "User-defined assertion is wrong", data: p, reason: $UserDefined]; lastTime _ p[time].l; }}; logicCutSet: PUBLIC ROPE _ "Logic"; -- for standard cells macroCutSet: PUBLIC ROPE _ "LogicMacro"; -- for composite cells (e.g. adder, counter, ...) fast: PUBLIC CoreFlat.CutSet _ CoreFlat.CreateCutSet[labels: LIST ["DPMacro", "FSM", "LogicMacro", "Memory", "Logic"]]; macro: PUBLIC CoreFlat.CutSet _ CoreFlat.CreateCutSet[labels: LIST ["LogicMacro", "Memory", "Logic"]]; gate: PUBLIC CoreFlat.CutSet _ CoreFlat.CreateCutSet[labels: LIST ["Logic"]]; transistors: PUBLIC CoreFlat.CutSet _ NIL; temporaryClockEvalHack: BOOL _ TRUE; GetBool: PROC [ct: CellType, prop: ATOM, default: BOOL] RETURNS [BOOL] ~ { rb: REF BOOL _ NARROW [CoreProperties.GetCellTypeProp[ct, prop]]; RETURN [IF rb=NIL THEN default ELSE rb^]; }; LogicTest: RosemaryUser.TestProc ~ { logicTime: NAT = Ports.PortIndex[cellType.public, "RosemaryLogicTime"]; memory: BOOL = GetBool[cellType, $Memory, FALSE]; p[logicTime].b _ TRUE; p[logicTime].d _ drive; DO ENABLE Rosemary.Stop => IF reason=$BoolWireHasX THEN REJECT ELSE { TerminalIO.PutF["Simulation completed; msg: %g; reason %g\n", IO.rope[msg], IO.atom[reason]]; EXIT}; p[logicTime].b _ NOT p[logicTime].b; IF temporaryClockEvalHack THEN Eval[memory: memory, clockEval: TRUE]; Eval[memory: memory, clockEval: FALSE]; ENDLOOP; }; RunRosemary: PUBLIC PROC [cellType: CellType, design: CD.Design, cutSet: CoreFlat.CutSet _ NIL] RETURNS [tester: RosemaryUser.Tester]= { globalNames: Sisyph.ROPES _ Sisyph.GetGlobalNames[Sisyph.Create[design]]; UnnamedOrGlobal: PROC [wire: Wire] RETURNS [BOOL] ~ { name: ROPE = CoreOps.GetShortWireName[wire]; RETURN [name=NIL OR RopeList.Memb[globalNames, name]]; }; Unconnected: PROC [wire: Wire] RETURNS [BOOL] ~ { RETURN [CoreProperties.GetWireProp[wire, Static.staticCutSetProp]#NIL]; }; NotBus: PROC [wire: Wire] RETURNS [BOOL] ~ { FOR i: NAT IN [0..wire.size) DO -- Skipped if wire is atomic IF wire.elements[i].size#0 THEN RETURN[TRUE]; ENDLOOP; RETURN [FALSE]; }; WorthGraphing: CoreOps.EachWireProc ~ { SELECT TRUE FROM UnnamedOrGlobal[wire] => RETURN [subWires: FALSE]; -- don't even consider sons Unconnected[wire] => RETURN [subWires: FALSE]; -- don't even consider sons NotBus[wire] => RETURN [subWires: TRUE]; -- will have interesting sons ENDCASE => graphWires _ CONS[NEW [CoreFlat.FlatWireRec _ [wire: wire]], graphWires]; }; AtomicsInGraph: PROC [wire: Wire] ~ { graphWires _ CONS[NEW[CoreFlat.FlatWireRec _ [flatCell: CoreFlat.rootCellType, wire: wire]], graphWires]; }; logicVdd, logicGnd: INT; graphWires: CoreFlat.FlatWires _ NIL; internal: Core.WireSeq; IF cellType.class#CoreClasses.recordCellClass THEN Error["I can't simulate this thing"]; internal _ NARROW[cellType.data, CoreClasses.RecordCellType].internal; [] _ CoreOps.VisitWireSeq[internal, WorthGraphing]; logicVdd _ CoreOps.GetWireIndex[cellType.public, "Vdd"]; -- -1 means not found logicGnd _ CoreOps.GetWireIndex[cellType.public, "Gnd"]; IF logicVdd#-1 THEN [] _ Rosemary.SetFixedWire[cellType.public[logicVdd], H]; IF logicGnd#-1 THEN [] _ Rosemary.SetFixedWire[cellType.public[logicGnd], L]; IF cutSet=NIL THEN { -- If cutset not specified, build it from cell type property $Simulation labels: LIST OF ROPE; SELECT CoreProperties.GetCellTypeProp[from: cellType, prop: $Simulation] FROM $Fast => labels _ LIST [macroCutSet, logicCutSet]; -- macros & gates $Transistors => labels _ NIL; -- transistor level ENDCASE => labels _ LIST [logicCutSet]; -- gate level cutSet _ CoreFlat.CreateCutSet[labels: labels]; }; tester _ RosemaryUser.TestProcedureViewer[ cellType: cellType, testButtons: LIST["Logic Test"], name: CoreOps.GetCellTypeName[cellType], displayWires: graphWires, graphWires: graphWires, recordDeltas: GetBool[cellType, $RecordDeltas, TRUE], cutSet: cutSet]; }; ExtractSelectedObjAndRunRosemary: PROC [comm: CDSequencer.Command] = { EachCellType: CoreCDUser.EachRootCellTypeProc ~ { cutSet: CoreFlat.CutSet; IF root=NIL THEN RETURN; cutSet _ NARROW[CoreProperties.GetCellTypeProp[root, $CutSet]]; [] _ RunRosemary[root, comm.design, cutSet]; }; TerminalIO.PutF["*** Warning: this command is going to disappear. Use menu instead. Note that this will require some changes to your cells to put the right properties for Rosemary.\n"]; [] _ CoreCDUser.EnumerateSelectedCellTypes[comm.design, EachCellType, Sisyph.mode]; }; CDSequencerExtras.RegisterCommand[key: $CoreRosemaryExtractSelectedObjAndRunRosemary, proc: ExtractSelectedObjAndRunRosemary, queue: doQueue]; RosemaryUser.RegisterTestProc["Logic Test", LogicTest]; END. κLogicRosemaryImpl.mesa Copyright Σ 1986, 1987 by Xerox Corporation. All rights reserved. Created by: Louis Monier December 30, 1986 7:40:13 pm PST Last Edited by: Louis Monier October 30, 1987 5:54:05 pm PST Last Edited by: Ross May 22, 1987 5:12:47 pm PDT Last Edited by: McCreight June 4, 1987 11:13:00 am PDT Jean-Marc Frailong December 8, 1987 3:38:55 pm PST Bertrand Serlet June 10, 1987 4:47:40 pm PDT Pradeep Sindhu July 20, 1987 4:54:36 pm PDT McCreight March 19, 1987 1:12:54 pm PST Hoel, February 20, 1987 6:11:31 pm PST Barth, June 5, 1987 10:38:02 am PDT This package provides the basic user-interface for interactive simulation using Rosemary, and a set of primitives: clock generator, oracle, rom, ... These primitives must be used for simulation only and do not produce any layout. Oracle Called from the interpreter by a user to bind a new file to an oracle Called from the interpreter by a user to find out which file is bound to an oracle -- syntax accepted: in _ " 0 2 32 (0 2) 1 (2 4 (3 3))" -- 0 means atomic wire -- 8 means a byte, ... -- (w1 w2 w3) means a composite wire made of ... -- I tag the wires which will receive sequences of values -- Wrong value during the simulation -- bit-wise comparison; if L or H, check; if X, ignore -- if L or H, drive; if X, tristate (drive_none) -- put values on "out" ports for current cycle -- compare values on "in" ports for cycle n used during simulation -- Parses the file and decorates every sub-wire of "In" and "Out" with the values -- Values are coded in hex, but digits are extended to accomodate X -- Hex digits are 0, 1, 2, ..., 9, A, B, C, D, E , F, X, or (b b b b) with b=0, 1, or X -- Examples of values: 37, FFEA7B, 7AXX2, 2BAD, XXXX -- If not enough digits are specified, the value is right-justified and the msb are zero-extended -- Atomic wires are restricted to 0, 1, X -- Parser always absorbs any white space before the token -- skip white space, then get a char and check it -- a hack to get the number of vectors -- parsed value is now left-justified in bigValue -- We know at this point how many tokens to find on a line -- Get the file and find the number of vectors -- Initialize values on In and Out wires -- Parse the file Clock Generator Assertion Checking Utilities -- These cutsets are used by Rosemary -- These are the user-interface version for use as CutSet property Read a boolean property from a CT with the specified default -- This is the engine that exercices oracle simulations -- Wires have no memory unless the $Memory property is set to $Yes (the only recognized value). -- a wire is innocent until proven guilty -- Let's make sure we have something to simulate -- Find out which wires to display: top-level only -- Prepare the cell for simulation -- Entry goes in Sisyph Menu ΚΟ– "cedar" style˜codešœ™KšœB™BKšœ6Οk™9Kšœ<™Kšœ˜Kšœ ˜ K˜—K˜KšœœŸ˜;Kšœœœ ˜š œ œœœœœ˜;Kšœ™—Kšœœœ ˜šœ œœ˜KšœœŸ˜;Kšœœ˜Kšœ˜—K˜KšŸQ™QKšŸC™CKšŸW™WKšŸ4™4KšŸa™aKšŸ)™)KšŸ9™9š œœœœœœœ ˜†K™2š  œœ œœœœ˜8Kšœœ˜šœœœ˜Kšœ!œ˜8—K˜—KšŸ&™&š   œœ œœœ œ ˜AKšœœŸ0˜Pš œœœœœ œ˜SKšœ œ˜Kšœ˜—Kšœ˜—š œœœ˜2šœœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ5œ˜S—K˜—š  œœœ˜9Kšœœ˜#šœœ˜šœ˜KšœœŸ˜+Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ ˜ Kšœ˜—šœ˜ Kšœœ˜šœœ˜"Kšœœœ ˜2Kšœœœ ˜5Kšœœœ ˜5Kšœ˜Kšœ3œ˜O—Kšœ˜——K˜—š   œœœœœ˜/Kšœœœœœœœ˜)—š œœ œœ˜AKšœ œŸ+˜BKšœœœ Ÿ%˜CKšœœ!˜)Kšœœ˜Kšœœœ,œ˜jšœœœ˜.Kšœ'˜'šœœœ˜Kšœ˜Kšœ˜—Kšœ˜Kšœ˜—KšŸ1™1šœœœ ˜Kšœ&˜&Kšœ˜—KšœŸ ˜%Kšœ˜—KšŸ:™:š  œœ œ˜#Kšœ˜Kšœ ˜ š œœœ˜8Kšœœ5˜=šœœœ˜Kšœ œ˜šœœ ˜Kšœ!˜!Kšœœ˜&—Kšœ˜Kšœ˜—šœ˜Kšœ œ"Ÿ˜?Kš œœœœ)œ˜PKšœ œ"Ÿ˜?Kšœ˜—K˜—KšœŸ˜:Kšœ ˜ KšœŸ$˜BK˜—š œœœ˜2šœ3œœ˜>Kšœ2œ˜E—Kš œœœœœ!œ˜MK˜—KšŸ.™.Kšœœœœ˜.Kšœ œŸ ˜OKšœ#˜#Kšœ˜KšœŸ˜6KšŸ(™(Kšœ'˜'Kšœ(˜(KšŸ™Kš œœœœœ˜EKšœœ˜šœœ˜Kšœ$œ˜,Kšœ*œ˜1Kšœ3œ˜O—K˜——™Kš œœ7˜Nš  œœœœ œœ˜Xšœ4˜4Kšœ-˜-—Kšœ(œœ˜7Kšœ(œœ˜7Kšœ/œœ˜EKšœ-œœ ˜BKšœG˜GKšœ$˜$KšœZ˜ZK˜K˜—Kšœ œœ˜%šœœœ˜Kšœ œœœ˜Kšœœ˜Kšœ œ˜Kšœ œ˜Kšœ˜—š  œ˜#Kš œœ œœœœœ˜XKšœ œœœŸ˜1KšœZ˜ZKšœœ5œœ˜VKšœ œ0œœ˜KKšœ œ0œœ˜KKšœœ7œœ˜YKšœ˜Kšœ œ˜(Kšœ œ˜(Kšœœ˜6Kšœ˜Kšœ˜Kšœ˜K˜—š œ˜%Kšœœ ˜%Kšœœ˜ Kšœœ˜Kšœ˜Kšœœ ˜%Kšœœœ˜#Kšœœ!˜:Kšœœœœ˜IKšœ0œ˜Hšœ œœ˜Kšœ!œœœ˜@Kšœ˜Kšœ˜ —Kšœ˜Kšœ˜——™Kš  œœ+˜>š œœœœ˜/šœ0˜0Kšœ5˜5—Kšœ ˜ KšœC˜CK˜—Kšœ œœ˜#šœœœ˜Kšœ œœœ˜Kšœ˜—š œ˜Kš œœ œœœœœ˜VKšœb˜bKšœ!˜!Kšœ˜Kšœ˜K˜—š  œ˜!Kšœœ ˜$Kšœœ˜ Kšœ œœV˜~Kšœ˜Kšœ˜——™ JšŸ%™%Jšœ œœŸ˜<šœ œœŸ1˜[J˜—J™BJšœœ1œ6˜wJšœœ1œ$˜fJšœœ1œ ˜MJšœ œœ˜*K˜šœœœ˜$K˜—š  œœœ œœœ˜JKšœœ™œ œ˜]Kšœ˜—Jšœœ˜$Kšœœ!œ˜EJšœ œ˜'Kšœ˜—K˜K˜—š   œœœœ#œœ!˜ˆKšœœ0˜IKšŸ)™)š œœœœ˜5Kšœœ"˜,Kšœœœ#˜6K˜—š  œœœœ˜1Kšœ<œ˜GK˜—š œœœœ˜,š œœœœŸ˜