From 90bb47d18140e381e65bd2b51fd793a0692b56a0 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Tue, 11 Jan 2022 23:51:08 -0700 Subject: verilog: fix const func eval with upto variables --- CHANGELOG | 4 +++ frontends/ast/ast.h | 1 + frontends/ast/simplify.cc | 13 ++++++-- tests/verilog/func_upto.sv | 77 ++++++++++++++++++++++++++++++++++++++++++++++ tests/verilog/func_upto.ys | 7 +++++ 5 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 tests/verilog/func_upto.sv create mode 100644 tests/verilog/func_upto.ys diff --git a/CHANGELOG b/CHANGELOG index 1451ea07c..4312ec7ee 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -5,6 +5,10 @@ List of major changes and improvements between releases Yosys 0.14 .. Yosys 0.14-dev -------------------------- + * Verilog + - Fixed evaluation of constant functions with variables or arguments with + reversed dimensions + Yosys 0.13 .. Yosys 0.14 -------------------------- diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 48ec9a063..80497c131 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -268,6 +268,7 @@ namespace AST struct varinfo_t { RTLIL::Const val; int offset; + bool range_swapped; bool is_signed; AstNode *arg = nullptr; bool explicitly_sized; diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 18b1e1e11..524ae6318 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -5134,6 +5134,8 @@ bool AstNode::replace_variables(std::map &varia width = min(std::abs(children.at(0)->range_left - children.at(0)->range_right) + 1, width); } offset -= variables.at(str).offset; + if (variables.at(str).range_swapped) + offset = -offset; std::vector &var_bits = variables.at(str).val.bits; std::vector new_bits(var_bits.begin() + offset, var_bits.begin() + offset + width); AstNode *newNode = mkconst_bits(new_bits, variables.at(str).is_signed); @@ -5191,7 +5193,8 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) log_file_error(filename, location.first_line, "Incompatible re-declaration of constant function wire %s.\n", stmt->str.c_str()); } variable.val = RTLIL::Const(RTLIL::State::Sx, width); - variable.offset = min(stmt->range_left, stmt->range_right); + variable.offset = stmt->range_swapped ? stmt->range_left : stmt->range_right; + variable.range_swapped = stmt->range_swapped; variable.is_signed = stmt->is_signed; variable.explicitly_sized = stmt->children.size() && stmt->children.back()->type == AST_RANGE; @@ -5276,8 +5279,12 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) int width = std::abs(range->range_left - range->range_right) + 1; varinfo_t &v = variables[stmt->children.at(0)->str]; RTLIL::Const r = stmt->children.at(1)->bitsAsConst(v.val.bits.size()); - for (int i = 0; i < width; i++) - v.val.bits.at(i+offset-v.offset) = r.bits.at(i); + for (int i = 0; i < width; i++) { + int index = i + offset - v.offset; + if (v.range_swapped) + index = -index; + v.val.bits.at(index) = r.bits.at(i); + } } delete block->children.front(); diff --git a/tests/verilog/func_upto.sv b/tests/verilog/func_upto.sv new file mode 100644 index 000000000..547e5d325 --- /dev/null +++ b/tests/verilog/func_upto.sv @@ -0,0 +1,77 @@ +`default_nettype none + +module evil; + parameter HI = 3; + parameter LO = 0; + parameter SPAN = 1; + parameter [HI:LO] A_VAL = 4'b0110; + parameter [HI:LO] B_VAL = 4'b1100; + parameter [2:0] SWAPS = 0; + + localparam D_LEFT = !(SWAPS[0]) ? HI : LO; + localparam D_RIGHT = (SWAPS[0]) ? HI : LO; + localparam E_LEFT = !(SWAPS[1]) ? HI : LO; + localparam E_RIGHT = (SWAPS[1]) ? HI : LO; + localparam F_LEFT = !(SWAPS[2]) ? HI : LO; + localparam F_RIGHT = (SWAPS[2]) ? HI : LO; + + localparam [HI:LO] A_CONST = A_VAL; + localparam [HI:LO] B_CONST = B_VAL; + localparam [HI:LO] C_CONST = F(A_CONST, B_CONST); + + reg [HI:LO] C_WIRE, C_FUNC; + always @* begin + assert (C_CONST == C_WIRE); + assert (C_CONST == C_FUNC); + end + + initial begin : blk + reg [HI:LO] A_WIRE; + reg [HI:LO] B_WIRE; + reg [D_LEFT:D_RIGHT] D; + reg [E_LEFT:E_RIGHT] E; + reg [F_LEFT:F_RIGHT] F_WIRE; + reg [31:0] i; + A_WIRE = A_VAL; + B_WIRE = B_VAL; + D = A_WIRE; + E = B_WIRE; + F_WIRE = 0; + for (i = LO; i + SPAN < HI; i = i + SPAN) + if (SPAN == 1) + F_WIRE[i] = D[i] && E[i]; + else + F_WIRE[i+:SPAN] = D[i+:SPAN] && E[i+:SPAN]; + C_WIRE = F_WIRE; + C_FUNC = F(A_WIRE, B_WIRE); + end + + function automatic [F_LEFT:F_RIGHT] F( + input [D_LEFT:D_RIGHT] D, + input [E_LEFT:E_RIGHT] E); + reg [31:0] i; + F = 0; + for (i = LO; i + SPAN < HI; i = i + SPAN) + if (SPAN == 1) + F[i] = D[i] && E[i]; + else + F[i+:SPAN] = D[i+:SPAN] && E[i+:SPAN]; + endfunction +endmodule + +module top; + for (genvar hi = 0; hi < 3; hi++) + for (genvar lo = 0; lo <= hi; lo++) + for (genvar span = 1; span <= hi - lo + 1; span++) + for (genvar a_val = 0; a_val < 2 ** (hi - lo + 1); a_val++) + for (genvar b_val = 0; b_val < 2 ** (hi - lo + 1); b_val++) + for (genvar swaps = 0; swaps < 2 ** 3; swaps++) + evil #( + .HI(hi), + .LO(lo), + .SPAN(span), + .A_VAL(a_val), + .B_VAL(b_val), + .SWAPS(swaps) + ) e(); +endmodule diff --git a/tests/verilog/func_upto.ys b/tests/verilog/func_upto.ys new file mode 100644 index 000000000..7a8c53506 --- /dev/null +++ b/tests/verilog/func_upto.ys @@ -0,0 +1,7 @@ +read_verilog -sv func_upto.sv +hierarchy -top top +proc +flatten +opt -full +select -module top +sat -verify -seq 1 -prove-asserts -enable_undef -- cgit v1.2.3