Electronics > FPGA

Bug in IVerilog and Yosys : non-constant function

(1/1)

Rainwater:
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: ---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
--- End code ---
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: ---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
--- End code ---

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.

Rainwater:
9 hours later ... :horse:  |O  :wtf:  :palm:  :scared:  :rant:
without altering the logic, simply the way it was written, the error is fixed.


--- Code: ---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
--- End code ---
should be

--- Code: ---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

--- End code ---

Discovered this debugging Iverilog 1 step at a time.
https://github.com/steveicarus/iverilog/blob/master/elab_expr.cc
line #2967

--- Code: ---if (dscope->parent() != scope->parent() || !dscope->is_const_func()) {
--- End code ---
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: ---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
--- End code ---

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.

xvr:
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?

Navigation

[0] Message Index

There was an error while thanking
Thanking...
Go to full version
Powered by SMFPacks Advanced Attachments Uploader Mod