Many circuits can be written in more than one way. The versions differ in depth, area and the assumption they rely on.
Structure | Levels | Cells (incl. flops) | Assumption |
|---|---|---|---|
16:1 mux, binary select ( | 6 | 43 | None |
16:1 mux, one-hot select ( | 5 | 65 | Exactly one select bit set; needs 16 select flops |
8-way priority select (if-else chain, 8-bit data) | 10 | 240 | None (lowest index wins) |
8-way select, parallel AND-OR | 4 | 201 | At most one request active |
Read each panel from the inputs on the left to y on the right; the highlighted path is the longest one.
The chain puts req0 at the last mux, so the lowest index wins. Every extra input adds one mux to the path.
The AND-OR has the same depth for any input once its OR tree is built: one AND, then about log2 N OR levels.
With two requests high, the chain still returns d0, but the AND-OR returns the OR of both words.
The one-hot mux is only slightly shallower and bigger: the tool already builds a good tree for d[s].
The priority example is the strong one: the chain is 10 levels and 240 cells, while the parallel form is 4 levels and 201 cells, but it can change the result when several requests are active.
Six replacements trade assumptions or latency for depth. Each row names what makes it shallower and what to watch.
Pattern | Why it is shallower | Watch for |
|---|---|---|
One-hot or AND-OR selects | Parallel instead of chained decisions | The one-hot guarantee must hold; add an assertion |
Balanced operator trees | log N depth instead of N | Tools often balance plain sums, but not when mixed with enables or width changes |
Late signal to the last mux | The late path sees one gate instead of several | Write it so; synthesis may keep that order |
Registered control (decode in the previous cycle) | Moves decode off the data path | One cycle of extra latency |
Parallel prefix adders / comparators | log N carry/compare depth | More area (see the Kogge-Stone example) |
Replace | Cuts a 20-level path | Pipeline stage added |
It computes the OR of selected data rather than the priority winner. onehot0 guarantees equivalence for arbitrary data; overlapping requests can agree for particular data but that observation does not establish an interface guarantee.
The chain and parallel forms plus a testbench that compares them on random requests.
// Priority select as an if-else chain (lowest index wins) versus a parallel AND-OR.
module prio_chain (input logic [7:0] req, input logic [7:0] [7:0] data, output logic [7:0] y);
always_comb begin
y = '0;
for (int i = 7; i >= 0; i--) if (req[i]) y = data[i]; // later iterations (lower index) override
end
endmodule
// Valid only when at most one request is active (guaranteed by the caller).
module prio_onehot (input logic [7:0] req, input logic [7:0] [7:0] data, output logic [7:0] y);
always_comb begin
y = '0;
for (int i = 0; i < 8; i++) y |= data[i] & {8{req[i]}};
end
endmodule
Equivalence is guaranteed under known onehot0 requests, not if and only if onehot0 holds. Multiple requests can agree when the extra data contributes no new bits (including identical or zero data). The directed source checks all 256 request masks with distinct-bit data, then equal-data agreement and 01/02 disagreement, followed by the existing random experiment. In the random run, 18845 of 19284 multi-request cases gave different results. Keep $onehot0(req) asserted at the real caller boundary and reject unknown requests; the experiment deliberately includes illegal overlaps.
Directed bench, run with Icarus Verilog 13.0 (2026-10-16): prints PASS. It checks all 256 request masks with distinct-bit data, then equal-data agreement and 01/02 disagreement. In the random run, 18845 of 19284 multi-request cases differed; that count depends on the run.
The levels and cell counts in the first table are measured mapping results.