DIRECTORY BitOps, Core, CoreFlat, Ports, PW, Rope, Rosemary, RosemaryUser, Sisyph, TerminalIO; RosemaryExample: CEDAR PROGRAM IMPORTS CoreFlat, Ports, PW, Rosemary, RosemaryUser, Sisyph, TerminalIO = BEGIN myDesignName: Rope.ROPE = "MyDesign"; -- the name of the ChipNDale file MyCell resides in myCx: Sisyph.Context _ Sisyph.Create[PW.OpenDesign[myDesignName]]; -- the Sisyph context derived from this design; needed for extraction Error: PROC [msg: Rope.ROPE] ~ {TerminalIO.PutRopes[msg, "\n"]; ERROR}; MyCellName: Rope.ROPE = Rosemary.Register[roseClassName: "MyCell", init: MyCellInit, evalSimple: MyCellSimple]; MyCell: PROC RETURNS [ct: Core.CellType] = { ct _ Sisyph.ES[name: "MyCell", cx: myCx]; [] _ Rosemary.BindCellType[cellType: ct, roseClassName: MyCellName]; Ports.InitPorts[ct, l, none, "Vdd", "Gnd", "Clock"]; -- level (H, L, X), and inputs only Ports.InitPorts[ct, ls, none, "In"]; -- level sequence, and input only Ports.InitPorts[ct, ls, drive, "Out"]; -- level sequence, and output only }; MyCellState: TYPE = REF MyCellStateRec; MyCellStateRec: TYPE = RECORD [ in, out, vdd, gnd, ck: NAT _ LAST[NAT], previousClock: Ports.Level _ L, master, slave: Ports.LevelSequence ]; MyCellInit: Rosemary.InitProc = { -- PROC [cellType: Core.CellType, p: Ports.Port, oldStateAny: REF ANY _ NIL, steady: BOOL _ FALSE] RETURNS [stateAny: REF ANY _ NIL]n: NAT _ NARROW[CoreProperties.GetCellTypeProp[cellType, $n], REF NAT]^ state: MyCellState _ IF oldStateAny#NIL THEN NARROW[oldStateAny] ELSE NEW[MyCellStateRec]; [state.in, state.out, state.vdd, state.gnd, state.ck] _ Ports.PortIndexes[cellType.public, "In", "Out", "Vdd", "Gnd", "Clock"]; state.master _ NEW[Ports.LevelSequenceRec[4]]; state.slave _ NEW[Ports.LevelSequenceRec[4]]; Ports.SetLS[state.master, X]; Ports.SetLS[state.slave, X]; -- initialize the state stateAny _ state; -- you have to return the state as a REF ANY, so don't forget this }; MyCellSimple: Rosemary.EvalProc = { -- PROC [p: Ports.Port, stateAny: REF ANY] state: MyCellState _ NARROW[stateAny]; IF p[state.vdd].l#H OR p[state.gnd].l#L THEN Error["Turn on the power supply, please"]; SELECT p[state.ck].l FROM L => Ports.CopyLS[from: p[state.in].ls, to: state.master]; H => IF state.previousClock=L THEN Ports.CopyLS[from: state.master, to: state.slave]; -- up transition ENDCASE => NULL; Ports.CopyLS[from: state.slave, to: p[state.out].ls]; -- always state.previousClock _ p[state.ck].l; }; MyCellTest: RosemaryUser.TestProc = { -- PROC [cellType: Core.CellType, p: Ports.Port, Eval: PROC] in, out, vdd, gnd, ck: NAT _ LAST[NAT]; [in, out, vdd, gnd, ck] _ Ports.PortIndexes[cellType.public, "In", "Out", "Vdd", "Gnd", "Clock"]; [] _ Rosemary.SetFixedWire[cellType.public[vdd], H]; [] _ Rosemary.SetFixedWire[cellType.public[gnd], L]; [] _ Ports.InitPort[cellType.public[ck], l]; [] _ Ports.InitTesterDrive[cellType.public[ck], force]; [] _ Ports.InitPort[cellType.public[in], ls]; [] _ Ports.InitTesterDrive[cellType.public[in], force]; [] _ Ports.InitPort[cellType.public[out], ls]; [] _ Ports.InitTesterDrive[cellType.public[out], none]; Ports.LCToLS[0FH, p[in].ls]; -- initial value, in hex notation p[ck].l _ L; p[out].d _ none; Eval[]; p[ck].l _ H; Eval[]; p[ck].l _ L; p[out].d _ none; Eval[]; p[ck].l _ H; Ports.LCToLS[0FH, p[out].ls]; -- the expected value p[out].d _ expect; Eval[]; }; CreateSimulation: PROC [ct: Core.CellType, cutSets: LIST OF Rope.ROPE _ NIL] = { tester: RosemaryUser.Tester _ RosemaryUser.TestProcedureViewer[ cellType: ct, testButtons: LIST["OnOfTheManyPossibleTests"], name: "MyCellTest", displayWires: RosemaryUser.DisplayPortLeafWires[ct], cutSet: CoreFlat.CreateCutSet[cellTypes: cutSets] ]; Rosemary.Initialize[simulation: tester.display.simulation, steady: FALSE] }; RosemaryUser.RegisterTestProc["MyCellTest", MyCellTest]; -- associates a test proc with a button [] _ CreateSimulation[ct: MyCell[], cutSets: LIST[MyCellName]]; END. MyCellName: Rope.ROPE = Rosemary.Register[roseClassName: "MyCell", init: MyCellInit, evalSimple: MyCellSimple]; MyCell: PROC RETURNS [ct: Core.CellType] = { ct _ either extract the cell or calls a proc; [] _ Rosemary.BindCellType[cellType: ct, roseClassName: MyCellName]; Ports.InitPorts[ct, l, ls, b, c, lc, none, drive, "Vdd", "Gnd", "Clock"]; }; MyCellState: TYPE = REF MyCellStateRec; MyCellStateRec: TYPE = RECORD [ in, out, vdd, gnd, ck: NAT _ LAST[NAT], any other state: any type, including Ports.Level and Ports.LevelSequence ]; MyCellInit: Rosemary.InitProc = { state: MyCellState _ IF oldStateAny#NIL THEN NARROW[oldStateAny] ELSE NEW[MyCellStateRec]; [state.in, state.out] _ Ports.PortIndexes[cellType.public, "In", "Out"]; stateAny _ state; -- you have to return the state as a REF ANY, so don't forget this }; MyCellSimple: Rosemary.EvalProc = { state: MyCellState _ NARROW[stateAny]; body of the proc }; MyCellTest: RosemaryUser.TestProc = { -- PROC [cellType: Core.CellType, p: Ports.Port, Eval: PROC] in, out: NAT _ Ports.PortIndex[cellType.public, "In", "Out"]; [] _ Rosemary.SetFixedWire[cellType.public[vdd], H]; [] _ Rosemary.SetFixedWire[cellType.public[gnd], L]; [] _ Ports.InitPort[cellType.public[ck], l, ls, b, c, lc]; [] _ Ports.InitTesterDrive[cellType.public[ck], none, force, expect]; set values and drives on ports Eval[]; set values and drives on ports Eval[]; }; CreateSimulation: PROC [ct: CellType, cutSets: LIST OF Rope.ROPE _ NIL] = { tester _ RosemaryUser.TestProcedureViewer[ cellType: ct, testButtons: LIST["OnOfTheManyPossibleTests"], name: "MyCellTest", displayWires: RosemaryUser.DisplayPortLeafWires[ct], cutSet: CoreFlat.CreateCutSet[cellTypes: cutSets] ]; Rosemary.Initialize[simulation: tester.display.simulation, steady: FALSE] }; RosemaryUser.RegisterTestProc["MyCellTest", MyCellTest]; [] _ CreateSimulation[ct: MyCell[], cutSets: LIST[MyCellName]]; ²RosemaryExample.tioga Copyright c 1987 by Xerox Corporation. All rights reserved. Last Edited by: Louis Monier January 5, 1987 8:15:51 pm PST Barth, January 30, 1987 2:50:55 pm PST -- This is an example of simulation using Rosemary; three parts: -- how to get a cellType (by extracting an icon in a CD design); -- how to define a high-level behavioral simulation procedure for this cellType; -- how to write a test procedure for this a cellType; -- Generic advice: go take a look at the Ports and BitOps interfaces. Convenient thingies -- The generic error MyCell -- This binds a pair of procs (initialization and simulation) with the name under which a cellType will be registered -- This proc returns the cellType; -- We suppose that there is a cell "MyCell.icon" in the design "MyDesign". -- extract the cell by name -- we supoose that the public wires are "Vdd", "Gnd", "Clock", Seq["In", 4], Seq["Out", 4]; -- register this cellType with Rosemary; -- the pair of procs cited above can now be used for simulation -- specify the type and direction of wires for simulation -- This is the safest way to proceed: for every public wire, you need an index in order to get the the value on the coprresponding port; nothing garantees the order in which wires appear, so if you hide these indexes in the global frame, you might get a stale value. The best place is in this record. It is a pain to redefine such a record for every cellType you simulate, but it is sooooo much safer... -- with LAST[NAT] you'll catch non-initializes values -- the state associated with the cell: in this case two LevelSequence -- This proc is called once before the simulation starts; it was registered above -- create a new state or reuse an old one -- finds the index of public wires in the cellType -- This proc is called by Rosemary whenever ... (RICK, HELP!!!!) -- This is an example of edge-triggered latch where the output is always a copy of `slave': when the clock is low, it samples the input into master; on an up-transition of the clock, it copies the value of master into the slave and stop sampling the input. -- Rosemary can call this proc whenever it pleases, so we need to keep in the state a value of the previous clock in order to differentiate. -- can't hurt! -- level sequences are refs, so you need this proc to copy the values -- This proc is called once per Eval[] -- port indexes, again -- power on -- the clock is a level (one bit, values among L, H, X), and the tester forces its value -- the input is a level sequence, and the tester forces its value -- the output is a sequence, and the tester ignores its value initially -- the register now contains 0FH; output is ignored (because of `none') -- Because of expect, the computed value will be compared with the value we specify. -- If the output is incorrect, an error window will open. -- Final call: this creates a tester panel -- creates a simulation; the cutset specifies to use the simulation proc defined for this cell ΚU˜codešœ™Kšœ Οmœ1™K˜Kšœ ˜ Kšœ˜J˜J˜Kšœ ˜ ˜JšœG™G—K˜Kšœ ˜ Kšœ˜J˜J˜Kšœ ˜ Kšœ ˜3Kšœ˜˜KšœT™TK™9—K˜—K˜K™*š ‘œžœžœžœžœžœ˜Pšœ?˜?Kšœ˜Kšœ žœ˜/Kšœ˜Kšœ5˜5Kšœ1˜1Kšœ˜—JšœCžœ˜IK˜—K˜šœ9˜9Kš '˜'—šœ-žœ˜?K™^——K˜Kšžœ˜K™KšΟt‘ €œžœ$€œ€œ€œ €œ€œ €œ˜wš €‘€œžœžœ€œ€œ˜0Kš€œ€œ€œ'€œ˜1Kš œ%€œ€œ€œ €œ˜HKšœ€œ€œ€œ €œ€œ€œ€œ€œ€œ€œ˜SKšœ˜—Kš €œ €œžœžœ€œ€œ˜+š€œ€œžœžœ˜!Kš €œ€œžœžœžœ˜)Kš€œ€<˜LKšœ˜—š€‘ €œ’˜$Kšœ€œ €œžœ žœžœžœžœžœ€œ€œ˜^Kš œ€œ€œ'€œ €œ˜Lšœ˜Kš B˜B—Kšœ˜—š€‘ €œ˜%Kšœ€œ €œžœ ˜(Kš€œ€˜Kšœ˜—K˜š‘ œ £9˜bKš €œ€œžœ$€œ €œ˜AKšœ4˜4šœ4˜4K™—Kš œ$€œ€œ€œ€œ˜>Kš œ+€œ€œ€œ€œ˜IK˜Jš€œ€˜ J˜Jš€œ€˜ J˜K˜—š ‘œžœžœžœžœžœ˜Kšœ*˜*Kšœ˜Kšœ žœ€œ€œ˜1Kšœ€œ €œ˜Kšœ5˜5Kšœ1˜1Kšœ˜—JšœCžœ˜IK˜—K˜Kš œ€œ €œ€œ €œ˜=Kš œ€œ€œ žœ€œ €œ˜CK˜Inil˜J˜—…—0*7