Bug in IVerilog and Yosys : non-constant function - fixed - Page 1
Forum section: electronics / general

author: Rainwater
author_rank: Regular Contributor
timestamp: June 22, 2024, 02:33:42 pm
content: Update: bug has been fixed as of commit number 2024-6-26In 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 herehttps://github.com/Adivinedude/FPGA-toolbox/blob/refactor_counter/math_pipelined.vline # 132Code:generate// loop through each unit and assign the in and outsfor( 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 properlyfor( 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 = r_cmp[f_NaryRecursionGetUnitInputAddress(CHUNK_COUNT, CMP_LUT_WIDTH, unit_index, input_index)];end// perform the function and store the outputalways @( posedge clk ) r_cmp[CHUNK_COUNT+unit_index] <= & unit_inputs; // edit operation hereend`undef OPERATIONendgenerateunit_index, input_index, and idx are defined at genvar in line 69-71the functions are defined herehttps://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 invaliderror messageCode: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 timesthe 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.

author: Rainwater
author_rank: Regular Contributor
timestamp: June 22, 2024, 11:48:26 pm
content: 9 hours later ...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 beginif( (results + `next_level_unit_count) <= unit) begin// requested unit is on a different iteration, proceed to the next iterationiterator_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;elseiterator_NaryRecursionGetUnitWidth = lut_width;endend`undef next_level_unit_countendendfunctionshould beCode: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;endfunctionDiscovered this debugging Iverilog 1 step at a time.https://github.com/steveicarus/iverilog/blob/master/elab_expr.ccline #2967Code: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: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)beginfor (iterator_NaryRecursionGetUnitWidth=0; base>0; iterator_NaryRecursionGetUnitWidth=iterator_NaryRecursionGetUnitWidth+1) beginif( base == 1 ) beginiterator_NaryRecursionGetUnitWidth = 0;base = 0;end else beginif( (results + `next_level_unit_count) <= unit ) beginbase = `next_level_unit_count;results = results + `next_level_unit_count;end else beginbase = 0;if( (unit - results ) == `next_level_unit_count-1 ) beginiterator_NaryRecursionGetUnitWidth = base % lut_width == 0 ? lut_width : base % lut_width;end else beginiterator_NaryRecursionGetUnitWidth = lut_width;endendendendend`undef next_level_unit_countendfunctionSo 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.

author: xvr
author_rank: Frequent Contributor
timestamp: June 24, 2024, 12:53:18 pm
content: Just a guess - may be iVerilog (and sby) requires thanonly oneassignment to function return variable will be inside function to allow it to be constant?