DAToolsIntroAdder4BehProc.mesa
Bland, October 9, 1987 12:07:21 pm PDT
Louis Monier October 9, 1987 9:56:34 am PDT
The Directory Statement lists all interfaces needed at compile time.
DIRECTORY
Core, CoreClasses, CoreCreate, Ports, Rope, Rosemary, RosemaryUser;
DAToolsIntroAdder4BehProc: CEDAR PROGRAM
The Import Statement lists all interfaces needed at run time.
IMPORTS CoreClasses, CoreCreate, Ports, Rosemary
~ BEGIN
CellType : TYPE = Core.CellType;
CellTypes: TYPE = LIST OF Core.CellType;
Level: TYPE = Ports.Level;
Properties : TYPE = Core.Properties;
ROPE: TYPE = Core.ROPE;
Wire: TYPE = Core.Wire;
Wires: TYPE = Core.Wires;
PA is a binding between a public wire of the celltype and the corresponding actual wire of a cellInstance
PA: TYPE = CoreCreate.PA;
WR: TYPE = CoreCreate.WR;
FlipFlop: TYPE = RECORD[master, slave: Ports.Level];
FlipFlops: TYPE = RECORD[master, slave: Ports.LevelSequence];
AdderState: TYPE = REF AdderStateRec;
AdderStateRec: TYPE = RECORD [
reg1: FlipFlop, -- holds the carry out
reg4: FlipFlops, -- holds the sum
en, CIN, A, B, SUM, Cout, Clock: NAT
];
Adder4Definition: PUBLIC PROC [] RETURNS [ct: CellType] = {
The name and size of all structured public wires must be given. Atomic public wires are named without size.
public: Wire ← CoreCreate.WireList[
LIST[
CoreCreate.Seq["SUM",4],
CoreCreate.Seq["A",4],
CoreCreate.Seq["B",4],
"en",
"Clock",
"Cout",
"CIN"
]];
This creates a celltype with the two things that Rosemary needs: the celltype's public wire sequence and its property list.
ct ← CoreClasses.CreateUnspecified[public: public];
[] ← Rosemary.BindCellType[cellType: ct, roseClassName: Adder4BehProcName];
ls = level sequence, used for structured wires.
l = level, used for atomic wires.
The Oracle's inputs, Cout and SUM, have drive. Its outputs do not.
Ports.InitPorts[ct, ls, none, "A", "B"];
Ports.InitPorts[ct, l, none, "en", "Clock", "CIN"];
Ports.InitPorts[ct, l, drive, "Cout"];
Ports.InitPorts[ct, ls, drive,"SUM"];
};
Adder4BehProcInit: Rosemary.InitProc = {
--PROC [cellType: Core.CellType, p: Ports.Port, oldStateAny: REF ANY ← NIL] RETURNS [stateAny: REF ANY ← NIL]--
adderstate: AdderState ← IF oldStateAny=NIL THEN NEW[AdderStateRec] ELSE NARROW[oldStateAny, AdderState];
adderstate.reg4.master ← NEW[Ports.LevelSequenceRec[4]];
adderstate.reg4.slave ← NEW[Ports.LevelSequenceRec[4]];
Ports.SetLS[adderstate.reg4.master, X];
Ports.SetLS[adderstate.reg4.slave, X];
adderstate.reg1.master ← X;
adderstate.reg1.slave ← X;

This next procedure call is a convenience. It returns the indices of the wires in the public. Names are chosen to allow the sequence of port wires to be indexed by familiar names rather than numbers.
{OPEN adderstate; -- to avoid having to say adderstate.mumble ... --
[en, CIN, A, B, SUM, Cout, Clock] ← Ports.PortIndexes[cellType.public, "en", "CIN", "A", "B","SUM", "Cout", "Clock"];
};
stateAny ← adderstate;
};
Adder4BehProcEval: Rosemary.EvalProc = {
--PROC [p: Ports.Port, stateAny: REF ANY, clockEval: BOOL]--
This procedure models an edge-triggered flipflop.
i, numHigh: INT;
adderstate: AdderState ← NARROW[stateAny];
{OPEN adderstate;
The purpose of the clockEval is to decompose each settle in two phases in order to let the clocks settle before using them to modify states. A typical test proc is composed of two calls to the Eval proc, one with clockEval=TRUE, during which all combinatorial paths settle, including clocks, but during which no state depending on a clock is changed; then one with clockEval=FALSE where everything must be evaluated.
Inputs are copied into the master portion of the flipflop while the clock is low and enable is high.
IF ~clockEval AND p[Clock].l=L AND p[en].l=H THEN {
sum: Ports.Level;
carry: Ports.Level ← p[CIN].l;
numHigh ← 0;
FOR i DECREASING IN [0..3] DO
[carry, sum] ← Ports.SumL[p[A].ls[i], p[B].ls[i], carry];
adderstate.reg4.master[i] ← sum;
ENDLOOP;
adderstate.reg1.master ← carry;
};
Values are output by the slave portion of the edge-triggered flipflop when the clock is high. (Enable is only an input to the master part of the flipflop, c.f. Logic.)
IF ~clockEval AND p[Clock].l=H THEN{
Ports.CopyLS[from: adderstate.reg4.master, to: adderstate.reg4.slave];
adderstate.reg1.slave ← adderstate.reg1.master;
};
Always assign the values of the registers to the output wires.
p[Cout].l ← adderstate.reg1.slave;
Ports.CopyLS[from: adderstate.reg4.slave, to: p[SUM].ls];
}};
Most important: If the cell has edge-triggered behavior, register it with scheduleIfClockEval: TRUE
Adder4BehProcName: ROPE = Rosemary.Register[roseClassName: "Adder4Definition", init: Adder4BehProcInit, evalSimple: Adder4BehProcEval, scheduleIfClockEval: TRUE];
END.