Search code examples
verilogcpu-architecturedigital-logic

Function to calculate a value inside a Verilog generate loop


I am trying to create a parametrized circuit for the multiplication stage of a BCD Wallace Tree Multiplier, which I implemented in Orcad. The trouble I'm having is that I need to calculate the bit positions that each two digits that result from BCD multiplication will inhabit. Here is my code:

module bcd_mult_1_n #(parameter N = 8)
  (input [N * 4 - 1:0] num1, num2, output reg [2 * 4 * N * N - 1:0] partProds);

  genvar i, j;

  generate
    for(i = 0; i < N; i = i + 1) begin : dig1
      for(j = 0; j < N; j = j + 1) begin : dig2
        localparam lsd = posLSD(i, j);
        localparam msd = posMSD(i, j);
        bcd_mult_1 bcd_mult(num1[i * 4 + 3:i * 4], num2[j * 4 + 3:j * 4],
                            partProds[msd * 4 + 3:msd * 4], partProds[lsd * 4 + 3: lsd * 4]);
      end
    end
  endgenerate

In the above code, numPrev(i + j) needs to return a value calculated something like this

int numPrev(int x) {
  int acc = 0;
  for(int i = x; i > 0; i++) acc = acc + 2 * i;
  return acc;
}

Thanks to help from @Morgan I have created the following function; the logic is meant to count up and down a sort of triangle of values which rise from 1 to N and back down to 1.

  function integer posLSD;
    input integer x, y;
    integer weight;
    integer acc;
    integer num;
    integer i;
    weight = x + y;
    acc = 0;
    if(weight >= N) num = N - 1;
    else num = weight;
    for(i = num; i > 0; i = i - 1)
      acc = acc + 2 * i;
    if(weight >= N) begin
      for(i = 2 * N - weight; i <= N; i = i + 1) begin
        acc = acc + 2 * i;
      end
      acc = acc + N - weight + y - 1;
    end
    else
      acc = acc + y;
    posLSD = acc;
  endfunction

  function integer posMSD;
    input integer x, y;
    integer acc;
    integer weight;
    acc = posLSD(x, y);
    weight = x + y;
    if(weight < N) acc = acc + weight + 1;
    else acc = acc + 2 * N - weight - 1;
    posMSD = acc;
  endfunction

How could I achieve this functionality? If needed, I could use SystemVerilog constructs.


Solution

  • When I change to use a function I get the error Packed dimension must specify a range. I think you need to think about your partProds width and connections.

    Using a function:

    module bcd_mult_1_n #(
      parameter N = 8
    )  (
      input [N * 4 - 1:0] num1, 
      input [N * 4 - 1:0] num2, 
      output reg [2 * 4 * N * N] partProds
    );
    
      integer prev = 1;
      genvar i, j;
      generate
        for(i = 0; i < N; i = i + 1) begin : dig1
          for(j = 0; j < N; j = j + 1) begin : dig2
            bcd_mult_1 
              bcd_mult(
                num1[i * 4 + 3:i * 4],
                num2[j * 4 + 3:j * 4], 
                partProds[numPrev(i+j) + 2*j + i + 1], 
                partProds[numPrev(i+j) + j]
              );
          end
        end
      endgenerate
    
      function numPrev;
        input integer x ;
        integer acc;
        begin
          acc = 0;
          for(int ij = x; ij > 0; ij++) begin
            acc = acc + 2 * ij;
          end
          numPrev = acc;
        end
      endfunction
    
    endmodule
    
    module bcd_mult_1(
      input [3:0]a,
      input [3:0]b,
      input c,
      input d
    );
    
    endmodule
    

    Example on EDA Playground.