<> <> <> <> <<>> DIRECTORY CD, CDCells, CDIO, CDMenus, CDOps, CDSatellites, CDSequencer, Core, CoreClasses, CoreCreate, CoreDirectory, CoreFlat, CoreOps, IO, Logic, Ports, PW, Rosemary, RosemaryUser, Sinix, Sisyph, TerminalIO; LogicImpl: CEDAR PROGRAM IMPORTS CDCells, CDIO, CDMenus, CDOps, CDSatellites, CoreClasses, CoreCreate, CoreDirectory, CoreOps, IO, Ports, PW, Rosemary, RosemaryUser, Sinix, Sisyph, TerminalIO EXPORTS Logic = BEGIN OPEN Logic, CoreCreate; <> defaultLibName: ROPE = "CMOSB"; defaultLib: CoreDirectory.Library _ CoreDirectory.FetchLibrary[defaultLibName]; schDesignName: ROPE = "Logic"; schDesign: CD.Design _ PW.OpenDesign[schDesignName]; cx: Sisyph.Context _ Sisyph.Create[schDesign, Sisyph.defaultGlobalNames]; <<-- lib can be passed by context, once there is more than one lib>> FetchSC: PROC [name: ROPE] RETURNS [ct: CellType] ~ { ct _ CoreDirectory.Fetch[library: defaultLib, key: name]; IF ct=NIL THEN { TerminalIO.WriteF["CellType %g not in library %g", IO.rope[name], IO.rope[defaultLibName]]; ERROR}; -- maybe a signal }; InitPorts: PROC [ct: CellType, initType: Ports.PortType _ l, initDrive: Ports.Drive _ none, n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10: ROPE _ NIL] = { IF n0#NIL THEN [] _ Ports.InitPort[CoreOps.FindWire[ct.public, n0], initType, initDrive] ELSE RETURN; IF n1#NIL THEN [] _ Ports.InitPort[CoreOps.FindWire[ct.public, n1], initType, initDrive] ELSE RETURN; IF n2#NIL THEN [] _ Ports.InitPort[CoreOps.FindWire[ct.public, n2], initType, initDrive] ELSE RETURN; IF n3#NIL THEN [] _ Ports.InitPort[CoreOps.FindWire[ct.public, n3], initType, initDrive] ELSE RETURN; IF n4#NIL THEN [] _ Ports.InitPort[CoreOps.FindWire[ct.public, n4], initType, initDrive] ELSE RETURN; IF n5#NIL THEN [] _ Ports.InitPort[CoreOps.FindWire[ct.public, n5], initType, initDrive] ELSE RETURN; IF n6#NIL THEN [] _ Ports.InitPort[CoreOps.FindWire[ct.public, n6], initType, initDrive] ELSE RETURN; IF n7#NIL THEN [] _ Ports.InitPort[CoreOps.FindWire[ct.public, n7], initType, initDrive] ELSE RETURN; IF n8#NIL THEN [] _ Ports.InitPort[CoreOps.FindWire[ct.public, n8], initType, initDrive] ELSE RETURN; IF n9#NIL THEN [] _ Ports.InitPort[CoreOps.FindWire[ct.public, n9], initType, initDrive] ELSE RETURN; IF n10#NIL THEN [] _ Ports.InitPort[CoreOps.FindWire[ct.public, n10], initType, initDrive] ELSE RETURN; }; PortIndexes: PROC [wire: Wire, n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10: ROPE _ NIL] RETURNS [i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10: 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; }; NotL: PROC [a: Ports.Level] RETURNS [b: Ports.Level] ~ { b_ SELECT a FROM L => H, H => L, ENDCASE => X}; <> 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 _ Rosemary.BindCellType[FetchSC["vdd"], VddName]; [vdd] _ PortIndexes[ct.public, "Vdd"]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: "Logic"]; [] _ InitPorts[ct, l, drive, "Vdd"]; }; VddSimple: Rosemary.EvalProc = {p[vdd].l _ H}; Gnd: PUBLIC PROC RETURNS [ct: CellType] = { ct _ Rosemary.BindCellType[FetchSC["vdd"], GndName]; [gnd] _ PortIndexes[ct.public, "Gnd"]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: "Logic"]; [] _ 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 _ Rosemary.BindCellType[FetchSC["inv"], InvName]; [invVdd, invGnd, invIn, invOut] _ PortIndexes[ct.public, "Vdd", "Gnd", "I", "X"]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: "Logic"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "I"]; [] _ InitPorts[ct, l, drive, "X"]; }; InvSimple: Rosemary.EvalProc = { p[invOut].l _ SELECT p[invIn].l FROM L => H, H => L, ENDCASE => X }; <> And2Name: ROPE = Rosemary.Register[roseClassName: "And2", evalSimple: And2Simple]; And3Name: ROPE = Rosemary.Register[roseClassName: "And3", evalSimple: And3Simple]; And4Name: ROPE = Rosemary.Register[roseClassName: "And4", evalSimple: And4Simple]; and2Vdd, and2Gnd, and2InA, and2InB, and2Out: NAT; and3Vdd, and3Gnd, and3InA, and3InB, and3InC, and3Out: NAT; and4Vdd, and4Gnd, and4InA, and4InB, and4InC, and4InD, and4Out: NAT; And2: PUBLIC PROC RETURNS [ct: CellType] = { ct _ Rosemary.BindCellType[FetchSC["and2"], And2Name]; [and2Vdd, and2Gnd, and2InA, and2InB, and2Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "X"]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: "Logic"]; [] _ 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 _ Rosemary.BindCellType[FetchSC["and3"], And3Name]; [and3Vdd, and3Gnd, and3InA, and3InB, and3InC, and3Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "I-C", "X"]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: "Logic"]; [] _ 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 _ Rosemary.BindCellType[FetchSC["and4"], And4Name]; [and4Vdd, and4Gnd, and4InA, and4InB, and4InC, and4InD, and4Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "I-C", "I-D", "X"]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: "Logic"]; [] _ 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; }; <> Nand2Name: ROPE = Rosemary.Register[roseClassName: "Nand2", evalSimple: Nand2Simple]; Nand3Name: ROPE = Rosemary.Register[roseClassName: "Nand3", evalSimple: Nand3Simple]; Nand4Name: ROPE = Rosemary.Register[roseClassName: "Nand4", evalSimple: Nand4Simple]; nand2Vdd, nand2Gnd, nand2InA, nand2InB, nand2Out: NAT; nand3Vdd, nand3Gnd, nand3InA, nand3InB, nand3InC, nand3Out: NAT; nand4Vdd, nand4Gnd, nand4InA, nand4InB, nand4InC, nand4InD, nand4Out: NAT; Nand2: PUBLIC PROC RETURNS [ct: CellType] = { ct _ Rosemary.BindCellType[FetchSC["nand2"], Nand2Name]; [nand2Vdd, nand2Gnd, nand2InA, nand2InB, nand2Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "X"]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: "Logic"]; [] _ 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 _ Rosemary.BindCellType[FetchSC["nand3"], Nand3Name]; [nand3Vdd, nand3Gnd, nand3InA, nand3InB, nand3InC, nand3Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "I-C", "X"]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: "Logic"]; [] _ 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 _ Rosemary.BindCellType[FetchSC["nand4"], Nand4Name]; [nand4Vdd, nand4Gnd, nand4InA, nand4InB, nand4InC, nand4InD, nand4Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "I-C", "I-D", "X"]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: "Logic"]; [] _ 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; }; <> Or2Name: ROPE = Rosemary.Register[roseClassName: "Or2", evalSimple: Or2Simple]; Or3Name: ROPE = Rosemary.Register[roseClassName: "Or3", evalSimple: Or3Simple]; Or4Name: ROPE = Rosemary.Register[roseClassName: "Or4", evalSimple: Or4Simple]; or2Vdd, or2Gnd, or2InA, or2InB, or2Out: NAT; or3Vdd, or3Gnd, or3InA, or3InB, or3InC, or3Out: NAT; or4Vdd, or4Gnd, or4InA, or4InB, or4InC, or4InD, or4Out: NAT; Or2: PUBLIC PROC RETURNS [ct: CellType] = { ct _ Rosemary.BindCellType[FetchSC["or2"], Or2Name]; [or2Vdd, or2Gnd, or2InA, or2InB, or2Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "X"]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: "Logic"]; [] _ 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 _ Rosemary.BindCellType[FetchSC["or3"], Or3Name]; [or3Vdd, or3Gnd, or3InA, or3InB, or3InC, or3Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "I-C", "X"]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: "Logic"]; [] _ 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 _ Rosemary.BindCellType[FetchSC["or4"], Or4Name]; [or4Vdd, or4Gnd, or4InA, or4InB, or4InC, or4InD, or4Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "I-C", "I-D", "X"]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: "Logic"]; [] _ 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; }; <> Nor2Name: ROPE = Rosemary.Register[roseClassName: "Nor2", evalSimple: Nor2Simple]; Nor3Name: ROPE = Rosemary.Register[roseClassName: "Nor3", evalSimple: Nor3Simple]; Nor4Name: ROPE = Rosemary.Register[roseClassName: "Nor4", evalSimple: Nor4Simple]; nor2Vdd, nor2Gnd, nor2InA, nor2InB, nor2Out: NAT; nor3Vdd, nor3Gnd, nor3InA, nor3InB, nor3InC, nor3Out: NAT; nor4Vdd, nor4Gnd, nor4InA, nor4InB, nor4InC, nor4InD, nor4Out: NAT; Nor2: PUBLIC PROC RETURNS [ct: CellType] = { ct _ Rosemary.BindCellType[FetchSC["nor2"], Nor2Name]; [nor2Vdd, nor2Gnd, nor2InA, nor2InB, nor2Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "X"]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: "Logic"]; [] _ 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 _ Rosemary.BindCellType[FetchSC["nor3"], Nor3Name]; [nor3Vdd, nor3Gnd, nor3InA, nor3InB, nor3InC, nor3Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "I-C", "X"]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: "Logic"]; [] _ 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 _ Rosemary.BindCellType[FetchSC["nor4"], Nor4Name]; [nor4Vdd, nor4Gnd, nor4InA, nor4InB, nor4InC, nor4InD, nor4Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "I-C", "I-D", "X"]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: "Logic"]; [] _ 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 _ Rosemary.BindCellType[FetchSC["xor2"], Xor2Name]; [xor2Vdd, xor2Gnd, xor2InA, xor2InB, xor2Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "X"]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: "Logic"]; [] _ 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 _ Rosemary.BindCellType[FetchSC["xnor2"], Xnor2Name]; [xnor2Vdd, xnor2Gnd, xnor2InA, xnor2InB, xnor2Out] _ PortIndexes[ct.public, "Vdd", "Gnd", "I-A", "I-B", "X"]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: "Logic"]; [] _ 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 _ CoreClasses.CreateUnspecified[public: Wires["Vdd", "Gnd", "A", "B", "selA", "nOut"], name: InvMux2Name]; [] _ Rosemary.BindCellType[ct, InvMux2Name]; [invMux2Vdd, invMux2Gnd, invMux2A, invMux2B, invMux2selA, invMux2nOut] _ PortIndexes[ct.public, "Vdd", "Gnd", "A", "B", "selA", "nOut"]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: "Logic"]; [] _ 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; }; <> MSFFName: ROPE = Rosemary.Register[roseClassName: "MSFF", init: MSFFInit, evalSimple: MSFFSimple]; msFFVdd, msFFGnd, msFFD, msFFQ, msFFNQ, msFFClock, msFFnReset, msFFnPreset: NAT; LatchRef: TYPE = REF LatchRec; LatchRec: TYPE = RECORD [val, prevCK: Ports.Level]; MSFF: PUBLIC PROC RETURNS [ct: CellType] = { ct _ CoreClasses.CreateUnspecified[ name: MSFFName, public: Wires["Vdd", "Gnd", "D", "Q", "NQ", "CK", "nR", "nP"]]; [] _ Rosemary.BindCellType[cellType: ct, roseClassName: MSFFName]; [msFFVdd, msFFGnd, msFFD, msFFQ, msFFNQ, msFFClock, msFFnReset, msFFnPreset] _ PortIndexes[ct.public, "Vdd", "Gnd", "D", "Q", "NQ", "CK", "nR", "nP"]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: "Logic"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "D", "CK", "nR", "nP"]; [] _ InitPorts[ct, l, drive, "Q", "NQ"]; }; MSFFInit: Rosemary.InitProc = { state: LatchRef _ NEW[LatchRec _ [X, X]]; stateAny _ state; }; MSFFSimple: Rosemary.EvalProc = { state: LatchRef _ NARROW[stateAny]; IF state.prevCK=L AND p[msFFClock].l=H THEN -- transition up {p[msFFQ].l _ p[msFFD].l; p[msFFNQ].l _ NotL[p[msFFD].l]}; SELECT TRUE FROM p[msFFnReset].l=L AND p[msFFnPreset].l=H => {p[msFFQ].l _ L; p[msFFNQ].l _ H}; p[msFFnReset].l=H AND p[msFFnPreset].l=L => {p[msFFQ].l _ L; p[msFFNQ].l _ H}; p[msFFnReset].l=L AND p[msFFnPreset].l=L => {p[msFFQ].l _ H; p[msFFNQ].l _ H}; ENDCASE; state.val _ p[msFFQ].l; state.prevCK _ p[msFFClock].l; }; <> Latch1Name: ROPE = Rosemary.Register[roseClassName: "Latch1", init: Latch1Init, evalSimple: Latch1Simple]; latch1Vdd, latch1Gnd, latch1D, latch1Q, latch1NQ, latch1Enable, latch1nReset, latch1nPreset: NAT; Latch1: PUBLIC PROC RETURNS [ct: CellType] = { ct _ CoreClasses.CreateUnspecified[ name: Latch1Name, public: Wires["Vdd", "Gnd", "D", "Q", "NQ", "E", "nR", "nP"]]; [latch1Vdd, latch1Gnd, latch1D, latch1Q, latch1NQ, latch1Enable, latch1nReset, latch1nPreset] _ PortIndexes[ct.public, "Vdd", "Gnd", "D", "Q", "NQ", "E", "nR", "nP"]; [] _ Rosemary.BindCellType[cellType: ct, roseClassName: Latch1Name]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: "Logic"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "D", "E", "nR", "nP"]; [] _ InitPorts[ct, l, drive, "Q", "NQ"]; }; Latch1Init: Rosemary.InitProc = { state: REF Ports.Level _ NEW[Ports.Level _ X]; stateAny _ state; }; Latch1Simple: Rosemary.EvalProc = { state: REF Ports.Level _ NARROW[stateAny]; SELECT p[latch1Enable].l FROM H => {state^ _ p[latch1Q].l _ p[latch1D].l; p[latch1NQ].l _ NotL[p[latch1D].l]}; X => IF state^#p[latch1D].l THEN state^ _ X; ENDCASE; IF p[latch1nReset].l = L THEN {state^ _ p[latch1Q].l _ L; p[latch1NQ].l _ H}; IF p[latch1nPreset].l = L THEN {state^ _ p[latch1Q].l _ H; p[latch1NQ].l _ L}; }; <> RegisterName: ROPE = Rosemary.Register[roseClassName: "Register", init: RegisterInit, evalSimple: RegisterSimple]; registerVdd, registerGnd, registerCK, registerInput, registerOutput, registernEnable, registernClear: NAT; RegRef: TYPE = REF RegRec; RegRec: TYPE = RECORD [ prevCK: Ports.Level, val: PACKED SEQUENCE size: NAT OF Ports.Level]; Register: PUBLIC PROC [b: NAT] RETURNS [ct: CellType] = { ct _ CoreClasses.CreateUnspecified[name: RegisterName, public: Wires["Vdd", "Gnd", "CK", Seq["Input", b], Seq["Output", b], "nE", "nCl"]]; [] _ Rosemary.BindCellType[cellType: ct, roseClassName: RegisterName]; [registerVdd, registerGnd, registerCK, registerInput, registerOutput, registernEnable, registernClear] _ PortIndexes[ct.public, "Vdd", "Gnd", "CK", "Input", "Output", "nE", "nCl"]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: "Logic"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "CK", "nE", "nCl"]; [] _ InitPorts[ct, ls, none, "Input"]; [] _ InitPorts[ct, ls, drive, "Output"]; }; RegisterInit: Rosemary.InitProc = { size: NAT _ p[registerInput].ls.size; state: RegRef _ NEW[RegRec[size]]; state.prevCK _ X; FOR i: NAT IN [0..size) DO state.val[i] _ X; ENDLOOP; stateAny _ state; }; RegisterSimple: Rosemary.EvalProc = { state: RegRef _ NARROW[stateAny]; IF NOT(state.prevCK=L AND p[registerCK].l=H) THEN RETURN; -- no up transition IF p[registernClear].l=L THEN { FOR i: NAT IN [0..p[registerOutput].ls.size) DO state.val[i] _ p[registerOutput].ls[i] _ L; ENDLOOP; RETURN}; IF p[registernEnable].l#L THEN RETURN; FOR i: NAT IN [0..p[registerInput].ls.size) DO state.val[i] _ p[registerOutput].ls[i] _ p[registerInput].ls[i]; ENDLOOP; state.prevCK _ p[registerCK].l; }; <> LatchName: ROPE = Rosemary.Register[roseClassName: "Latch", init: LatchInit, evalSimple: LatchSimple]; latchVdd, latchGnd, latchInput, latchOutput, latchEnable, latchClear: NAT; Latch: PUBLIC PROC [b: NAT] RETURNS [ct: CellType] = { ct _ CoreClasses.CreateUnspecified[name: LatchName, public: Wires["Vdd", "Gnd", Seq["Input", b], Seq["Output", b], "E", "cl"]]; [] _ Rosemary.BindCellType[cellType: ct, roseClassName: LatchName]; [latchVdd, latchGnd, latchInput, latchOutput, latchEnable, latchClear] _ PortIndexes[ct.public, "Vdd", "Gnd", "Input", "Output", "E", "cl"]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: "Logic"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "E", "cl"]; [] _ InitPorts[ct, ls, none, "Input"]; [] _ InitPorts[ct, ls, drive, "Output"]; }; LatchInit: Rosemary.InitProc = { size: NAT _ p[latchInput].ls.size; state: RegRef _ NEW[RegRec[size]]; FOR i: NAT IN [0..size) DO state.val[i] _ X; ENDLOOP; stateAny _ state; }; LatchSimple: Rosemary.EvalProc = { state: RegRef _ NARROW[stateAny]; IF p[latchClear].l=H THEN { FOR i: NAT IN [0..p[latchOutput].ls.size) DO state.val[i] _ p[latchOutput].ls[i] _ L; ENDLOOP; RETURN}; IF p[latchEnable].l#H THEN RETURN; FOR i: NAT IN [0..p[latchInput].ls.size) DO state.val[i] _ p[latchOutput].ls[i] _ p[latchInput].ls[i]; ENDLOOP; }; <> TstBufferName: ROPE = Rosemary.Register[roseClassName: "TstBuffer", evalSimple: TstBufferSimple]; tstBufferVdd, tstBufferGnd, tstBufferInput, tstBufferOutput, tstBuffernEnable: NAT; TstBuffer: PUBLIC PROC [b: NAT] RETURNS [ct: CellType] = { ct _ CoreClasses.CreateUnspecified[name: TstBufferName, public: Wires["Vdd", "Gnd", Seq["Input", b], Seq["Output", b], "nE"]]; [] _ Rosemary.BindCellType[cellType: ct, roseClassName: TstBufferName]; [tstBufferVdd, tstBufferGnd, tstBufferInput, tstBufferOutput, tstBuffernEnable] _ PortIndexes[ct.public, "Vdd", "Gnd", "Input", "Output", "nE"]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: "Logic"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "nE"]; [] _ InitPorts[ct, ls, none, "Input"]; [] _ InitPorts[ct, ls, none, "Output"]; }; TstBufferSimple: Rosemary.EvalProc = { IF p[tstBuffernEnable].l=L THEN { p[tstBufferOutput].ls[i].d _ drive; FOR i: NAT IN [0..p[tstBufferOutput].ls.size) DO p[tstBufferOutput].ls[i] _ p[tstBufferInput].ls[i]; ENDLOOP; }; ELSE p[tstBufferOutput].ls[i].d _ none; }; <> AdderName: ROPE = Rosemary.Register[roseClassName: "Adder", evalSimple: AdderSimple]; adderVdd, adderGnd, adderA, adderB, adderSum, adderCarryIn, adderCarryOut: NAT; <<-- b>1 please>> <<-- Sum[0] is the (wrong Mesa order) high-order bit>> Adder: PUBLIC PROC [b: NAT] RETURNS [ct: CellType] = { oneBitAdder: CellType _ Sisyph.ES["oneBitAdder.sch", cx]; -- designed by Alfred insts: CellInstances _ LIST[Instance[oneBitAdder, ["A", "A[0]"], ["B", "B[0]"], ["Sum", "Sum[0]"], ["Cout", "carryOut"], ["C", "carry[0]"]]]; IF b<2 THEN ERROR; -- we'll be more graceful soon!!! FOR i: NAT IN [1..b-1) DO insts _ CONS[ Instance[oneBitAdder, ["A", Index["A", i]], ["B", Index["B", i]], ["Sum", Index["Sum", i]], ["Cout", Index["carry", i-1]], ["C", Index["carry", i]]], insts]; ENDLOOP; insts _ CONS[ Instance[oneBitAdder, ["A", Index["A", b-1]], ["B", Index["B", b-1]], ["Sum", Index["Sum", b-1]], ["Cout", Index["carry", b-2]], ["C", "carryIn"]], insts]; ct _ Cell[ name: AdderName, public: Wires["Vdd", "Gnd", "carryIn", Seq["A", b], Seq["B", b], Seq["Sum", b], "carryOut"], onlyInternal: Wires[Seq["carry", b-1]], instances: insts]; [adderVdd, adderGnd, adderA, adderB, adderSum, adderCarryIn, adderCarryOut] _ PortIndexes[ct.public, "Vdd", "Gnd", "A", "B", "Sum", "carryIn", "carryOut"]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: "Logic"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd", "carryIn"]; [] _ InitPorts[ct, l, drive, "carryOut"]; [] _ InitPorts[ct, ls, none, "A", "B"]; [] _ InitPorts[ct, ls, drive, "Sum"]; }; AdderSimple: Rosemary.EvalProc = { Sum: 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) THEN H ELSE L; }; carry: Ports.Level _ p[adderCarryIn].l; FOR i: NAT IN [0..p[adderSum].ls.size) DO [carry, p[adderSum].ls[i]] _ Sum[p[adderA].ls[i], p[adderB].ls[i], carry]; ENDLOOP; p[adderCarryOut].l _ carry; }; <> ConstantName: ROPE = Rosemary.Register[roseClassName: "Constant", init: ConstantInit, evalSimple: ConstantSimple]; constantVdd, constantGnd, constantOutput: NAT; RegRef: TYPE = REF RegRec; RegRec: TYPE = RECORD [ prevCK: Ports.Level, val: PACKED SEQUENCE size: NAT OF Ports.Level]; Constant: PUBLIC PROC [b: NAT, v: INT] RETURNS [ct: CellType] = { ct _ CoreClasses.CreateUnspecified[name: ConstantName, public: Wires["Vdd", "Gnd", Seq["Output", b]]]; [] _ Rosemary.BindCellType[cellType: ct, roseClassName: ConstantName]; [constantVdd, constantGnd, constantOutput] _ PortIndexes[ct.public, "Vdd", "Gnd", "Output"]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: "Logic"]; [] _ InitPorts[ct, l, none, "Vdd", "Gnd"]; [] _ InitPorts[ct, lc, drive, "Output"]; }; ConstantSimple: Rosemary.EvalProc = { p[constantOutput].lc _ v; -- get v from a prop!!!! }; 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]]"]; }; ClockGenName: ROPE = Rosemary.Register[roseClassName: "ClockGen", init: ClockGenInit, evalSimple: ClockGenSimple]; clockGenClock, clockGenTime: NAT; ClockGen: PUBLIC PROC [up, dn, firstUp: NAT] RETURNS [ct: CellType] ~ { ct _ CoreClasses.CreateUnspecified[ name: ClockGenName, public: Wires["Clock", "Time"]]; [] _ Rosemary.BindCellType[cellType: ct, roseClassName: ClockGenName]; [clockGenClock, clockGenTime] _ PortIndexes[ct.public, "Clock", "Time"]; [] _ Rosemary.AddCutSets[cellType: ct, cs1: "Logic"]; [] _ InitPorts[ct, b, drive, "Clock"]; [] _ InitPorts[ct, b, none, "Time"]; }; ClockState: TYPE = REF ClockStateRec; ClockStateRec: TYPE = RECORD [ counter: INT _ 0, lastTime: BOOL _ TRUE]; ClockGenInit: Rosemary.InitProc = { state: ClockState _ NEW[ClockStateRec]; stateAny _ state; }; ClockGenSimple: Rosemary.EvalProc = { state: ClockState _ NARROW[stateAny]; p[clockGenClock].b _ p[clockGenTime].b; }; 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] = { IF ~IsSingleSelected[selected, multiple] THEN RETURN [FALSE]; IF ~CDCells.IsCell[selected.ob] THEN { TerminalIO.WriteRope["\n** Selected instance is not a cellcan't do it.\n"]; RETURN[FALSE]; }; RETURN[TRUE]; }; IsSingleSelected: PROC [selected: CD.Instance, multiple: BOOL] RETURNS [BOOL] = { IF selected=NIL THEN { TerminalIO.WriteRope["\n** No current selection--can't do it.\n"]; RETURN[FALSE]; }; IF multiple THEN { TerminalIO.WriteRope["\n** Multiple instances selected--can't do it.\n"]; RETURN[FALSE]; }; RETURN[TRUE]; }; ExtractSelectedObjAndRunRosemary: PROC [comm: CDSequencer.Command] = { selected: CD.Instance; multiple: BOOL; sim: Rosemary.Simulation; cx: Sisyph.Context _ Sisyph.Create[comm.design, LIST["Vdd", "Gnd", "Time"]]; cellType: CellType; rct: CoreClasses.RecordCellType; wDir: ROPE _ CDIO.GetWorkingDirectory[comm.design]; logicVdd, logicGnd: NAT; [selected, multiple] _ CDOps.SelectedInstance[comm.design]; IF ~IsSingleSelectedAndCell[selected, multiple] THEN RETURN; [] _ CDSatellites.EnforceInvariants[comm.design, CDOps.InstList[comm.design]]; cellType _ NARROW [Sinix.Extract[obj: selected.ob, mode: Sisyph.sisyphMode, properties: selected.properties, userData: cx].result]; cellType _ CoreOps.ToBasic[cellType]; <<-- this cellType better have as only public: "Vdd", "Gnd", "Time" !!!!>> 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 recCT: CellType _ CoreOps.ToBasic[rct[i].type]; IF recCT.class=CoreClasses.recordCellClass THEN { IF sim#NIL THEN ERROR; sim _ RosemaryUser.TestProcedureViewer[cellType: cellType, testButtons: LIST["Logic Test"], name: "Logic Test", displayWires: RosemaryUser.DisplayInstancePortLeafWires[[CoreFlat.NullPath, rct[i]]], flatten: TRUE, cutSets: LIST["Logic"]]; }; ENDLOOP; }; <<-- Entry goes in Sisyph Menu>> CDMenus.ImplementEntryCommand[menu: $OtherProgramMenu, entry: "Sisyph Extract and Rosemary", p: ExtractSelectedObjAndRunRosemary, key: $CoreRosemaryExtractSelectedObjAndRunRosemary]; RosemaryUser.RegisterTestProc["Logic Test", LogicTest]; END.