<> <> <> <> <> <> <<>> DIRECTORY CoreCreate, IO, Logic, LogicUtils, Ports, Rosemary; LogicCounterImpl: CEDAR PROGRAM IMPORTS CoreCreate, IO, LogicUtils, Ports EXPORTS Logic = BEGIN OPEN LogicUtils, CoreCreate; <> <> CounterState: TYPE ~ REF CounterStateRec; CounterStateRec: TYPE ~ RECORD [ <> cin, cout, load, input, output, noutput, ck: NAT _ LAST[NAT], -- all counters count: NAT _ LAST[NAT], -- up only bin, bout, up, down: NAT _ LAST[NAT], -- up/down only master, slave: Ports.LevelSequence ]; <> CounterCLG: PUBLIC PROC [n: NAT] RETURNS [ct: CellType] = { < PIn[n], nCOut[n], CIn, COut (of the counter. CIn must also enable counting)>> <> clpCell2: ARRAY BOOL OF CellType; -- indexed by PIn polarity clpCell1: CellType; -- 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; -- 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 <> 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; <> 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]; }; <> CounterUpRoseClass: ROPE = RoseClass["CounterUp", CounterUpInit, CounterUpSimple, TRUE]; CounterUp: PUBLIC PROC [b: NAT] RETURNS [ct: CellType] = { < Cin, Cout, Load, Count, Input[b], Output[b], nOutput[b]>> <> 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, CounterUpRoseClass]; 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; }; <> CounterUpDownRoseClass: ROPE = RoseClass["CounterUpDown", CounterUpDownInit, CounterUpDownSimple, TRUE]; CounterUpDown: PUBLIC PROC [b: NAT] RETURNS [ct: CellType] = { < Cin, Cout, Bin, Bout, Load, Up, Down, Input[b], Output[b], nOutput[b]>> <> 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, CounterUpDownRoseClass]; 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]; }; <> <> 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]; }; <> 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.