This chapter presents the standard combinational building blocks used everywhere in digital design. Multiplexers are covered in depth, including their use for implementing arbitrary logic functions via Shannon's expansion theorem. Decoders (including demultiplexers) and encoders (binary and priority) are discussed as fundamental address-translation and selection circuits. Code converters (e.g., BCD to 7-segment display) and arithmetic comparison circuits (magnitude comparators) are also presented. The major Verilog section introduces the conditional operator (?:), if-else statements, the case statement, for loops, the full set of Verilog operators, the generate construct, and tasks/functions — essentially all the Verilog constructs needed for combinational circuit description.
A decoder takes an $n$-bit input and asserts exactly one of its $2^n$ outputs. A demultiplexer (demux) takes one data line plus an $n$-bit select and routes the data to one of $2^n$ outputs (the others stay at 0). The two circuits share an internal structure — a demux is just a decoder whose data-line gates each output.
The output corresponding to the binary value of the input is high; all others are low. Equivalently $y_i = m_i$ (minterm $i$).
A demux equals a decoder whose output is gated by a data input: $y_i = D \cdot \text{(decode of select)}_i$.
Toggle D to off and watch the selected output drop to 0 — the demux only routes the data bit, it doesn't generate one. With $D=1$ the demux behaves identically to the decoder above.
A multiplexer reverses the demux: it has $2^n$ data inputs $D_0, D_1, D_2, D_3$, an $n$-bit select, and a single output $y$ which equals whichever data line the select points to. $y = D_{(\text{select})}$.
Gold cells = data inputs currently 1. The cell with the green outline is the one currently routed through. The output $y$ takes that cell's value: if the outlined cell is gold (1) the output is 1; if dim (0) the output is 0.
Three-way comparison (decoder, demultiplexer, multiplexer):
| Decoder | Demultiplexer | Multiplexer | |
|---|---|---|---|
| Direction | $n$ → $2^n$ | $1 + n$ → $2^n$ (fan-out) | $2^n + n$ → 1 (fan-in) |
| Inputs | $n$ select bits | 1 data + $n$ select | $2^n$ data + $n$ select |
| Outputs | $2^n$ minterm signals | $2^n$ (one carries data, rest 0) | 1 (carries selected input) |
| Behavior | $y_i = 1$ iff input $= i$ | $y_i = D$ iff sel $= i$, else 0 | $y = D_{\text{sel}}$ |
| Boolean form | $y_i = m_i(s)$ | $y_i = D \cdot m_i(s)$ | $y = \sum_i D_i \cdot m_i(s)$ |
| Use case | address decode, minterm generation, ROM rows | routing one signal to many destinations (clock distribution, write-enable) | selecting one of many sources (bus arbitration, ALU operand pick, function realization via Shannon expansion) |
Duality. A demux and a MUX are inverse circuits — connect them back-to-back with the same select, and the data on $D_i$ at the demux input reappears unchanged at the MUX output. This is the basis of time-division multiplexing: many channels share one wire by alternating selects.
Decoder vs MUX. A decoder generates all $2^n$ minterms; a MUX uses minterms internally to select among inputs. Equivalently: a MUX is built from a decoder + AND gates + a big OR. So decoders are the building block; MUXes and demuxes are decoder-based variants — read-direction (MUX, $2^n$→1) vs. write-direction (demux, 1→$2^n$).
Shannon's expansion theorem decomposes any Boolean function on a chosen variable into two simpler "cofactor" pieces. It's the algebraic foundation of MUX-based logic synthesis, BDDs, and recursive function analysis.
Theorem (SOP form):
$f(x_1, x_2, \ldots, x_n) \;=\; \overline{x_1}\cdot f(0, x_2, \ldots, x_n) \;+\; x_1 \cdot f(1, x_2, \ldots, x_n)$
Theorem (POS / dual form):
$f(x_1, x_2, \ldots, x_n) \;=\; \bigl(x_1 + f(0, x_2, \ldots, x_n)\bigr) \cdot \bigl(\overline{x_1} + f(1, x_2, \ldots, x_n)\bigr)$
The two pieces are called the cofactors of $f$ with respect to $x_1$:
| Notation | Meaning |
|---|---|
| $f_{x_1=0}$, $f|_{x_1=0}$, $f_0$ | substitute $x_1=0$ everywhere in $f$ → 0-cofactor |
| $f_{x_1=1}$, $f|_{x_1=1}$, $f_1$ | substitute $x_1=1$ everywhere in $f$ → 1-cofactor |
$\boxed{\,f \;=\; \overline{x_1}\,f_0 \;+\; x_1\,f_1\,}$
Connection to a 2-to-1 MUX — that's literally MUX2 with select $= x_1$, data inputs $f_0$ and $f_1$:
Recursive application — break a function down to a tree of MUXes:
$f \;=\; \overline{x_1}\bigl[\overline{x_2} f_{00} + x_2 f_{01}\bigr] + x_1\bigl[\overline{x_2} f_{10} + x_2 f_{11}\bigr]$
Each cofactor is itself expanded on the next variable, producing a binary tree with $2^n$ leaves (constants 0 or 1, equal to the truth-table values). This is a binary decision diagram (BDD) before any reduction.
Worked example. $f(w_1, w_2, w_3) = w_1 w_2 + \overline{w_1} w_3$. Expand on $w_1$:
Useful identities & properties:
| Identity | Note |
|---|---|
| $f = \overline{x}\,f_0 + x\,f_1$ | canonical SOP form |
| $f = (x + f_0)(\overline{x} + f_1)$ | canonical POS form (the dual) |
| $f_0 \cdot f_1 \neq 0 \Rightarrow$ Boolean diff | $\partial f / \partial x = f_0 \oplus f_1$ (XOR of cofactors) |
| $f_0 = f_1 \iff f$ is independent of $x$ | used to detect "vacuous" variables |
| $(f \cdot g)_{x=v} = f_{x=v} \cdot g_{x=v}$ | cofactoring distributes over AND, OR, NOT, XOR |
Where it shows up:
Quick recipe: to express $f$ with a 2-to-1 MUX selected by $x_i$ — compute $f_0$ and $f_1$ by substitution, wire them as the two data inputs, wire $x_i$ as select. To go further (tree of MUXes), expand each cofactor on the next variable. The recursion bottoms out at the constants 0 and 1.
An encoder turns a one-of-$2^n$ one-hot signal into an $n$-bit binary index. A decoder does the reverse: it turns an $n$-bit binary index back into a one-hot signal. Connected back-to-back with the same width, they form an identity on valid one-hot inputs — exactly like a demux/MUX pair, but in the opposite direction.
$\text{one-hot}\;\xrightarrow{\;\text{encoder}\;}\;\text{binary index}\;\xrightarrow{\;\text{decoder}\;}\;\text{one-hot}$
Side-by-side block diagram (4-to-2 encoder → 2-to-4 decoder):
Truth-table round-trip — encoder squeezes 4 wires into 2; decoder expands them back. On valid one-hot inputs the round-trip is identity:
| W₃W₂W₁W₀ (one-hot) | y₁y₀ (encoded) | Y₃Y₂Y₁Y₀ (decoded) | match? |
|---|---|---|---|
| 0001 | 00 | 0001 | ✓ |
| 0010 | 01 | 0010 | ✓ |
| 0100 | 10 | 0100 | ✓ |
| 1000 | 11 | 1000 | ✓ |
| 0000 (invalid) | 00 | 0001 (wrong!) | × |
Back-to-back chain with a valid gate — the row in red shows why a plain encoder output is ambiguous: input 0001 and input 0000 both produce y = 00. To distinguish them, the encoder asserts an extra valid bit (= OR of all one-hot inputs), and the decoder uses it as enable so its outputs stay 0000 when no input was asserted:
Where this pair shows up:
Verilog — minimal back-to-back pair:
module binary_encoder_4to2(input [3:0] W, output reg [1:0] y, output valid);
assign valid = |W; // 1 if any input is asserted
always @(*) case (W)
4'b0001: y = 2'b00;
4'b0010: y = 2'b01;
4'b0100: y = 2'b10;
4'b1000: y = 2'b11;
default: y = 2'b00; // ambiguous without 'valid'
endcase
endmodule
module dec2to4(input [1:0] W, input En, output reg [3:0] Y);
always @(*) case ({En, W})
3'b100: Y = 4'b0001;
3'b101: Y = 4'b0010;
3'b110: Y = 4'b0100;
3'b111: Y = 4'b1000;
default: Y = 4'b0000;
endcase
endmodule
module enc_dec_link(input [3:0] W, output [3:0] Y);
wire [1:0] y;
wire valid;
binary_encoder_4to2 enc(.W(W), .y(y), .valid(valid));
dec2to4 dec(.W(y), .En(valid), .Y(Y));
endmodule
Footnote on the valid output. A plain (non-priority) encoder cannot tell "no input asserted" from "input 0 asserted" — both produce y = 00. The valid = OR-of-all-inputs bit fixes this: it gates the downstream decoder so the round-trip is correct even when no source line is active. For a priority encoder, valid doubles as the "any request pending" signal feeding the arbiter.
A multiplexer (MUX) picks one of $2^n$ data sources and routes it to a single output. A demultiplexer (DEMUX) does the reverse: it takes one data input and steers it to one of $2^n$ outputs (the rest stay at 0). Connected back-to-back with a shared select, MUX→DEMUX makes a perfect time-division multiplexed (TDM) link: many channels share one wire, alternating in time.
$D_0 \ldots D_{2^n-1}\;\xrightarrow{\;\text{MUX}\;}\;\text{1 wire}\;\xrightarrow{\;\text{DEMUX}\;}\;Y_0 \ldots Y_{2^n-1}$
Side-by-side block diagram (4-to-1 MUX → 1-to-4 DEMUX):
Round-trip table — with the same select on both sides, $Y_i = D_i$ for the selected slot, all other $Y_j = 0$ (the demux floor):
| sel | MUX out (= shared wire) | DEMUX outputs Y₃Y₂Y₁Y₀ | live channel |
|---|---|---|---|
| 00 | D₀ | 000 D₀ | channel 0 |
| 01 | D₁ | 00 D₁ 0 | channel 1 |
| 10 | D₂ | 0 D₂ 00 | channel 2 |
| 11 | D₃ | D₃ 000 | channel 3 |
TDM timing — rotate sel through 00 → 01 → 10 → 11 in successive time slots; each source $D_i$ owns the wire for one slot, and the demux drops it onto the matching $Y_i$:
Where this pair shows up:
Verilog — minimal back-to-back pair:
module mux4to1(input [3:0] D, input [1:0] sel, output reg out);
always @(*) case (sel)
2'b00: out = D[0];
2'b01: out = D[1];
2'b10: out = D[2];
2'b11: out = D[3];
endcase
endmodule
module demux1to4(input in, input [1:0] sel, output reg [3:0] Y);
always @(*) begin
Y = 4'b0000;
case (sel)
2'b00: Y[0] = in;
2'b01: Y[1] = in;
2'b10: Y[2] = in;
2'b11: Y[3] = in;
endcase
end
endmodule
module tdm_link(input [3:0] D, input [1:0] sel, output [3:0] Y);
wire bus; // the shared 1-bit wire
mux4to1 tx(.D(D), .sel(sel), .out(bus));
demux1to4 rx(.in(bus), .sel(sel), .Y(Y));
endmodule
Note. The MUX/DEMUX pair carries data (one wire, value-bearing); the encoder/decoder pair carries an index (binary number, position-bearing). Both pairs are inverse circuits, but they operate on different abstractions: data routing vs. address translation.
Here's a concrete walk-through using a 3-variable function.
Take $F(A, B, C) = A + BC$ with 3 variables ($n = 3$), so there are $2^3 = 8$ minterms ($m_0$ through $m_7$). [cs.ucr]
Evaluate $F$ for every input combination: [cs.ucr]
| $i$ | A | B | C | Minterm $m_i$ | $F(A,B,C)$ |
|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | $A'B'C'$ | 0 |
| 1 | 0 | 0 | 1 | $A'B'C$ | 0 |
| 2 | 0 | 1 | 0 | $A'BC'$ | 0 |
| 3 | 0 | 1 | 1 | $A'BC$ | 1 |
| 4 | 1 | 0 | 0 | $AB'C'$ | 1 |
| 5 | 1 | 0 | 1 | $AB'C$ | 1 |
| 6 | 1 | 1 | 0 | $ABC'$ | 1 |
| 7 | 1 | 1 | 1 | $ABC$ | 1 |
Only minterms where $F = 1$ survive (multiplying by 0 eliminates the rest): [caslab.ee.ncku.edu]
$$F(A,B,C) = m_3 \cdot 1 + m_4 \cdot 1 + m_5 \cdot 1 + m_6 \cdot 1 + m_7 \cdot 1$$Substituting the actual minterm products: [cs.ucr]
$$F(A,B,C) = A'BC + AB'C' + AB'C + ABC' + ABC$$Written in shorthand notation: [jazapka.people.ysu]
$$F(A,B,C) = \Sigma\, m(3, 4, 5, 6, 7)$$The formula is simply saying: OR together every minterm for which the function outputs 1. Each minterm $m_i$ is exactly 1 for one and only one input combination, so the sum "selects" the rows in the truth table where $F = 1$. This canonical SOP is the fully expanded Shannon decomposition over all variables simultaneously. [cs.ucr]
Here is a full worked example using the dual POS form of Shannon's expansion.
Let $F(A, B, C) = A + BC$, and expand on $X_1 = A$: [en.wikipedia]
$$F = (A + F(0, B, C)) \cdot (A' + F(1, B, C))$$Negative cofactor — set $A = 0$: [en.wikipedia]
$$F(0, B, C) = 0 + BC = BC$$Positive cofactor — set $A = 1$: [en.wikipedia]
$$F(1, B, C) = 1 + BC = 1$$Since $A' + 1 = 1$ (anything OR'd with 1 is 1):
$$F(A, B, C) = (A + BC) \cdot 1 = A + BC$$The function is confirmed correctly $\checkmark$
To reach the fully canonical POS (maxterm form), apply the theorem recursively to each remaining sub-function. Expand $BC$ on variable $B$: [eplauchu.files.wordpress]
$$BC = (B + C \cdot 0)(B' + C \cdot 1) = (B + 0)(B' + C) = B(B' + C)$$Wait — in POS, the canonical expansion over all variables yields maxterms where $F = 0$. From the earlier truth table, $F = 0$ only at rows $i = 0, 1, 2$ (i.e., $A=0, BC=0$):
| $i$ | A | B | C | Maxterm $M_i$ | $F$ |
|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | $A+B+C$ | 0 |
| 1 | 0 | 0 | 1 | $A+B+C'$ | 0 |
| 2 | 0 | 1 | 0 | $A+B'+C$ | 0 |
| 3–7 | — | — | — | — | 1 |
So the canonical POS is: [eplauchu.files.wordpress]
$$F(A,B,C) = \Pi\, M(0, 1, 2) = (A+B+C)(A+B+C')(A+B'+C)$$| SOP (Shannon direct) | POS (Shannon dual) | |
|---|---|---|
| Operator | $x \cdot F_x + x' \cdot F_{x'}$ | $(x + F_{x=0})(x' + F_{x=1})$ |
| Canonical form | Sum of minterms where $F = 1$ | Product of maxterms where $F = 0$ |
| Building blocks | Minterms $m_i$ | Maxterms $M_i$ |
The dual POS form is particularly useful when a function has fewer 0s than 1s in the truth table — the POS expression will then be more compact. [eplauchu.files.wordpress]
By convention the highest-indexed asserted input wins: I₃ > I₂ > I₁ > I₀. The encoder reports the index of that winning input on (Y₁, Y₀), and V=1 whenever any input is active.
In an if / else if chain this is the input checked first:
if (in[3]) out = 2'd3; // highest priority else if (in[2]) out = 2'd2; else if (in[1]) out = 2'd1; else if (in[0]) out = 2'd0; // lowest priority
To make input 0 the highest priority instead, just reverse the order of the chain.
Then I₀ > I₁ > I₂ > I₃. The output (Y₁,Y₀) still reports the index of the winning input, but every term must gate on the complements of the higher-priority inputs.
| I₃ | I₂ | I₁ | I₀ | Y₁ | Y₀ | V |
|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | x | x | 0 |
| x | x | x | 1 | 0 | 0 | 1 |
| x | x | 1 | 0 | 0 | 1 | 1 |
| x | 1 | 0 | 0 | 1 | 0 | 1 |
| 1 | 0 | 0 | 0 | 1 | 1 | 1 |
$Y_0 = I_1\overline{I_0} + I_3\overline{I_2}\,\overline{I_1}\,\overline{I_0}$
$Y_1 = \overline{I_0}\,\overline{I_1}(I_2 + I_3)$
$V = I_0 + I_1 + I_2 + I_3$
Compared to the I₃-highest case ($Y_1 = I_3 + I_2$, $Y_0 = I_3 + I_1\overline{I_2}$), flipping the priority to I₀ makes the equations longer because the higher-priority inputs now need to be explicitly suppressed.
Naming only I₁ as highest doesn't fully specify the order of the other three. The usual reading is a cyclic shift (round-robin style): I₁ > I₂ > I₃ > I₀.
| I₃ | I₂ | I₁ | I₀ | Y₁ | Y₀ | V |
|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | x | x | 0 |
| x | x | 1 | x | 0 | 1 | 1 |
| x | 1 | 0 | x | 1 | 0 | 1 |
| 1 | 0 | 0 | x | 1 | 1 | 1 |
| 0 | 0 | 0 | 1 | 0 | 0 | 1 |
$Y_0 = I_1 + I_3\overline{I_2}\,\overline{I_1}$
$Y_1 = \overline{I_1}(I_2 + I_3)$
$V = I_0 + I_1 + I_2 + I_3$
Because I₀ is now the lowest priority and its index is 00, no I₀ term appears in either output — it's "selected" only when all higher-priority inputs are 0, and that selection is encoded by Y₁Y₀ = 00.
case statement.段位示意:a = 上橫,b = 右上,c = 右下,d = 下橫,e = 左下,f = 左上,g = 中橫。BCD 用 ABCD = wxyz。
| 十進位 | BCD (wxyz) | a | b | c | d | e | f | g |
|---|---|---|---|---|---|---|---|---|
| 0 | 0000 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
| 1 | 0001 | 0 | 1 | 1 | 0 | 0 | 0 | 0 |
| 2 | 0010 | 1 | 1 | 0 | 1 | 1 | 0 | 1 |
| 3 | 0011 | 1 | 1 | 1 | 1 | 0 | 0 | 1 |
| 4 | 0100 | 0 | 1 | 1 | 0 | 0 | 1 | 1 |
| 5 | 0101 | 1 | 0 | 1 | 1 | 0 | 1 | 1 |
| 6 | 0110 | 1 | 0 | 1 | 1 | 1 | 1 | 1 |
| 7 | 0111 | 1 | 1 | 1 | 0 | 0 | 0 | 0 |
| 8 | 1000 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| 9 | 1001 | 1 | 1 | 1 | 1 | 0 | 1 | 1 |
特殊規律:
1111111),是最完整的圖形。AgtB, AeqB, AltB. Give the truth table and simplified equations. See Compound Gates for XNOR (≡) used in equality detection.if-else chain inside an always block.case statement in Verilog doesn't cover all possible input combinations and no default is provided? What type of hardware is inferred?Gray code (reflected binary code) is a binary numbering system where two consecutive values differ in exactly one bit.
| Dec | Binary | Gray | Dec | Binary | Gray |
|---|---|---|---|---|---|
| 0 | 0000 | 0000 | 8 | 1000 | 1100 |
| 1 | 0001 | 0001 | 9 | 1001 | 1101 |
| 2 | 0010 | 0011 | 10 | 1010 | 1111 |
| 3 | 0011 | 0010 | 11 | 1011 | 1110 |
| 4 | 0100 | 0110 | 12 | 1100 | 1010 |
| 5 | 0101 | 0111 | 13 | 1101 | 1011 |
| 6 | 0110 | 0101 | 14 | 1110 | 1001 |
| 7 | 0111 | 0100 | 15 | 1111 | 1000 |
Each row changes only one bit from the row above. Compare with binary: 0011 → 0100 changes 3 bits at once.
Why it matters:
Conversion formulas:
A crossbar switch is a network element that lets any input be routed to any output, like a digital "patch panel". The simplest non-trivial case is the 2×2 crossbar: two inputs ($x_1, x_2$), two outputs ($y_1, y_2$), and one control bit $s$ that picks between two connection patterns:
| $s$ | routing | $y_1$ | $y_2$ |
|---|---|---|---|
| 0 | straight (pass-through) | $x_1$ | $x_2$ |
| 1 | crossed (swap) | $x_2$ | $x_1$ |
Schematic of the two routing patterns:
Boolean expressions:
$y_1 = \overline{s}\,x_1 + s\,x_2 \;=\; \mathrm{MUX2}(s; x_1, x_2)$
$y_2 = \overline{s}\,x_2 + s\,x_1 \;=\; \mathrm{MUX2}(s; x_2, x_1)$
Each output is a 2-to-1 MUX: when $s=0$ pick the "straight" input, when $s=1$ pick the "crossed" input. Two MUXes total.
Block diagram:
Each MUX has its top data line wired straight from $x_i$ and its bottom data line wired across from $x_j$. The single control $s$ flips both MUXes simultaneously.
Verilog:
module crossbar_2x2 ( input x1, x2, s, output y1, y2 ); assign y1 = s ? x2 : x1; assign y2 = s ? x1 : x2; endmodule
Why it matters. Crossbar switches scale up to $n \times n$ networks (used in CPU register files, multiprocessor memory networks, network-on-chip routers). An $n \times n$ crossbar takes $n$ parallel $n$-to-1 MUXes — non-blocking but $O(n^2)$ in size, hence the use of multistage networks (Clos, Beneš) for larger $n$.
The three-input majority function $M(w_1, w_2, w_3)$ outputs 1 when at least two of the three inputs are 1, and 0 otherwise. It's the Boolean version of "majority vote": each input is a yes/no vote, the output is the winning side.
Truth table:
| $w_1$ | $w_2$ | $w_3$ | $M$ | comment |
|---|---|---|---|---|
| 0 | 0 | 0 | 0 | no votes for 1 |
| 0 | 0 | 1 | 0 | only one vote |
| 0 | 1 | 0 | 0 | only one vote |
| 0 | 1 | 1 | 1 | two votes |
| 1 | 0 | 0 | 0 | only one vote |
| 1 | 0 | 1 | 1 | two votes |
| 1 | 1 | 0 | 1 | two votes |
| 1 | 1 | 1 | 1 | all three |
Boolean expression (minimum SOP):
$M = w_1 w_2 + w_1 w_3 + w_2 w_3$ 必背
(any pair of 1s makes $M=1$ — three 2-input AND terms ORed together).
4-to-1 MUX implementation strategy. Use $w_1, w_2$ as select inputs ($s_1 s_0 = w_1 w_2$). The MUX output for each select pattern is whatever the truth table dictates, parameterized by $w_3$:
| $w_1 w_2$ | MUX line | $M$ when $w_3{=}0$ | $M$ when $w_3{=}1$ | data input |
|---|---|---|---|---|
| 00 | $I_0$ | 0 | 0 | 0 |
| 01 | $I_1$ | 0 | 1 | $w_3$ |
| 10 | $I_2$ | 0 | 1 | $w_3$ |
| 11 | $I_3$ | 1 | 1 | 1 |
Result: connect $I_0 = 0$, $I_1 = I_2 = w_3$, $I_3 = 1$. The 4-to-1 MUX automatically produces the majority output for whatever $(w_1, w_2, w_3)$ comes in.
Why majority is interesting: it's the canonical example of a "voting" / "fault-masking" function — used in triple-modular redundancy (TMR), where three copies of a signal are voted on to mask a single fault. Also a classic K-map example because its prime-implicant SOP form has no static hazards.
mux2to1 with inputs w0, w1, s and output f, using a continuous assign with the conditional operator ?:.if-else statement inside an always block.case statement inside an always block, with a 2-bit select vector $S$.En, using a case statement on the concatenation {En, W}.if-else (for the enable) and a case statement (for the input pattern).seg7 that implements a hexadecimal-to-7-segment display decoder. The 4-bit input is hex and the 7-bit output is leds; use a case statement listing all 16 patterns.casex statement that treats lower-priority bits as don't-cares. Provide a valid output flag $z$.for loop that iterates over the four output positions, asserting $Y[k]=1$ when $W=k$ and $\text{En}=1$.for loop. Exploit the fact that, in an always block, multiple assignments to the same variable retain the last assignment, so the highest priority input wins.==, >, <) inside an if-else chain to drive outputs AeqB, AgtB, AltB.generate construct with a for loop and gate-level primitives to specify an $n$-bit ripple-carry adder. Use a genvar index and parameterize $n$.task for the inner 4-to-1 multiplexer, called from a case statement inside an always block.— example 4.10function rather than a task. Explain the syntactic and semantic differences from the task-based version.Shift selects between (a) pass-through $Y=W$, $k=0$ and (b) right-shift by one with $y_3=0$, $y_2=w_3$, $y_1=w_2$, $y_0=w_1$, $k=w_0$.A barrel shifter is a combinational circuit that shifts (or rotates) an $n$-bit vector by any amount in one clock cycle, regardless of how many bits the shift is. Unlike a sequential shift register, which moves one position per clock, a barrel shifter performs the entire shift through pure combinational logic — exploiting parallel multiplexers.
Two flavors:
Problem 4.43 asks for a rotating 4-bit shifter ($n=4$) with shift amounts $\{0,1,2,3\}$ selected by a 2-bit control $S = s_1 s_0$.
Functional table (input $W = w_3 w_2 w_1 w_0$, output $Y = y_3 y_2 y_1 y_0$):
| $S$ | shift | $y_3$ | $y_2$ | $y_1$ | $y_0$ |
|---|---|---|---|---|---|
| 00 | 0 | $w_3$ | $w_2$ | $w_1$ | $w_0$ |
| 01 | 1 right | $w_0$ | $w_3$ | $w_2$ | $w_1$ |
| 10 | 2 right | $w_1$ | $w_0$ | $w_3$ | $w_2$ |
| 11 | 3 right | $w_2$ | $w_1$ | $w_0$ | $w_3$ |
Each output bit needs a 4-to-1 MUX whose data inputs are the four candidate source bits and whose select is $S$. From the table, reading down each $y_i$ column tells you the data inputs to MUX$_i$:
Pattern: each MUX$_i$ has data inputs $(w_i, w_{(i-1)\bmod 4}, w_{(i-2)\bmod 4}, w_{(i-3)\bmod 4})$ — exactly the cyclic shift of $W$ starting at position $i$.
Schematic (four parallel 4-to-1 MUXes sharing the same $S$):
Verilog (parameterized for any $n$ that is a power of 2):
module barrel_rot4 ( input [3:0] W, input [1:0] S, output [3:0] Y ); // each output is the input rotated right by S assign Y = (W >> S) | (W << (4 - S)); endmodule
The expression `(W >> S) | (W << (4-S))` is the canonical right-rotate idiom: bits shifted off the bottom re-enter at the top via the inverted shift. The synthesis tool will turn this into the four 4-to-1 MUXes shown above.
Cost & depth. An $n$-bit barrel rotator built from $n$ parallel $n$-to-1 MUXes uses $O(n^2)$ gates and one MUX-delay. For larger $n$, a logarithmic multi-stage barrel shifter ($\log_2 n$ stages of 2-to-1 MUXes per bit) cuts cost to $O(n \log n)$ at the price of $\log_2 n$ MUX delays — the standard ALU shifter design in modern CPUs.
dec2to4 module) and a single reduction-OR over the AND of decoder outputs with the data vector.if-else with explicit bit assignments, and another using the Verilog shift operator >>.>> instead of explicit bit assignments?Style 1 — explicit bit assignments:
module shifter_if (input [3:0] R, input shift, output reg [3:0] Q);
always @* begin
if (shift) begin
Q[3] = 1'b0; // fill MSB with 0
Q[2] = R[3];
Q[1] = R[2];
Q[0] = R[1]; // R[0] discarded
end else
Q = R;
end
endmoduleStyle 2 — using >>:
module shifter_op (input [3:0] R, input shift, output [3:0] Q);
assign Q = shift ? (R >> 1) : R;
endmoduleWhy prefer >>?
| Aspect | Explicit if-else | >> operator |
|---|---|---|
| Lines of code | ~10 | 1 |
| Bug surface | Easy to swap two bit indices and miss it | Compiler enforces the relation |
| Scales to wider words | One extra line per bit | Same line works for any width |
| Parameterizable | Need to template every assignment | assign Q = R >> 1; works for any [N-1:0] |
| Variable shift amount | Need a large case / mux network | R >> n — synthesizer builds the barrel shifter |
| Synthesized hardware | Identical wire-rename | Identical wire-rename |
Bottom line: the two are electrically identical for a fixed 1-bit shift (both synthesize to a trivial wire-rename — no flip-flops). But >> is the right level of abstraction: it states the operation rather than its implementation. For parameterized widths or variable shift amounts, >> saves you from writing a barrel multiplexer by hand. The textbook asks for both styles to make clear that HDL operators are not magic — they're shorthand for what you could otherwise write structurally.