LogicCounterImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Last Edited by: Louis Monier January 8, 1987 1:45:05 pm PST
Jean-Marc Frailong March 26, 1987 5:29:45 pm PST
Barth, October 22, 1986 11:48:51 am PDT
DIRECTORY CoreCreate, CoreOps, IO, Logic, LogicUtils, Static, Sisyph;
LogicCounterImpl: CEDAR PROGRAM
IMPORTS CoreCreate, CoreOps, IO, Logic, LogicUtils, Static, Sisyph
EXPORTS Logic
= BEGIN OPEN Logic, CoreCreate;
Counter - This type of counter is obsolete and should be rewritten/deleted
CounterName: ROPE = "Counter";
Counter: PUBLIC PROC [b: NAT] RETURNS [ct: CellType] = {
counter1B: CellType ← LogicUtils.Extract["counter1B.sch", TRUE]; -- designed by Alfred
insts: CellInstances ← NIL;
IF b=0 THEN LogicUtils.Error["Please provide the number of bits for the counter"];
IF b=1 THEN LogicUtils.Error["Sorry, but a counter must have more than one bit"];
FOR i: NAT IN [0..b) DO
insts ← CONS[
Instance[counter1B,
["dataIn", Index["Input", i]], ["Output", Index["Output", i]],
["carryIn", IF i=b-1 THEN "Cin" ELSE Index["carry", i]],
["carryOut", IF i=0 THEN "Cout" ELSE Index["carry", i-1]],
["nCount", "s1"], ["LoadOrDown", "s0"]],
insts];
ENDLOOP;
ct ← Cell[
name: CounterName,
public: Wires["Vdd", "Gnd", "s0", "s1", "Cin", "Cout", "CK", Seq["Input", b], Seq["Output", b]],
onlyInternal: Wires[Seq["carry", b-1]],
instances: insts];
};
CounterUp - Two flavors, ripple (slow) and lookahead (fast)
CounterUp: PUBLIC PROC [b: NAT, type: CounterType] RETURNS [ct: CellType] = {
Public: Cin, Cout, Load, Count, Input[b], Output[b], nOutput[b]
Two types of CounterUp maye be generated: ripple and lookahead. Ripple is smaller, but much slower (refer to curves in documentation). Lookahead is faster, and should barely make it to 40MHz for 32 bits. It might be necessary in the future to add a new flavor, pipelined counters.
BufferCell: PROC [name: ROPE, drive: NAT] RETURNS [ct: CellType] ~ {
Extract the cell with the "drive" context variable set to NEW [NAT ← drive]. Avoids perturbing the LogicUtils context for nothing...
cx: Sisyph.Context ← Sisyph.Copy[LogicUtils.GetLogicContext[]];
Sisyph.Store[cx, "drive", NEW[NAT ← drive]];
ct ← Sisyph.ES[name, cx];
};
RippleCounterUp: PROC [b: NAT] RETURNS [ct: CellType] = {
Ripple counter up generator. Bits are generated in pairs (slightly faster and smaller), and an odd bit is added as MSB if needed.
ctCell2: CellType = LogicUtils.Extract["counterUp2B.sch", TRUE]; -- for each pair of bits
ctCell1: CellType = LogicUtils.Extract["counterUp1B.sch", TRUE]; -- termination for odd b
insts: CellInstances;
input, output, nOutput, carry, cout: Wire;
pairs: NAT = b/2; -- number of full bit pairs
odd: NAT = b-2*pairs; -- 1 if b is odd, 0 if b is even
input ← Seq["Input", b];
output ← Seq["Output", b];
nOutput ← Seq["nOutput", b];
carry ← Seq["carry", b/2];
insts ← LIST [Instance[BufferCell["counterUpCtrl.sch", (b+3)/4]]]; -- driver cell
FOR i: NAT IN [0..pairs) DO -- setup the cell pairs
bit: NAT ← 2*i+odd; -- index of high-order bit of current pair
insts ← CONS[
Instance[ctCell2,
["QL", output[bit+1]], ["QH", output[bit]],
["nQL", nOutput[bit+1]], ["nQH", nOutput[bit]],
["inputL", input[bit+1]], ["inputH", input[bit]],
["carryIn", IF i=pairs-1 THEN "Cin" ELSE carry[i+1]],
["carryOut", carry[i]],
["load", "load"], ["count", "count"], ["nLoad", "nLoad"], ["CK", "CK"]],
insts];
ENDLOOP;
IF odd=0 THEN cout ← CoreOps.SetShortWireName[carry[0], "Cout"]
ELSE { -- need to add special 1-bit cell as MSB of the counter
cout ← CoreOps.CreateWire[name: "Cout"];
insts ← CONS[
Instance[ctCell1,
["Q", output[0]],
["nQ", nOutput[0]],
["input", input[0]],
["carryIn", carry[0]],
["carryOut", cout],
["load", "load"], ["count", "count"], ["nLoad", "nLoad"], ["CK", "CK"]],
insts];
};
ct ← Cell[
name: IO.PutFR["RippleCounterUp%g", IO.int[b]],
public: Wires["Vdd", "Gnd", "CK", "Load", "Count", "Cin", cout, input, output, nOutput],
onlyInternal: Wires[carry, "load", "nLoad", "count"],
instances: insts];
};
ClpBy2: PROC [n: NAT] RETURNS [ct: CellType] = {
Public: PIn[n], nCOut[n], CIn, COut (of the counter. CIn must also enable counting)
Carry lookahead propagation for a counter. Merges by steps of 2 and inverts at each stage. The construction is not recursive because orphan bits raise trouble in the recursive structure. Internal instances are named to help troubleshooting.
clpCell2: ARRAY BOOL OF CellType ← [
LogicUtils.Extract["counterCLP2N.sch"], -- stages with negative PIn, CIn
LogicUtils.Extract["counterCLP2P.sch"]]; -- stages with positive PIn, CIn
clpCell1: CellType ← LogicUtils.Extract["counterCLPX1.sch"]; -- for orphan bits
insts: CellInstances ← NIL;
internals: LIST OF WRNIL;
publicPIn, publicCOut: Wire; -- the public wires
pIn, cOut, pOut, cIn: Wire; -- wires between stages
polarity: BOOLTRUE; -- polarity of PIn for current stage
publicPIn ← Seq["PIn", n];
publicCOut ← Seq["nCOut", n];
pOut ← publicPIn; cIn ← publicCOut;
FOR size: NAT ← n, (size+1)/2 WHILE size>2 DO -- for each stage, size = nbr of stage inputs
This loop does all except for the last stage
blocks: NAT = (size+1)/2; -- CLP cells for this stage
pIn ← pOut; cOut ← cIn; -- transfer from lower stage
pOut ← Seq[size: blocks]; cIn ← Seq[size: blocks]; -- to next stage
internals ← CONS [pOut, CONS [cIn, internals]]; -- add "outputs" to internals
FOR i: NAT IN [0..blocks) DO
source: NAT = 2*i; -- index into pIn, cOut
IF source=size-1 THEN { -- special case, 1 single bit, always LSB, may be orphan
insts ← CONS[
InstanceList[
type: clpCell1,
pas: LIST [["PIn", pIn[source]], ["COut", cOut[source]], ["POut", pOut[i]], ["CIn", cIn[i]]],
name: IO.PutFR["%g/%g", IO.int[i], IO.int[blocks]]],
insts];
}
ELSE { -- 2 input CLP, may be negative or positive
insts ← CONS[
InstanceList[
type: clpCell2[polarity],
pas: LIST [["PIn0", pIn[source]], ["PIn1", pIn[source+1]], ["COut0", cOut[source]], ["COut1", cOut[source+1]], ["POut", pOut[i]], ["CIn", cIn[i]]],
name: IO.PutFR["%g/%g", IO.int[i], IO.int[blocks]]],
insts];
};
ENDLOOP;
polarity ← NOT polarity; -- invert polarity for next stage
ENDLOOP;
Handle last stage, always has 2 inputs. A special trick removes the carry input
IF polarity THEN -- last stage: positive inputs
insts ← CONS[
Instance[LogicUtils.Extract["counterCLP2PL.sch"],
["Force", "Vdd"],
["PIn", pOut],
["COut", cIn],
["CIn", "CIn"], ["COutX", "COut"]],
insts]
ELSE -- last stage: negative inputs
insts ← CONS[
Instance[LogicUtils.Extract["counterCLP2NL.sch"],
["Force", "Gnd"],
["PIn", pOut],
["COut", cIn],
["CIn", "CIn"], ["COutX", "COut"]],
insts];
ct ← Cell[
name: IO.PutFR["CLP%g", IO.int[n]],
public: Wires["Vdd", "Gnd", publicPIn, publicCOut, "COut", "CIn"],
onlyInternal: WireList[internals],
instances: insts];
};
LookaheadCounterUp: PROC [b: NAT] RETURNS [ct: CellType] ~ {
Lookahead counter up generator. A carry propagation tree is generated by CLP and assembled here.
ctBit: CellType = LogicUtils.Extract["counterUp1B2.sch", TRUE]; -- basic counter bit, inverted Cin
insts: CellInstances;
input, output, nOutput, ncarry: Wire;
input ← Seq["Input", b];
output ← Seq["Output", b];
nOutput ← Seq["nOutput", b];
ncarry ← Seq["ncarry", b];
insts ← LIST [Instance[BufferCell["counterUpCtrl2.sch", (b+3)/4]]]; -- driver cell
FOR i: NAT IN [0..b) DO -- collect elementary bits
insts ← CONS[
Instance[ctBit,
["Q", output[i]],
["nQ", nOutput[i]],
["input", input[i]],
["ncin", ncarry[i]],
["load", "load"], ["ncount", "ncount"], ["nLoad", "nLoad"], ["CK", "CK"]],
insts];
ENDLOOP;
insts ← CONS[ -- add the carry lookahead logic
Instance[ClpBy2[b],
["PIn", output], ["nCOut", ncarry], ["COut", "Cout"], ["CIn", "Cin"]],
insts];
ct ← Cell[
name: IO.PutFR["FastCounterUp%g", IO.int[b]],
public: Wires["Vdd", "Gnd", "CK", "Load", "Count", "Cin", "Cout", input, output, nOutput],
onlyInternal: Wires[ncarry, "load", "nLoad", "ncount"],
instances: insts];
};
IF b=0 THEN LogicUtils.Error["Please provide the number of bits for the up counter"];
IF b=1 THEN LogicUtils.Error["Sorry, but a counter must have more than one bit"];
ct ← IF type=ripple THEN RippleCounterUp[b] ELSE LookaheadCounterUp[b];
};
CounterUpName: ROPE = "CounterUp";
CounterUp: PUBLIC PROC [b: NAT, type: CounterType] RETURNS [ct: CellType] = {
CounterType: TYPE ~ {ripple, lookahead, best};
ctCell: CellType ← LogicUtils.Extract["counterUp1B.sch", TRUE];
ctCtrl: CellType;
insts: CellInstances;
input, output, nOutput, carry, cout: Wire;
IF b=0 THEN LogicUtils.Error["Please provide the number of bits for the up counter"];
IF b=1 THEN LogicUtils.Error["Sorry, but a counter must have more than one bit"];
Sisyph.Store[LogicUtils.GetLogicContext[], "publicD", NEW[NATIF b<4 THEN 1 ELSE b/4]];
ctCtrl ← LogicUtils.Extract["counterUp1BCtrl.sch"];
insts ← LIST[Instance[ctCtrl]];
input ← Seq["Input", b];
output ← Seq["Output", b];
nOutput ← Seq["nOutput", b];
carry ← Seq["carry", b];
cout ← CoreOps.SetShortWireName[carry[0], "Cout"];
FOR i: NAT IN [0..b) DO
insts ← CONS[
Instance[ctCell,
["Q", output[i]],
["nQ", nOutput[i]],
["input", input[i]],
["carryIn", IF i=b-1 THEN "Cin" ELSE carry[i+1]],
["carryOut", carry[i]],
["load", "load"], ["count", "count"], ["en", "en"], ["nEn", "nEn"], ["CK", "CK"]],
insts];
ENDLOOP;
ct ← Cell[
name: CounterUpName,
public: Wires["Vdd", "Gnd", "CK", "Load", "Count", "Cin", cout, input, output, nOutput],
onlyInternal: Wires["load", "count", "en", "nEn", carry ],
instances: insts];
};
TestCounterUp: PROC [b: NAT] RETURNS [ct: CellType] = {
ctCell: CellType ← LogicUtils.SCBlock[LogicUtils.Extract["counterUp1B.sch", TRUE]];
ctCtrl: CellType;
insts: CellInstances;
input, output, nOutput, carry, cout: Wire;
IF b=0 THEN LogicUtils.Error["Please provide the number of bits for the up counter"];
IF b=1 THEN LogicUtils.Error["Sorry, but a counter must have more than one bit"];
Sisyph.Store[LogicUtils.cx, "publicD", NEW[NATIF b<4 THEN 1 ELSE b/4]];
ctCtrl ← LogicUtils.Extract["counterUp1BCtrl.sch"];
insts ← LIST[Instance[ctCtrl]];
input ← Seq["Input", b];
output ← Seq["Output", b];
nOutput ← Seq["nOutput", b];
carry ← Seq["carry", b];
cout ← CoreOps.SetShortWireName[carry[0], "Cout"];
FOR i: NAT IN [0..b) DO
insts ← CONS[
Instance[ctCell,
["Q", output[i]],
["nQ", nOutput[i]],
["input", input[i]],
["carryIn", IF i=b-1 THEN "Cin" ELSE carry[i+1]],
["carryOut", carry[i]],
["load", "load"], ["count", "count"], ["freeze", "freeze"], ["CK", "CK"]],
insts];
ENDLOOP;
ct ← Cell[
name: CounterUpName,
public: Wires["Vdd", "Gnd", "CK", "Load", "Count", "Cin", cout, input, output, nOutput],
onlyInternal: Wires["load", "count", "freeze", carry ],
instances: insts];
};
Left-ShiftReg
ShRegName: ROPE = "ShReg";
ShRegLeft: PUBLIC PROC [b: NAT] RETURNS [ct: CellType] = {
shCell: CellType ← LogicUtils.Extract["shReg1B.sch", TRUE];
shCtrl: CellType;
insts: CellInstances;
output, outMSB: Wire;
IF b=0 THEN LogicUtils.Error["Please provide the number of bits for the shift register"];
IF b=1 THEN LogicUtils.Error["A shift register must have more than one bit"];
Sisyph.Store[LogicUtils.GetLogicContext[], "publicD", NEW[NATIF b<4 THEN 1 ELSE b/4]];
shCtrl ← LogicUtils.Extract["shRegCtrl.sch"];
insts ← LIST[Instance[shCtrl]];
output ← Seq["Output", b];
outMSB ← CoreOps.SetShortWireName[output[0], "outMSB"];
FOR i: NAT IN [0..b) DO
insts ← CONS[
Instance[shCell,
["Q", output[i]],
["prev", IF i=b-1 THEN "inLSB" ELSE output[i+1]],
["nQ", Index["nOutput", i]],
["input", Index["Input", i]],
["load", "load"], ["shift", "shift"], ["en", "en"], ["nEn", "nEn"], ["CK", "CK"]],
insts];
ENDLOOP;
ct ← Cell[
name: ShiftRegName,
public: Wires["Vdd", "Gnd", "CK", "Load", "Shift", "inLSB", outMSB, Seq["Input", b], output, Seq["nOutput", b]],
onlyInternal: Wires["load", "shift", "en", "nEn"],
instances: insts];
};
ShiftReg
ShiftRegName: ROPE = "ShiftReg";
ShiftReg: PUBLIC PROC [b: NAT] RETURNS [ct: CellType] = {
ff: CellType ← FF4[];
insts: CellInstances ← NIL;
fake: Wire ← Static.UnconnectedOK[Seq["fake", b]];
IF b=0 THEN LogicUtils.Error["Please provide the number of bits for the shift register"];
IF b=1 THEN LogicUtils.Error["A shift register must have more than one bit"];
FOR i: NAT IN [0..b) DO
insts ← CONS[
Instance[ff,
["D0", IF i=0 THEN "inR" ELSE Index["Output", i-1]],
["D1", IF i=b-1 THEN "inL" ELSE Index["Output", i+1]],
["D2", Index["Output", i]],
["D3", Index["Input", i]],
["Q", Index["Output", i]],
["NQ", Index[fake, i]],
["s0", "s0"], ["s1", "s0"], ["s2", "s1"]],
insts];
ENDLOOP;
ct ← Cell[
name: ShiftRegName,
public: Wires["Vdd", "Gnd", "s0", "s1", "CK", "inL", "inR", Seq["Input", b], Seq["Output", b]],
onlyInternal: Wires[fake],
instances: insts];
};
END.
[] ← Counter[2];
[] ← ShiftReg[2];