LogicImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Barth, May 20, 1986 5:04:05 pm PDT
Last Edited by: Louis Monier July 21, 1986 11:55:42 pm PDT
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;
Utilities
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: ROPENIL] = {
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: ROPENIL] RETURNS [i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10: NATLAST[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};
Zero and One
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};
Inverter
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
};
And
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;
};
Nand
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;
};
Or
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;
};
Nor
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;
};
Xor and Xnor
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;
};
Mux
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;
};
Master-slave Flip-Flop
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;
};
Latch
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};
};
Register
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;
};
Latch
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;
};
Tristate Buffer
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;
};
Adder
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;
};
Constant
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: BOOLTRUE];
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 cell—can'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: ROPECDIO.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.