diff --git a/Changes b/Changes index 2e765de1e..b43f2fa0c 100644 --- a/Changes +++ b/Changes @@ -11,6 +11,8 @@ indicates the contributor was also the author of the fix; Thanks! ** Support $sformatf, bug977. [Johan Bjork] +*** Support elaboration assertions, bug973. [Johan Bjork] + **** Add VerilatedScopeNameMap for introspection, bug966. [Todd Strader] **** Fix very long module names, bug937. [Todd Strader] diff --git a/bin/verilator b/bin/verilator index 6123f11d5..7841581fa 100755 --- a/bin/verilator +++ b/bin/verilator @@ -3340,6 +3340,10 @@ with "unused" in the name, or put the appropriate lint_off around the wire. Having unused signals in one place makes it easy to find what is unused, and reduces the number of lint_off pragmas, reducing bugs. +=item USERINFO, USERWARN, USERERROR, USERFATAL + +A SystemVerilog elaboration-time assertion print was executed. + =item VARHIDDEN Warns that a task, function, or begin/end block is declaring a variable by diff --git a/src/V3Error.h b/src/V3Error.h index 38bcf42fd..0b7cf44ad 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -96,6 +96,10 @@ public: UNPACKED, // Unsupported unpacked UNSIGNED, // Comparison is constant due to unsigned arithmetic UNUSED, // No receivers + USERERROR, // Elaboration time $error + USERFATAL, // Elaboration time $fatal + USERINFO, // Elaboration time $info + USERWARN, // Elaboration time $warning VARHIDDEN, // Hiding variable WIDTH, // Width mismatch WIDTHCONCAT, // Unsized numbers/parameters in concatenations @@ -132,6 +136,7 @@ public: "REALCVT", "REDEFMACRO", "SELRANGE", "STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET", "UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNPACKED", "UNSIGNED", "UNUSED", + "USERERROR", "USERFATAL", "USERINFO", "USERWARN", "VARHIDDEN", "WIDTH", "WIDTHCONCAT", " MAX" }; diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index 7667c30c9..24bb6b441 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -343,13 +343,6 @@ private: virtual void visit(AstDisplay* nodep, AstNUser* vup) { nodep->iterateChildren(*this); if (nodep->filep()) expectDescriptor(nodep, nodep->filep()->castNodeVarRef()); - if (!m_assertp - && (nodep->displayType() == AstDisplayType::DT_INFO - || nodep->displayType() == AstDisplayType::DT_WARNING - || nodep->displayType() == AstDisplayType::DT_ERROR - || nodep->displayType() == AstDisplayType::DT_FATAL)) { - nodep->v3error(nodep->verilogKwd()+" only allowed under an assertion."); - } } virtual void visit(AstUdpTable* nodep, AstNUser*) { diff --git a/src/V3Simulate.h b/src/V3Simulate.h index 7233eacb8..d0594085b 100644 --- a/src/V3Simulate.h +++ b/src/V3Simulate.h @@ -580,6 +580,7 @@ private: } } virtual void visit(AstStop* nodep, AstNUser*) { + if (jumpingOver(nodep)) return; if (m_params) { // This message seems better than an obscure $stop // The spec says $stop is just ignored, it seems evil to ignore assertions clearOptimizable(nodep,"$stop executed during function constification; maybe indicates assertion firing"); @@ -695,9 +696,78 @@ private: if (!m_params) { badNodeType(nodep); return; } } + virtual void visit(AstSFormatF *nodep, AstNUser *) { + if (jumpingOver(nodep)) return; + nodep->iterateChildren(*this); + if (m_params) { + AstNode* nextArgp = nodep->exprsp(); + + string result = ""; + string format = nodep->text(); + string::const_iterator pos = format.begin(); + bool inPct = false; + for (; pos != format.end(); ++pos) { + if (!inPct && pos[0] == '%') { + inPct = true; + } else if (!inPct) { // Normal text + result += *pos; + } else { // Format character + AstNode* argp = nextArgp; + inPct = false; + nextArgp = nextArgp->nextp(); + + if (V3Number::displayedFmtLegal(tolower(pos[0]))) { + V3Number* nump = fetchNumberNull(argp); + if (!nump) { + clearOptimizable(nodep, "Argument for $display like statement is not constant"); + break; + } + string format = string("%") + pos[0]; + result += nump->displayed(format); + } else { + switch (tolower(pos[0])) { + case '%': + result += "%"; + break; + default: + clearOptimizable(nodep, "Unknown $display-like format code."); + break; + } + } + } + } + nodep->text(result); + } + } + + virtual void visit(AstDisplay *nodep, AstNUser *) { + if (jumpingOver(nodep)) return; + nodep->iterateChildren(*this); + if (m_params) { + switch (nodep->displayType()) { + case AstDisplayType::DT_DISPLAY: // FALLTHRU + case AstDisplayType::DT_INFO: + v3warn(USERINFO, nodep->fmtp()->text()); + break; + case AstDisplayType::DT_ERROR: + v3warn(USERERROR, nodep->fmtp()->text()); + break; + case AstDisplayType::DT_WARNING: + v3warn(USERWARN, nodep->fmtp()->text()); + break; + case AstDisplayType::DT_FATAL: + v3warn(USERFATAL, nodep->fmtp()->text()); + break; + case AstDisplayType::DT_WRITE: // FALLTHRU + default: + clearOptimizable(nodep, "Unexpected display type"); + } + } + } + // default // These types are definately not reducable - // AstCoverInc, AstDisplay, AstArraySel, AstStop, AstFinish, + // AstCoverInc, AstArraySel, AstFinish, // AstRand, AstTime, AstUCFunc, AstCCall, AstCStmt, AstUCStmt virtual void visit(AstNode* nodep, AstNUser*) { if (jumpingOver(nodep)) return; diff --git a/test_regress/t/t_assert_elab.pl b/test_regress/t/t_assert_elab.pl new file mode 100755 index 000000000..f91289753 --- /dev/null +++ b/test_regress/t/t_assert_elab.pl @@ -0,0 +1,18 @@ +#!/usr/bin/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. + +compile ( + ); + +execute ( + check_finished=>1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_assert_elab.v b/test_regress/t/t_assert_elab.v new file mode 100644 index 000000000..ae07b536a --- /dev/null +++ b/test_regress/t/t_assert_elab.v @@ -0,0 +1,24 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2015 by Johan Bjork. + +module t; + localparam str = "string"; + function logic checkParameter(input logic [8:0] N); + if (N == 1) + return 0; + $fatal(1, "Parameter %d is invalid...%s and %s", N, str, "constant both work"); + endfunction + +`ifdef FAILING_ASSERTIONS + localparam x = checkParameter(5); +`else + localparam x = checkParameter(1); +`endif + + initial begin + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_assert_elab_bad.pl b/test_regress/t/t_assert_elab_bad.pl new file mode 100755 index 000000000..341a150e1 --- /dev/null +++ b/test_regress/t/t_assert_elab_bad.pl @@ -0,0 +1,28 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2009 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. + +top_filename("t/t_assert_elab.v"); +unlink("$Self->{obj_dir}/t_assert_elab_bad.log"); + + +compile ( + v_flags2 => ['+define+FAILING_ASSERTIONS', + $Self->{v3}?'--assert':($Self->{nc}?'+assert':'')], + fails => 1, +); + +execute ( + fails => $Self->{vlt}, +); + +file_grep ("$Self->{obj_dir}/vlt_compile.log", +qr/%Warning-USERFATAL: Parameter 5 is invalid...string and constant both work/); + +ok(1); +1;