Each slave owns an address range written as an explicit localparam base and limit pair. The pairs live in one place so the map can be reviewed against the software headers.
Ranges must not overlap. An overlap wakes two slaves at once, which the select check below catches.
Slave | Base | Limit | Select |
|---|---|---|---|
UART | 32'h0000_1000 | 32'h0000_1FFF |
|
SPI | 32'h0000_2000 | 32'h0000_2FFF |
|
Default | — | — |
|
The decoder compares the address against every pair and raises one select per slave. One-hot internal selects keep the comparison shallow on wide maps.
Unmapped addresses need a defined error completion. The AND-OR datapath below returns zero when nothing is selected; it does not electrically float. Without default response control, the master may hang or receive a false successful zero. An electrically floating tri-state bus is a different architecture.
The bottom three rows show which slave is selected. Slot 3 is the unmapped access.
Slot 0: addr 0x1000 is the UART base, so sel0 is 1.
Slot 1: addr 0x2000 is the SPI base, so sel1 is 1.
Slot 2: addr 0x1FFF is the UART limit boundary, so sel0 is still 1.
Slot 3: addr 0x3000 matches nothing, so sel0 and sel1 are 0 and default_err is 1.
Slot 4: addr 0x1004 returns to the UART range, so sel0 is 1 again.
The base and limit pairs overlap. Exactly one select may be high for a mapped address, so an overlap is a map bug, and the testbench flags it with a one-hot check.
The data mux parks at zero, but that is not a valid completion contract. Depending on control, the master hangs or mistakes zero for successful data. Supply a default error response; there is no tri-state floating wire in this datapath.
The decoder plus a testbench that checks corners, sweeps 20000 addresses around the regions against a reference and asserts exactly one select on every mapped access.
// bus_decode: base and limit pairs with a one-hot select and a default-slave flag.
module bus_decode #(
parameter [31:0] BASE0 = 32'h0000_1000,
parameter [31:0] LIMIT0 = 32'h0000_1FFF,
parameter [31:0] BASE1 = 32'h0000_2000,
parameter [31:0] LIMIT1 = 32'h0000_2FFF
)(
input logic [31:0] addr,
output logic sel0, sel1,
output logic default_err
);
assign sel0 = (addr >= BASE0) && (addr <= LIMIT0);
assign sel1 = (addr >= BASE1) && (addr <= LIMIT1);
assign default_err = !(sel0 || sel1);
endmodule