Arrays of interface instances in SystemVerilog with a parameterized number of elements

I use SystemVerilog for synthesis. I struggled with the fact that the interface arrays are not really arrays in SystemVerilog, and the index should be a constant value, but exceeded it using many generate for and assign patterns to overcome what is really a language restriction (if I can emulate the effect using more code, the language could just do The Right Thing (tm)).

For the next pseudo-code, I leave for myself most of what is in real code (modports, tasks, etc.). I have an interface:

 interface i_triplex(); logic a; // input wire logic b; // output wire logic [127:0] data; // output wires endinterface 

And I pass an array of these interfaces to a module that 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 is the preferred way to use an entire interface instance in an array uniformly - regardless of the NUNITS value? I have some suggestions, but I really want to know what other engineers can offer.

Suggestion 1: Use VHDL.

Proposition 2: Reset 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 

Proposition 3: Use struct for input wires and struct for output wires instead of an interface.

Proposition 4: Use a preprocessor system that deploys generate for loops inside processes (what the language should do anyway!), So the resulting code looks like (pre-processed using 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 

Proposition 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 
+5
source share
4 answers

Arrays of instances of modules or interfaces cannot be considered as ordinary arrays, since the parameterization, block generation, and defparam commands can make the elements of an array instance not unique. This cannot happen with variable / wire arrays.

My suggestion would be a modification of your suggestion 2; Put arrays of variables / wires inside one instance of the interface.

+1
source

Suggestion 1 : VHDL can be practical. However, it seems to be becoming marginalized in industry.

Proposition 2 . In my opinion, interfaces are relevant if you intend to reuse it and implement verification / protocols into it. If you can unzip your interface like this, while keeping your mind, then I see no excuse for the interface in the first place.

Proposition 3 : I never tried to synthesize a struct , this might be a good idea.

Proposition 4 : A simple solution, although quite verbose.

Proposition 5 . I used something similar for one of my projects. However, I wrote a kind of adapter module to hide the destination.
In fact, when I need something like this, I try to write an atomic module that runs on a fixed number of interfaces. Then I use the for generate structures to summarize it in the interface array.

0
source

what about sentence # 6, use a parameterized interface:

 interface I #(NPORTS = 8); logic clk; logic a[NPORTS]; logic b[NPORTS]; logic [127:0] data [NPORTS]; endinterface // module roundrobin#(NUMPORTS = 8) (I t); logic [127:0] data[NUMPORTS]; always_ff @(posedge t.clk) begin data <= t.data; end endmodule // roundrobin 

Note that you do not need a loop in the system verilog. you can use array assignments:

 data <= t.data; 

and for convenience you can add functions or instructions to the interface itself, i.e.

 interface I #(NPORTS = 8); logic clk; logic a[NPORTS]; logic b[NPORTS]; logic [127:0] data [NPORTS]; function logic [127:0] getData(int n); return data[n]; endfunction // getData endinterface // I 

and use

  data[i] <= t.getData(i); 

Sorry, the above example is probably not very useful, but it may give you an idea.

0
source

Maybe I'm missing something, why not put all your code from roundrobin_triplex into the generate (you don't need additional assignments)

 interface i_triplex(); logic a; // input wire logic b; // output wire logic [127:0] data; // output wires initial $fmonitor(1,data); endinterface module roundrobin_triplex#(parameter int NUNITS = 8) ( input wire clk, input wire rst, i_triplex t[NUNITS] ); genvar i; for( i=0; i<NUNITS; i++)begin always_ff @(posedge clk) begin if (rst) begin t[i].data <=0; end else begin t[i].data <=t[i].data+1; end end end endmodule module top; parameter P=4; bit clk,rst; i_triplex ii[P](); roundrobin_triplex #(P)uut(clk,rst,ii); initial begin rst=1; repeat(2) @(posedge clk); rst=0; repeat(10) @(posedge clk); $finish; end always #5 clk =~clk; endmodule 
0
source

Source: https://habr.com/ru/post/1269754/


All Articles