From f719d66129fb5f35daf7c268c34988b6e5379bf5 Mon Sep 17 00:00:00 2001 From: Artur Bieniek Date: Tue, 23 Sep 2025 23:17:07 +0200 Subject: [PATCH] Fix timeprecision backward assignment (#6469) Signed-off-by: Artur Bieniek --- src/V3EmitCFunc.h | 6 ++-- src/V3ParseImp.cpp | 2 +- src/V3ParseImp.h | 3 ++ src/verilog.y | 8 +++++ test_regress/t/t_timescale_nobackwards.out | 10 ++++++ test_regress/t/t_timescale_nobackwards.py | 18 ++++++++++ test_regress/t/t_timescale_nobackwards.v | 41 ++++++++++++++++++++++ 7 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 test_regress/t/t_timescale_nobackwards.out create mode 100755 test_regress/t/t_timescale_nobackwards.py create mode 100644 test_regress/t/t_timescale_nobackwards.v diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index 9d192d302..68a297396 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -1180,8 +1180,10 @@ public: void visit(AstTime* nodep) override { putns(nodep, "VL_TIME_UNITED_Q("); UASSERT_OBJ(!nodep->timeunit().isNone(), nodep, "$time has no units"); - puts(cvtToStr(nodep->timeunit().multiplier() - / v3Global.rootp()->timeprecision().multiplier())); + const double time + = nodep->timeunit().multiplier() / v3Global.rootp()->timeprecision().multiplier(); + UASSERT_OBJ(time >= 1, nodep, "TimeQ is less than 1, will result in division by zero"); + puts(cvtToStr(time)); puts(")"); } void visit(AstTimeD* nodep) override { diff --git a/src/V3ParseImp.cpp b/src/V3ParseImp.cpp index 5b134e2b2..fd16faf96 100644 --- a/src/V3ParseImp.cpp +++ b/src/V3ParseImp.cpp @@ -119,7 +119,7 @@ void V3ParseImp::lexTimescaleParse(FileLine* fl, const char* textp) { VTimescale prec; VTimescale::parseSlashed(fl, textp, unit /*ref*/, prec /*ref*/); m_timeLastUnit = v3Global.opt.timeComputeUnit(unit); - v3Global.rootp()->timeprecisionMerge(fl, prec); + m_timeLastPrec = v3Global.opt.timeComputePrec(prec); } AstPragma* V3ParseImp::createTimescale(FileLine* fl, bool unitSet, double unitVal, bool precSet, double precVal) { diff --git a/src/V3ParseImp.h b/src/V3ParseImp.h index e4f850116..15d54ec5f 100644 --- a/src/V3ParseImp.h +++ b/src/V3ParseImp.h @@ -168,6 +168,7 @@ class V3ParseImp final { AstNode* m_tagNodep = nullptr; // Points to the node to set to m_tag or nullptr to not set. VTimescale m_timeLastUnit; // Last `timescale's unit + VTimescale m_timeLastPrec; // Last `timescale's precision public: VL_DEFINE_DEBUG_FUNCTIONS; @@ -185,6 +186,7 @@ public: AstPragma* createTimescale(FileLine* fl, bool unitSet, double unitVal, bool precSet, double precVal) VL_MT_DISABLED; VTimescale timeLastUnit() const { return m_timeLastUnit; } + VTimescale timeLastPrec() const { return m_timeLastPrec; } void lexFileline(FileLine* fl) { m_lexFileline = fl; } FileLine* lexFileline() const { return m_lexFileline; } @@ -286,6 +288,7 @@ public: , m_filterp{filterp} { m_lexKwdLast = stateVerilogRecent(); m_timeLastUnit = v3Global.opt.timeDefaultUnit(); + m_timeLastPrec = v3Global.opt.timeDefaultPrec(); } ~V3ParseImp() VL_MT_DISABLED; void parserClear() VL_MT_DISABLED; diff --git a/src/verilog.y b/src/verilog.y index d6a660d3a..96290e020 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -1062,6 +1062,8 @@ packageFront: $$->lifetime($2); $$->modTrace(GRAMMARP->allTracingOn($$->fileline())); $$->timeunit(PARSEP->timeLastUnit()); + PARSEP->rootp()->timeprecisionMerge($$->fileline(), + PARSEP->timeLastPrec()); PARSEP->rootp()->addModulesp($$); } ; @@ -1199,6 +1201,8 @@ modFront: $$->inLibrary(PARSEP->inLibrary() || $$->fileline()->celldefineOn()); $$->modTrace(GRAMMARP->allTracingOn($$->fileline())); $$->timeunit(PARSEP->timeLastUnit()); + PARSEP->rootp()->timeprecisionMerge($$->fileline(), + PARSEP->timeLastPrec()); $$->unconnectedDrive(PARSEP->unconnectedDrive()); PARSEP->rootp()->addModulesp($$); } | modFront sigAttrScope { $$ = $1; } @@ -1581,6 +1585,8 @@ pgmFront: $$->inLibrary(PARSEP->inLibrary() || $$->fileline()->celldefineOn()); $$->modTrace(GRAMMARP->allTracingOn($$->fileline())); $$->timeunit(PARSEP->timeLastUnit()); + PARSEP->rootp()->timeprecisionMerge($$->fileline(), + PARSEP->timeLastPrec()); PARSEP->rootp()->addModulesp($$); } ; @@ -7145,6 +7151,8 @@ checkerFront: // IEEE: part of checker_declaration { $$ = new AstModule{$2, *$2, PARSEP->libname(), AstModule::Checker{}}; $$->modTrace(GRAMMARP->allTracingOn($$->fileline())); $$->timeunit(PARSEP->timeLastUnit()); + PARSEP->rootp()->timeprecisionMerge($$->fileline(), + PARSEP->timeLastPrec()); $$->unconnectedDrive(PARSEP->unconnectedDrive()); } | checkerFront sigAttrScope { $$ = $1; } ; diff --git a/test_regress/t/t_timescale_nobackwards.out b/test_regress/t/t_timescale_nobackwards.out new file mode 100644 index 000000000..0f8890323 --- /dev/null +++ b/test_regress/t/t_timescale_nobackwards.out @@ -0,0 +1,10 @@ +Time scale of mod is 1ps / 1ps +0 +Time scale of pkg is 1ps / 1ps +0 +Time scale of CHK is 1ps / 1ps +0 +Time scale of PRG is 1ps / 1ps +0 +Time scale of CLS is 1ps / 1ps +0 diff --git a/test_regress/t/t_timescale_nobackwards.py b/test_regress/t/t_timescale_nobackwards.py new file mode 100755 index 000000000..592c3fc9a --- /dev/null +++ b/test_regress/t/t_timescale_nobackwards.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2025 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 + +import vltest_bootstrap + +test.scenarios('simulator') + +test.compile() + +test.execute(expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_timescale_nobackwards.v b/test_regress/t/t_timescale_nobackwards.v new file mode 100644 index 000000000..1664fe4fd --- /dev/null +++ b/test_regress/t/t_timescale_nobackwards.v @@ -0,0 +1,41 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2025 by Antmicro. +// SPDX-License-Identifier: CC0-1.0 + +`define checkf function void f(); $printtimescale; $display("%0t", $time); endfunction + +package pkg; + `checkf; +endpackage + +checker CHK(); + `checkf; +endchecker + +program PRG; + `checkf; +endprogram + +class CLS; + static `checkf; +endclass + +module mod; + CHK chk(); + PRG prg(); + initial begin + $printtimescale; + $display("%0t", $time); + + pkg::f(); + chk.f(); + prg.f(); + CLS::f(); + + $finish; + end +endmodule + +`timescale 1ns / 10ps