From 55ad95060996d3398ef8eee883f5ec71d935e731 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 19 Dec 2023 19:22:54 -0500 Subject: [PATCH] Fix power operator with wide numbers and constants (#4721) (#4763) --- Changes | 2 +- src/V3Const.cpp | 6 +---- src/V3Number.cpp | 11 ++++++--- src/V3Number.h | 1 + test_regress/t/TestCheck.h | 2 ++ test_regress/t/t_math_pow.v | 7 +++++- test_regress/t/t_math_pow7.cpp | 42 ++++++++++++++++++++++++++++++++++ test_regress/t/t_math_pow7.pl | 27 ++++++++++++++++++++++ test_regress/t/t_math_pow7.v | 29 +++++++++++++++++++++++ 9 files changed, 117 insertions(+), 10 deletions(-) create mode 100644 test_regress/t/t_math_pow7.cpp create mode 100755 test_regress/t/t_math_pow7.pl create mode 100644 test_regress/t/t_math_pow7.v diff --git a/Changes b/Changes index aba862006..5c962a317 100644 --- a/Changes +++ b/Changes @@ -47,7 +47,7 @@ Verilator 5.019 devel * Fix compilers seeing empty input due to file system races (#4708). [Flavien Solt] * Fix shift of > 32-bit number (#4719). [Flavien Solt] * Fix Windows include gates in filesystem Flush implementation. (#4720). [William D. Jones] -* Fix 0**0 with wide numbers (#4721). [Flavien Solt] +* Fix power operator with wide numbers and constants (#4721) (#4763). [Flavien Solt] * Fix parameter passing to ports (#4723). [Ryszard Rozak, Antmicro Ltd.] * Fix block names of nested do..while loops (#4728). [Ryszard Rozak, Antmicro Ltd.] diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 7f91aff2a..353d03a6d 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -3434,10 +3434,6 @@ class ConstVisitor final : public VNVisitor { TREEOP ("AstPowSS {$rhsp.isZero}", "replaceNum(nodep, 1)"); // Overrides lhs zero rule TREEOP ("AstPowSU {$rhsp.isZero}", "replaceNum(nodep, 1)"); // Overrides lhs zero rule TREEOP ("AstPowUS {$rhsp.isZero}", "replaceNum(nodep, 1)"); // Overrides lhs zero rule - TREEOP ("AstPow {$lhsp.isZero, !$rhsp.isZero}", "replaceZeroChkPure(nodep,$rhsp)"); - TREEOP ("AstPowSU {$lhsp.isZero, !$rhsp.isZero}", "replaceZeroChkPure(nodep,$rhsp)"); - TREEOP ("AstPowUS {$lhsp.isZero, !$rhsp.isZero}", "replaceZeroChkPure(nodep,$rhsp)"); - TREEOP ("AstPowSU {$lhsp.isZero, !$rhsp.isZero}", "replaceZeroChkPure(nodep,$rhsp)"); TREEOP ("AstOr {$lhsp.isZero, $rhsp}", "replaceWRhs(nodep)"); TREEOP ("AstShiftL {$lhsp.isZero, $rhsp}", "replaceZeroChkPure(nodep,$rhsp)"); TREEOP ("AstShiftLOvr {$lhsp.isZero, $rhsp}", "replaceZeroChkPure(nodep,$rhsp)"); @@ -3479,7 +3475,7 @@ class ConstVisitor final : public VNVisitor { TREEOP ("AstMul {operandIsPowTwo($lhsp), operandsSameSize($lhsp,,$rhsp)}", "replaceMulShift(nodep)"); // a*2^n -> a< a>>n TREEOP ("AstModDiv{$lhsp, operandIsPowTwo($rhsp)}", "replaceModAnd(nodep)"); // a % 2^n -> a&(2^n-1) - TREEOP ("AstPow {operandIsTwo($lhsp), $rhsp}", "replacePowShift(nodep)"); // 2**a == 1<castAdd()->lhsp(),$rhsp}, $lhsp->castAdd()->rhsp()}"); // ((a+x)-y) -> (a+(x-y)) TREEOPC("AstAnd {$lhsp.isOne, matchRedundantClean(nodep)}", "DONE") // 1 & (a == b) -> (IData)(a == b) // Trinary ops diff --git a/src/V3Number.cpp b/src/V3Number.cpp index cc2afeb61..e51111b0f 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -482,6 +482,11 @@ V3Number& V3Number::setAllBitsXRemoved() { } } } +V3Number& V3Number::setValue1() { + m_data.num()[0] = {1, 0}; + for (int i = 1; i < words(); i++) m_data.num()[i] = {0, 0}; + return *this; +} V3Number& V3Number::setMask(int nbits) { setZero(); @@ -2139,18 +2144,18 @@ V3Number& V3Number::opPow(const V3Number& lhs, const V3Number& rhs, bool lsign, NUM_ASSERT_OP_ARGS2(lhs, rhs); NUM_ASSERT_LOGIC_ARGS2(lhs, rhs); if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX(); - if (rhs.isEqZero()) return setQuad(1); // Overrides lhs 0 -> return 0 + if (rhs.isEqZero()) return setValue1(); // Overrides lhs 0 -> return 1 // We may want to special case when the lhs is 2, so we can get larger outputs if (rsign && rhs.isNegative()) { if (lhs.isEqZero()) { return setAllBitsXRemoved(); } else if (lhs.isEqOne()) { - return setQuad(1); + return setValue1(); } else if (lsign && lhs.isEqAllOnes()) { if (rhs.bitIs1(0)) { return setAllBits1(); // -1^odd=-1 } else { - return setQuad(1); // -1^even=1 + return setValue1(); // -1^even=1 } } return setZero(); diff --git a/src/V3Number.h b/src/V3Number.h index e695f717d..c692d2701 100644 --- a/src/V3Number.h +++ b/src/V3Number.h @@ -581,6 +581,7 @@ public: V3Number& setAllBitsZ(); V3Number& setAllBits0(); V3Number& setAllBits1(); + V3Number& setValue1(); V3Number& setMask(int nbits); // IE if nbits=1, then 0b1, if 2->0b11, if 3->0b111 etc // ACCESSORS diff --git a/test_regress/t/TestCheck.h b/test_regress/t/TestCheck.h index 17a25accb..4b46c142b 100644 --- a/test_regress/t/TestCheck.h +++ b/test_regress/t/TestCheck.h @@ -12,6 +12,8 @@ #ifndef TEST_CHECK_H_ #define TEST_CHECK_H_ +#include + extern int errors; #ifdef TEST_VERBOSE diff --git a/test_regress/t/t_math_pow.v b/test_regress/t/t_math_pow.v index 7bb0a4bc4..bf7236e89 100644 --- a/test_regress/t/t_math_pow.v +++ b/test_regress/t/t_math_pow.v @@ -1,7 +1,7 @@ // DESCRIPTION: Verilator: Verilog Test module // // This file ONLY is placed under the Creative Commons Public Domain, for -// any use, without warranty, 2005 by Wilson Snyder. +// any use, without warranty, 2023 by Wilson Snyder. // SPDX-License-Identifier: CC0-1.0 `define STRINGIFY(x) `"x`" @@ -235,6 +235,11 @@ module t (/*AUTOARG*/ $write("- cyc%0d: %0x**%0x = sh %0x\n", cyc, a, b, shifted); `endif // Constant versions + `checkh(67'h0 ** 21'h0, 67'h1); + `checkh(67'h1 ** 21'h0, 67'h1); + `checkh(67'h2 ** 21'h0, 67'h1); + `checkh(67'h0 ** 21'h1, 67'h0); + `checkh(67'h0 ** 21'h4, 67'h0); `checkh(67'h1 ** 21'h31, 67'h1); `checkh(67'h2 ** 21'h10, 67'h10000); `checkh(67'd10 ** 21'h3, 67'h3e8); diff --git a/test_regress/t/t_math_pow7.cpp b/test_regress/t/t_math_pow7.cpp new file mode 100644 index 000000000..703e10f00 --- /dev/null +++ b/test_regress/t/t_math_pow7.cpp @@ -0,0 +1,42 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +// +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +#include VM_PREFIX_INCLUDE + +#include "TestCheck.h" + +int errors = 0; + +std::unique_ptr topp; +int main(int argc, char** argv) { + vluint64_t sim_time = 1100; + const std::unique_ptr contextp{new VerilatedContext}; + contextp->commandArgs(argc, argv); + topp.reset(new VM_PREFIX{"top"}); + + topp->eval(); + { contextp->timeInc(10); } + + int cyc = 0; + + while ((contextp->time() < sim_time) && !contextp->gotFinish()) { + topp->eval(); + contextp->timeInc(5); + + ++cyc; + if (cyc > 10) break; + } + + TEST_CHECK_EQ(topp->out_data, 1); + + topp->final(); + topp.reset(); + + printf("*-* All Finished *-*\n"); + return errors != 0; +} diff --git a/test_regress/t/t_math_pow7.pl b/test_regress/t/t_math_pow7.pl new file mode 100755 index 000000000..0a4dc8a6b --- /dev/null +++ b/test_regress/t/t_math_pow7.pl @@ -0,0 +1,27 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + make_top_shell => 0, + make_main => 0, + verilator_flags2 => [ + "--exe", + "$Self->{t_dir}/$Self->{name}.cpp" + ], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_math_pow7.v b/test_regress/t/t_math_pow7.v new file mode 100644 index 000000000..68a14e599 --- /dev/null +++ b/test_regress/t/t_math_pow7.v @@ -0,0 +1,29 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2005 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`define STRINGIFY(x) `"x`" + +`define stop $stop +`ifdef VERILATOR + `define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0) +`else + `define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); end while(0) +`endif + +module t (/*AUTOARG*/ + // Outputs + out_data + ); + + output [11:0] out_data; + wire [11:0] out_data; + wire [11:0] a; + wire [2:0] b; + assign a = 12'h000 ** { b }; + assign b = 3'b0; + assign out_data = a; + +endmodule