<> <> <> <> <<>> DIRECTORY BitOps, CoreCreate, CoreFlat, Logic, LogicUtils, Ports, Rosemary; LogicMuxesImpl: CEDAR PROGRAM IMPORTS BitOps, CoreCreate, CoreFlat, Logic, LogicUtils, Ports, Rosemary EXPORTS Logic = BEGIN OPEN Logic, CoreCreate; <> <<-- Public: "Vdd", "Gnd", Seq["Select", n], Seq["In", n], "Output">> MuxDN1Name: ROPE = "MuxDN1"; MuxDN1: PUBLIC PROC [n: NAT] RETURNS [ct: CellType] ~ { SELECT n FROM 0 => LogicUtils.Error["Please provide parameters for 1-bit decoded multiplexer"]; 1 => LogicUtils.Error["What the hell is a 1-input decoded multiplexer ???"]; 2 => RETURN[LogicUtils.Extract["NormalizedMuxD21.sch", TRUE]]; 3 => RETURN[LogicUtils.Extract["NormalizedMuxD31.sch", TRUE]]; 4 => RETURN[LogicUtils.Extract["NormalizedMuxD41.sch", TRUE]]; ENDCASE => { <<-- the output is through a single inverter>> insts: CellInstances _ LIST[Instance[Inv[], ["I", "nOutput"], ["X", "Output"]]]; <<-- In[i] is connected to an inverting tristate driver whose enable is Select[i]>> seq: CellType _ CoreCreate.SequenceCell[ baseCell: TristateI[], count: n, sequencePorts: Wires["I", "EN"]]; insts _ CONS[Instance[seq, ["I", "In"], ["EN", "Select"], ["X", "nOutput"]], insts]; ct _ Cell[ name: MuxDN1Name, public: Wires["Vdd", "Gnd", Seq["Select", n], Seq["In", n], "Output"], onlyInternal: Wires["nOutput"], instances: insts]; }; }; <> <<-- Public: "Vdd", "Gnd", Seq["Select", s], Seq["In", n], "Output", with s=NbBits[n]>> MuxN1Name: ROPE = "MuxN1"; MuxN1: PUBLIC PROC [n: NAT] RETURNS [ct: CellType] = { SELECT n FROM 0 => LogicUtils.Error["Please provide parameters for 1-bit encoded multiplexer"]; 1 => LogicUtils.Error["What the hell is a 1-input encoded multiplexer ???"]; 2 => RETURN[LogicUtils.Extract["NormalizedMux21.sch", TRUE]]; 3 => RETURN[LogicUtils.Extract["NormalizedMux31.sch", TRUE]]; 4 => RETURN[LogicUtils.Extract["NormalizedMux41.sch", TRUE]]; ENDCASE => { s: INT _ BitOps.NBits[n]; insts: CellInstances _ LIST[ Instance[MuxDN1[n], ["Select", "decoded"], ["In", "In"], ["Output", "Output"]], Instance[DecoderS[s, n], ["Address", "Select"], ["Select", "decoded"]]]; ct _ Cell[name: MuxN1Name, public: Wires["Vdd", "Gnd", Seq["Select", s], Seq["In", n], "Output"], onlyInternal: Wires[Seq["decoded", n]], instances: insts]; }; }; <> <<-- 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]; }; <> <<-- 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]; }; }; <> <<-- 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 a=1 THEN SELECT s FROM 1 => RETURN[LogicUtils.Extract["decoder11.sch", TRUE]]; 2 => RETURN[LogicUtils.Extract["decoder12.sch", TRUE]]; ENDCASE => NULL; IF s=0 THEN s _ BitOps.TwoToThe[a]; 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]; }; END. <<>>