Fix width extension on delays (#5045).

This commit is contained in:
Wilson Snyder 2024-04-13 08:16:59 -04:00
parent aac2563a07
commit 5d8da6b4ac
6 changed files with 84 additions and 6 deletions

View File

@ -16,6 +16,7 @@ Verilator 5.025 devel
* Support __en/__out signals on top level inout ports (#4812) (#4856). [Paul Wright] * Support __en/__out signals on top level inout ports (#4812) (#4856). [Paul Wright]
* Fix consecutive zero-delays (#5038). [Krzysztof Bieganski, Antmicro Ltd.] * Fix consecutive zero-delays (#5038). [Krzysztof Bieganski, Antmicro Ltd.]
* Fix `$system` with string argument (#5042). * Fix `$system` with string argument (#5042).
* Fix width extension on delays (#5045).
Verilator 5.024 2024-04-05 Verilator 5.024 2024-04-05

View File

@ -196,9 +196,9 @@ public:
VlProcessRef process; // Data of the suspended process, null if not needed VlProcessRef process; // Data of the suspended process, null if not needed
VlDelayedCoroutineQueue& queue; VlDelayedCoroutineQueue& queue;
std::vector<VlCoroutineHandle>& queueZeroDelay; std::vector<VlCoroutineHandle>& queueZeroDelay;
uint64_t delay; const uint64_t delay;
VlDelayPhase phase; const VlDelayPhase phase;
VlFileLineDebug fileline; const VlFileLineDebug fileline;
bool await_ready() const { return false; } // Always suspend bool await_ready() const { return false; } // Always suspend
void await_suspend(std::coroutine_handle<> coro) { void await_suspend(std::coroutine_handle<> coro) {
@ -211,7 +211,7 @@ public:
void await_resume() const {} void await_resume() const {}
}; };
VlDelayPhase phase = (delay == 0) ? VlDelayPhase::INACTIVE : VlDelayPhase::ACTIVE; const VlDelayPhase phase = (delay == 0) ? VlDelayPhase::INACTIVE : VlDelayPhase::ACTIVE;
#ifdef VL_DEBUG #ifdef VL_DEBUG
if (phase == VlDelayPhase::INACTIVE) { if (phase == VlDelayPhase::INACTIVE) {
VL_WARN_MT(filename, lineno, VL_UNKNOWN, VL_WARN_MT(filename, lineno, VL_UNKNOWN,

View File

@ -898,7 +898,7 @@ class TimingControlVisitor final : public VNVisitor {
if (!constp || !constp->isZero()) { if (!constp || !constp->isZero()) {
// Scale the delay // Scale the delay
const double timescaleFactor = calculateTimescaleFactor(nodep, nodep->timeunit()); const double timescaleFactor = calculateTimescaleFactor(nodep, nodep->timeunit());
if (valuep->dtypep()->isDouble()) { if (valuep->dtypep()->skipRefp()->isDouble()) {
valuep = new AstRToIRoundS{ valuep = new AstRToIRoundS{
flp, new AstMulD{flp, valuep, flp, new AstMulD{flp, valuep,
new AstConst{flp, AstConst::RealDouble{}, timescaleFactor}}}; new AstConst{flp, AstConst::RealDouble{}, timescaleFactor}}};

View File

@ -650,7 +650,7 @@ class WidthVisitor final : public VNVisitor {
} }
if (nodep->fileline()->timingOn()) { if (nodep->fileline()->timingOn()) {
if (v3Global.opt.timing().isSetTrue()) { if (v3Global.opt.timing().isSetTrue()) {
userIterate(nodep->lhsp(), WidthVP{nullptr, BOTH}.p()); iterateCheckDelay(nodep, "delay", nodep->lhsp(), BOTH);
iterateAndNextNull(nodep->stmtsp()); iterateAndNextNull(nodep->stmtsp());
return; return;
} else if (v3Global.opt.timing().isSetFalse()) { } else if (v3Global.opt.timing().isSetFalse()) {
@ -6634,6 +6634,26 @@ class WidthVisitor final : public VNVisitor {
} }
(void)underp; // cppcheck (void)underp; // cppcheck
} }
void iterateCheckDelay(AstNode* nodep, const char* side, AstNode* underp, Stage stage) {
// Coerce child to 64-bit delay if not already. Child is self-determined
// underp may change as a result of replacement
if (stage & PRELIM) {
underp = userIterateSubtreeReturnEdits(underp, WidthVP{SELF, PRELIM}.p());
}
if (stage & FINAL) {
AstNodeDType* expDTypep;
if (underp->dtypep()->skipRefp()->isDouble()) { // V3Timing will later convert double
expDTypep = nodep->findDoubleDType();
} else {
FileLine* const newFl = new FileLine{underp->fileline()};
newFl->warnOff(V3ErrorCode::WIDTHEXPAND, true);
underp->fileline(newFl);
expDTypep = nodep->findLogicDType(64, 64, VSigning::UNSIGNED);
}
underp = iterateCheck(nodep, side, underp, SELF, FINAL, expDTypep, EXTEND_EXP, false);
}
(void)underp; // cppcheck
}
void iterateCheckReal(AstNode* nodep, const char* side, AstNode* underp, Stage stage) { void iterateCheckReal(AstNode* nodep, const char* side, AstNode* underp, Stage stage) {
// Coerce child to real if not already. Child is self-determined // Coerce child to real if not already. Child is self-determined
// e.g. nodep=ADDD, underp=ADD in ADDD(ADD(a,b), real-CONST) // e.g. nodep=ADDD, underp=ADD in ADDD(ADD(a,b), real-CONST)

View File

@ -0,0 +1,22 @@
#!/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(vlt => 1);
compile(
verilator_flags2 => ["--exe --main --timing"],
);
execute(
check_finished => 1,
) if !$Self->{vlt};
ok(1);
1;

View File

@ -0,0 +1,35 @@
// 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
module t;
int tim1;
int tim2;
real rtim1;
real rtim2;
initial begin
tim1 = 2;
tim2 = 3;
// verilator lint_off WIDTHEXPAND
# (tim1 < tim2);
// verilator lint_on WIDTHEXPAND
if ($time != 1) $stop;
// verilator lint_off WIDTHEXPAND
# (tim1);
// verilator lint_on WIDTHEXPAND
if ($time != 1 + 2) $stop;
rtim1 = 2;
rtim2 = 2.6;
# (rtim1 + rtim2); // Rounds up
if ($time != 1 + 2 + 5) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule