Search code examples
verilogfpgavivadosynthesis

Error: [VRFC 10-2951] 'WIDTH_DIFF' is not a constant


I am trying to do some width manipulation on the data path and need to pad some some zeros when necessary. I have written the following bit of logic in verilog and trying to synthesize. The following code is a minimal working example and shows the issue that I am facing. When I run the below code.

module mwe
    #(parameter RWIDTH = 20, // can be 20 or 16
      parameter BWIDTH = 16  // is generally always 16
     )
    (
    input clk,
    input rst,
    input a,
    output reg [RWIDTH -1:0] y
    );

    wire     [8*BWIDTH-1:0]          native_wdata_bus;  // 128 bit bus
     reg     [8*RWIDTH-1:0]          modified_wdata_bus;    // can be 128 bit or 160 bit bus based on RDATA configuration

    wire     [8*RWIDTH-1:0]          native_rdata_bus;  // can be 128 bit or 160 bit bus based on RDATA configuration
     reg     [8*BWIDTH-1:0]          modified_rdata_bus;    // generally is 128 bit bus

    // locally calulating the WIDTH_DIFF
    localparam WIDTH_DIFF = RWIDTH-BWIDTH;

    // function to pad zeros
    function [WIDTH_DIFF -1 : 0] pad_zeros(input WIDTH_DIFF);
        pad_zeros = {WIDTH_DIFF{1'b0}};
    endfunction

    always @* begin : width_change
        integer i;
        for (i=0; i<8; i=i+1) begin
            modified_rdata_bus[BWIDTH*i +: BWIDTH-1] = native_rdata_bus[(RWIDTH*i)+WIDTH_DIFF +: (RWIDTH-1)-WIDTH_DIFF];
            if(RWIDTH != BWIDTH)
                modified_wdata_bus[(RWIDTH*i) +: (RWIDTH-1)] = {native_wdata_bus[(BWIDTH*i) +: (BWIDTH-1)], pad_zeros(WIDTH_DIFF)};
            else
                modified_wdata_bus[RWIDTH*i +: RWIDTH-1] = native_wdata_bus[BWIDTH*i +: BWIDTH-1];
            end
    end

endmodule

I get the following when I compile the code using Vivado xvlog.

INFO: [VRFC 10-2263] Analyzing Verilog file "/home/rtl/mwe/mwe.v" into library work
INFO: [VRFC 10-311] analyzing module mwe
ERROR: [VRFC 10-2951] 'WIDTH_DIFF' is not a constant [/home/rtl/mwe/mwe.v:23]
ERROR: [VRFC 10-2865] module 'mwe' ignored due to previous errors [/home/rtl/mwe/mwe.v:1]

I have been looking at other errors similar to mine Verilog If statement - Signal is not a Constant. But it still doesn't exactly answer my question. Why does the Verilog compiler interpret that WIDTH_DIFF is not constant?

Though I am interested to resolve the issue, I am also trying to understand how the verilog interprets the above piece of code (any pointers would be helpful).


Solution

  • In the function declaration, you used: input WIDTH_DIFF. The input is a variable type, not a constant type. Therefore, in the expression {WIDTH_DIFF{1'b0}} inside the function, WIDTH_DIFF is interpreted as a variable, not a constant.

    You can remove the function and directly use the concatenation inline. Change:

    modified_wdata_bus[(RWIDTH*i) +: (RWIDTH-1)] = {native_wdata_bus[(BWIDTH*i) +: (BWIDTH-1)], pad_zeros(WIDTH_DIFF)};
    

    to:

    modified_wdata_bus[(RWIDTH*i) +: (RWIDTH-1)] = {native_wdata_bus[(BWIDTH*i) +: (BWIDTH-1)], {WIDTH_DIFF{1'b0}}};