verilog: fix size and signedness of array querying functions
authorJannis Harder <me@jix.one>
Fri, 20 May 2022 19:46:39 +0000 (21:46 +0200)
committerZachary Snow <zachary.j.snow@gmail.com>
Mon, 30 May 2022 13:11:31 +0000 (09:11 -0400)
genrtlil.cc and simplify.cc had inconsistent and slightly broken
handling of signedness for array querying functions. These functions are
defined to return a signed result. Simplify always produced an unsigned
and genrtlil always a signed 32-bit result ignoring the context.

Includes tests for the the relvant edge cases for context dependent
conversions.

CHANGELOG
frontends/ast/genrtlil.cc
frontends/ast/simplify.cc
tests/verilog/sign_array_query.ys [new file with mode: 0644]

index d64d592d292fb5dfca9720315cdf9cb17089a803..4ee364a57c7a62756fb46e5310b2959ae59e7f03 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -12,6 +12,8 @@ Yosys 0.17 .. Yosys 0.17-dev
     - Fixed an issue where simplifying case statements by removing unreachable
       cases could result in the wrong signedness being used for comparison with
       the remaining cases
+    - Fixed size and signedness computation for expressions containing array
+      querying functions
 
 Yosys 0.16 .. Yosys 0.17
 --------------------------
index 6ef7da7a953e9fe94661cdcee1efc9d83a34d83c..a569c5ae2e4eb91a347b4e1b7a88cdf8c6837376 100644 (file)
@@ -1089,8 +1089,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
                        break;
                }
                if (str == "\\$size" || str == "\\$bits" || str == "\\$high" || str == "\\$low" || str == "\\$left" || str == "\\$right") {
-                       width_hint = 32;
-                       sign_hint = true;
+                       width_hint = max(width_hint, 32);
                        break;
                }
                if (current_scope.count(str))
index c2adcafd0e05a6a0333aa3511cc430d6c3ca8b64..2d9d6dc79c2ba52df31f72608e3c9b529a1a33df 100644 (file)
@@ -3450,7 +3450,7 @@ skip_dynamic_range_lvalue_expansion:;
                                else {
                                        result = width * mem_depth;
                                }
-                               newNode = mkconst_int(result, false);
+                               newNode = mkconst_int(result, true);
                                goto apply_newNode;
                        }
 
diff --git a/tests/verilog/sign_array_query.ys b/tests/verilog/sign_array_query.ys
new file mode 100644 (file)
index 0000000..f955450
--- /dev/null
@@ -0,0 +1,52 @@
+logger -expect-no-warnings
+
+read_verilog -formal <<EOT
+module top(input clk);
+    reg [-1:-1] x;
+    reg good = 0;
+    reg signed [31:0] zero = 0;
+
+    always @(posedge clk) begin
+        case ($left(x) + zero) 36'shfffffffff: good = 1; endcase
+        assert (good);
+    end
+endmodule
+EOT
+
+prep -top top
+sim -n 3 -clock clk
+
+design -reset
+
+read_verilog -formal <<EOT
+module top(input clk);
+    reg [-1:-1] x;
+    reg good = 0;
+
+    always @(posedge clk) begin
+        case ($left(x)) 36'sh0ffffffff: good = 1; (32'h0 + $left(good)): ; endcase
+        assert (good);
+    end
+
+endmodule
+EOT
+
+prep -top top
+sim -n 3 -clock clk
+
+design -reset
+
+read_verilog -formal <<EOT
+module top(input clk);
+    reg [-1:-1] x;
+    reg good = 1;
+
+    always @(posedge clk) begin
+        case (36'sh100000000 + $left(x)) -1: good = 0; endcase
+        assert (good);
+    end
+endmodule
+EOT
+
+prep -top top
+sim -n 3 -clock clk