Decoded b-Bit n-Input multiplexer
-- A simple sequence of muxDN1; easier to layout and faster than the encoded version!
-- I still have to add the buffers on the select lines (*)
MuxDName: ROPE = Rosemary.Register[roseClassName: "MuxD", init: MuxInit, evalSimple: MuxDSimple];
MuxD:
PUBLIC
PROC [n, b:
NAT]
RETURNS [ct: CellType] = {
wl: LIST OF WR ← NIL;
muxDN1: CellType ← MuxDN1[n];
inputOfMux: Wire ← FindWire[muxDN1.public, "In"];
insts: CellInstances ← NIL;
input: Wire ← Seq["In", n, Seq[size: b]];
output: Wire ← Seq["Output", b];
select: Wire ← Seq["Select", n];
IF n=0 OR b=0 THEN LogicUtils.Error["Please provide parameters for decoded multiplexer"];
IF b=1 THEN LogicUtils.Error["Please use the 1-bit version of the multiplexer"];
IF n=1 THEN LogicUtils.Error["What the hell is a 1-input decoded multiplexer ???"];
-- Create b instances of type MuxDN1[n], with pretty complex bindings
FOR bit:
NAT
IN [0..b)
DO
pas: LIST OF PA;
actual: Wire;
wrs: LIST OF WR ← NIL;
FOR choice:
NAT
DECREASING
IN [0..n)
DO
wrs ← CONS[input[choice][bit], wrs];
ENDLOOP;
actual ← WireList[wrs];
wl ← CONS[actual, wl];
pas ← LIST[["Output", output[bit]], ["Select", select], [inputOfMux, actual]];
insts ← CONS[InstanceList[muxDN1, pas], insts];
ENDLOOP;
ct ← Cell[
name: MuxName,
public: Wires["Vdd", "Gnd", select, input, output],
onlyInternal: WireList[wl],
instances: insts];
[] ← Rosemary.BindCellType[cellType: ct, roseClassName: MuxDName];
[] ← CoreFlat.CellTypeCutLabels[ct, macroCutSet];
Ports.InitPorts[ct, l, none, "Vdd", "Gnd"];
Ports.InitPorts[ct, ls, none, "Select"];
Ports.InitPorts[ct, ls, drive, "Output"];
FOR i: NAT IN [0..n) DO Ports.InitPorts[ct, ls, none, input[i]]; ENDLOOP;
};
WhichSingleHigh:
PROC [ls: Ports.LevelSequence]
RETURNS [n:
NAT ←
LAST[
NAT], ok:
BOOL ←
FALSE] ~ {
FOR i:
NAT
IN [0..ls.size)
DO
SELECT
TRUE
FROM
ls[i]=X => RETURN[i, FALSE]; -- invalid select line
ls[i]=H AND ok => RETURN[n, FALSE]; -- more than one high
ls[i]=H AND ~ok => {n ← i; ok ← TRUE}; -- remember this one
ENDCASE => NULL;
ENDLOOP;
};
MuxDSimple: Rosemary.EvalProc = {
state: MuxState ← NARROW[stateAny];
n: NAT; ok: BOOL;
[n, ok] ← WhichSingleHigh[p[state.select].ls];
IF ok THEN Ports.CopyLS[from: p[state.in][n].ls, to: p[state.out].ls]
ELSE Ports.SetLS[p[state.out].ls, X];
};
Encoded Muxes
-- Make a special case for n=2, 3, 4 using the 1-bit decoded vesion and buffers (*)
MuxName: ROPE = Rosemary.Register[roseClassName: "Mux", init: MuxInit, evalSimple: MuxSimple];
Mux:
PUBLIC
PROC [n, b:
NAT]
RETURNS [ct: CellType] = {
sizeSel: INT ← BitOps.NBits[n];
input: Wire ← Seq["In", n, Seq[size: b]];
insts: CellInstances ←
LIST[
Instance[DecoderS[sizeSel, n], ["Address", "Select"], ["Select", "decoded"]],
Instance[MuxD[n, b], ["Select", "decoded"], ["In", "In"], ["Output", "Output"]]];
ct ← Cell[
name: MuxName,
public: Wires["Vdd", "Gnd", Seq["Select", sizeSel], input, Seq["Output", b]],
onlyInternal: Wires[Seq["decoded", n]],
instances: insts];
[] ← Rosemary.BindCellType[cellType: ct, roseClassName: MuxName];
[] ← CoreFlat.CellTypeCutLabels[ct, macroCutSet];
Ports.InitPorts[ct, l, none, "Vdd", "Gnd"];
Ports.InitPorts[ct, ls, none, "Select"];
Ports.InitPorts[ct, ls, drive, "Output"];
FOR i: NAT IN [0..n) DO Ports.InitPorts[ct, ls, none, input[i]]; ENDLOOP;
};
MuxState: TYPE = REF MuxStateRec;
MuxStateRec:
TYPE =
RECORD [
select, in, out: NAT ← LAST[NAT]];
MuxInit: Rosemary.InitProc = {
state: MuxState ← NEW[MuxStateRec];
[state.select, state.in, state.out] ← Ports.PortIndexes[cellType.public, "Select", "In", "Output"];
stateAny ← state};
MuxSimple: Rosemary.EvalProc = {
state: MuxState ← NARROW[stateAny];
IF LogicUtils.HasX[p[state.select].ls] THEN Ports.SetLS[p[state.out].ls, X]
ELSE {
sel: NAT ← Ports.LSToC[p[state.select].ls];
IF sel>=p[state.in].size THEN Rosemary.Stop[];
Ports.CopyLS[from: p[state.in][sel].ls, to: p[state.out].ls];
};
};
Decoder
-- The simple decoder is implemented as "s" a-input nors; each input is inverted twice to produce complementary values, and the inputs of the nors are chosen among those.
DecoderSName: ROPE = Rosemary.Register[roseClassName: "DecoderS", init: DecoderSInit, evalSimple: DecoderSSimple];
DecoderS:
PUBLIC
PROC [a:
NAT, s:
NAT ← 0]
RETURNS [ct: CellType] = {
inv, nor: CellType;
norInput, address, nAd, nnAd, select: Wire;
insts: CellInstances ← NIL;
IF a=0 THEN LogicUtils.Error["Please provide parameter(s) for decoder"];
IF s=0 THEN s ← BitOps.TwoToThe[a];
IF a=1
THEN
SELECT s
FROM
1 => RETURN[LogicUtils.Extract["decoder11.sch", TRUE]];
2 => RETURN[LogicUtils.Extract["decoder12.sch", TRUE]];
ENDCASE => NULL;
inv ← Inv[];
nor ← Nor[a];
norInput ← FindWire[nor.public, "I"];
address ← Seq["Address", a];
nAd ← Seq["nAd", a];
nnAd ← Seq["nnAd", a];
select ← Seq["Select", s];
-- inverter pairs on all inputs
FOR i:
NAT
IN [0..a)
DO
insts ← CONS[Instance[inv, ["I", address[i]], ["X", nAd[i]] ], insts];
insts ← CONS[Instance[inv, ["I", nAd[i]], ["X", nnAd[i]] ], insts];
ENDLOOP;
-- one a-input nor per output
FOR i:
NAT
IN [0..s)
DO
pas: LIST OF PA ← LIST[["X", select[i]]];
-- recognize the input "i"
FOR in:
NAT
IN [0..a)
DO
pas ← CONS[[norInput[in], IF BitOps.EBFW[i, in, a] THEN nAd[in] ELSE nnAd[in]], pas];
ENDLOOP;
insts ← CONS[InstanceList[nor, pas], insts];
ENDLOOP;
ct ← Cell[name: DecoderSName,
public: Wires["Vdd", "Gnd", address, select],
onlyInternal: Wires[nAd, nnAd],
instances: insts];
[] ← Rosemary.BindCellType[cellType: ct, roseClassName: DecoderSName];
[] ← CoreFlat.CellTypeCutLabels[ct, macroCutSet];
Ports.InitPorts[ct, l, none, "Vdd", "Gnd"];
Ports.InitPorts[ct, ls, none, "Address"];
Ports.InitPorts[ct, ls, drive, "Select"];
};
DecoderState: TYPE = REF DecoderStateRec;
DecoderStateRec:
TYPE =
RECORD [
decoderAd, decoderSel, decoderEnable: NAT ← LAST[NAT]];
DecoderSInit: Rosemary.InitProc = {
state: DecoderState ← NEW[DecoderStateRec];
[state.decoderAd, state.decoderSel] ← Ports.PortIndexes[cellType.public, "Address", "Select"];
stateAny ← state};
DecoderSSimple: Rosemary.EvalProc = {
state: DecoderState ← NARROW[stateAny];
ad: NAT;
IF LogicUtils.HasX[p[state.decoderAd].ls] THEN {Ports.SetLS[p[state.decoderSel].ls, X]; RETURN};
ad ← Ports.LSToC[p[state.decoderAd].ls];
IF ad>p[state.decoderSel].ls.size THEN LogicUtils.Error["The address is out of bounds"];
Ports.SetLS[p[state.decoderSel].ls, L];
p[state.decoderSel].ls[ad] ← H;
};
-- The decoder with enable: if enable=L all outputs are low
DecoderName: ROPE = Rosemary.Register[roseClassName: "Decoder", init: DecoderInit, evalSimple: DecoderSimple];
Decoder:
PUBLIC
PROC [a:
NAT, s:
NAT ← 0]
RETURNS [ct: CellType] = {
inv: CellType ← Inv[];
nor: CellType ← Nor[a+1]; -- one more input for nEnable
norInput: Wire ← FindWire[nor.public, "I"];
insts: CellInstances ← LIST[Instance[inv, ["I", "Enable"], ["X", "nEnable"]]]; -- invert enable
address: Wire ← Seq["Address", a];
nAd: Wire ← Seq["nAd", a];
nnAd: Wire ← Seq["nnAd", a];
select: Wire;
IF s=0 THEN s ← BitOps.TwoToThe[a];
select ← Seq["Select", s];
-- inverter pairs on all inputs
FOR i:
NAT
IN [0..a)
DO
insts ← CONS[Instance[inv, ["I", address[i]], ["X", nAd[i]] ], insts];
insts ← CONS[Instance[inv, ["I", nAd[i]], ["X", nnAd[i]] ], insts];
ENDLOOP;
-- one (a+1)-input nor per output
FOR i:
NAT
IN [0..s)
DO
pas: LIST OF PA ← LIST[["X", select[i]], [norInput[a], "nEnable"]];
-- recognize the input "i"
FOR in:
NAT
IN [0..a)
DO
pas ← CONS[[norInput[in], IF BitOps.EBFW[i, in, a] THEN nAd[in] ELSE nnAd[in]], pas];
ENDLOOP;
insts ← CONS[InstanceList[nor, pas], insts];
ENDLOOP;
ct ← Cell[name: DecoderName,
public: Wires["Vdd", "Gnd", address, select, "Enable"],
onlyInternal: Wires[nAd, nnAd, "nEnable"],
instances: insts];
[] ← Rosemary.BindCellType[cellType: ct, roseClassName: DecoderName];
[] ← CoreFlat.CellTypeCutLabels[ct, macroCutSet];
Ports.InitPorts[ct, l, none, "Vdd", "Gnd", "Enable"];
Ports.InitPorts[ct, ls, none, "Address"];
Ports.InitPorts[ct, ls, drive, "Select"];
};
DecoderInit: Rosemary.InitProc = {
state: DecoderState ← NEW[DecoderStateRec];
[state.decoderAd, state.decoderSel, state.decoderEnable] ← Ports.PortIndexes[cellType.public, "Address", "Select", "Enable"];
stateAny ← state};
DecoderSimple: Rosemary.EvalProc = {
state: DecoderState ← NARROW[stateAny];
SELECT p[state.decoderEnable].l
FROM
L => Ports.SetLS[p[state.decoderSel].ls, L];
H => {
ad: NAT;
IF LogicUtils.HasX[p[state.decoderAd].ls] THEN {Ports.SetLS[p[state.decoderSel].ls, X]; RETURN};
ad ← Ports.LSToC[p[state.decoderAd].ls];
IF ad>p[state.decoderSel].ls.size THEN LogicUtils.Error["The address is out of bounds"];
Ports.SetLS[p[state.decoderSel].ls, L]; p[state.decoderSel].ls[ad] ← H};
ENDCASE => Ports.SetLS[p[state.decoderSel].ls, X];
};