Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Arrays of interface instances in SystemVerilog with parametrized number of elements

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
like image 820
apriori Avatar asked Jul 12 '17 13:07

apriori


1 Answers

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.

like image 125
dave_59 Avatar answered Oct 27 '22 00:10

dave_59