LogicImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Last Edited by: Louis Monier August 7, 1986 2:25:55 am PDT
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;
New Class
libCellClass: PUBLIC Core.CellClass ← CoreOps.SetClassPrintProc[NEW [Core.CellClassRec ← [name: "LibCell", recast: RecastLibCell]], PrintLibCell];
CreateLibCell: PUBLIC PROC [public: Wire, ctName, libName, name: ROPENIL, 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]];
};
Utilities
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: ROPENIL] = {
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: ROPENIL] RETURNS [i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11: 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;
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;
};
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 ← 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};
Inverter(s)
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
};
Tristate Driver
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};
};
And
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: BOOLTRUE;
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;
};
Nand
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: BOOLTRUE;
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;
};
Or
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: BOOLTRUE;
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;
};
Nor
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: BOOLTRUE;
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;
};
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 ← 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;
};
Mux
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;
};
Basic building block for Flip-Flops
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;
};
Edge-Triggered Flip-Flops
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;
};
Clock Generator
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: BOOLTRUE];
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.firstEdge => ~state.initLow,
normTime< state.dn => FALSE,
ENDCASE => TRUE;
state.lastTime ← p[clockGenTime].b;
};
Assertion Checking
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 cell—can'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"]]];
Sisyph.Store[cx: cx, var: Sisyph.globalNamesRope, value: Sisyph.Cons["Time", Sisyph.Eval[cx, Sisyph.globalNamesRope]]];
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.