<> <> <> <> <> <> <> <<>> <<>> <> <<>> <<>> DIRECTORY CoreClasses, CoreCreate, CoreFlat, IO, Logic, LogicUtils, Ports, Rosemary; LogicSimpleImpl: CEDAR PROGRAM IMPORTS CoreClasses, CoreCreate, CoreFlat, IO, Logic, LogicUtils, Ports, Rosemary EXPORTS Logic = BEGIN OPEN Logic, CoreCreate; <<-- Corresponding to very common types of publics>> IXRef: TYPE = REF IXRec; IXRec: TYPE = RECORD [in, out: NAT _ LAST[NAT]]; I4XRef: TYPE = REF I4XRec; I4XRec: TYPE = RECORD [in0, in1, in2, in3, out: NAT _ LAST[NAT]]; IXInit: Rosemary.InitProc = { state: IXRef _ IF oldStateAny=NIL THEN NEW[IXRec] ELSE NARROW[oldStateAny]; [state.in, state.out] _ Ports.PortIndexes[cellType.public, "I", "X"]; stateAny _ state; }; I2XInit: Rosemary.InitProc = { state: I4XRef _ IF oldStateAny=NIL THEN NEW[I4XRec] ELSE NARROW[oldStateAny]; [state.in0, state.in1, state.out] _ Ports.PortIndexes[cellType.public, "I-A", "I-B", "X"]; stateAny _ state; }; <> InvName: ROPE = Rosemary.Register[roseClassName: "Inv", init: InvInit, evalSimple: InvSimple]; Inv: PUBLIC PROC RETURNS [ct: CellType] = { ct _ LogicUtils.MakeSC[nameInLib: "inv", width: 2, name: InvName, public: Wires["Vdd", "Gnd", "I", "X"]]; Ports.InitPorts[ct, l, none, "Vdd", "Gnd", "I"]; Ports.InitPorts[ct, l, drive, "X"]; }; InvInit: Rosemary.InitProc = { state: IXRef _ IF oldStateAny=NIL THEN NEW[IXRec] ELSE NARROW[oldStateAny]; [state.in, state.out] _ Ports.PortIndexes[cellType.public, "I", "X"]; stateAny _ state}; InvSimple: Rosemary.EvalProc = { state: IXRef _ NARROW[stateAny]; p[state.out].l _ SELECT p[state.in].l FROM L => H, H => L, ENDCASE => X; }; BufferName: ROPE = Rosemary.Register[roseClassName: "Buffer", init: InvInit, evalSimple: InvSimple]; <<-- A buffer of drive d is equivalent to d inverters connected in parallel>> Buffer: PUBLIC PROC[d: NAT] RETURNS [ct: CellType] = { buffer2: CellType _ LogicUtils.MakeSC[nameInLib: "invBuffer", width: 3, name: BufferName, public: Wires["Vdd", "Gnd", "I", "X"]]; ct _ SequenceCell[name: BufferName, baseCell: buffer2, count: MAX[d/2, 1]]; [] _ CoreFlat.CellTypeCutLabels[ct, logicCutSet]; Ports.InitPorts[ct, l, none, "Vdd", "Gnd", "I"]; Ports.InitPorts[ct, l, drive, "X"]; }; <> TstRef: TYPE = REF TstRec; TstRec: TYPE = RECORD [in, out, en, nEn: NAT _ LAST[NAT]]; TstInit: Rosemary.InitProc = { state: TstRef _ IF oldStateAny=NIL THEN NEW[TstRec] ELSE NARROW[oldStateAny]; [state.in, state.out, state.en, state.nEn] _ Ports.PortIndexes[cellType.public, "I", "X", "EN", "NEN"]; stateAny _ state; }; TstDriverName: ROPE = Rosemary.Register[roseClassName: "TstDriver", init: TstInit, evalSimple: TstDriverSimple]; TstDriver: PUBLIC PROC RETURNS [ct: CellType] = { ct _ LogicUtils.MakeSC[nameInLib: "tstDriver", width: 4, name: TstDriverName, public: Wires["Vdd", "Gnd", "I", "X", "EN", "NEN"]]; Ports.InitPorts[ct, l, none, "Vdd", "Gnd", "I", "EN", "NEN", "X"]; }; TstDriverSimple: Rosemary.EvalProc = { -- by Pradeep state: TstRef _ NARROW[stateAny]; {OPEN state; IF p[en].l#L AND p[in].l#L THEN { -- N-Section of TstDriver p[out].d _ drive; IF p[en].l=H AND p[in].l=H THEN p[out].l _ L ELSE p[out].l _ X; RETURN; }; IF p[nEn].l#H AND p[in].l#H THEN { -- P-Section of TstDriver p[out].d _ drive; IF p[nEn].l=L AND p[in].l=L THEN p[out].l _ H ELSE p[out].l _ X; RETURN; }; p[out].d _ none; }}; TristateI: PUBLIC PROC RETURNS [ct: CellType] ~ {ct _ LogicUtils.Extract["3BufferI.icon", TRUE]}; TristateNI: PUBLIC PROC RETURNS [ct: CellType] ~ {ct _ LogicUtils.Extract["3BufferNI.icon", TRUE]}; <> B4: TYPE = {and, nand, or, nor}; nameInLib: ARRAY B4 OF ROPE = ["and", "nand", "or", "nor"]; nameOfCT: ARRAY B4 OF ROPE = ["And", "Nand", "Or", "Nor"]; rootCT: ARRAY B4 OF B4 = [nor, nand, nand, nor]; leafCT: ARRAY B4 OF B4 = [nand, and, nor, or]; InternalB4: PROC [b4: B4, n: NAT] RETURNS [ct: CellType] = { scPublic: Wire _ SELECT n FROM 2 => Wires["Vdd", "Gnd", "I-A", "I-B", "X"], 3 => Wires["Vdd", "Gnd", "I-A", "I-B", "I-C", "X"], 4 => Wires["Vdd", "Gnd", "I-A", "I-B", "I-C", "I-D", "X"], ENDCASE => ERROR; nameLib: ROPE _ IO.PutFR["%g%g", IO.rope[nameInLib[b4]], IO.int[n]]; nameCT: ROPE _ IO.PutFR["%g%g", IO.rope[nameOfCT[b4]], IO.int[n]]; sc: CellType _ LogicUtils.MakeSC[ nameInLib: nameLib, name: nameCT, width: n+1+(IF b4=and OR b4=or THEN 1 ELSE 0), public: scPublic]; pas: LIST OF PA _ LIST[["I-A", "I[0]"], ["I-B", "I[1]"]]; IF n>2 THEN pas _ CONS[["I-C", "I[2]"], pas]; IF n>3 THEN pas _ CONS[["I-D", "I[3]"], pas]; ct _ Cell[name: IO.PutFR["Normalized%g", IO.rope[nameCT]], public: Wires["Vdd", "Gnd", Seq["I", n], "X"], instances: LIST[InstanceList[sc, pas]]]; }; <<-- and -> nor2(nand)>> <<-- nand -> nand2(and)>> <<-- or -> nand2(nor)>> <<-- nor -> nor2(or)>> B4Large: PROC [b4: B4, n: NAT] RETURNS [ct: CellType] ~ { input: Wire = Seq["I", n]; n1: NAT _ n/2; root, c1, c2: CellInstance; SELECT n FROM 0, 1 => LogicUtils.Error["@@@ This should never happen, call implementor @@@"]; 2, 3, 4 => RETURN[InternalB4[b4, n]]; ENDCASE => NULL; -- for n>4, see further root _ Instance[InternalB4[rootCT[b4], 2], ["I", Wires["One", "Two"]]]; c1 _ Instance[B4Large[leafCT[b4], n1], ["X", "One"], ["I", Range[input, 0, n1]]]; c2 _ Instance[B4Large[leafCT[b4], n-n1], ["X", "Two"], ["I", Range[input, n1, n-n1]]]; ct _ Cell[name: IO.PutFR["%g%g", IO.rope[nameOfCT[b4]], IO.int[n]], public: Wires["Vdd", "Gnd", input, "X"], onlyInternal: Wires["One", "Two"], instances: LIST[root, c1, c2]]; }; <> AndName: ROPE = Rosemary.Register[roseClassName: "And", init: IXInit, evalSimple: AndSimple]; And: PUBLIC PROC[n: NAT] RETURNS [ct: CellType] = { IF n=0 THEN LogicUtils.Error["Please specify the number of inputs of the `and' gate"]; IF n=1 THEN LogicUtils.Error["What the hell is a 1-input `and' gate???"]; ct _ B4Large[and, n]; [] _ Rosemary.BindCellType[cellType: ct, roseClassName: AndName]; [] _ CoreFlat.CellTypeCutLabels[ct, logicCutSet]; Ports.InitPorts[ct, l, none, "Vdd", "Gnd"]; Ports.InitPorts[ct, ls, none, "I"]; Ports.InitPorts[ct, l, drive, "X"]; }; AndSimple: Rosemary.EvalProc = { state: IXRef _ NARROW[stateAny]; allHigh: BOOL _ TRUE; FOR i: NAT IN [0..p[state.in].ls.size) DO IF p[state.in].ls[i]=L THEN {p[state.out].l _ L; RETURN}; allHigh _ allHigh AND p[state.in].ls[i]=H; ENDLOOP; p[state.out].l _ SELECT TRUE FROM allHigh => H, ENDCASE => X; }; <> NandName: ROPE = Rosemary.Register[roseClassName: "Nand", init: IXInit, evalSimple: NandSimple]; Nand: PUBLIC PROC[n: NAT] RETURNS [ct: CellType] = { IF n=0 THEN LogicUtils.Error["Please specify the number of inputs of the `nand' gate"]; IF n=1 THEN LogicUtils.Error["What the hell is a 1-input `nand' gate???"]; ct _ B4Large[nand, n]; [] _ Rosemary.BindCellType[cellType: ct, roseClassName: NandName]; [] _ CoreFlat.CellTypeCutLabels[ct, logicCutSet]; Ports.InitPorts[ct, l, none, "Vdd", "Gnd"]; Ports.InitPorts[ct, ls, none, "I"]; Ports.InitPorts[ct, l, drive, "X"]; }; NandSimple: Rosemary.EvalProc = { state: IXRef _ NARROW[stateAny]; allHigh: BOOL _ TRUE; FOR i: NAT IN [0..p[state.in].ls.size) DO IF p[state.in].ls[i]=L THEN {p[state.out].l _ H; RETURN}; allHigh _ allHigh AND p[state.in].ls[i]=H; ENDLOOP; p[state.out].l _ SELECT TRUE FROM allHigh => L, ENDCASE => X; }; <> OrName: ROPE = Rosemary.Register[roseClassName: "Or", init: IXInit, evalSimple: OrSimple]; Or: PUBLIC PROC[n: NAT] RETURNS [ct: CellType] = { IF n=0 THEN LogicUtils.Error["Please specify the number of inputs of the `or' gate"]; IF n=1 THEN LogicUtils.Error["What the hell is a 1-input `or' gate???"]; ct _ B4Large[or, n]; [] _ Rosemary.BindCellType[cellType: ct, roseClassName: OrName]; [] _ CoreFlat.CellTypeCutLabels[ct, logicCutSet]; Ports.InitPorts[ct, l, none, "Vdd", "Gnd"]; Ports.InitPorts[ct, ls, none, "I"]; Ports.InitPorts[ct, l, drive, "X"]; }; OrSimple: Rosemary.EvalProc = { state: IXRef _ NARROW[stateAny]; allLow: BOOL _ TRUE; FOR i: NAT IN [0..p[state.in].ls.size) DO IF p[state.in].ls[i]=H THEN {p[state.out].l _ H; RETURN}; allLow _ allLow AND p[state.in].ls[i]=L; ENDLOOP; p[state.out].l _ SELECT TRUE FROM allLow => L, ENDCASE => X; }; <> NorName: ROPE = Rosemary.Register[roseClassName: "Nor", init: IXInit, evalSimple: NorSimple]; Nor: PUBLIC PROC[n: NAT] RETURNS [ct: CellType] = { IF n=0 THEN LogicUtils.Error["Please specify the number of inputs of the `nor' gate"]; IF n=1 THEN LogicUtils.Error["What the hell is a 1-input `nor' gate???"]; ct _ B4Large[nor, n]; [] _ Rosemary.BindCellType[cellType: ct, roseClassName: NorName]; [] _ CoreFlat.CellTypeCutLabels[ct, logicCutSet]; Ports.InitPorts[ct, l, none, "Vdd", "Gnd"]; Ports.InitPorts[ct, ls, none, "I"]; Ports.InitPorts[ct, l, drive, "X"]; }; NorSimple: Rosemary.EvalProc = { state: IXRef _ NARROW[stateAny]; allLow: BOOL _ TRUE; FOR i: NAT IN [0..p[state.in].ls.size) DO IF p[state.in].ls[i]=H THEN {p[state.out].l _ L; RETURN}; allLow _ allLow AND p[state.in].ls[i]=L; ENDLOOP; p[state.out].l _ SELECT TRUE FROM allLow => H, ENDCASE => X; }; <> Xor2Name: ROPE = Rosemary.Register[roseClassName: "Xor2", init: I2XInit, evalSimple: Xor2Simple]; Xnor2Name: ROPE = Rosemary.Register[roseClassName: "Xnor2", init: I2XInit, evalSimple: Xnor2Simple]; Xor2: PUBLIC PROC RETURNS [ct: CellType] = { ct _ LogicUtils.MakeSC[nameInLib: "xor2", name: Xor2Name, width: 6, public: Wires["Vdd", "Gnd", "I-A", "I-B", "X"]]; Ports.InitPorts[ct, l, none, "Vdd", "Gnd", "I-A", "I-B"]; Ports.InitPorts[ct, l, drive, "X"]; }; Xor2Simple: Rosemary.EvalProc = { state: I4XRef _ NARROW[stateAny]; p[state.out].l _ SELECT TRUE FROM p[state.in0].l=X OR p[state.in1].l=X => X, p[state.in0].l=p[state.in1].l => L, ENDCASE => H; }; Xnor2: PUBLIC PROC RETURNS [ct: CellType] = { ct _ LogicUtils.MakeSC[nameInLib: "xnor2", name: Xnor2Name, width: 6, public: Wires["Vdd", "Gnd", "I-A", "I-B", "X"]]; Ports.InitPorts[ct, l, none, "Vdd", "Gnd", "I-A", "I-B"]; Ports.InitPorts[ct, l, drive, "X"]; }; Xnor2Simple: Rosemary.EvalProc = { state: I4XRef _ NARROW[stateAny]; p[state.out].l _ SELECT TRUE FROM p[state.in0].l=X OR p[state.in1].l=X => X, p[state.in0].l=p[state.in1].l => H, ENDCASE => L; }; <> A22o2iName: ROPE = Rosemary.Register[roseClassName: "A22o2i", init: CG4Init, evalSimple: A22o2iSimple]; A21o2iName: ROPE = Rosemary.Register[roseClassName: "A21o2i", init: CG3Init, evalSimple: A21o2iSimple]; O22a2iName: ROPE = Rosemary.Register[roseClassName: "O22a2i", init: CG4Init, evalSimple: O22a2iSimple]; CG4Init: Rosemary.InitProc = { state: I4XRef _ IF oldStateAny=NIL THEN NEW[I4XRec] ELSE NARROW[oldStateAny]; [state.in0, state.in1, state.in2, state.in3, state.out] _ Ports.PortIndexes[cellType.public, "A", "B", "C", "D", "X"]; stateAny _ state; }; CG3Init: Rosemary.InitProc = { state: I4XRef _ IF oldStateAny=NIL THEN NEW[I4XRec] ELSE NARROW[oldStateAny]; [state.in0, state.in1, state.in2, state.out] _ Ports.PortIndexes[cellType.public, "A", "B", "C", "X"]; stateAny _ state; }; A22o2i: PUBLIC PROC[] RETURNS [ct: CellType] = { ct _ LogicUtils.MakeSC[nameInLib: "a22o2i", width: 5, name: A22o2iName, public: Wires["Vdd", "Gnd", "A", "B", "C", "D", "X"]]; Ports.InitPorts[ct, l, none, "Vdd", "Gnd", "A", "B", "C", "D"]; Ports.InitPorts[ct, l, drive, "X"]; }; A22o2iSimple: Rosemary.EvalProc = { state: I4XRef _ NARROW[stateAny]; p[state.out].l _ SELECT TRUE FROM (p[state.in0].l=H AND p[state.in1].l=H) OR (p[state.in2].l=H AND p[state.in3].l=H) => L, (p[state.in0].l=L OR p[state.in1].l=L) AND (p[state.in2].l=L OR p[state.in3].l=L) => H, ENDCASE => X; }; A21o2i: PUBLIC PROC[] RETURNS [ct: CellType] = { ct _ LogicUtils.MakeSC[nameInLib: "a21o2i", width: 4, name: A21o2iName, public: Wires["Vdd", "Gnd", "A", "B", "C", "X"]]; Ports.InitPorts[ct, l, none, "Vdd", "Gnd", "A", "B", "C"]; Ports.InitPorts[ct, l, drive, "X"]; }; A21o2iSimple: Rosemary.EvalProc = { state: I4XRef _ NARROW[stateAny]; p[state.out].l _ SELECT TRUE FROM (p[state.in0].l=H AND p[state.in1].l=H) OR p[state.in2].l=H => L, (p[state.in0].l=L OR p[state.in1].l=L) AND p[state.in2].l=L => H, ENDCASE => X; }; O22a2i: PUBLIC PROC[] RETURNS [ct: CellType] = { ct _ LogicUtils.MakeSC[nameInLib: "o22a2i", width: 5, name: O22a2iName, public: Wires["Vdd", "Gnd", "A", "B", "C", "D", "X"]]; Ports.InitPorts[ct, l, none, "Vdd", "Gnd", "A", "B", "C", "D"]; Ports.InitPorts[ct, l, drive, "X"]; }; O22a2iSimple: Rosemary.EvalProc = { state: I4XRef _ NARROW[stateAny]; p[state.out].l _ SELECT TRUE FROM (p[state.in0].l=H OR p[state.in1].l=H) AND (p[state.in2].l=H OR p[state.in3].l=H) => L, (p[state.in0].l=L AND p[state.in1].l=L) OR (p[state.in2].l=L AND p[state.in3].l=L) => H, ENDCASE => X; }; <> FFName: ROPE = Rosemary.Register[roseClassName: "FF", init: FFInit, evalSimple: FFSimple]; FlipFlop: PUBLIC PROC RETURNS [ct: CellType] = { ct _ LogicUtils.MakeSC[nameInLib: "ff", width: 10, name: FFName, public: Wires["Vdd", "Gnd", "D", "Q", "NQ", "CK"]]; Ports.InitPorts[ct, l, none, "Vdd", "Gnd", "D", "CK"]; Ports.InitPorts[ct, l, drive, "Q", "NQ"]; }; FFRef: TYPE = REF FFRec; FFRec: TYPE = RECORD [ ffD, ffQ, ffNQ, ffClock: NAT _ LAST[NAT], master, slave: Ports.Level]; FFInit: Rosemary.InitProc = { state: FFRef _ IF oldStateAny=NIL THEN NEW[FFRec] ELSE NARROW[oldStateAny]; state.master _ state.slave _ X; [state.ffD, state.ffQ, state.ffNQ, state.ffClock] _ Ports.PortIndexes[cellType.public, "D", "Q", "NQ", "CK"]; p[state.ffQ].l _ p[state.ffNQ].l _ X; stateAny _ state; }; FFSimple: Rosemary.EvalProc = { <<-- of course state.master is the inverse of the physical master level in the current CMosB implementation, but nobody has access to the real value, so let's keep things simple...>> state: FFRef _ NARROW[stateAny]; SELECT p[state.ffClock].l FROM L => state.master _ p[state.ffD].l; H => state.slave _ state.master; ENDCASE => { IF state.slave#state.master THEN state.slave _ X; IF state.master#p[state.ffD].l THEN state.master _ X; }; p[state.ffQ].l _ state.slave; p[state.ffNQ].l _ Ports.NotL[state.slave]; }; <> FFenName: ROPE = Rosemary.Register[roseClassName: "FFen", init: FFenInit, evalSimple: FFenSimple]; FlipFlopEnable: PUBLIC PROC RETURNS [ct: CellType] = { ct _ LogicUtils.MakeSC[nameInLib: "ffEn", width: 14, name: FFenName, public: Wires["Vdd", "Gnd", "D", "Q", "NQ", "CK", "en", "nEn"]]; Ports.InitPorts[ct, l, none, "Vdd", "Gnd", "D", "CK", "en", "nEn"]; Ports.InitPorts[ct, l, drive, "Q", "NQ"]; }; FFenRef: TYPE = REF FFenRec; FFenRec: TYPE = RECORD [ ffD, ffQ, ffNQ, ffClock, ffen, ffnEn: NAT _ LAST[NAT], master, slave: Ports.Level]; FFenInit: Rosemary.InitProc = { state: FFenRef _ IF oldStateAny=NIL THEN NEW[FFenRec] ELSE NARROW[oldStateAny]; state.master _ state.slave _ X; [state.ffD, state.ffQ, state.ffNQ, state.ffClock, state.ffen, state.ffnEn, ] _ Ports.PortIndexes[cellType.public, "D", "Q", "NQ", "CK", "en", "nEn"]; p[state.ffQ].l _ p[state.ffNQ].l _ X; stateAny _ state; }; FFenSimple: Rosemary.EvalProc = { <<-- of course state.master is the inverse of the physical master level in the current CMosB implementation, but nobody has access to the real value, so let's keep things simple...>> state: FFenRef _ NARROW[stateAny]; SELECT p[state.ffClock].l FROM L => { state.master _ SELECT TRUE FROM p[state.ffen].l=H AND p[state.ffnEn].l=L => p[state.ffD].l, p[state.ffen].l=L AND p[state.ffnEn].l=H => state.slave, ENDCASE => X; }; H => state.slave _ state.master; ENDCASE => { IF state.slave#state.master THEN state.slave _ X; IF state.master#p[state.ffD].l THEN state.master _ X; }; p[state.ffQ].l _ state.slave; p[state.ffNQ].l _ Ports.NotL[state.slave]; }; <> FFARName: ROPE = Rosemary.Register[roseClassName: "FFAR", init: FFARInit, evalSimple: FFARSimple]; FlipFlopAsyncReset: PUBLIC PROC RETURNS [ct: CellType] = { ct _ CoreClasses.CreateUnspecified[name: FFARName, public: Wires["Vdd", "Gnd", "D", "Q", "NQ", "CK", "r"]]; Ports.InitPorts[ct, l, none, "Vdd", "Gnd", "D", "CK", "r"]; Ports.InitPorts[ct, l, drive, "Q", "NQ"]; }; FFARRef: TYPE = REF FFARRec; FFARRec: TYPE = RECORD [ ffD, ffQ, ffNQ, ffClock, ffR: NAT _ LAST[NAT], master, slave: Ports.Level]; FFARInit: Rosemary.InitProc = { state: FFARRef _ IF oldStateAny=NIL THEN NEW[FFARRec] ELSE NARROW[oldStateAny]; state.master _ state.slave _ X; [state.ffD, state.ffQ, state.ffNQ, state.ffClock, state.ffR] _ Ports.PortIndexes[cellType.public, "D", "Q", "NQ", "CK", "r"]; p[state.ffQ].l _ p[state.ffNQ].l _ X; stateAny _ state; }; FFARSimple: Rosemary.EvalProc = { state: FFARRef _ NARROW[stateAny]; SELECT p[state.ffR].l FROM L => -- normal mode of operation SELECT p[state.ffClock].l FROM L => state.master _ p[state.ffD].l; H => state.slave _ state.master; ENDCASE => { IF state.slave#state.master THEN state.slave _ X; IF state.master#p[state.ffD].l THEN state.master _ X; }; H => state.slave _ state.master _ L; -- asynchronous reset ENDCASE => state.slave _ state.master _ X; -- mushy reset p[state.ffQ].l _ state.slave; p[state.ffNQ].l _ Ports.NotL[state.slave]; }; <> RSName: ROPE = Rosemary.Register[roseClassName: "RS", init: RSInit, evalSimple: RSSimple]; RS: PUBLIC PROC RETURNS [ct: CellType] = { ct _ CoreClasses.CreateUnspecified[name: RSName, public: Wires["Vdd", "Gnd", "R", "S", "Q", "nQ"]]; Ports.InitPorts[ct, l, none, "Vdd", "Gnd", "R", "S"]; Ports.InitPorts[ct, l, drive, "Q", "NQ"]; }; RSRef: TYPE = REF RSRec; RSRec: TYPE = RECORD [ r, s, q, nq: NAT _ LAST[NAT], bit: Ports.Level]; -- a copy of Q RSInit: Rosemary.InitProc = { state: RSRef _ IF oldStateAny=NIL THEN NEW[RSRec] ELSE NARROW[oldStateAny]; state.bit _ X; [state.r, state.s, state.q, state.nq] _ Ports.PortIndexes[cellType.public, "R", "S", "Q", "nQ"]; p[state.q].l _ p[state.nq].l _ X; stateAny _ state; }; RSSimple: Rosemary.EvalProc = { state: RSRef _ NARROW[stateAny]; SELECT TRUE FROM p[state.r].l=H => { state.bit _ p[state.q].l _ L; p[state.nq].l _ Ports.NotL[p[state.s].l]; }; p[state.r].l=L AND p[state.s].l=H => { state.bit _ p[state.q].l _ H; p[state.nq].l _ L; }; p[state.r].l=L AND p[state.s].l=L => { p[state.q].l _ state.bit; p[state.nq].l _ Ports.NotL[state.bit]; }; ENDCASE => state.bit _ p[state.q].l _ p[state.nq].l _ X; }; <> FF2: PUBLIC PROC RETURNS [ct: CellType] = {ct _ LogicUtils.Extract["ff2.sch", TRUE]}; FF4: PUBLIC PROC RETURNS [ct: CellType] = {ct _ LogicUtils.Extract["ff4.sch", TRUE]}; <> StorageName: ROPE = Rosemary.Register[roseClassName: "Storage", init: StorageInit, evalSimple: StorageSimple]; Storage: PUBLIC PROC RETURNS [ct: CellType] = { bit, nBit: NAT; ct _ CoreClasses.CreateUnspecified[name: StorageName, public: Wires["Vdd", "Gnd", "bit", "nbit"]]; [] _ Rosemary.BindCellType[cellType: ct, roseClassName: StorageName]; Ports.InitPorts[ct, l, none, "Vdd", "Gnd", "bit", "nbit"]; [bit, nBit] _ Ports.PortIndexes[ct.public, "bit", "nbit"]; [] _ Rosemary.SetWire[wire: ct.public[bit], memory: TRUE]; [] _ Rosemary.SetWire[wire: ct.public[nBit], memory: TRUE]; [] _ CoreFlat.CellTypeCutLabels[ct, logicCutSet]; }; StorageRef: TYPE = REF StorageRec; StorageRec: TYPE = RECORD [bit, nBit: NAT _ LAST[NAT]]; StorageInit: Rosemary.InitProc = { state: StorageRef _ NEW[StorageRec]; {OPEN state; [bit, nBit] _ Ports.PortIndexes[cellType.public, "bit", "nbit"]; p[bit].l _ X; p[bit].d _ driveWeak; p[nBit].l _ X; p[nBit].d _ driveWeak}; stateAny _ state}; StorageSimple: Rosemary.EvalProc = {NULL}; -- cf. Pradeep <> DLName: ROPE = Rosemary.Register[roseClassName: "DL", init: DLInit, evalSimple: DLSimple]; DLatch: PUBLIC PROC RETURNS [ct: CellType] = { ct _ LogicUtils.MakeSC[nameInLib: "dLatch", width: 9, name: DLName, public: Wires["Vdd", "Gnd", "D", "Q", "S"]]; Ports.InitPorts[ct, l, none, "Vdd", "Gnd", "D", "S"]; Ports.InitPorts[ct, l, drive, "Q"]; }; DLRef: TYPE = REF DLRec; DLRec: TYPE = RECORD [ dlD, dlQ, dlS: NAT _ LAST[NAT], mem: Ports.Level]; DLInit: Rosemary.InitProc = { state: DLRef _ IF oldStateAny=NIL THEN NEW[DLRec] ELSE NARROW[oldStateAny]; state.mem _ X; [state.dlD, state.dlQ, state.dlS] _ Ports.PortIndexes[cellType.public, "D", "Q", "S"]; p[state.dlQ].l _ X; stateAny _ state; }; DLSimple: Rosemary.EvalProc = { state: DLRef _ NARROW[stateAny]; IF p[state.dlS].l=H THEN state.mem _ p[state.dlD].l ELSE IF p[state.dlS].l=X THEN IF p[state.dlD].l#state.mem THEN state.mem _ X; p[state.dlQ].l _ state.mem; }; END.