0

I am getting the following error in System Verilog with VCS synthesizer:

The following access has an invalid number of indices. bus[i]

I am basically trying to do a parametrizable mux made of interfaces, with the select bus being one-hot:

module myMux
    #(int unsigned WIDTH=3)
    (
        my_interface              bus[WIDTH-1:0],
        input  logic [WIDTH-1:0]  select,
        output logic [31:0]       out_data
    )
    always_comb begin
        out_data = 'x;
        for (int unsigned i=0; i < WIDTH; i++) begin
            if (select[i]) out_data = bus[i].in_data;
        end
    end
endmodule

I tried the different methods outlined in this answer here (including using |= ) but I always get the same error. Using a "genvar i" instead of an int does not even compile.

If I replace bus[i] with bus[0], then it compiles (but it is not what I want) . . . also, replacing WIDTH with a number in the for statement (ie i < 1) gives me the same error even though it is less than the value of WIDTH.

Any ideas? the code needs to be synthesizable.

Community
  • 1
  • 1
user4061565
  • 545
  • 1
  • 5
  • 16
  • One other thing . . . if I change the interface to register signals than it works (but it is not what I want). – user4061565 Nov 07 '15 at 07:53
  • Is your bus declared as [WIDTH-1:0] or it should be `bus[WIDTH]`. Moreover, select line seems to be single bit from the code, it should be `input select [WIDTH]`. The genvar solution must work, you might have done some silly mistake. – sharvil111 Nov 07 '15 at 10:14
  • @shavill111 oh , that is a typo when I copied it into the question. Select is declared as [WIDTH-1:0] while out_data is a 32 bit bus. Corrected in the question above. – user4061565 Nov 08 '15 at 04:03
  • I tried compiling with the latest version of VCS, and still go an error on these lines, but this time it was "bus[i].in_data. Reason of type check failure : Only constant index is supported here." I still don't know how to do a simple MUX with interfaces, I can't believe that it can't be done. – user4061565 Nov 08 '15 at 04:22
  • @sharvil111 For the genvar alternative in the other post, I get the following error "Variable "out_data" is driven by multiple structural drivers." – user4061565 Nov 08 '15 at 05:58
  • Actually you must put down some trial code here, that didn't worked. I had a similar issue and I did this: `for(genvar i=0;i – sharvil111 Nov 08 '15 at 11:26
  • I have tried with assign statement and its working fine. Please find the exa. code at http://www.edaplayground.com/x/LJ8 – H.Modh Nov 09 '15 at 05:34
  • @H.Modh Interesting (I did not know about edaplayground . . . thanks!) . . . there is one more difference in the simplified code attached in the question, select and out_data are defined as "logic" (updated). In your working code example, if I add "bit" to mux io to match your ports, I get the same error I was getting "Variable "out_data" is driven by multiple structural drivers." Why? and is leaving out the port type legal? – user4061565 Nov 09 '15 at 16:12
  • 1
    When we don't specify any data-type to the port declaration, then the signal will default to a wire type. So, we needed a continuous assignment statement.... But in the second case, we have specified the data-type as a logic.... so continuous assignment will not work over there.. we should use the procedural assignment. Please check the modified code at the same link: edaplayground.com/x/LJ8 – H.Modh Nov 10 '15 at 05:50
  • Thanks, I did not realize that there are cases that one cannot use logic where wire is used. Another observation: in your code example, if I change the always block to always @(*) it still compiles, but if I change it to always_comb or always_latch the error comes back . . . odd, another area I did not realize that there subtle differences. – user4061565 Nov 10 '15 at 15:06

1 Answers1

4

Accessing an instances of an arrayed interface can only be accessed via a simulation constant (parameter, genvar, or hard-coded number). Data types and design elements both use dotted names to access there respected member or hierarchical-name, but the rules for accessing index arrays are different. Best description I can quickly find is in IEEE Std 1800-2012 § 23.6 Hierarchical names and § 23.7 Member selects and hierarchical names.

Here are two possible solutions:

Tri-state solution: floating if select is 0, x on the bit with multiple conflicting drivers.

module myMux
    #(int unsigned WIDTH=3)
    (
        my_interface              bus[WIDTH-1:0],
        input  logic [WIDTH-1:0]  select,
        output wire  [31:0]       out_data
    );
  for (genvar i=0; i < WIDTH; i++) begin : loop
    assign out_data = select[i] ? bus[i].in_data : 'z;
  end
endmodule

Priority selector: using a local 2D array to map the interface instances. This map can be accessed in an always block. If you are on FPGA, this is the better solution as it doesn't need tri-state.

module myMux
    #(int unsigned WIDTH=3)
    (
        my_interface              bus[WIDTH-1:0],
        input  logic [WIDTH-1:0]  select,
        output logic [31:0]       out_data
    );
  logic [31:0] map [WIDTH];
  for (genvar i=0; i < WIDTH; i++) begin : loop
    assign map[i] = bus[i].in_data;
  end
  always_comb begin
    out_data = 'x;
    for(int unsigned i=0; i<WIDTH; i++) begin
      if (select[i]) out_data = map[i];
    end
  end
endmodule
Greg
  • 18,111
  • 5
  • 46
  • 68
  • For the first one (tri-state solution), it still will not compile for me as I get the error: "Variable "out_data" is driven by multiple structural drivers." The second one, "Priority selector", compiled for me even though I don't really understand why the map is needed in the first place . . . so I am going to approve the answer. One question . . . when synthesized, will it flatten it out without priority, or will it add logic complexity and try to keep the priority? – user4061565 Nov 10 '15 at 02:20
  • The tri-state solution needs `out_data` to be declared as a `wire`, not `logic`. It may not synthesize with fpga (limited number of tri-state drivers). For the priority selector, the synthesizer may keep the priority. It can flatten if `select` is guaranteed to be one-hot, or a pragma (if synthesizer supports it, check manual), or maybe a setting in the synthesizer options. – Greg Nov 10 '15 at 07:04
  • Thanks! If I change out_data to wire as you have, then even the first compiles. I can even change the assignment to 'x instead of 'z. I thought logic (which can hold 4 states including z and x) could be used everywhere that wire could be used, but obviously there are some subtleties! – user4061565 Nov 10 '15 at 14:58
  • 1
    `'z` is floating (no-driver). `'x` is driven, but has a unknown/illegal value. `wire` allows multiple concurrent assignments (conflicting 0/1/X assignments results in X. Z does not conflict with anything), and it cannot be assigned in an always block. `logic` & `reg` are assigned in always blocks and cannot have multiple concurrent assignments. If two or more always blocks assign the same register, last assignments wins, and is not synthesizable. – Greg Nov 10 '15 at 17:31
  • Bro, I've been scratching my head for hours. I'm a noob at System Verilog but now I realized that you are encoding the selector using `one-hot` and not regular binary like I'm used to. Is there any benefit of doing it the way you do? – StickySli Mar 19 '23 at 02:15