verilog: fix const func eval with upto variables
authorZachary Snow <zach@zachjs.com>
Wed, 12 Jan 2022 06:51:08 +0000 (23:51 -0700)
committerZachary Snow <zachary.j.snow@gmail.com>
Fri, 11 Feb 2022 20:01:51 +0000 (21:01 +0100)
CHANGELOG
frontends/ast/ast.h
frontends/ast/simplify.cc
tests/verilog/func_upto.sv [new file with mode: 0644]
tests/verilog/func_upto.ys [new file with mode: 0644]

index 1451ea07caa0c81b6fc548dd476f7a5e5a97fd36..4312ec7ee58ee86b2653789540d740cac80fe4e3 100644 (file)
--- 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
 --------------------------
 
index 48ec9a0630e355504ecbbdbfed982ff1bd53da48..80497c131dc613779b61f7f7b8229974c384f35e 100644 (file)
@@ -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;
index 18b1e1e11a15b95777e395833fdd06056c90b98d..524ae6318673f86712f10672c2d28784dcd93766 100644 (file)
@@ -5134,6 +5134,8 @@ bool AstNode::replace_variables(std::map<std::string, AstNode::varinfo_t> &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<RTLIL::State> &var_bits = variables.at(str).val.bits;
                std::vector<RTLIL::State> 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 (file)
index 0000000..547e5d3
--- /dev/null
@@ -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 (file)
index 0000000..7a8c535
--- /dev/null
@@ -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