mirror of
https://github.com/verilator/verilator.git
synced 2025-01-01 04:07:34 +00:00
Fix REALCVT warning on integral timescale conversions (#5378).
This commit is contained in:
parent
d8fdfa6be2
commit
f0cd6dd95c
1
Changes
1
Changes
@ -14,6 +14,7 @@ Verilator 5.029 devel
|
|||||||
**Minor:**
|
**Minor:**
|
||||||
|
|
||||||
* Improve Verilation thread pool (#5161). [Bartłomiej Chmiel, Antmicro Ltd.]
|
* Improve Verilation thread pool (#5161). [Bartłomiej Chmiel, Antmicro Ltd.]
|
||||||
|
* Fix REALCVT warning on integral timescale conversions (#5378). [Liam Braun]
|
||||||
* Fix dot fallback finding wrong symbols (#5394). [Arkadiusz Kozdra, Antmicro Ltd.]
|
* Fix dot fallback finding wrong symbols (#5394). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||||
|
|
||||||
|
|
||||||
|
@ -388,6 +388,17 @@ void V3Number::nodep(AstNode* nodep) VL_MT_STABLE {
|
|||||||
//======================================================================
|
//======================================================================
|
||||||
// Global
|
// Global
|
||||||
|
|
||||||
|
bool V3Number::epsilonEqual(double a, double b) {
|
||||||
|
return std::fabs(a - b)
|
||||||
|
<= (std::numeric_limits<double>::epsilon() * std::max(1.0, std::max(a, b)));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool V3Number::epsilonIntegral(double a) {
|
||||||
|
const double dint = static_cast<double>(static_cast<int64_t>(a));
|
||||||
|
// Check all the rounding possibilities, as we did truncation above rather than rounding
|
||||||
|
return epsilonEqual(a, dint) || epsilonEqual(a, dint - 1) || epsilonEqual(a, dint + 1);
|
||||||
|
}
|
||||||
|
|
||||||
int V3Number::log2b(uint32_t num) {
|
int V3Number::log2b(uint32_t num) {
|
||||||
// See also opCLog2
|
// See also opCLog2
|
||||||
for (int bit = 31; bit > 0; bit--) {
|
for (int bit = 31; bit > 0; bit--) {
|
||||||
@ -2551,6 +2562,23 @@ void V3Number::selfTest() {
|
|||||||
|
|
||||||
void V3Number::selfTestThis() {
|
void V3Number::selfTestThis() {
|
||||||
// The self test has a "this" so UASSERT_SELFTEST/errorEndFatal works correctly
|
// The self test has a "this" so UASSERT_SELFTEST/errorEndFatal works correctly
|
||||||
|
|
||||||
|
UASSERT_SELFTEST(bool, V3Number::epsilonEqual(0, 0), true);
|
||||||
|
UASSERT_SELFTEST(bool, V3Number::epsilonEqual(1e19, 1e19), true);
|
||||||
|
UASSERT_SELFTEST(bool, V3Number::epsilonEqual(9, 0.0001), false);
|
||||||
|
UASSERT_SELFTEST(bool, V3Number::epsilonEqual(1, 1 + std::numeric_limits<double>::epsilon()),
|
||||||
|
true);
|
||||||
|
UASSERT_SELFTEST(bool, V3Number::epsilonEqual(0.009, 0.00899999999999999931998839741709),
|
||||||
|
true);
|
||||||
|
|
||||||
|
UASSERT_SELFTEST(bool, V3Number::epsilonIntegral(0), true);
|
||||||
|
UASSERT_SELFTEST(bool, V3Number::epsilonIntegral(1), true);
|
||||||
|
UASSERT_SELFTEST(bool, V3Number::epsilonIntegral(-1), true);
|
||||||
|
UASSERT_SELFTEST(bool, V3Number::epsilonIntegral(1.0001), false);
|
||||||
|
UASSERT_SELFTEST(bool, V3Number::epsilonIntegral(0.9999), false);
|
||||||
|
UASSERT_SELFTEST(bool, V3Number::epsilonIntegral(-1.0001), false);
|
||||||
|
UASSERT_SELFTEST(bool, V3Number::epsilonIntegral(-0.9999), false);
|
||||||
|
|
||||||
UASSERT_SELFTEST(int, log2b(0), 0);
|
UASSERT_SELFTEST(int, log2b(0), 0);
|
||||||
UASSERT_SELFTEST(int, log2b(1), 0);
|
UASSERT_SELFTEST(int, log2b(1), 0);
|
||||||
UASSERT_SELFTEST(int, log2b(0x40000000UL), 30);
|
UASSERT_SELFTEST(int, log2b(0x40000000UL), 30);
|
||||||
|
@ -32,14 +32,6 @@
|
|||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
// Return if two numbers within Epsilon of each other
|
|
||||||
inline bool v3EpsilonEqual(double a, double b) {
|
|
||||||
return std::fabs(a - b)
|
|
||||||
<= (std::numeric_limits<double>::epsilon() * std::max(1.0, std::max(a, b)));
|
|
||||||
}
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
|
|
||||||
class AstNode;
|
class AstNode;
|
||||||
class AstNodeDType;
|
class AstNodeDType;
|
||||||
class FileLine;
|
class FileLine;
|
||||||
@ -662,6 +654,8 @@ public:
|
|||||||
bool operator<(const V3Number& rhs) const { return isLtXZ(rhs); }
|
bool operator<(const V3Number& rhs) const { return isLtXZ(rhs); }
|
||||||
|
|
||||||
// STATICS
|
// STATICS
|
||||||
|
static bool epsilonEqual(double a, double b); // True if number within Epsilon of the other
|
||||||
|
static bool epsilonIntegral(double a); // True if number rounds to integer within Epsilon
|
||||||
static int log2b(uint32_t num);
|
static int log2b(uint32_t num);
|
||||||
static int log2bQuad(uint64_t num);
|
static int log2bQuad(uint64_t num);
|
||||||
static void selfTest();
|
static void selfTest();
|
||||||
|
@ -200,7 +200,7 @@ public:
|
|||||||
varNum.opIToRD(pinValuep->num());
|
varNum.opIToRD(pinValuep->num());
|
||||||
var = varNum.toDouble();
|
var = varNum.toDouble();
|
||||||
}
|
}
|
||||||
return v3EpsilonEqual(var, hierOptParamp->num().toDouble());
|
return V3Number::epsilonEqual(var, hierOptParamp->num().toDouble());
|
||||||
} else { // Now integer type is assumed
|
} else { // Now integer type is assumed
|
||||||
// Bitwidth of hierOptParamp is accurate because V3Width already calculated in the
|
// Bitwidth of hierOptParamp is accurate because V3Width already calculated in the
|
||||||
// previous run. Bitwidth of pinValuep is before width analysis, so pinValuep is casted
|
// previous run. Bitwidth of pinValuep is before width analysis, so pinValuep is casted
|
||||||
|
@ -1506,9 +1506,9 @@ class WidthVisitor final : public VNVisitor {
|
|||||||
const AstConst* const constp = VN_CAST(nodep->lhsp(), Const);
|
const AstConst* const constp = VN_CAST(nodep->lhsp(), Const);
|
||||||
UASSERT_OBJ(constp && constp->isDouble(), nodep, "Times should be doubles");
|
UASSERT_OBJ(constp && constp->isDouble(), nodep, "Times should be doubles");
|
||||||
UASSERT_OBJ(!nodep->timeunit().isNone(), nodep, "$time import no units");
|
UASSERT_OBJ(!nodep->timeunit().isNone(), nodep, "$time import no units");
|
||||||
double time = constp->num().toDouble();
|
const double timePrescale = constp->num().toDouble();
|
||||||
UASSERT_OBJ(!v3Global.rootp()->timeprecision().isNone(), nodep, "Never set precision?");
|
UASSERT_OBJ(!v3Global.rootp()->timeprecision().isNone(), nodep, "Never set precision?");
|
||||||
time /= nodep->timeunit().multiplier();
|
const double time = timePrescale / nodep->timeunit().multiplier();
|
||||||
// IEEE claims you should round to time precision here, but no simulator seems to do this
|
// IEEE claims you should round to time precision here, but no simulator seems to do this
|
||||||
AstConst* const newp = new AstConst{nodep->fileline(), AstConst::RealDouble{}, time};
|
AstConst* const newp = new AstConst{nodep->fileline(), AstConst::RealDouble{}, time};
|
||||||
nodep->replaceWith(newp);
|
nodep->replaceWith(newp);
|
||||||
@ -7305,10 +7305,7 @@ class WidthVisitor final : public VNVisitor {
|
|||||||
if (const AstConst* const constp = VN_CAST(nodep, Const)) {
|
if (const AstConst* const constp = VN_CAST(nodep, Const)) {
|
||||||
// We convert to/from int32_t rather than use floor() as want to make sure is
|
// We convert to/from int32_t rather than use floor() as want to make sure is
|
||||||
// representable in integer's number of bits
|
// representable in integer's number of bits
|
||||||
if (constp->isDouble()
|
if (constp->isDouble() && V3Number::epsilonIntegral(constp->num().toDouble())) {
|
||||||
&& v3EpsilonEqual(
|
|
||||||
constp->num().toDouble(),
|
|
||||||
static_cast<double>(static_cast<int32_t>(constp->num().toDouble())))) {
|
|
||||||
warnOn = false;
|
warnOn = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,15 @@
|
|||||||
%Warning-REALCVT: t/t_lint_realcvt_bad.v:10:11: Implicit conversion of real to integer
|
%Warning-REALCVT: t/t_lint_realcvt_bad.v:12:18: Implicit conversion of real to integer
|
||||||
10 | i = 23.2;
|
12 | time t_bad1 = 9.001ns;
|
||||||
| ^~~~
|
| ^~~~~~~
|
||||||
... For warning description see https://verilator.org/warn/REALCVT?v=latest
|
... For warning description see https://verilator.org/warn/REALCVT?v=latest
|
||||||
... Use "/* verilator lint_off REALCVT */" and lint_on around source to disable this message.
|
... Use "/* verilator lint_off REALCVT */" and lint_on around source to disable this message.
|
||||||
|
%Warning-REALCVT: t/t_lint_realcvt_bad.v:13:18: Implicit conversion of real to integer
|
||||||
|
13 | time t_bad2 = 9.999ns;
|
||||||
|
| ^~~~~~~
|
||||||
|
%Warning-REALCVT: t/t_lint_realcvt_bad.v:17:18: Implicit conversion of real to integer
|
||||||
|
17 | time t_bad3 = 9ps;
|
||||||
|
| ^~~
|
||||||
|
%Warning-REALCVT: t/t_lint_realcvt_bad.v:23:22: Implicit conversion of real to integer
|
||||||
|
23 | integer i_bad21 = 23.1;
|
||||||
|
| ^~~~
|
||||||
%Error: Exiting due to
|
%Error: Exiting due to
|
||||||
|
@ -4,10 +4,22 @@
|
|||||||
// any use, without warranty, 2011 by Wilson Snyder.
|
// any use, without warranty, 2011 by Wilson Snyder.
|
||||||
// SPDX-License-Identifier: CC0-1.0
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
`timescale 1ns/1ps
|
||||||
|
|
||||||
module sub;
|
module sub;
|
||||||
integer i;
|
|
||||||
initial begin
|
time t_ok1 = 9ns; // > 1ns units
|
||||||
i = 23.2;
|
time t_bad1 = 9.001ns; // < 1ns units
|
||||||
i = 23.0; // No warning - often happens with units of time
|
time t_bad2 = 9.999ns; // < 1ns units
|
||||||
end
|
|
||||||
|
time t_ok2 = 9.001us; // > 1ns units
|
||||||
|
|
||||||
|
time t_bad3 = 9ps; // < 1ns units
|
||||||
|
|
||||||
|
realtime rt_ok10 = 9.001ns; // < 1ns units
|
||||||
|
realtime rt_ok11 = 9ps; // < 1ns units
|
||||||
|
|
||||||
|
integer i_ok20 = 23.0; // No warning
|
||||||
|
integer i_bad21 = 23.1;
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
Loading…
Reference in New Issue
Block a user