~
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 = public or actual wires
PA: TYPE = CoreCreate.PA;
WR: TYPE = CoreCreate.WR;
FlipFlop: TYPE = RECORD[master, slave: Ports.Level];
AdderState: TYPE = REF AdderStateRec;
AdderStateRec: TYPE = RECORD [
prevClk: Ports.Level,
Reg1: FlipFlop,
Reg4: ARRAY [0..3] OF FlipFlop,
tempCin: Ports.Level
];
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" ]];
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.prevClk ← X;
FOR i:
INT
IN [0..3]
DO
adderstate.Reg4[i].master ← X;
adderstate.Reg4[i].slave ← X;
ENDLOOP;
adderstate.Reg1.master ← X;
adderstate.Reg1.slave ← X;
This next procedure call is a convenience. It returns the names of the wires as numerical indices, thus allowing the sequence of port wires to be indexed by familiar names rather than numbers.
[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]--
i, numHigh: INT;
adderstate: AdderState ← NARROW[stateAny];
This procedure models an edge-triggered flipflop. Values can be copied into the master portion of the flipflop on the falling edge of the clock if enable is high.
IF adderstate.prevClk = H AND p[Clock].l = L AND p[en].l = H
THEN {adderstate.tempCin ← p[CIN].l;
numHigh ← 0;
FOR i DECREASING IN [0..3] DO
numHigh ← 0;
IF p[A].ls[i] = H THEN numHigh ← numHigh + 1;
IF p[B].ls[i] = H THEN numHigh ← numHigh + 1;
IF adderstate.tempCin = H THEN numHigh ← numHigh + 1;
adderstate.Reg4[i].master ← IF numHigh MOD 2 = 1 THEN H ELSE L;
adderstate.tempCin ← IF numHigh >= 2 THEN H ELSE L;
ENDLOOP;
adderstate.Reg1.master ← adderstate.tempCin;};
Values are output by the slave portion of the edge-triggered flipflop when the previous clock was low and the current clock is high. (Enable is only an input to the master part of the flipflop, c.f. Logic.)
IF adderstate.prevClk = L AND p[Clock].l = H
THEN{ FOR i IN [0..3] DO
adderstate.Reg4[i].slave ← adderstate.Reg4[i].master;
ENDLOOP;
adderstate.Reg1.slave ← adderstate.Reg1.master;};
p[Cout].l ← adderstate.Reg1.slave;
FOR i:
INT
IN [0..3]
DO
p[SUM].ls[i] ← adderstate.Reg4[i].slave;
ENDLOOP;
adderstate.prevClk ← p[Clock].l;
};
Adder4BehProcName:
ROPE = Rosemary.Register[roseClassName: "Adder4Definition", init: Adder4BehProcInit, evalSimple: Adder4BehProcEval];