<> <> <> <<>> DIRECTORY CD, CDCells, CDMenus, CDOps, CDSequencer, Core, CoreClasses, CoreCreate, CoreDirectory, CoreFlat, CoreOps, CoreProperties, HashTable, IO, Logic, Ports, PW, PWCore, Rosemary, RosemaryUser, Sinix, Sisyph, TerminalIO; LogicImpl: CEDAR PROGRAM IMPORTS CDCells, CDMenus, CDOps, CoreClasses, CoreCreate, CoreDirectory, CoreOps, CoreProperties, HashTable, IO, Ports, PW, Rosemary, RosemaryUser, Sinix, Sisyph, TerminalIO EXPORTS Logic = BEGIN OPEN Logic, CoreCreate; <> libCellClass: PUBLIC Core.CellClass _ CoreOps.SetClassPrintProc[NEW [Core.CellClassRec _ [name: "LibCell", recast: RecastLibCell]], PrintLibCell]; CreateLibCell: PUBLIC PROC [public: Wire, ctName, libName, name: ROPE _ NIL, props: Properties _ NIL] RETURNS [ct: CellType] = { ct _ CoreOps.CreateCellType[ class: libCellClass, public: public, data: NEW[LibCellRec _ [libName, ctName]], name: name, props: props]; }; RecastLibCell: Core.RecastProc = { -- check public!!!! scRef: LibCellRef _ NARROW [me.data]; lib: CoreDirectory.Library _ CoreDirectory.FetchLibrary[scRef.libName]; schCell: CellType _ CoreDirectory.Fetch[library: lib, key: scRef.ctName]; IF schCell=NIL THEN {TerminalIO.WriteF["CellType %g not in library %g", IO.rope[scRef.ctName], IO.rope[scRef.libName]]; ERROR}; -- maybe a signal ? new _ CoreClasses.CreatePermutedRecordCell[iconPublic: me.public, schCell: schCell, table: CreateIdentityTable[me.public, schCell.public]] }; CreateIdentityTable: PROC [iconPublic, schPublic: Wire] RETURNS [table: HashTable.Table] ~ { FindWire: PROC [iconPublic: Wire, name: ROPE] RETURNS [iconWire: Wire _ NIL] ~ { n: INT _ CoreOps.GetWireIndex[iconPublic, name]; IF n>=0 THEN RETURN[iconPublic[n]]; }; AddInTable: CoreOps.EachWireProc ~ { name: ROPE _ CoreOps.GetShortWireName[wire]; iconWire: Wire; IF name=NIL THEN RETURN; iconWire _ FindWire[iconPublic, name]; IF iconWire=NIL THEN RETURN; [] _ HashTable.Store[table, wire, iconWire]; }; table _ HashTable.Create[]; [] _ CoreOps.VisitWire[schPublic, AddInTable]; }; PrintLibCell: CoreOps.PrintClassProc = { scRef: LibCellRef _ NARROW [data]; CoreOps.PrintIndent[indent, out]; out.PutF["Cell '%g' from library '%g'\n", IO.rope[scRef.ctName], IO.rope[scRef.libName]]; }; <> logicCutSet: PUBLIC ROPE _ "Logic"; macroCutSet: PUBLIC ROPE _ "LogicMacro"; defaultLibName: ROPE = "CMOSB"; schDesignName: ROPE = "Logic"; schDesign: CD.Design _ PW.OpenDesign[schDesignName]; cx: PUBLIC Sisyph.Context _ Sisyph.Create[schDesign]; <<-- lib can be passed by context, once there is more than one lib>> MakeSC: PROC [nameInLib, name: ROPE, public: Wire] RETURNS [ct: CellType] ~ { ct _ CreateLibCell[name: name, public: public, ctName: nameInLib, libName: defaultLibName]; -- a global ct _ Rosemary.BindCellType[ct, name]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: logicCutSet]; }; InitPorts: PUBLIC PROC [ct: CellType, initType: Ports.PortType _ l, initDrive: Ports.Drive _ none, n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10: ROPE _ NIL] = { InitP: PROC [ct: CellType, initType: Ports.PortType, initDrive: Ports.Drive, n: ROPE] ~ { [] _ Ports.InitPort[CoreOps.FindWire[ct.public, n], initType, initDrive]; }; IF n0#NIL THEN InitP[ct, initType, initDrive, n0] ELSE RETURN; IF n1#NIL THEN InitP[ct, initType, initDrive, n1] ELSE RETURN; IF n2#NIL THEN InitP[ct, initType, initDrive, n2] ELSE RETURN; IF n3#NIL THEN InitP[ct, initType, initDrive, n3] ELSE RETURN; IF n4#NIL THEN InitP[ct, initType, initDrive, n4] ELSE RETURN; IF n5#NIL THEN InitP[ct, initType, initDrive, n5] ELSE RETURN; IF n6#NIL THEN InitP[ct, initType, initDrive, n6] ELSE RETURN; IF n7#NIL THEN InitP[ct, initType, initDrive, n7] ELSE RETURN; IF n8#NIL THEN InitP[ct, initType, initDrive, n8] ELSE RETURN; IF n9#NIL THEN InitP[ct, initType, initDrive, n9] ELSE RETURN; IF n10#NIL THEN InitP[ct, initType, initDrive, n10] ELSE RETURN; }; PortIndexes: PUBLIC PROC [wire: Wire, n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11: ROPE _ NIL] RETURNS [i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11: NAT _ LAST[NAT]] ~ { IF n0#NIL THEN i0 _ Ports.PortIndex[wire, n0] ELSE RETURN; IF n1#NIL THEN i1 _ Ports.PortIndex[wire, n1] ELSE RETURN; IF n2#NIL THEN i2 _ Ports.PortIndex[wire, n2] ELSE RETURN; IF n3#NIL THEN i3 _ Ports.PortIndex[wire, n3] ELSE RETURN; IF n4#NIL THEN i4 _ Ports.PortIndex[wire, n4] ELSE RETURN; IF n5#NIL THEN i5 _ Ports.PortIndex[wire, n5] ELSE RETURN; IF n6#NIL THEN i6 _ Ports.PortIndex[wire, n6] ELSE RETURN; IF n7#NIL THEN i7 _ Ports.PortIndex[wire, n7] ELSE RETURN; IF n8#NIL THEN i8 _ Ports.PortIndex[wire, n8] ELSE RETURN; IF n9#NIL THEN i9 _ Ports.PortIndex[wire, n9] ELSE RETURN; IF n10#NIL THEN i10 _ Ports.PortIndex[wire, n10] ELSE RETURN; IF n11#NIL THEN i11 _ Ports.PortIndex[wire, n11] ELSE RETURN; }; NotL: PUBLIC PROC [a: Ports.Level] RETURNS [b: Ports.Level] ~ { b_ SELECT a FROM L => H, H => L, ENDCASE => X}; SumL: PUBLIC PROC [a, b, c: Ports.Level] RETURNS [carry, s: Ports.Level] ~ { IF a=X OR b=X OR c=X THEN RETURN[X, X]; carry _ IF (a=H AND b=H) OR (b=H AND c=H) OR (c=H AND a=H) THEN H ELSE L; s _ IF (a=H AND b=H AND c=L) OR (b=H AND c=H AND a=L) OR (c=H AND a=H AND b=L) OR (a=L AND b=L AND c=L) THEN L ELSE H; }; CopyLS: PUBLIC PROC [from, to: Ports.LevelSequence] ~ { FOR i: NAT IN [0..from.size) DO to[i] _ from[i]; ENDLOOP; }; SetLS: PUBLIC PROC [seq: Ports.LevelSequence, level: Ports.Level] ~ { FOR i: NAT IN [0..seq.size) DO seq[i] _ level; ENDLOOP; }; <> VddName: ROPE = Rosemary.Register[roseClassName: "Vdd", evalSimple: VddSimple]; GndName: ROPE = Rosemary.Register[roseClassName: "Gnd", evalSimple: GndSimple]; vdd, gnd: NAT; Vdd: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "vdd", name: VddName, public: Wires["Vdd"]]; [vdd] _ PortIndexes[ct.public, "Vdd"]; [] _ InitPorts[ct, l, drive, "Vdd"]; }; VddSimple: Rosemary.EvalProc = {p[vdd].l _ H}; Gnd: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "gnd", name: GndName, public: Wires["Gnd"]]; [gnd] _ PortIndexes[ct.public, "Gnd"]; [] _ InitPorts[ct, l, drive, "Gnd"]; }; GndSimple: Rosemary.EvalProc = {p[gnd].l _ L}; <> InvName: ROPE = Rosemary.Register[roseClassName: "Inv", evalSimple: InvSimple]; invVdd, invGnd, invIn, invOut: NAT; Inv: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "inv", name: InvName, public: Wires["Vdd", "Gnd", "I", "X"]]; [invVdd, invGnd, invIn, invOut] _ PortIndexes[ct.public, "Vdd", "Gnd", "I", "X"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "I"]; [] _ InitPorts[ct, l, drive, "X"]; }; Buffer: PUBLIC PROC[d: NAT] RETURNS [ct: CellType] = { ct _ Inv[]; -- good enough for now!!!! }; InvSimple: Rosemary.EvalProc = { p[invOut].l _ SELECT p[invIn].l FROM L => H, H => L, ENDCASE => X }; <> TstDriverName: ROPE = Rosemary.Register[roseClassName: "TstDriver", evalSimple: TstDriverSimple]; tstDriverVdd, tstDriverGnd, tstDriverIn, tstDriverOut, tstDriverEN, tstDriverNEN: NAT; TstDriver: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "tstDriver", name: TstDriverName, public: Wires["Vdd", "Gnd", "I", "X", "EN", "NEN"]]; [tstDriverVdd, tstDriverGnd, tstDriverIn, tstDriverOut] _ PortIndexes[ct.public, "Vdd", "Gnd", "I", "X", "EN", "NEN"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "I", "EN", "NEN", "X"]; }; TstDriverSimple: Rosemary.EvalProc = { IF p[tstDriverEN].l#NotL[p[tstDriverNEN].l] THEN { p[tstDriverOut].d _ drive; p[tstDriverOut].l _ X; RETURN}; SELECT p[tstDriverEN].l FROM H => {p[tstDriverOut].l _ NotL[p[tstDriverIn].l]; p[tstDriverOut].d _ drive}; L => {p[tstDriverOut].d _ none}; ENDCASE => {p[tstDriverOut].l _ X; p[tstDriverOut].d _ drive}; }; <> AndName: ROPE = Rosemary.Register[roseClassName: "And", evalSimple: AndSimple]; And2Name: ROPE = Rosemary.Register[roseClassName: "And2", evalSimple: And2Simple]; And3Name: ROPE = Rosemary.Register[roseClassName: "And3", evalSimple: And3Simple]; And4Name: ROPE = Rosemary.Register[roseClassName: "And4", evalSimple: And4Simple]; andVdd, andGnd, andIn, andOut: NAT; and2Vdd, and2Gnd, and2InA, and2InB, and2Out: NAT; and3Vdd, and3Gnd, and3InA, and3InB, and3InC, and3Out: NAT; and4Vdd, and4Gnd, and4InA, and4InB, and4InC, and4InD, and4Out: NAT; And: PUBLIC PROC[n: NAT] RETURNS [ct: CellType] = { IF n<2 THEN ERROR; -- improve ct _ CoreClasses.CreateUnspecified[name: AndName, public: Wires["Vdd", "Gnd", Seq["I", n], "X"]]; [] _ Rosemary.BindCellType[cellType: ct, roseClassName: AndName]; [andVdd, andGnd, andIn, andOut] _ PortIndexes[ct.public, "Vdd", "Gnd", "I", "X"]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: macroCutSet]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd"]; [] _ InitPorts[ct, ls, none, "I"]; [] _ InitPorts[ct, l, drive, "X"]; }; AndSimple: Rosemary.EvalProc = { allHigh: BOOL _ TRUE; FOR i: NAT IN [0..p[andIn].ls.size) DO IF p[andIn].ls[i]=L THEN {p[andOut].l _ L; RETURN}; allHigh _ allHigh AND p[andIn].ls[i]=H; ENDLOOP; p[andOut].l _ SELECT TRUE FROM allHigh => H, ENDCASE => X; }; And2: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "and2", name: And2Name, public: Wires["Vdd", "Gnd", "I-A", "I-B", "X"]]; [and2Vdd, and2Gnd, and2InA, and2InB, and2Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "X"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "I-A", "I-B"]; [] _ InitPorts[ct, l, drive, "X"]; }; And2Simple: Rosemary.EvalProc = { p[and2Out].l _ SELECT TRUE FROM p[and2InA].l=L OR p[and2InB].l=L => L, p[and2InA].l=H AND p[and2InB].l=H => H, ENDCASE => X; }; And3: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "and3", name: And3Name, public: Wires["Vdd", "Gnd", "I-A", "I-B", "I-C", "X"]]; [and3Vdd, and3Gnd, and3InA, and3InB, and3InC, and3Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "I-C", "X"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "I-A", "I-B", "I-C"]; [] _ InitPorts[ct, l, drive, "X"]; }; And3Simple: Rosemary.EvalProc = { p[and3Out].l _ SELECT TRUE FROM p[and3InA].l=L OR p[and3InB].l=L OR p[and3InC].l=L => L, p[and3InA].l=H AND p[and3InB].l=H AND p[and3InC].l=H => H, ENDCASE => X; }; And4: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "and4", name: And4Name, public: Wires["Vdd", "Gnd", "I-A", "I-B", "I-C", "I-D", "X"]]; [and4Vdd, and4Gnd, and4InA, and4InB, and4InC, and4InD, and4Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "I-C", "I-D", "X"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "I-A", "I-B", "I-C", "I-D"]; [] _ InitPorts[ct, l, drive, "X"]; }; And4Simple: Rosemary.EvalProc = { p[and4Out].l _ SELECT TRUE FROM p[and4InA].l=L OR p[and4InB].l=L OR p[and4InC].l=L OR p[and4InD].l=L => L, p[and4InA].l=H AND p[and4InB].l=H AND p[and4InC].l=H AND p[and4InD].l=H => H, ENDCASE => X; }; <> NandName: ROPE = Rosemary.Register[roseClassName: "Nand", evalSimple: AndSimple]; Nand2Name: ROPE = Rosemary.Register[roseClassName: "Nand2", evalSimple: Nand2Simple]; Nand3Name: ROPE = Rosemary.Register[roseClassName: "Nand3", evalSimple: Nand3Simple]; Nand4Name: ROPE = Rosemary.Register[roseClassName: "Nand4", evalSimple: Nand4Simple]; nandVdd, nandGnd, nandIn, nandOut: NAT; nand2Vdd, nand2Gnd, nand2InA, nand2InB, nand2Out: NAT; nand3Vdd, nand3Gnd, nand3InA, nand3InB, nand3InC, nand3Out: NAT; nand4Vdd, nand4Gnd, nand4InA, nand4InB, nand4InC, nand4InD, nand4Out: NAT; Nand: PUBLIC PROC[n: NAT] RETURNS [ct: CellType] = { IF n<2 THEN ERROR; -- improve ct _ CoreClasses.CreateUnspecified[name: NandName, public: Wires["Vdd", "Gnd", Seq["I", n], "X"]]; [] _ Rosemary.BindCellType[cellType: ct, roseClassName: NandName]; [nandVdd, nandGnd, nandIn, nandOut] _ PortIndexes[ct.public, "Vdd", "Gnd", "I", "X"]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: macroCutSet]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd"]; [] _ InitPorts[ct, ls, none, "I"]; [] _ InitPorts[ct, l, drive, "X"]; }; NandSimple: Rosemary.EvalProc = { allHigh: BOOL _ TRUE; FOR i: NAT IN [0..p[nandIn].ls.size) DO IF p[nandIn].ls[i]=L THEN {p[nandOut].l _ H; RETURN}; allHigh _ allHigh AND p[nandIn].ls[i]=H; ENDLOOP; p[nandOut].l _ SELECT TRUE FROM allHigh => L, ENDCASE => X; }; Nand2: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "nand2", name: Nand2Name, public: Wires["Vdd", "Gnd", "I-A", "I-B", "X"]]; [nand2Vdd, nand2Gnd, nand2InA, nand2InB, nand2Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "X"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "I-A", "I-B"]; [] _ InitPorts[ct, l, drive, "X"]; }; Nand2Simple: Rosemary.EvalProc = { p[nand2Out].l _ SELECT TRUE FROM p[nand2InA].l=L OR p[nand2InB].l=L => H, p[nand2InA].l=H AND p[nand2InB].l=H => L, ENDCASE => X; }; Nand3: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "nand3", name: Nand3Name, public: Wires["Vdd", "Gnd", "I-A", "I-B", "I-C", "X"]]; [nand3Vdd, nand3Gnd, nand3InA, nand3InB, nand3InC, nand3Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "I-C", "X"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "I-A", "I-B", "I-C"]; [] _ InitPorts[ct, l, drive, "X"]; }; Nand3Simple: Rosemary.EvalProc = { p[nand3Out].l _ SELECT TRUE FROM p[nand3InA].l=L OR p[nand3InB].l=L OR p[nand3InC].l=L => H, p[nand2InA].l=H AND p[nand2InB].l=H AND p[nand3InC].l=H => L, ENDCASE => X; }; Nand4: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "nand4", name: Nand4Name, public: Wires["Vdd", "Gnd", "I-A", "I-B", "I-C", "I-D", "X"]]; [nand4Vdd, nand4Gnd, nand4InA, nand4InB, nand4InC, nand4InD, nand4Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "I-C", "I-D", "X"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "I-A", "I-B", "I-C", "I-D"]; [] _ InitPorts[ct, l, drive, "X"]; }; Nand4Simple: Rosemary.EvalProc = { p[nand4Out].l _ SELECT TRUE FROM p[nand4InA].l=L OR p[nand4InB].l=L OR p[nand4InC].l=L OR p[nand4InD].l=L => H, p[nand4InA].l=H AND p[nand4InB].l=H AND p[nand4InC].l=H AND p[nand4InD].l=H => L, ENDCASE => X; }; <> OrName: ROPE = Rosemary.Register[roseClassName: "Or", evalSimple: OrSimple]; Or2Name: ROPE = Rosemary.Register[roseClassName: "Or2", evalSimple: Or2Simple]; Or3Name: ROPE = Rosemary.Register[roseClassName: "Or3", evalSimple: Or3Simple]; Or4Name: ROPE = Rosemary.Register[roseClassName: "Or4", evalSimple: Or4Simple]; orVdd, orGnd, orIn, orOut: NAT; or2Vdd, or2Gnd, or2InA, or2InB, or2Out: NAT; or3Vdd, or3Gnd, or3InA, or3InB, or3InC, or3Out: NAT; or4Vdd, or4Gnd, or4InA, or4InB, or4InC, or4InD, or4Out: NAT; Or: PUBLIC PROC[n: NAT] RETURNS [ct: CellType] = { IF n<2 THEN ERROR; -- improve ct _ CoreClasses.CreateUnspecified[name: OrName, public: Wires["Vdd", "Gnd", Seq["I", n], "X"]]; [] _ Rosemary.BindCellType[cellType: ct, roseClassName: OrName]; [orVdd, orGnd, orIn, orOut] _ PortIndexes[ct.public, "Vdd", "Gnd", "I", "X"]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: macroCutSet]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd"]; [] _ InitPorts[ct, ls, none, "I"]; [] _ InitPorts[ct, l, drive, "X"]; }; OrSimple: Rosemary.EvalProc = { allLow: BOOL _ TRUE; FOR i: NAT IN [0..p[orIn].ls.size) DO IF p[orIn].ls[i]=H THEN {p[orOut].l _ H; RETURN}; allLow _ allLow AND p[orIn].ls[i]=L; ENDLOOP; p[orOut].l _ SELECT TRUE FROM allLow => L, ENDCASE => X; }; Or2: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "or2", name: Or2Name, public: Wires["Vdd", "Gnd", "I-A", "I-B", "X"]]; [or2Vdd, or2Gnd, or2InA, or2InB, or2Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "X"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "I-A", "I-B"]; [] _ InitPorts[ct, l, drive, "X"]; }; Or2Simple: Rosemary.EvalProc = { -- same proc for both p[or2Out].l _ SELECT TRUE FROM p[or2InA].l=H OR p[or2InB].l=H => H, p[or2InA].l=L AND p[or2InB].l=L => L, ENDCASE => X; }; Or3: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "or3", name: Or3Name, public: Wires["Vdd", "Gnd", "I-A", "I-B", "I-C", "X"]]; [or3Vdd, or3Gnd, or3InA, or3InB, or3InC, or3Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "I-C", "X"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "I-A", "I-B", "I-C"]; [] _ InitPorts[ct, l, drive, "X"]; }; Or3Simple: Rosemary.EvalProc = { -- same proc for both p[or3Out].l _ SELECT TRUE FROM p[or3InA].l=H OR p[or3InB].l=H OR p[or3InC].l=H => H, p[or3InA].l=L AND p[or3InB].l=L AND p[or3InC].l=L => L, ENDCASE => X; }; Or4: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "or4", name: Or4Name, public: Wires["Vdd", "Gnd", "I-A", "I-B", "I-C", "I-D", "X"]]; [or4Vdd, or4Gnd, or4InA, or4InB, or4InC, or4InD, or4Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "I-C", "I-D", "X"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "I-A", "I-B", "I-C", "I-D"]; [] _ InitPorts[ct, l, drive, "X"]; }; Or4Simple: Rosemary.EvalProc = { -- same proc for both p[or4Out].l _ SELECT TRUE FROM p[or4InA].l=H OR p[or4InB].l=H OR p[or4InC].l=H OR p[or4InD].l=H => H, p[or4InA].l=L AND p[or4InB].l=L AND p[or4InC].l=L AND p[or4InD].l=L => L, ENDCASE => X; }; <> NorName: ROPE = Rosemary.Register[roseClassName: "Nor", evalSimple: NorSimple]; Nor2Name: ROPE = Rosemary.Register[roseClassName: "Nor2", evalSimple: Nor2Simple]; Nor3Name: ROPE = Rosemary.Register[roseClassName: "Nor3", evalSimple: Nor3Simple]; Nor4Name: ROPE = Rosemary.Register[roseClassName: "Nor4", evalSimple: Nor4Simple]; norVdd, norGnd, norIn, norOut: NAT; nor2Vdd, nor2Gnd, nor2InA, nor2InB, nor2Out: NAT; nor3Vdd, nor3Gnd, nor3InA, nor3InB, nor3InC, nor3Out: NAT; nor4Vdd, nor4Gnd, nor4InA, nor4InB, nor4InC, nor4InD, nor4Out: NAT; Nor: PUBLIC PROC[n: NAT] RETURNS [ct: CellType] = { IF n<2 THEN ERROR; -- improve ct _ CoreClasses.CreateUnspecified[name: NorName, public: Wires["Vdd", "Gnd", Seq["I", n], "X"]]; [] _ Rosemary.BindCellType[cellType: ct, roseClassName: NorName]; [norVdd, norGnd, norIn, norOut] _ PortIndexes[ct.public, "Vdd", "Gnd", "I", "X"]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: macroCutSet]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd"]; [] _ InitPorts[ct, ls, none, "I"]; [] _ InitPorts[ct, l, drive, "X"]; }; NorSimple: Rosemary.EvalProc = { allLow: BOOL _ TRUE; FOR i: NAT IN [0..p[norIn].ls.size) DO IF p[norIn].ls[i]=H THEN {p[norOut].l _ L; RETURN}; allLow _ allLow AND p[norIn].ls[i]=L; ENDLOOP; p[norOut].l _ SELECT TRUE FROM allLow => H, ENDCASE => X; }; Nor2: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "nor2", name: Nor2Name, public: Wires["Vdd", "Gnd", "I-A", "I-B", "X"]]; [nor2Vdd, nor2Gnd, nor2InA, nor2InB, nor2Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "X"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "I-A", "I-B"]; [] _ InitPorts[ct, l, drive, "X"]; }; Nor2Simple: Rosemary.EvalProc = { -- same proc for both p[nor2Out].l _ SELECT TRUE FROM p[nor2InA].l=H OR p[nor2InB].l=H => L, p[nor2InA].l=L AND p[nor2InB].l=L => H, ENDCASE => X; }; Nor3: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "nor3", name: Nor3Name, public: Wires["Vdd", "Gnd", "I-A", "I-B", "I-C", "X"]]; [nor3Vdd, nor3Gnd, nor3InA, nor3InB, nor3InC, nor3Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "I-C", "X"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "I-A", "I-B", "I-C"]; [] _ InitPorts[ct, l, drive, "X"]; }; Nor3Simple: Rosemary.EvalProc = { -- same proc for both p[nor3Out].l _ SELECT TRUE FROM p[nor3InA].l=H OR p[nor3InB].l=H OR p[nor3InC].l=H => L, p[nor3InA].l=L AND p[nor3InB].l=L AND p[nor3InC].l=L => H, ENDCASE => X; }; Nor4: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "nor4", name: Nor4Name, public: Wires["Vdd", "Gnd", "I-A", "I-B", "I-C", "I-D", "X"]]; [nor4Vdd, nor4Gnd, nor4InA, nor4InB, nor4InC, nor4InD, nor4Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "I-C", "I-D", "X"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "I-A", "I-B", "I-C", "I-D"]; [] _ InitPorts[ct, l, drive, "X"]; }; Nor4Simple: Rosemary.EvalProc = { -- same proc for both p[nor4Out].l _ SELECT TRUE FROM p[nor4InA].l=H OR p[nor4InB].l=H OR p[nor4InC].l=H OR p[nor4InD].l=H => L, p[nor4InA].l=L AND p[nor4InB].l=L AND p[nor4InC].l=L AND p[nor4InD].l=L => H, ENDCASE => X; }; <> Xor2Name: ROPE = Rosemary.Register[roseClassName: "Xor2", evalSimple: Xor2Simple]; Xnor2Name: ROPE = Rosemary.Register[roseClassName: "Xnor2", evalSimple: Xnor2Simple]; xor2Vdd, xor2Gnd, xor2InA, xor2InB, xor2Out: NAT; xnor2Vdd, xnor2Gnd, xnor2InA, xnor2InB, xnor2Out: NAT; Xor2: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "xor2", name: Xor2Name, public: Wires["Vdd", "Gnd", "I-A", "I-B", "X"]]; [xor2Vdd, xor2Gnd, xor2InA, xor2InB, xor2Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "X"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "I-A", "I-B"]; [] _ InitPorts[ct, l, drive, "X"]; }; Xor2Simple: Rosemary.EvalProc = { p[xor2Out].l _ SELECT TRUE FROM p[xor2InA].l=X OR p[xor2InB].l=X => X, (p[xor2InA].l=H AND p[xor2InB].l=H) OR (p[xor2InA].l=L AND p[xor2InB].l=L) => L, ENDCASE => H; }; Xnor2: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "xnor2", name: Xnor2Name, public: Wires["Vdd", "Gnd", "I-A", "I-B", "X"]]; [xnor2Vdd, xnor2Gnd, xnor2InA, xnor2InB, xnor2Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "X"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "I-A", "I-B"]; [] _ InitPorts[ct, l, drive, "X"]; }; Xnor2Simple: Rosemary.EvalProc = { p[xnor2Out].l _ SELECT TRUE FROM p[xnor2InA].l=X OR p[xnor2InB].l=X => X, (p[xnor2InA].l=H AND p[xnor2InB].l=H) OR (p[xnor2InA].l=L AND p[xnor2InB].l=L) => H, ENDCASE => L; }; <> InvMux2Name: ROPE = Rosemary.Register[roseClassName: "InvMux2", evalSimple: InvMux2Simple]; invMux2Vdd, invMux2Gnd, invMux2A, invMux2B, invMux2selA, invMux2nOut: NAT; InvMux2: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "invMux2", name: InvMux2Name, public: Wires["Vdd", "Gnd", "A", "B", "selA", "nOut"]]; [invMux2Vdd, invMux2Gnd, invMux2A, invMux2B, invMux2selA, invMux2nOut] _ PortIndexes[ct.public, "Vdd", "Gnd", "A", "B", "selA", "nOut"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "A", "B", "selA"]; [] _ InitPorts[ct, l, drive, "nOut"]; }; InvMux2Simple: Rosemary.EvalProc = { p[invMux2nOut].l _ SELECT p[invMux2selA].l FROM H => p[invMux2A].l, L => p[invMux2B].l, ENDCASE => IF p[invMux2A].l=p[invMux2B].l THEN p[invMux2A].l ELSE X; }; <> BFFName: ROPE = Rosemary.Register[roseClassName: "BFF", init: BFFInit, evalSimple: BFFSimple]; bffVdd, bffGnd, bffD0, bffD1, bffD2, bffD3, bffs0, bffs1, bffs2, bffClock, bffQ, bffNQ: NAT; FFRef: TYPE = REF FFRec; FFRec: TYPE = RECORD [val, prevCK: Ports.Level]; BasicFlipFlop: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "BFF", name: BFFName, public: Wires["Vdd", "Gnd", "D0", "D1", "D2", "D3", "s0", "s1", "s2", "CK", "Q", "NQ"]]; [bffVdd, bffGnd, bffD0, bffD1, bffD2, bffD3, bffs0, bffs1, bffs2, bffClock, bffQ, bffNQ] _ PortIndexes[ct.public, "Vdd", "Gnd", "D0", "D1", "D2", "D3", "s0", "s1", "s2", "CK", "Q", "NQ"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "D0", "D1", "D2", "D3", "CK", "s0", "s1", "s2"]; [] _ InitPorts[ct, l, drive, "Q", "NQ"]; }; BFFInit: Rosemary.InitProc = { state: FFRef _ NEW[FFRec _ [X, X]]; stateAny _ state; }; BFFSimple: Rosemary.EvalProc = { state: FFRef _ NARROW[stateAny]; IF ~(state.prevCK=L AND p[bffClock].l=H) THEN {state.prevCK _ p[bffClock].l; RETURN}; state.val _ SELECT TRUE FROM p[bffs2].l=L AND p[bffs0].l=L => p[bffD0].l, p[bffs2].l=L AND p[bffs0].l=H => p[bffD1].l, p[bffs2].l=H AND p[bffs1].l=L => p[bffD2].l, p[bffs2].l=H AND p[bffs1].l=H => p[bffD3].l, ENDCASE => X; p[bffQ].l _ state.val; p[bffNQ].l _ NotL[state.val]; -- after an up transition state.prevCK _ p[bffClock].l; }; <> FFName: ROPE = Rosemary.Register[roseClassName: "FF", init: FFInit, evalSimple: FFSimple]; ffVdd, ffGnd, ffD, ffQ, ffNQ, ffClock: NAT; <<>> FlipFlop: PUBLIC PROC RETURNS [ct: CellType] = { ct _ MakeSC[nameInLib: "FF", name: FFName, public: Wires["Vdd", "Gnd", "D", "Q", "NQ", "CK"]]; [ffVdd, ffGnd, ffD, ffQ, ffNQ, ffClock] _ PortIndexes[ct.public, "Vdd", "Gnd", "D", "Q", "NQ", "CK"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "D", "CK"]; [] _ InitPorts[ct, l, drive, "Q", "NQ"]; }; FFInit: Rosemary.InitProc = { state: FFRef _ NEW[FFRec _ [X, X]]; stateAny _ state; }; FFSimple: Rosemary.EvalProc = { state: FFRef _ NARROW[stateAny]; IF ~(state.prevCK=L AND p[ffClock].l=H) THEN {state.prevCK _ p[ffClock].l; RETURN}; state.val _ p[ffD].l; p[ffQ].l _ state.val; p[ffNQ].l _ NotL[state.val]; -- after an up transition state.prevCK _ p[ffClock].l; }; <> ClockGenName: ROPE = Rosemary.Register[roseClassName: "ClockGen", init: ClockGenInit, evalSimple: ClockGenSimple]; clockGenClock, clockGenTime: NAT; ClockGen: PUBLIC PROC [up, dn, firstEdge: NAT, initLow: BOOL] RETURNS [ct: CellType] ~ { ct _ CoreClasses.CreateUnspecified[ name: ClockGenName, public: Wires["Clock", "Time"]]; CoreProperties.PutCellTypeProp[ct, $up, NEW[NAT _ up]]; CoreProperties.PutCellTypeProp[ct, $dn, NEW[NAT _ dn]]; CoreProperties.PutCellTypeProp[ct, $firstEdge, NEW[NAT _ firstEdge]]; CoreProperties.PutCellTypeProp[ct, $initLow, NEW[BOOL _ initLow]]; [] _ Rosemary.BindCellType[cellType: ct, roseClassName: ClockGenName]; [clockGenClock, clockGenTime] _ PortIndexes[ct.public, "Clock", "Time"]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: logicCutSet]; [] _ InitPorts[ct, b, drive, "Clock"]; [] _ InitPorts[ct, b, none, "Time"]; }; ClockState: TYPE = REF ClockStateRec; ClockStateRec: TYPE = RECORD [ up, dn, firstEdge: INT, initLow: BOOL, counter: INT _ 0, lastTime: BOOL _ TRUE]; ClockGenInit: Rosemary.InitProc = { state: ClockState _ NEW[ClockStateRec]; state.up _ NARROW[CoreProperties.GetCellTypeProp[cellType, $up], REF NAT]^; state.dn _ NARROW[CoreProperties.GetCellTypeProp[cellType, $dn], REF NAT]^; state.firstEdge _ NARROW[CoreProperties.GetCellTypeProp[cellType, $firstEdge], REF NAT]^; state.initLow _ NARROW[CoreProperties.GetCellTypeProp[cellType, $initLow], REF BOOL]^; state.lastTime _ p[clockGenTime].b; stateAny _ state; }; ClockGenSimple: Rosemary.EvalProc = { t0, normTime: INT; state: ClockState _ NARROW[stateAny]; IF state.lastTime=p[clockGenTime].b THEN RETURN; 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[clockGenClock].b _ SELECT TRUE FROM state.counter ~state.initLow, normTime< state.dn => FALSE, ENDCASE => TRUE; state.lastTime _ p[clockGenTime].b; }; <> StopName: ROPE = Rosemary.Register[roseClassName: "Stop", evalSimple: StopSimple]; StopInput: NAT; Stop: PUBLIC PROC [] RETURNS [ct: CellType] ~ { ct _ CoreClasses.CreateUnspecified[ name: StopName, public: Wires["ShouldBeFalse"]]; [] _ Rosemary.BindCellType[cellType: ct, roseClassName: StopName]; [StopInput] _ PortIndexes[ct.public, "ShouldBeFalse"]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: logicCutSet]; [] _ InitPorts[ct, b, none, "Time"]; }; StopSimple: Rosemary.EvalProc = { IF p[StopInput].l#L THEN Rosemary.Stop[msg: "User-defined assertion is wrong", data: p, reason: $Client]; }; -- **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** <<>> <<-- These belong in Sch, but Sch must be redone, so in the mean time...>> RoseProbeProp: ATOM _ $RoseProbe; -- only value: $Yes SetObjectPort: PUBLIC PROC [cx: Sisyph.Context, initType: Ports.PortType _ b, initDrive: Ports.Drive _ none] = { Sisyph.Eval[cx, "coreProps _ CoreProperties.PutProp[coreProps, $PortData, NEW[Ports.PortDataRec _ [ type: initType, drive: initDrive]]]"]; }; SetObjectTesterDrive: PUBLIC PROC [cx: Sisyph.Context, initDrive: Ports.Drive _ none] = { Sisyph.Eval[cx, "coreProps _ CoreProperties.PutProp[coreProps, $PortTesterDrive, NEW[Ports.Drive _ initDrive]]"]; }; LogicTest: RosemaryUser.TestProc ~ { logicTime: NAT _ Ports.PortIndex[cellType.public, "Time"]; p[logicTime].b _ TRUE; p[logicTime].d _ drive; DO p[logicTime].b _ NOT p[logicTime].b; Eval[]; ENDLOOP; }; IsSingleSelectedAndCell: PROC [selected: CD.Instance, multiple: BOOL] RETURNS [BOOL _ FALSE] = { SELECT TRUE FROM selected=NIL => TerminalIO.WriteRope["\n** No current selection--can't do it.\n"]; multiple => TerminalIO.WriteRope["\n** Multiple instances selected--can't do it.\n"]; ~CDCells.IsCell[selected.ob] => TerminalIO.WriteRope["\n** Not a cellcan't do it.\n"]; ENDCASE => RETURN[TRUE]; }; ExtractSelectedObjAndRunRosemary: PROC [comm: CDSequencer.Command] = { ListOfDisplayWires: PROC [inst: CellInstance] RETURNS [displayWires: CoreFlat.FlatWires] ~ { wire: Wire _ inst.actual; FOR i: NAT IN [0..wire.size) DO displayWires _ CONS[NEW[CoreFlat.FlatWireRec _ [path: CoreFlat.NullPath, wire: wire[i]]], displayWires]; ENDLOOP; }; selected: CD.Instance; multiple: BOOL; sim: Rosemary.Simulation; cx: Sisyph.Context _ Sisyph.Create[comm.design]; cellType: CellType _ NIL; displayInst: CellInstance _ NIL; rct: CoreClasses.RecordCellType; logicVdd, logicGnd: NAT; [selected, multiple] _ CDOps.SelectedInstance[comm.design]; IF ~IsSingleSelectedAndCell[selected, multiple] THEN RETURN; Sisyph.Store[cx: cx, var: Sisyph.globalNamesRope, value: NEW[LIST OF ROPE _ Sisyph.List["Time", "Gnd", "Vdd"]]]; <> cellType _ NARROW [Sinix.Extract[obj: selected.ob, mode: Sisyph.sisyphMode, properties: selected.properties, userData: cx].result]; cellType _ CoreOps.ToBasic[cellType]; IF cellType.class#CoreClasses.recordCellClass THEN ERROR; logicVdd _ Ports.PortIndex[cellType.public, "Vdd"]; logicGnd _ Ports.PortIndex[cellType.public, "Gnd"]; [] _ Rosemary.SetFixedWire[cellType.public[logicVdd], H]; [] _ Rosemary.SetFixedWire[cellType.public[logicGnd], L]; rct _ NARROW[cellType.data]; FOR i: NAT IN [0..rct.size) DO IF CoreProperties.GetCellInstanceProp[rct[i], RoseProbeProp]#NIL THEN displayInst _ rct[i]; ENDLOOP; IF displayInst=NIL THEN ERROR; -- nothing to display sim _ RosemaryUser.TestProcedureViewer[ cellType: cellType, testButtons: LIST["Logic Test"], name: "Logic Test", displayWires: ListOfDisplayWires[displayInst], flatten: TRUE, cutSets: LIST[logicCutSet, macroCutSet]]; }; <<-- Entry goes in Sisyph Menu>> CDMenus.ImplementEntryCommand[menu: $OtherProgramMenu, entry: "Sisyph Extract and Rosemary", p: ExtractSelectedObjAndRunRosemary, key: $CoreRosemaryExtractSelectedObjAndRunRosemary]; RosemaryUser.RegisterTestProc["Logic Test", LogicTest]; END.