<> <> <> <> <> <> <<>> DIRECTORY BitOps, Core, CoreCreate, CoreOps, IO, Logic, LogicUtils, Ports, Rosemary; LogicMuxesImpl: CEDAR PROGRAM IMPORTS BitOps, CoreCreate, CoreOps, IO, Logic, LogicUtils, Ports EXPORTS Logic = BEGIN OPEN LogicUtils, CoreCreate; <> <> <<>> ReverseBits: PUBLIC PROC [b: NAT] RETURNS [public: Core.Wires] ~ { <> wA: Wire _ Seq["A", b]; wB: Wire _ Seq["B", b]; IF b=0 THEN Error["Please provide parameters for ReverseBits"]; FOR i: NAT IN [0..b) DO wB[i] _ wA[b-1-i] ENDLOOP; public _ LIST [wA, wB]; }; Transpose: PUBLIC PROC [b, w: NAT] RETURNS [public: Core.Wires] ~ { <> wSide: Wire _ Seq["wSide", w, Seq[size: b]]; bSide: Wire _ Seq["bSide", b, Seq[size: w]]; IF b=0 OR w=0 THEN Error["Please provide parameters for Transpose"]; FOR i: NAT IN [0..w) DO word: Wire = wSide[i]; FOR j: NAT IN [0..b) DO bSide[j][i] _ word[j] ENDLOOP; ENDLOOP; public _ LIST [wSide, bSide]; }; Interleave: PUBLIC PROC [b: NAT] RETURNS [public: Core.Wires] ~ { <> even: Wire _ Seq["Even", b]; odd: Wire _ Seq["Odd", b]; result: Wire _ Seq["Result", 2*b]; IF b=0 THEN Error["Please provide parameters for Interleave"]; FOR i: NAT IN [0..b) DO result[2*i] _ even[i]; result[2*i+1] _ odd[i]; ENDLOOP; public _ LIST [even, odd, result]; }; <<1-Bit multiplexers>> <> <<-- Public: "Vdd", "Gnd", Seq["Select", n], Seq["In", n], "Output">> MuxDN1: PUBLIC PROC [n: NAT] RETURNS [ct: CellType] ~ { fullName: ROPE = IO.PutFR["MuxDN1 n=%g", IO.int[n]]; ct _ CacheFetch[fullName]; IF ct#NIL THEN RETURN[ct]; SELECT n FROM 0 => Error["Please provide parameters for 1-bit decoded multiplexer"]; 1 => Error["What the hell is a 1-input decoded multiplexer ???"]; 2 => ct _ SCBlock[Extract["NormalizedMuxD21.sch"]]; 3 => ct _ SCBlock[Extract["NormalizedMuxD31.sch"]]; 4 => ct _ SCBlock[Extract["NormalizedMuxD41.sch"]]; ENDCASE => ct _ Extract["muxDN1.sch", LIST[["n", n]]]; CacheStore[fullName, ct]; }; <> <<-- Public: "Vdd", "Gnd", Seq["Select", s], Seq["In", n], "Output", with s=NbBits[n]>> MuxN1: PUBLIC PROC [n: NAT] RETURNS [ct: CellType] = { fullName: ROPE = IO.PutFR["MuxN1 n=%g", IO.int[n]]; ct _ CacheFetch[fullName]; IF ct#NIL THEN RETURN[ct]; SELECT n FROM 0 => Error["Please provide parameters for 1-bit encoded multiplexer"]; 1 => Error["What the hell is a 1-input encoded multiplexer ???"]; 2 => ct _ SCBlock[Extract["NormalizedMux21.sch"]]; 3 => ct _ SCBlock[Extract["NormalizedMux31.sch"]]; 4 => ct _ SCBlock[Extract["NormalizedMux41.sch"]]; ENDCASE => ct _ Extract["muxN1.sch", LIST[["nb", n], ["ad", BitOps.NBits[n]]]]; CacheStore[fullName, ct]; }; <> <> <> <<-- A simple sequence of muxDN1; easier to layout and faster than the encoded version!>> MuxDRoseClass: ROPE = RoseClass["MuxD", MuxInit, MuxDSimple]; MuxD: PUBLIC PROC [n, b: NAT] RETURNS [ct: CellType] = { input: Wire; fullName: ROPE = IO.PutFR["MuxD n=%g b=%g", IO.int[n], IO.int[b]]; ct _ CacheFetch[fullName]; IF ct#NIL THEN RETURN[ct]; IF n=0 OR b=0 THEN Error["Please provide parameters for decoded multiplexer"]; IF b=1 THEN Error["Please use the 1-bit version of the decoded multiplexer"]; IF n=1 THEN Error["What the hell is a 1-input decoded multiplexer ???"]; ct _ Extract[IF b<=4 THEN "MuxDSmall.sch" ELSE "MuxDLarge.sch", LIST [["nb", b], ["nw", n]]]; SimulateMacro[ct, MuxDRoseClass]; input _ CoreOps.FindWire[ct.public, "In"]; 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; CacheStore[fullName, ct]; }; 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 version and buffers (*)>> MuxRoseClass: ROPE = RoseClass["Mux", MuxInit, MuxSimple]; Mux: PUBLIC PROC [n, b: NAT] RETURNS [ct: CellType] = { input: Wire; fullName: ROPE = IO.PutFR["Mux n=%g b=%g", IO.int[n], IO.int[b]]; ct _ CacheFetch[fullName]; IF ct#NIL THEN RETURN[ct]; IF n=0 OR b=0 THEN Error["Please provide parameters for multiplexer"]; IF b=1 THEN Error["Please use the 1-bit version of the multiplexer"]; IF n=1 THEN Error["What the hell is a 1-input multiplexer ???"]; IF n=2 THEN ct _ Extract["mux2b.sch", LIST [["nb", b]]] ELSE ct _ Extract["mux.sch", LIST [["nb", b], ["nw", n], ["na", BitOps.NBits[n]]]]; SimulateMacro[ct, MuxRoseClass]; input _ CoreOps.FindWire[ct.public, "In"]; 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; CacheStore[fullName, ct]; }; MuxState: TYPE = REF MuxStateRec; MuxStateRec: TYPE = RECORD [ select, in, out: NAT _ LAST[NAT]]; MuxInit: Rosemary.InitProc = { state: MuxState _ IF oldStateAny=NIL THEN NEW[MuxStateRec] ELSE NARROW[oldStateAny]; [state.select, state.in, state.out] _ Ports.PortIndexes[cellType.public, "Select", "In", "Output"]; stateAny _ state; }; MuxSimple: Rosemary.EvalProc = { state: MuxState _ NARROW[stateAny]; IF Ports.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 Ports.SetLS[p[state.out].ls, X] -- range exceeded ELSE Ports.CopyLS[from: p[state.in][sel].ls, to: p[state.out].ls]; }; }; <> <<-- 2 inputs, n bits>> InvMuxRoseClass: ROPE = RoseClass["InvMux", InvMuxInit, InvMuxSimple]; InvMux: PUBLIC PROC [b: NAT] RETURNS [ct: CellType] = { fullName: ROPE = IO.PutFR["InvMux b=%g", IO.int[b]]; ct _ CacheFetch[fullName]; IF ct#NIL THEN RETURN[ct]; IF b=0 THEN Error["Please specify size of inverting mux"]; ct _ Extract["invMux2b.sch", LIST[["b", b]]]; SimulateMacro[ct, InvMuxRoseClass]; Ports.InitPorts[ct, l, none, "Select"]; Ports.InitPorts[ct, ls, none, "In0", "In1"]; Ports.InitPorts[ct, ls, drive, "nOut"]; CacheStore[fullName, ct]; }; InvMuxState: TYPE = REF InvMuxStateRec; InvMuxStateRec: TYPE = RECORD [ select, in0, in1, out: NAT _ LAST[NAT]]; InvMuxInit: Rosemary.InitProc = { state: InvMuxState _ NEW[InvMuxStateRec]; [state.select, state.in0, state.in1, state.out] _ Ports.PortIndexes[cellType.public, "Select", "In0", "In1", "nOut"]; stateAny _ state; }; InvMuxSimple: Rosemary.EvalProc = { state: InvMuxState _ NARROW[stateAny]; SELECT p[state.select].l FROM L => Ports.NotLS[a: p[state.in0].ls, b: p[state.out].ls]; H => Ports.NotLS[a: p[state.in1].ls, b: p[state.out].ls]; ENDCASE => Ports.SetLS[p[state.out].ls, X]; }; <> <> DecoderState: TYPE = REF DecoderStateRec; DecoderStateRec: TYPE = RECORD [decoderAd, decoderSel, decoderEnable: NAT _ LAST[NAT]]; <<-- (Address, nAd, nnAd)[0..a)>> DecoderBuffer: PROC [a: NAT] RETURNS [ct: CellType] ~ { drive: INT = BitOps.TwoToThe[a-1]; ct _ SequenceCell[baseCell: Logic.SymDriver[drive], count: a, sequencePorts: Wires["I", "nX", "X"]]; }; <> <<-- Select[0..s), (nAd, nnAd)[0..a) with a>=2>> DecoderSBody: PROC [a, s: NAT] RETURNS [ct: CellType] ~ { nor: CellType; norInput, nAd, nnAd, select: Wire; insts: CellInstances _ NIL; nor _ Logic.Nor[a]; -- a>= 2 norInput _ FindWire[nor.public, "I"]; nAd _ Seq["nAd", a]; nnAd _ Seq["nnAd", a]; select _ Seq["Select", s]; <<-- 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: "DecoderSBody", public: Wires["Vdd", "Gnd", nAd, nnAd, select], instances: insts]; }; <<-- 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. >> DecoderSRoseClass: ROPE = RoseClass["DecoderS", DecoderSInit, DecoderSSimple]; DecoderS: PUBLIC PROC [a: NAT, s: NAT _ 0] RETURNS [ct: CellType] = { fullName: ROPE; IF a=0 THEN Error["Please provide parameter(s) for decoder"]; IF s>BitOps.TwoToThe[a] THEN Error["s too large in decoder"]; IF s=0 THEN s _ BitOps.TwoToThe[a]; fullName _ IO.PutFR["DecoderS a=%g s=%g", IO.int[a], IO.int[s]]; ct _ CacheFetch[fullName]; IF ct#NIL THEN RETURN[ct]; SELECT TRUE FROM a=1 AND s=1 => ct _ SCBlock[Extract["decoder11.sch"]]; a=1 AND s=2 => ct _ SCBlock[Extract["decoder12.sch"]]; ENDCASE => { -- general case nAd: Wire _ Seq["nAd", a]; nnAd: Wire _ Seq["nnAd", a]; select: Wire _ Seq["Select", s]; address: Wire _ Seq["Address", a]; insts: CellInstances _ NIL; insts _ CONS[Instance[DecoderBuffer[a], ["I", address], ["nX", nAd], ["X", nnAd] ], insts]; insts _ CONS[Instance[DecoderSBody[a, s], ["Select", select], ["nAd", nAd], ["nnAd", nnAd] ], insts]; ct _ Cell[name: "DecoderS", public: Wires["Vdd", "Gnd", address, select], onlyInternal: Wires[nAd, nnAd], instances: insts]; }; SimulateMacro[ct, DecoderSRoseClass]; Ports.InitPorts[ct, ls, none, "Address"]; Ports.InitPorts[ct, ls, drive, "Select"]; CacheStore[fullName, ct]; }; DecoderSInit: Rosemary.InitProc = { state: DecoderState _ IF oldStateAny=NIL THEN NEW[DecoderStateRec] ELSE NARROW[oldStateAny]; [state.decoderAd, state.decoderSel] _ Ports.PortIndexes[cellType.public, "Address", "Select"]; stateAny _ state; }; DecoderSSimple: Rosemary.EvalProc = { state: DecoderState _ NARROW[stateAny]; ad: NAT; IF Ports.HasX[p[state.decoderAd].ls] THEN {Ports.SetLS[p[state.decoderSel].ls, X]; RETURN}; ad _ Ports.LSToC[p[state.decoderAd].ls]; Ports.SetLS[p[state.decoderSel].ls, L]; IF ad> <<-- The decoder with enable: if enable=L all outputs are low>> <<-- nEn, Select[0..s), (nAd, nnAd)[0..a)with a>=2>> DecoderBody: PROC [a, s: NAT] RETURNS [ct: CellType] ~ { nor: CellType _ Logic.Nor[a+1]; -- one more input for nEn norInput, nAd, nnAd, select: Wire; insts: CellInstances _ NIL; norInput _ FindWire[nor.public, "I"]; nAd _ Seq["nAd", a]; nnAd _ Seq["nnAd", a]; select _ Seq["Select", s]; <<-- one (a+1)-input nor per output>> FOR i: NAT IN [0..s) DO pas: LIST OF PA _ LIST[["X", select[i]], [norInput[a], "nEn"]]; <<-- 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: "DecoderBody", public: Wires["Vdd", "Gnd", nAd, nnAd, select, "nEn"], instances: insts]; }; DecoderRoseClass: ROPE = RoseClass["Decoder", DecoderInit, DecoderSimple]; Decoder: PUBLIC PROC [a: NAT, s: NAT _ 0] RETURNS [ct: CellType] = { address, nAd, nnAd, select: Wire; insts: CellInstances _ NIL; fullName: ROPE; IF a=0 THEN Error["Please provide parameter(s) for decoder with enable"]; IF s>BitOps.TwoToThe[a] THEN Error["s too large in decoder"]; IF s=0 THEN s _ BitOps.TwoToThe[a]; fullName _ IO.PutFR["Decoder a=%g s=%g", IO.int[a], IO.int[s]]; ct _ CacheFetch[fullName]; IF ct#NIL THEN RETURN[ct]; address _ Seq["Address", a]; nAd _ Seq["nAd", a]; nnAd _ Seq["nnAd", a]; select _ Seq["Select", s]; insts _ CONS[Instance[DecoderBuffer[a], ["I", address], ["nX", nAd], ["X", nnAd] ], insts]; insts _ CONS[Instance[Logic.InvDriver[s], ["I", "Enable"], ["X", "nEn"] ], insts]; insts _ CONS[Instance[DecoderBody[a, s], ["Select", select], ["nAd", nAd], ["nnAd", nnAd], ["nEn", "nEn"] ], insts]; ct _ Cell[name: "Decoder", public: Wires["Vdd", "Gnd", address, select, "Enable"], onlyInternal: Wires[nAd, nnAd, "nEn"], instances: insts]; SimulateMacro[ct, DecoderRoseClass]; Ports.InitPorts[ct, l, none, "Enable"]; Ports.InitPorts[ct, ls, none, "Address"]; Ports.InitPorts[ct, ls, drive, "Select"]; CacheStore[fullName, ct]; }; DecoderInit: Rosemary.InitProc = { state: DecoderState _ IF oldStateAny=NIL THEN NEW[DecoderStateRec] ELSE NARROW[oldStateAny]; [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 Ports.HasX[p[state.decoderAd].ls] THEN {Ports.SetLS[p[state.decoderSel].ls, X]; RETURN}; ad _ Ports.LSToC[p[state.decoderAd].ls]; Ports.SetLS[p[state.decoderSel].ls, L]; IF ad Ports.SetLS[p[state.decoderSel].ls, X]; }; END. <<>>