LogicMuxesImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Last Edited by: Louis Monier August 26, 1987 6:11:47 pm PDT
Jean-Marc Frailong October 22, 1987 0:21:37 am PDT
Pradeep Sindhu February 27, 1987 2:51:12 pm PST
Barth, October 10, 1986 5:30:37 pm PDT
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;
Useful wire icons
The wire icons described here are all unnamed wire icons.
ReverseBits: PUBLIC PROC [b: NAT] RETURNS [public: Core.Wires] ~ {
Code for a wire icon that reverses the order of the bits within a b-bit bus. Each bit will have the structure described by p, a void rope meaning atomic.
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] ~ {
Code for a wire icon that transforms a bus of w words of b bits into a bus of b words of w bits (i.e. bSide[b][w] = wSide[w][b])
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] ~ {
Code for a wire icon that interleaves buses. The interleaved bus is E[0], O[0], E[1], ... The even and odd buses are b bits wide, the interleaved bus is 2b bits wide.
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
Decoded 1-Bit multiplexer
-- 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];
};
Encoded 1-Bit multiplexer
-- 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];
};
b-Bit n-Input multiplexers
Common code
Decoded b-Bit n-Input multiplexer
-- 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: NATLAST[NAT], ok: BOOLFALSE] ~ {
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 b-Bit n-Input multiplexer
-- 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: NATLAST[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];
};
};
Inverting b-Bit 2-Input multiplexer
-- 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: NATLAST[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];
};
Decoders
Shared types & procedures
DecoderState: TYPE = REF DecoderStateRec;
DecoderStateRec: TYPE = RECORD [decoderAd, decoderSel, decoderEnable: NATLAST[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"]];
};
Simple Decoder
-- 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 PALIST[["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<p[state.decoderSel].ls.size THEN p[state.decoderSel].ls[ad] ← H;
};
Decoder with enable
-- 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 PALIST[["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<p[state.decoderSel].ls.size THEN p[state.decoderSel].ls[ad] ← H};
ENDCASE => Ports.SetLS[p[state.decoderSel].ls, X];
};
END.