Multiplexers, encoders, decoders and comparators
- Explain and size multiplexers, demultiplexers, encoders, priority encoders, decoders, and comparators
- Compose larger selection logic
- Identify invalid inputs, default behavior, and combinational design defects
select
Explanation
Combinational logic has no stored history
A combinational output is determined by current inputs after propagation delay. It has no intended memory. Every output must have a defined result for every legal input combination, including invalid or idle conditions specified by the interface.
Multiplexers select data
A multiplexer, or mux, chooses one of several inputs. A 2-to-1 mux has data inputs d0 and d1, select s, and output y:
y = (!s && d0) || (s && d1)
An M-input mux needs at least ceil(log2(M)) select bits. A 4-to-1 mux needs two. If the number of inputs is not a power of two, some select codes are unused and require defined behavior.
Muxes appear in datapaths, register writeback, bus selection, and configurable test paths. A wide mux applies the same selection to each bit of a bus.
Demultiplexers and decoders direct control
A demultiplexer sends one data input to one selected output. A decoder converts a binary code into one active output. A 2-to-4 active-high decoder produces:
a1 a0 |
d3 d2 d1 d0 |
|---|---|
| 00 | 0001 |
| 01 | 0010 |
| 10 | 0100 |
| 11 | 1000 |
With an enable input, every output is inactive when disabled. Decoders are used for register addresses, operation selection, and one-hot controls.
Pay attention to polarity. A bubble or _n name commonly indicates active-low behavior. reset_n=0 means reset is asserted. Never infer polarity from a signal's purpose alone; read its definition.
Encoders report which input is active
An encoder performs the reverse mapping: one active input becomes a binary code. A plain encoder assumes exactly one input is active. If multiple inputs can be asserted, the output is ambiguous.
A priority encoder defines which request wins, such as the highest numbered input. It should also produce a valid output because output code zero can mean either “input zero won” or “no input is active.” Fixed priority is simple but can starve low-priority requesters that continuously compete with high-priority traffic.
Comparators
An equality comparator checks every corresponding bit and combines the matches. Magnitude comparison starts at the most significant unequal bit.
Signed and unsigned comparison can differ for the same bits:
a = 4'b1110
b = 4'b0011
unsigned: a=14, b=3, therefore a>b
signed: a=-2, b=3, therefore a<b
The interface must define signedness. Extending both operands correctly before comparison avoids accidental width rules.
Composition and timing
Larger muxes and decoders can be composed from smaller blocks. Functional composition is straightforward, but every added logic level contributes delay. A long priority chain may become a critical path. Balanced structures may be faster at the cost of area or complexity.
Total output definition
In a combinational RTL process, assign a default before conditional overrides or cover every branch. Missing an assignment means the output must retain its previous value, which implies a latch. A combinational loop occurs when a signal depends on itself through only combinational logic. Such loops are generally unstable, difficult to time, and rejected unless deliberately implemented with a specialized flow.
Review questions
- Are unused select or address codes defined?
- Is active polarity clear?
- Can multiple encoder inputs be asserted?
- Is “none selected” distinguishable from selecting index zero?
- Are comparisons signed or unsigned?
- Does every output receive a value on every path?
- Can priority cause starvation?
Worked example
Design a read mux for four 8-bit status registers.
Inputs are status0 through status3 and a 3-bit address. Valid addresses 0 through 3 select a register. Addresses 4 through 7 must return zero and assert read_error.
| Address | read_data |
read_error |
|---|---|---|
| 0 | status0 |
0 |
| 1 | status1 |
0 |
| 2 | status2 |
0 |
| 3 | status3 |
0 |
| 4–7 | 8'h00 |
1 |
A good combinational description starts with safe defaults:
always_comb begin
read_data = 8'h00;
read_error = 1'b0;
case (address)
3'd0: read_data = status0;
3'd1: read_data = status1;
3'd2: read_data = status2;
3'd3: read_data = status3;
default: read_error = 1'b1;
endcase
end
The default values define invalid addresses and prevent unintended storage. Verification should exercise every address, not only the four useful cases.
Check yourself
Why does a priority encoder need a valid output? What behavior should a mux define for unused select codes?