LogicCounterImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Last Edited by: Louis Monier September 30, 1987 7:09:28 pm PDT
Bertrand Serlet April 10, 1987 3:03:04 am PDT
Jean-Marc Frailong September 14, 1987 9:55:58 pm PDT
Barth, October 22, 1986 11:48:51 am PDT
DIRECTORY CoreCreate, IO, Logic, LogicUtils, Ports, Rosemary;
LogicCounterImpl: CEDAR PROGRAM
IMPORTS CoreCreate, IO, LogicUtils, Ports
EXPORTS Logic
= BEGIN OPEN LogicUtils, CoreCreate;
Counters
Shared types
CounterState: TYPE ~ REF CounterStateRec;
CounterStateRec: TYPE ~ RECORD [
cin, cout, load, count, input, output, noutput, ck: NATLAST[NAT], -- port indices
cin, cout, load, input, output, noutput, ck: NATLAST[NAT], -- all counters
count: NATLAST[NAT], -- up only
bin, bout, up, down: NATLAST[NAT], -- up/down only
master, slave: Ports.LevelSequence
];
Lookahead carry/borrow evaluator (used through schematics only)
CounterCLG: PUBLIC 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. CIn is used only to enable COut: the partial carries are computed independently from Cin. 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; -- indexed by PIn polarity
clpCell1: CellType; -- 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: BOOL; -- polarity of PIn for current stage (TRUE means positive)
fullName: ROPE = IO.PutFR["CounterCLG n=%g", IO.int[n]];
ct ← CacheFetch[fullName];
IF ct#NIL THEN RETURN[ct];
polarity ← TRUE; -- top-level PIn is in positive logic
clpCell1 ← Extract["counterCLPX1.sch"]; -- for orphan bits
clpCell2[FALSE] ← Extract["counterCLP2N.sch"]; -- stages with negative PIn, CIn
clpCell2[TRUE] ← Extract["counterCLP2P.sch"]; -- stages with positive PIn, CIn
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[Extract["counterCLP2PL.sch"],
["Force", "Vdd"],
["PIn", pOut],
["COut", cIn],
["CIn", "CIn"], ["COutX", "COut"]],
insts]
ELSE -- last stage: negative inputs
insts ← CONS[
Instance[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];
CacheStore[fullName, ct];
};
Up counter
CounterUp: PUBLIC PROC [b: NAT] RETURNS [ct: CellType] = {
Public => Cin, Cout, Load, Count, Input[b], Output[b], nOutput[b]
Generate an up-only counter with carry lookahead logic
fullName: ROPE = IO.PutFR["CounterUp b=%g", IO.int[b]];
ct ← CacheFetch[fullName];
IF ct#NIL THEN RETURN[ct];
IF b=0 THEN Error["Please provide the number of bits for the up counter"];
IF b=1 THEN Error["Sorry, but a counter must have more than one bit"];
ct ← Extract["CounterUp.sch", LIST[["nBits", b]]];
SimulateMacro[ct, RoseClass["CounterUp", CounterUpInit, CounterUpSimple, TRUE]];
Ports.InitPorts[ct, l, none, "CK", "Cin", "Load", "Count"]; Ports.InitPorts[ct, l, drive, "Cout"];
Ports.InitPorts[ct, ls, none, "Input"]; Ports.InitPorts[ct, ls, drive, "Output", "nOutput"];
CacheStore[fullName, ct];
};
CounterUpInit: Rosemary.InitProc ~ {
state: CounterState ← IF oldStateAny=NIL THEN NEW[CounterStateRec] ELSE NARROW[oldStateAny];
b: NAT;
[state.cin, state.cout, state.load, state.count, state.input, state.output, state.noutput, state.ck] ← Ports.PortIndexes[cellType.public, "Cin", "Cout", "Load", "Count", "Input", "Output", "nOutput", "CK"];
b ← p[state.input].ls.size; -- find out number of bits in counter
state.master ← NEW[Ports.LevelSequenceRec[b]]; Ports.SetLS[state.master, X];
state.slave ← NEW[Ports.LevelSequenceRec[b]]; Ports.SetLS[state.slave, X];
Ports.SetLS[p[state.output].ls, X];
Ports.SetLS[p[state.noutput].ls, X];
p[state.cout].l ← X;
stateAny ← state;
};
CounterUpSimple: Rosemary.EvalProc ~ {
state: CounterState ← NARROW [stateAny];
tmp: Ports.Level; -- working storage
-- Evaluate new internal (master/slave) state
IF ~clockEval THEN
SELECT p[state.ck].l FROM
L => { -- copy X, input, slave or slave+1 to master
count: Ports.Level = Ports.AndL[p[state.count].l, p[state.cin].l];
SELECT TRUE FROM
p[state.load].l=X => Ports.SetLS[state.master, X]; -- unknown
p[state.load].l=H => Ports.CopyLS[p[state.input].ls, state.master]; -- load
count=X => Ports.SetLS[state.master, X]; -- unknown
count=H => { -- need to count up by 1
tmp ← H;
FOR i: NAT DECREASING IN [0..state.master.size) DO -- increment
[tmp, state.master[i]] ← Ports.SumL[state.slave[i], L, tmp];
ENDLOOP;
};
ENDCASE => Ports.CopyLS[state.slave, state.master]; -- loop back
};
H => { -- copy master to slave
Ports.CopyLS[state.master, state.slave];
};
ENDCASE => { -- clock is unknown, all becomes unknown
Ports.SetLS[state.master, X]; Ports.SetLS[state.slave, X];
};
-- Pass internal state to the output port
Ports.CopyLS[state.slave, p[state.output].ls];
Ports.NotLS[state.slave, p[state.noutput].ls];
-- Compute Cout
tmp ← p[state.cin].l; -- compute cout
FOR i: NAT IN [0..state.slave.size) DO
tmp ← Ports.AndL[state.slave[i], tmp];
ENDLOOP;
p[state.cout].l ← tmp;
};
Up/Down counter
CounterUpDown: PUBLIC PROC [b: NAT] RETURNS [ct: CellType] = {
Public => Cin, Cout, Bin, Bout, Load, Up, Down, Input[b], Output[b], nOutput[b]
Generate an up-only counter with carry lookahead logic
fullName: ROPE = IO.PutFR["CounterUpDown b=%g", IO.int[b]];
ct ← CacheFetch[fullName];
IF ct#NIL THEN RETURN[ct];
IF b=0 THEN Error["Please provide the number of bits for the up counter"];
IF b=1 THEN Error["Sorry, but a counter must have more than one bit"];
ct ← Extract["CounterUpDown.sch", LIST[["nBits", b]]];
SimulateMacro[ct, RoseClass["CounterUpDown", CounterUpDownInit, CounterUpDownSimple, TRUE]];
Ports.InitPorts[ct, l, none, "CK", "Cin", "Bin", "Load", "Up", "Down"];
Ports.InitPorts[ct, l, drive, "Cout", "Bout"];
Ports.InitPorts[ct, ls, none, "Input"]; Ports.InitPorts[ct, ls, drive, "Output", "nOutput"];
CacheStore[fullName, ct];
};
CounterUpDownInit: Rosemary.InitProc ~ {
state: CounterState ← IF oldStateAny=NIL THEN NEW[CounterStateRec] ELSE NARROW[oldStateAny];
b: NAT;
[state.cin, state.cout, state.bin, state.bout, state.up, state.down, state.load, state.input, state.output, state.noutput, state.ck] ← Ports.PortIndexes[cellType.public, "Cin", "Cout", "Bin", "Bout", "Up", "Down", "Load", "Input", "Output", "nOutput", "CK"];
b ← p[state.input].ls.size; -- find out number of bits in counter
state.master ← NEW[Ports.LevelSequenceRec[b]]; Ports.SetLS[state.master, X];
state.slave ← NEW[Ports.LevelSequenceRec[b]]; Ports.SetLS[state.slave, X];
Ports.SetLS[p[state.output].ls, X];
Ports.SetLS[p[state.noutput].ls, X];
p[state.cout].l ← X;
p[state.bout].l ← X;
stateAny ← state;
};
CounterUpDownSimple: Rosemary.EvalProc ~ {
state: CounterState ← NARROW [stateAny];
tmp: Ports.Level; -- working storage
-- Evaluate new internal (master/slave) state
IF ~clockEval THEN
SELECT p[state.ck].l FROM
L => { -- copy X, input, slave or slave+1 or slave-1 to master
up: Ports.Level = Ports.AndL[p[state.up].l, p[state.cin].l];
down: Ports.Level = Ports.AndL[p[state.down].l, p[state.bin].l];
SELECT TRUE FROM
p[state.load].l=X => Ports.SetLS[state.master, X]; -- unknown
p[state.load].l=H => Ports.CopyLS[p[state.input].ls, state.master]; -- load
up=X OR down=X => Ports.SetLS[state.master, X]; -- unknown
up=down => Ports.CopyLS[state.slave, state.master]; -- loop back
up=H => { -- need to count up
tmp ← H;
FOR i: NAT DECREASING IN [0..state.master.size) DO -- increment
[tmp, state.master[i]] ← Ports.SumL[state.slave[i], L, tmp];
ENDLOOP;
};
down=H => { -- need to count down: x-1 = ~(~x+1);
tmp ← H;
FOR i: NAT DECREASING IN [0..state.master.size) DO -- increment
[tmp, state.master[i]] ← Ports.SumL[Ports.NotL[state.slave[i]], L, tmp];
state.master[i] ← Ports.NotL[state.master[i]];
ENDLOOP;
};
ENDCASE => ERROR; -- cannot happen
};
H => { -- copy master to slave
Ports.CopyLS[state.master, state.slave];
};
ENDCASE => { -- clock is unknown, all becomes unknown
Ports.SetLS[state.master, X]; Ports.SetLS[state.slave, X];
};
-- Pass internal state to the output port
Ports.CopyLS[state.slave, p[state.output].ls];
Ports.NotLS[state.slave, p[state.noutput].ls];
-- Compute Cout
tmp ← p[state.cin].l;
FOR i: NAT IN [0..state.slave.size) DO
tmp ← Ports.AndL[state.slave[i], tmp];
ENDLOOP;
p[state.cout].l ← tmp;
-- Compute Bout
tmp ← Ports.NotL[p[state.bin].l];
FOR i: NAT IN [0..state.slave.size) DO
tmp ← Ports.OrL[state.slave[i], tmp];
ENDLOOP;
p[state.bout].l ← Ports.NotL[tmp];
};
Code for obsolete icons, should be removed ASAP
Counter - Superseded by CounterUp & CounterUpDown
Counter: PUBLIC PROC [b: NAT] RETURNS [ct: CellType] = {
insts: CellInstances ← NIL;
fullName: ROPE = IO.PutFR["ObsoleteCounter b=%g", IO.int[b]];
Obsolete["counter.icon is obsolete, use counterUp or counterUpDown"];
ct ← CacheFetch[fullName];
IF ct#NIL THEN RETURN[ct];
IF b=0 THEN Error["Please provide the number of bits for the counter"];
IF b=1 THEN Error["Sorry, but a counter must have more than one bit"];
FOR i: NAT IN [0..b) DO
insts ← CONS[
Instance[SCBlock[Extract["counter1B.sch"]], -- designed by Alfred
["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: "Counter",
public: Wires["Vdd", "Gnd", "s0", "s1", "Cin", "Cout", "CK", Seq["Input", b], Seq["Output", b]],
onlyInternal: Wires[Seq["carry", b-1]],
instances: insts];
CacheStore[fullName, ct];
};
ShiftReg - Superseded by ShReg (straight schematics)
ShiftRegName: ROPE = "ShiftReg";
ShiftReg: PUBLIC PROC [b: NAT] RETURNS [ct: CellType] = {
insts: CellInstances ← NIL;
fake: Wire ← Seq["fake", b];
fullName: ROPE = IO.PutFR["ObsoleteShiftReg b=%g", IO.int[b]];
Obsolete["shiftReg.icon is obsolete, use shReg instead"];
ct ← CacheFetch[fullName];
IF ct#NIL THEN RETURN[ct];
IF b=0 THEN Error["Please provide the number of bits for the shift register"];
IF b=1 THEN Error["A shift register must have more than one bit"];
FOR i: NAT IN [0..b) DO
insts ← CONS[
Instance[SCBlock[Extract["ff4.sch"]],
["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: "ShiftReg",
public: Wires["Vdd", "Gnd", "s0", "s1", "CK", "inL", "inR", Seq["Input", b], Seq["Output", b]],
onlyInternal: Wires[fake],
instances: insts];
CacheStore[fullName, ct];
};
END.