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 WR ← NIL;
publicPIn, publicCOut: Wire; -- the public wires
pIn, cOut, pOut, cIn: Wire; -- wires between stages
polarity: BOOL ← TRUE; -- 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];
};
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[NAT←IF 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[NAT←IF 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];
};