I'm using SystemVerilog for synthesis. I fought with the fact that arrays of interfaces are not really arrays in SystemVerilog and the index has to be a constant value, but got over it using at lot of boilerplate generate for
and assign
statements to overcome what is really a language limitation (if I can emulate the effect using more code, the language could just do The Right Thing(tm) itself).
For the following pseudo-code, I leave out much of what's there in the real code (modports, tasks, etc) for clarity. I have an interface:
interface i_triplex();
logic a; // input wire
logic b; // output wire
logic [127:0] data; // output wires
endinterface
And I am passing an array of these interfaces to a module which looks like
module roundrobin_triplex#(
parameter int NUNITS = 8
)
(
input wire clk,
input wire rst,
i_triplex t[NUNITS]
);
always_ff @(posedge clk) begin
if (rst) begin
// insert code to initialize the "data" member
// in all interface instances in the array.
end
else begin
// ...
end
end
endmodule
What would your preferred way to use all interface instance in the array uniformly -- regardless of the value of NUNITS
? I have some suggestions, but I am eager to learn what other engineers can come up with.
Suggestion 1: Use VHDL.
Suggestion 2: Scrap the interface and do it oldschool Verilog-style, as in
module roundrobin_triplex#(
parameter int NUNITS = 8
)
(
input wire clk,
input wire rst,
// This was once a proud i_triplex array
input wire i_triplex_a[NUNITS],
input wire i_triplex_b[NUNITS],
input wire [127:0] i_triplex_data[NUNITS],
);
always_ff @(posedge clk) begin
if (rst) begin
for (int i = 0; i < NUNITS; i++)
i_triplex_data[i] <= '1;
end
else begin
// ...
end
end
endmodule
Suggestion 3:
Use a struct
for input wires and a struct
for output wires instead of the interface.
Suggestion 4:
Use a preprocessor-like system that unrolls generate for
loops inside processes (what the language should do anyway!), so the resulting code looks like (preprocessed with NUNITS=4):
module roundrobin_triplex#(
parameter int NUNITS = 8
)
(
input wire clk,
input wire rst,
i_triplex t[NUNITS]
);
always_ff @(posedge clk) begin
if (rst) begin
i_triplex.data[0] <= '1;
i_triplex.data[1] <= '1;
i_triplex.data[2] <= '1;
i_triplex.data[3] <= '1;
end
else begin
// ...
end
end
endmodule
Suggestion 5:
Use the generate for
/ assign
solution:
module roundrobin_triplex#(
parameter int NUNITS = 8
)
(
input wire clk,
input wire rst,
i_triplex t[NUNITS]
);
wire i_triplex_a[NUNITS];
wire i_triplex_b[NUNITS];
wire [127:0] i_triplex_data[NUNITS];
generate
genvar i;
// The wires of the interface which are to be driven
// from this module are assigned here.
for (i = 0; i < NUNITS; i++) begin
assign t[i].b = i_triplex_b[i];
assign t[i].data = i_triplex_data[i];
end
endgenerate
always_ff @(posedge clk) begin
if (rst) begin
for (int i = 0; i < NUNITS; i++)
i_triplex_data[i] <= '1;
end
else begin
// ...
end
end
endmodule
Arrays of module or interface instances cannot be treated as regular arrays because parameterization, generate blocks, and defparam statements can make elements of the array instance non-unique. That cannot happen with arrays of variables/wires.
My suggestion would be a modification of your suggestion 2; put arrays of variables/wires inside a single interface instance.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With