A flexible address decoder. Works for any address range at any starting point. The base and bound addresses are set as parameters, so the range is fixed. This decoder works by checking if the input address lies between the base and bound (inclusive) of a range by comparing against each possible address within the range, then outputs the OR-reduction of all these checks.
But there are a couple of caveats: your CAD tool will have to create a little netlist for up to all 2^ADDR_WIDTH possible addresses, and store the matches into a vector of up to 2^ADDR_WIDTH bits long, depending on the base and bound addresses. Elaborating and optimizing this logic can take a very long time and, as I understand it, Verilog implementations have a maximum vector width of a million or so, so this decoder will be likley unusable for address ranges more than 20 bits wide.
Also, even if your CAD tool can handle wider vectors, because we use an integer as counter, this decoder cannot be guaranteed to work for address ranges exceeding 32 bits, depending on your Verilog implementation.
I do not recommend this implementation. I include it because I have put it to good use inside a CPU for decoding register operands, and it might be a good choice for very small, fixed address ranges if your CAD tool cannot fully optimize the Behavioural Address Decoder.
`default_nettype none
module Address_Decoder_Static
#(
parameter ADDR_WIDTH = 0,
parameter ADDR_BASE = 0,
parameter ADDR_BOUND = 0
)
(
input wire [ADDR_WIDTH-1:0] addr,
output reg hit
);
localparam ADDR_COUNT = ADDR_BOUND - ADDR_BASE + 1;
localparam COUNT_ZERO = {ADDR_COUNT{1'b0}};
initial begin
hit = 1'b0;
end
integer i;
reg [ADDR_COUNT-1:0] per_addr_match = COUNT_ZERO;
Check each address in base/bound range for match, and store it in a vector
for later OR-reduction. Note that we select only the bit range we need
from the index i so it doesn't raise a width mismatch warning when
compared to the input address. This does mean problems if ADDR_WIDTH is
greater than 32 bits.
always @(*) begin
for(i = ADDR_BASE; i <= ADDR_BOUND; i = i + 1) begin : addr_decode
per_addr_match[i-ADDR_BASE] = (addr == i[ADDR_WIDTH-1:0]);
end
end
always @(*) begin : is_hit
hit = |per_addr_match;
end
endmodule