From 3adb31f53b7cee563994df1fee331767c4a95f03 Mon Sep 17 00:00:00 2001 From: Paul Wright <68547250+polmacanceart@users.noreply.github.com> Date: Tue, 2 Jan 2024 01:11:46 +0000 Subject: [PATCH] Fix $time not rounding up (#4790) (#4792) --- include/verilated_funcs.h | 3 +- test_regress/t/t_time.pl | 23 ++++++++++++ test_regress/t/t_time.v | 75 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+), 1 deletion(-) create mode 100755 test_regress/t/t_time.pl create mode 100644 test_regress/t/t_time.v diff --git a/include/verilated_funcs.h b/include/verilated_funcs.h index 9ad3dec61..39d97f83d 100644 --- a/include/verilated_funcs.h +++ b/include/verilated_funcs.h @@ -305,7 +305,8 @@ uint64_t VerilatedContext::time() const VL_MT_SAFE { // Time scaled from 1-per-precision into a module's time units ("Unit"-ed, not "United") // Optimized assuming scale is always constant. // Can't use multiply in Q flavor, as might lose precision -#define VL_TIME_UNITED_Q(scale) (VL_TIME_Q() / static_cast(scale)) +#define VL_TIME_ROUND(t, p) (((t) + ((p) / 2)) / (p)) +#define VL_TIME_UNITED_Q(scale) VL_TIME_ROUND(VL_TIME_Q(), static_cast(scale)) #define VL_TIME_UNITED_D(scale) (VL_TIME_D() / static_cast(scale)) // Return time precision as multiplier of time units diff --git a/test_regress/t/t_time.pl b/test_regress/t/t_time.pl new file mode 100755 index 000000000..0db50fc52 --- /dev/null +++ b/test_regress/t/t_time.pl @@ -0,0 +1,23 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2019 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(linter => 1); + +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_time.v b/test_regress/t/t_time.v new file mode 100644 index 000000000..024d1dcb0 --- /dev/null +++ b/test_regress/t/t_time.v @@ -0,0 +1,75 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2024 by Paul Wright. +// SPDX-License-Identifier: CC0-1.0 + +/* Working through the $time example from IEEE Std 1364-2005 +** Section 17.7.1 +** The example uses a 10ns timeunit with a 1ns timeprecision +** For 16ns $time should return 2 +** For 32ns $time should return 3 +**/ + +module t (); + timeunit 10ns; + timeprecision 1ns; + + longint should_be_2, should_be_3; + real should_be_1p6, should_be_3p2; + + initial + begin : initial_blk1 + should_be_2 = 0; + should_be_3 = 0; + #(16ns); + $display("$time=%d, $realtime=%g", $time(), $realtime()); + should_be_2 = $time(); + should_be_1p6 = $realtime(); + #(16ns); + $display("$time=%d, $realtime=%g", $time(), $realtime()); + should_be_3 = $time(); + should_be_3p2 = $realtime(); + #(16ns); + $finish(1); + end + initial + begin : initial_blk2 + #(100ns); + $display("%%Error: We should not get here"); + $finish(1); + end + + function bit real_chk(input real tvar, input real evar); + begin + real diff; + diff = tvar - evar; + return (diff < 1e-9) && (diff > -1e-9); + end + endfunction + + final + begin : last_blk + if (should_be_2 != 2) + begin + $display("%%Error: should_be_2 = %0d", + should_be_2); + $stop; + end + if (should_be_3 != 3) + begin + $display("%%Error: should_be_3 = %0d", + should_be_3); + $stop; + end + $display("Info: should_be_2 = %0d", should_be_2); + $display("Info: should_be_3 = %0d", should_be_3); + + chk_2 : assert(should_be_2 == 2); + chk_3 : assert(should_be_3 == 3); + chk_1p6 : assert(real_chk(should_be_1p6, 1.6)); + chk_3p2 : assert(real_chk(should_be_3p2, 3.2)); + $write("*-* All Finished *-*\n"); + end + +endmodule