Hi,
I’ve been working on a parameterized module that can instantiate multiple optional submodules depending on the configuration. Each submodule writes a value to a specific position in an array and asserts an enable signal to indicate valid data.
I have an implementation that works, but it doesn’t feel like the most elegant or intended way of solving this problem. The approach assigns bus indices dynamically based on the active submodules and uses a generate block to instantiate them conditionally.
In the example below, I’ve included only the shared signals across submodules. In reality, each submodule has extra unique signals that aren’t shown for simplicity.
Is there a better or more standard way to approach this situation?
module example_top #(
// Parameters for enabling/disabling submodules
parameter logic USE_A = 1, // Enable Submodule A
parameter logic USE_B = 0, // Enable Submodule B
parameter logic USE_C = 1 // Enable Submodule C
);
// Compute bus indices dynamically based on enabled submodules
localparam int IDX_A = 0;
localparam int IDX_B = IDX_A + USE_A;
localparam int IDX_C = IDX_B + USE_B;
// Define array sizes based on enabled submodules
localparam int ENDPOINTS = USE_A + USE_B + USE_C;
// Declare signals for interconnection
logic [ENDPOINTS-1:0] rd_ack;
logic [ENDPOINTS-1:0] wr_ack;
logic [31:0] rd_data [ENDPOINTS-1:0];
// Submodule instantiations
generate
if (USE_A) begin : gen_a
submodule_a u_a (
.rd_ack_o (rd_ack[IDX_A]),
.wr_ack_o (wr_ack[IDX_A]),
.rd_data_o(rd_data[IDX_A])
);
end
if (USE_B) begin : gen_b
submodule_b u_b (
.rd_ack_o (rd_ack[IDX_B]),
.wr_ack_o (wr_ack[IDX_B]),
.rd_data_o(rd_data[IDX_B])
);
end
if (USE_C) begin : gen_c
submodule_c u_c (
.rd_ack_o (rd_ack[IDX_C]),
.wr_ack_o (wr_ack[IDX_C]),
.rd_data_o(rd_data[IDX_C])
);
end
endgenerate
endmodule
Thanks in advance!