From 3c77c7bb924349615e672a61419f9c2b6aebc8ba Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 16 Nov 2022 21:10:39 -0500 Subject: [PATCH] Support and --- Changes | 1 + docs/guide/extensions.rst | 10 ++++++++++ src/V3AstNodeExpr.h | 33 +++++++++++++++++++++++++++++++ src/V3EmitCFunc.h | 3 +++ src/V3LinkParse.cpp | 4 ++++ src/V3Width.cpp | 5 +++++ src/verilog.l | 2 ++ src/verilog.y | 17 ++++++++++++---- test_regress/t/t_time_timeunit.pl | 22 +++++++++++++++++++++ test_regress/t/t_time_timeunit.v | 26 ++++++++++++++++++++++++ 10 files changed, 119 insertions(+), 4 deletions(-) create mode 100755 test_regress/t/t_time_timeunit.pl create mode 100644 test_regress/t/t_time_timeunit.v diff --git a/Changes b/Changes index 449c8a3ae..15133343c 100644 --- a/Changes +++ b/Changes @@ -17,6 +17,7 @@ Verilator 5.003 devel * Support named properties (#3667). [Ryszard Rozak, Antmicro Ltd] * Support randcase. * Support pre_randomize and post_randomize. +* Support $timeunit and $timeprecision. * Add ENUMVALUE warning when value misused for enum (#726). * Internal AST improvements, also affect XML format (#3721). [Geza Lore] * Change ENDLABEL from warning into an error. diff --git a/docs/guide/extensions.rst b/docs/guide/extensions.rst index fd65e8b0a..6aad4c6e6 100644 --- a/docs/guide/extensions.rst +++ b/docs/guide/extensions.rst @@ -73,6 +73,16 @@ or "`ifdef`"'s may break other tools. prints 5 digits per the C standard (this is unspecified in Verilog, but was incorporated into the 1800-2009). +.. option:: $timeprecision + + Returns the timeprecision of the model as an integer. This extension is + experimental and may be removed without deprecation. + +.. option:: $timeunit + + Returns the timeunit of the current module as an integer. This + extension is experimental and may be removed without deprecation. + .. option:: `coverage_block_off Specifies the entire begin/end block should be ignored for coverage diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 880d757d9..608e0db31 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -1597,6 +1597,39 @@ public: AstNodeDType* getChildDTypep() const override { return childDTypep(); } AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } }; +class AstTimePrecision final : public AstNodeExpr { + // Verilog $timeprecision +public: + AstTimePrecision(FileLine* fl) + : ASTGEN_SUPER_TimePrecision(fl) { + dtypeSetSigned32(); + } + ASTGEN_MEMBERS_AstTimePrecision; + string emitVerilog() override { return "$timeprecision"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return true; } + int instrCount() const override { return widthInstrs(); } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstTimeUnit final : public AstNodeExpr { + VTimescale m_timeunit; // Parent module time unit + // Verilog $timeunit +public: + AstTimeUnit(FileLine* fl) + : ASTGEN_SUPER_TimeUnit(fl) { + dtypeSetSigned32(); + } + ASTGEN_MEMBERS_AstTimeUnit; + string emitVerilog() override { return "$timeunit"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return true; } + int instrCount() const override { return widthInstrs(); } + bool same(const AstNode* /*samep*/) const override { return true; } + void timeunit(const VTimescale& flag) { m_timeunit = flag; } + VTimescale timeunit() const { return m_timeunit; } +}; class AstUCFunc final : public AstNodeExpr { // User's $c function // Perhaps this should be an AstNodeListop; but there's only one list math right now diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index d7ff08772..50b2f55c6 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -909,6 +909,9 @@ public: iterateAndNextNull(nodep->widthp()); puts(", vlSymsp->_vm_contextp__);\n"); } + void visit(AstTimePrecision* nodep) override { + puts("vlSymsp->_vm_contextp__->timeprecision()"); + } void visit(AstNodeSimpleText* nodep) override { const string text = m_inUC && m_useSelfForThis ? VString::replaceWord(nodep->text(), "this", "vlSelf") diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index 7dd81fb2a..4c8411869 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -577,6 +577,10 @@ private: iterateChildren(nodep); nodep->timeunit(m_modp->timeunit()); } + void visit(AstTimeUnit* nodep) override { + iterateChildren(nodep); + nodep->timeunit(m_modp->timeunit()); + } void visit(AstEventControl* nodep) override { cleanFileline(nodep); iterateChildren(nodep); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 1b8db1311..fff0970b9 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -446,6 +446,11 @@ private: // Widths: Constant, terminal void visit(AstTime* nodep) override { nodep->dtypeSetUInt64(); } void visit(AstTimeD* nodep) override { nodep->dtypeSetDouble(); } + void visit(AstTimePrecision* nodep) override { nodep->dtypeSetSigned32(); } + void visit(AstTimeUnit* nodep) override { + nodep->replaceWith( + new AstConst{nodep->fileline(), AstConst::Signed32(), nodep->timeunit().powerOfTen()}); + } void visit(AstScopeName* nodep) override { nodep->dtypeSetUInt64(); // A pointer, but not that it matters } diff --git a/src/verilog.l b/src/verilog.l index b0a6d01e3..07f165c92 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -281,7 +281,9 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "$test$plusargs" { FL; return yD_TESTPLUSARGS; } "$time" { FL; return yD_TIME; } "$timeformat" { FL; return yD_TIMEFORMAT; } + "$timeprecision" { FL; return yD_TIMEPRECISION; } "$timeskew" { FL; return yaTIMINGSPEC; } + "$timeunit" { FL; return yD_TIMEUNIT; } "$typename" { FL; return yD_TYPENAME; } "$ungetc" { FL; return yD_UNGETC; } "$urandom" { FL; return yD_URANDOM; } diff --git a/src/verilog.y b/src/verilog.y index 330cd4c0f..6ad8d718c 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -876,6 +876,8 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yD_TESTPLUSARGS "$test$plusargs" %token yD_TIME "$time" %token yD_TIMEFORMAT "$timeformat" +%token yD_TIMEPRECISION "$timeprecision" +%token yD_TIMEUNIT "$timeunit" %token yD_TYPENAME "$typename" %token yD_UNGETC "$ungetc" %token yD_UNIT "$unit" @@ -3861,10 +3863,11 @@ system_t_call: // IEEE: system_tf_call (as task) | yD_MONITOROFF parenE { $$ = new AstMonitorOff($1, true); } | yD_MONITORON parenE { $$ = new AstMonitorOff($1, false); } // - | yD_PRINTTIMESCALE { $$ = new AstPrintTimeScale($1); } - | yD_PRINTTIMESCALE '(' ')' { $$ = new AstPrintTimeScale($1); } - | yD_PRINTTIMESCALE '(' idClassSel ')' { $$ = new AstPrintTimeScale($1); DEL($3); } - | yD_TIMEFORMAT '(' expr ',' expr ',' expr ',' expr ')' { $$ = new AstTimeFormat($1, $3, $5, $7, $9); } + | yD_PRINTTIMESCALE { $$ = new AstPrintTimeScale{$1}; } + | yD_PRINTTIMESCALE '(' ')' { $$ = new AstPrintTimeScale{$1}; } + | yD_PRINTTIMESCALE '(' idClassSel ')' { $$ = new AstPrintTimeScale{$1}; DEL($3); } + | yD_TIMEFORMAT '(' expr ',' expr ',' expr ',' expr ')' + { $$ = new AstTimeFormat{$1, $3, $5, $7, $9}; } // | yD_READMEMB '(' expr ',' idClassSel ')' { $$ = new AstReadMem($1,false,$3,$5,nullptr,nullptr); } | yD_READMEMB '(' expr ',' idClassSel ',' expr ')' { $$ = new AstReadMem($1,false,$3,$5,$7,nullptr); } @@ -3994,6 +3997,12 @@ system_f_call_or_t: // IEEE: part of system_tf_call (can be task | yD_TANH '(' expr ')' { $$ = new AstTanhD($1,$3); } | yD_TESTPLUSARGS '(' expr ')' { $$ = new AstTestPlusArgs($1, $3); } | yD_TIME parenE { $$ = new AstTime{$1, VTimescale{VTimescale::NONE}}; } + | yD_TIMEPRECISION { $$ = new AstTimePrecision{$1}; } + | yD_TIMEPRECISION '(' ')' { $$ = new AstTimePrecision{$1}; } + | yD_TIMEPRECISION '(' idClassSel ')' { $$ = new AstTimePrecision{$1}; DEL($3); } + | yD_TIMEUNIT { $$ = new AstTimeUnit{$1}; } + | yD_TIMEUNIT '(' ')' { $$ = new AstTimeUnit{$1}; } + | yD_TIMEUNIT '(' idClassSel ')' { $$ = new AstTimeUnit{$1}; DEL($3); } | yD_TYPENAME '(' exprOrDataType ')' { $$ = new AstAttrOf($1, VAttrType::TYPENAME, $3); } | yD_UNGETC '(' expr ',' expr ')' { $$ = new AstFUngetC($1, $5, $3); } // Arg swap to file first | yD_UNPACKED_DIMENSIONS '(' exprOrDataType ')' { $$ = new AstAttrOf($1,VAttrType::DIM_UNPK_DIMENSIONS,$3); } diff --git a/test_regress/t/t_time_timeunit.pl b/test_regress/t/t_time_timeunit.pl new file mode 100755 index 000000000..4e42b8db0 --- /dev/null +++ b/test_regress/t/t_time_timeunit.pl @@ -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 2003 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( + ); + +execute( + check_finished => 1, + ); + +ok(1); + +1; diff --git a/test_regress/t/t_time_timeunit.v b/test_regress/t/t_time_timeunit.v new file mode 100644 index 000000000..e75d5ab98 --- /dev/null +++ b/test_regress/t/t_time_timeunit.v @@ -0,0 +1,26 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under The Creative Commons Public Domain, for +// any use, without warranty, 2022 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); + +module t; + + timeunit 1ns; + timeprecision 1ps; + + initial begin + `checkd($timeunit, -9); + `checkd($timeunit(), -9); + `checkd($timeunit(t), -9); + + `checkd($timeprecision, -12); + `checkd($timeprecision(), -12); + `checkd($timeprecision(t), -12); + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule