Author Topic: Bug in IVerilog and Yosys : non-constant function - fixed  (Read 2314 times)

0 Members and 1 Guest are viewing this topic.

Offline RainwaterTopic starter

  • Regular Contributor
  • *
  • Posts: 71
  • Country: us
Bug in IVerilog and Yosys : non-constant function - fixed
« on: June 22, 2024, 02:33:42 pm »
Update: bug has been fixed as of commit number 2024-6-26

In short, Im building a Nary tree to meet timing for some basic operations. &, |, and ^
Im using some `defines and `undefine statements to make the code reusable for each operations. (a.k.a a little hard to read and follow, but much easier to cut and paste)

I have wrote and tested the recursion functions, and can now calculate all the information needed to build the tree.
but when I try to use the value returned by the function, I get an error in my simulator(iVerilog), but not Gowin FPGA designer( no simulator.)

Error code can be found here
https://github.com/Adivinedude/FPGA-toolbox/blob/refactor_counter/math_pipelined.v
line # 132
Code: [Select]
generate
        // loop through each unit and assign the in and outs
        for( unit_index = 0; unit_index < CMP_VECTOR_SIZE; unit_index = unit_index + 1) begin : CMP_unit_loop
            // make the input wires for this unit   
/*129*/     wire [f_NaryRecursionGetUnitWidth(CHUNK_COUNT, CMP_LUT_WIDTH, unit_index)-1:0] unit_inputs;
            // assign the inputs to their proper place, unused inputs should be optimized away when set properly
            for( input_index = 0; input_index != CMP_LUT_WIDTH; input_index = input_index+1 ) begin : CMP_input_loop
/*132*/         if( f_NaryRecursionGetUnitInputAddress(CHUNK_COUNT, CMP_LUT_WIDTH, unit_index, input_index) != ~0 )
                    assign unit_inputs[input_index] = r_cmp[f_NaryRecursionGetUnitInputAddress(CHUNK_COUNT, CMP_LUT_WIDTH, unit_index, input_index)];
            end
            // perform the function and store the output
            always @( posedge clk ) r_cmp[CHUNK_COUNT+unit_index] <= & unit_inputs;  // edit operation here
        end
        `undef OPERATION
endgenerate
unit_index, input_index, and idx are defined at genvar in line 69-71

the functions are defined here
https://github.com/Adivinedude/FPGA-toolbox/blob/refactor_counter/recursion_iterators.v
#213 // f_NaryRecursionGetUnitWidth - Returns the total number of inputs for unit requested
#297 // f_NaryRecursionGetUnitInputAddress - Returns the index for the base bit requested. returns ~0 is input is request is invalid

error message
Code: [Select]
Starting Testbench with iVerilog
    ././toolbox/recursion_iterators.v:222: error: A function invoked by a constant function must be a constant function local to the current module.
    ././toolbox/recursion_iterators.v:322: error: A function invoked by a constant function must be a constant function local to the current module.
    ././toolbox/recursion_iterators.v:309: error: A function invoked by a constant function must be a constant function local to the current module.
    c:\Users\adivi\Desktop\fpga_projects\Tang_Nano_9K_blink\src\uart\toolbox\math_pipelined.v:132: error: `f_NaryRecursionGetUnitInputAddress' is not a constant function.
    c:\Users\adivi\Desktop\fpga_projects\Tang_Nano_9K_blink\src\uart\toolbox\math_pipelined.v:132: error: Cannot evaluate genvar conditional expression: (f_NaryRecursionGetUnitInputAddress(CHUNK_COUNT, CMP_LUT_WIDTH, unit_index, input_index))!=(~('sd0))
...(last two lines repeat many times

the obvious question is, How do I do this?
but line #129 also requires a constant value, but does not throw an error.
so now i'm questing my understanding of what a constant function is, I have read many google post about it, but none state where the official definition is located. I would love to read it myself.

Im stumped as to what to try next.
This seams simple enough but just doesn't work. its been a real pain in the @$$ for the last few hours.
« Last Edit: August 13, 2024, 10:41:44 am by Rainwater »
"You can't do that" - challenge accepted
 

Offline RainwaterTopic starter

  • Regular Contributor
  • *
  • Posts: 71
  • Country: us
Re: Fixing compiler error : non-constant function
« Reply #1 on: June 22, 2024, 11:48:26 pm »
9 hours later ... :horse:  |O  :wtf:  :palm:  :scared:  :rant:
without altering the logic, simply the way it was written, the error is fixed.

Code: [Select]
function automatic [7:0] iterator_NaryRecursionGetUnitWidth;
    input [7:0] base, lut_width, unit, results;
    integer next_level_unit_count;
    begin : block_NaryRecursionGetUnitWidth
        `define next_level_unit_count (base / lut_width * lut_width == base ? base / lut_width : base / lut_width + 1)
        //$display("\tbase:%d lut_width:%d unit:%d results:%d next:%d", base, lut_width, unit, results, next_level_unit_count);
        if( base == 1 )
            iterator_NaryRecursionGetUnitWidth = 0;    // overflow condition, requested unit not in range, width = 0 is a valid answer;
        else begin
            if( (results + `next_level_unit_count) <= unit) begin
                // requested unit is on a different iteration, proceed to the next iteration
                iterator_NaryRecursionGetUnitWidth = iterator_NaryRecursionGetUnitWidth(
                        `next_level_unit_count,
                        lut_width,
                        unit,
                        results + `next_level_unit_count);
            end else begin
                // requested unit is on this iteration.
                if( (unit - results ) == `next_level_unit_count-1 )
                    iterator_NaryRecursionGetUnitWidth = base % lut_width == 0 ? lut_width : base % lut_width;
                else
                    iterator_NaryRecursionGetUnitWidth = lut_width;
            end
        end
        `undef next_level_unit_count     
    end
endfunction
should be
Code: [Select]
function automatic integer iterator_NaryRecursionGetUnitWidth;
    input integer base, lut_width, unit, results;
        `define next_level_unit_count (base / lut_width * lut_width == base ? base / lut_width : base / lut_width + 1)
    iterator_NaryRecursionGetUnitWidth =
        (base == 1 )
            ? 0
            : (results + `next_level_unit_count) <= unit
                ? iterator_NaryRecursionGetUnitWidth(`next_level_unit_count,lut_width,unit,results + `next_level_unit_count)
                : (unit - results ) == `next_level_unit_count-1
                    ? base % lut_width == 0 ? lut_width : base % lut_width
                    : lut_width;
endfunction

Discovered this debugging Iverilog 1 step at a time.
https://github.com/steveicarus/iverilog/blob/master/elab_expr.cc
line #2967
Code: [Select]
if (dscope->parent() != scope->parent() || !dscope->is_const_func()) {dscope->is_const_func() return false, when processing this function, but the others written differently returns true. No clue as to why. but if anyone else tries this and finds hair stuck between their fingers, here is a fix.
sorry for double posing, felt it was worth it.

Edit: next day.
I discovered that with the latest rewrite, sby (formal solver) stopped working, throwing the same error, on the same function.
so after a little trial and error, This was fixed.
I suspect a bug in both IVerilog, and sby in detecting/classifying  if a function is constant.
Code: [Select]
function automatic integer iterator_NaryRecursionGetUnitWidth;
    input integer base, lut_width, unit, results;
    `define next_level_unit_count (base / lut_width * lut_width == base ? base / lut_width : base / lut_width + 1)
    begin
        for (iterator_NaryRecursionGetUnitWidth=0; base>0; iterator_NaryRecursionGetUnitWidth=iterator_NaryRecursionGetUnitWidth+1) begin
            if( base == 1 ) begin
                iterator_NaryRecursionGetUnitWidth = 0;
                base = 0;
            end else begin
                if( (results + `next_level_unit_count) <= unit ) begin
                    base = `next_level_unit_count;
                    results = results + `next_level_unit_count;
                end else begin
                    base = 0;
                    if( (unit - results ) == `next_level_unit_count-1 ) begin
                        iterator_NaryRecursionGetUnitWidth = base % lut_width == 0 ? lut_width : base % lut_width;
                    end else begin
                        iterator_NaryRecursionGetUnitWidth = lut_width;
                    end
                end
            end
        end
    end
    `undef next_level_unit_count
endfunction

So now I have 3 samples of code, which I believe incorrectly flag an error in different opensource toolchains.
This is supper strange, given that none of the other functions have required this much attention.
this was suppose to be really easy, given that Gowin does not support automatic retiming.
Cant wait for a new version to come out, I'll get to rewrite this all over again.
« Last Edit: June 24, 2024, 12:50:26 am by Rainwater »
"You can't do that" - challenge accepted
 

Offline xvr

  • Frequent Contributor
  • **
  • Posts: 656
  • Country: ie
    • LinkedIn
Re: Bug in IVerilog and Yosys : non-constant function
« Reply #2 on: June 24, 2024, 12:53:18 pm »
Just a guess - may be iVerilog (and sby) requires than only one assignment to function return variable will be inside function to allow it to be constant?
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf