1

I have an array of parameters WIDTHS, and I need to calculate another parameter RIGHT based on some values in WIDTHS in a generate block. Is this possible? If not, is there an alternative way?

Here is an example of what I am trying to do. Suppose we have a predefined register module REG which has inputs d, q, we (write enable), CLK and _RESET. I would like to create a new module called GroupReg, which instantiates N instances of REG. Each instance has a different width (hence the WIDTH parameter array). The d, q, and we of each group are aggregated in arrays with the same name in GroupReg and need to be specified for each instance. Specifying we is easy (we[i]) since it is only one bit. However, specifying d and q with the correct LEFT and RIGHT values is where I have problem with since each group has a different width.

Looks like the only way to assign a value to a parameter is upon its definition, which prevents assigning a value to it in a generate loop.

 module GroupReg(d, q, we, CLK, _RESET);
 parameter N = 4;               //Number of groups
 //INDICES has to have N+1 members. Last member should be 0
 parameter integer WIDTHS   [N:0]  = {40, 30, 20, 10, 0}; 
 parameter integer DW_TOTAL  = 128;

 input  logic [DW_TOTAL-1:0]        d;                  // Data Input
 input  logic [N-1:0]               we;                     // write enable
 input  logic                       CLK;                // Clock Input
 input  logic                       _RESET;           // Reset input (active low)
 output logic [DW_TOTAL-1:0]        q;            // Q output

 genvar i, j;
 for (i=N-1 ; i>=0 ; i--) begin:REGISTERS

  localparam WIDTH = WIDTHS[i];
  localparam LEFT  = RIGHT +  WIDTHS[i];;
  localparam RIGHT = 0;

  for (j = 0 ; j<i ; j++)        // <<----- Does not work
    RIGHT = RIGHT + WIDTH[j];  

  REG #(
             .DW              (WIDTH),
             ) 
  reg_i 
  ( 
   .d(d[LEFT:RIGHT]), 
   .q(q[LEFT:RIGHT]),
   .we(we[i]),
   .CLK(CLK),
  ._RESET(_RESET)  
  );
 end : REGISTERS
endmodule  
Ari
  • 7,251
  • 11
  • 40
  • 70
  • I don't think using the extra `for` loop is possible. You shouldn't interpret that loop as procedural code. What that loop does is create another level of hierarchy. – Tudor Timi Nov 06 '14 at 23:17

2 Answers2

1

I tried using the sum() array reduction method on WIDTHS and it worked in Aldec Riviera PRO:

module some_module;
  parameter N = 4;               //Number of groups
  parameter integer WIDTHS   [N:0]  = '{40, 30, 20, 10, 0};

  parameter integer DW_TOTAL  = WIDTHS.sum();

  initial begin
    $display("DW_TOTAL", DW_TOTAL);
  end
endmodule

If you're lucky it's going to work in your simulator too.

I anyway don't really get what you're trying to do making N a parameter, seeing as how you're anyway hardcoding a fixed number of values for the widths.

Tudor Timi
  • 7,453
  • 1
  • 24
  • 53
  • 1
    I tried it out in ModelSim and there it complains that `sum()` is not a constant value. It's silly, seeing as how `WIDTH` is an elaborate time constant (being a parameter and all). Point goes to Aldec! – Tudor Timi Nov 06 '14 at 21:17
  • Thanks. I was not aware about sum which is very useful, but I need to calculate a partial sum each time to calculate left and right correctly. – Ari Nov 06 '14 at 21:42
  • The LRM is very specific about which built in functions can be used in a constant expression. Some may seem overly restrictive, but if you try to add a `with` clause to the reduction, things get very complicated to evaluate as a constant expression because it needs to generate procedural code. Many vendors have relaxed some restrictions, but it is in a case by case basis. – dave_59 Nov 07 '14 at 01:21
  • @dave_59 I may be missing something, but for these methods, shouldn't it be that if all inputs are constants, then the output is also going to be a constant? Also, could you point us out to the section in the LRM that discusses constant expressions? – Tudor Timi Nov 07 '14 at 07:36
  • The LRM specifically lists them in "Section 11.2.1 Certain built-in system functions where the arguments are constant expressions are constant system function calls. Specifically, these are the conversion system functions listed in 20.5, the mathematical system functions listed in 20.8, and the bit vector system functions listed in 20.9." – dave_59 Nov 07 '14 at 15:50
0

This works in Modelsim:

module some_module;
  parameter N = 4;               //Number of groups
  parameter integer WIDTHS   [N:0]  = '{40, 30, 20, 10, 0};


  genvar i;
  for (i=N-1 ; i>=0 ; i--) begin
    localparam integer FOO[i:0] = WIDTHS[i:0];
    //localparam RIGHT = FOO.sum();

    initial begin
      foreach (FOO[i])
        $display("FOO[%0d] = %h", i, FOO[i]);
    end
  end
endmodule

The FOO parameter would only store the relevant entries from WIDTH for a specific loop iteration. If sum() would work, you'd be home free. The slicing syntax doesn't work in Riviera, however.

This is a typical example of vendors interpreting the standard differently, basically because it's not specific enough. Still, if you use a simulator from a different EDA company, try combining the two answers; maybe you're lucky and it works.

Tudor Timi
  • 7,453
  • 1
  • 24
  • 53
  • Tudor: I see that part of WIDTH is assigned to FOO, but what I was hoping for was to find a way to perform a function (i.e. sum) on that portion, not just an assignment. FOO.sum() didn't work for me, and I got the same "sum is not a valid constant function" error. It's surprising that there is not an easy way to describe a module like the one I am trying to define above. – Ari Nov 07 '14 at 23:54
  • 1
    @Ari I get what you wanted to do, but the idea was maybe your simulator supported both operation. Other than this I can't think of anything else you can do :( – Tudor Timi Nov 08 '14 at 10:46