“Four masters request a shared bus. Grant the lowest-numbered requester and steer its data out. Flag idle.”
The question tests arbitration plus steering. The trap is the idle case: index 0 cannot mean both requester 0 and no request.
State the interface first: one request bit per master, one data word per master, grant index, data out, and a valid flag. Then name the invariant: valid means some request is active, and the index names the lowest active one.
A loop from the high index down lets each active request overwrite the result, so the lowest active index wins. The loop unrolls into a chain of overrides in hardware.
Read the boxes top to bottom as loop iterations; each box shows the result after that iteration.
Only the highlighted iterations write. Index 3 writes first and index 1 overwrites it, so the lower index wins.
idx, valid and y are written together in each box, so grant and data cannot disagree.
If no bit were set, nothing would write and the start values would come out, with valid = 0.
N may be 1 (a single requester): the index width is guarded as localparam int SW = (N > 1) ? $clog2(N) : 1; because $clog2(1) is 0.
Input | valid | idx / y |
|---|---|---|
No bits set | 0 | Don't care (0) |
Bit 0 set | 1 | 0, data word 0 |
Bits 1 and 2 set | 1 | 1, data word 1 (lowest wins) |
All bits set | 1 | 0, data word 0 |
The data path is part of the answer. The winning index selects the winning data word in the same block, so grant and data can never disagree.
“Highest-numbered requester wins instead. What changes?” Scan from low to high (for (int i = 0; i < N; i++)) with the same overwrite-on-request body, so the highest active index overwrites last. For 4'b1010, index 1 is selected first and index 3 replaces it.
“64 requesters at speed. What changes?” The linear chain grows with N. Split the request vector into halves, encode each half, then combine with the halves valid flags for logarithmic depth.
“Add a mask input. What does it do?” Each request is qualified with its mask bit before encoding. A masked requester can never win, which is how software parks a faulty master.
A weaker answer writes a priority case without a default and without covering every select value. The missing cases hold state and synthesize a latch.
Another weak answer encodes the index in one block and muxes the data in another with different priority. Grant and data then disagree on overlapping requests.
Lowest-first grants index 1. Highest-first grants index 3.
So one priority decision drives both outputs. Separate blocks can encode different winners for the same request pattern.
The full priority mux plus a regression checking all 16 binary request patterns against a first-set-bit reference under two data fills.
`timescale 1ns/1ps
module prio_mux #(
parameter int N = 4, // must be at least 1
parameter int W = 8
) (
input logic [N-1:0] req,
input logic [N*W-1:0] d,
output logic [(N > 1 ? $clog2(N) : 1)-1:0] idx,
output logic valid,
output logic [W-1:0] y
);
// N = 1 guard ($clog2(1) is 0, so [$clog2(N)-1:0] would be [-1:0]).
localparam int SW = (N > 1) ? $clog2(N) : 1;
always_comb begin
idx = '0; valid = 1'b0; y = '0;
for (int i = N-1; i >= 0; i--) begin // scan from the high end so the lowest index wins last
if (req[i]) begin
idx = i[SW-1:0];
valid = 1'b1;
y = d[i*W +: W];
end
end
end
endmodule
Regression Run with Icarus Verilog 13.0 (2026-10-16): prints PASS. It checks all 16 binary request patterns against a first-set-bit reference under two data fills. It is not evidence for every N or four-state input.