diff --git a/src/V3Assert.cpp b/src/V3Assert.cpp index 9a75694ca..12d366fc5 100644 --- a/src/V3Assert.cpp +++ b/src/V3Assert.cpp @@ -518,6 +518,54 @@ class AssertVisitor final : public VNVisitor { iterateChildren(nodep); newPslAssertion(nodep, nodep->failsp()); } + void visit(AstAssertCtl* nodep) override { + if (VN_IS(m_modp, Class) || VN_IS(m_modp, Iface)) { + nodep->v3warn(E_UNSUPPORTED, "Unsupported: assertcontrols in classes or interfaces"); + VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); + return; + } + + iterateChildren(nodep); + + if (const AstConst* const constp = VN_CAST(nodep->controlTypep(), Const)) { + nodep->ctlType(constp->toSInt()); + } else if (nodep->ctlType() == VAssertCtlType::_TO_BE_EVALUATED) { + nodep->v3warn(E_UNSUPPORTED, "Unsupported: non-const assert control type expression"); + VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); + return; + } + + switch (nodep->ctlType()) { + case VAssertCtlType::ON: + case VAssertCtlType::OFF: + case VAssertCtlType::KILL: { + UINFO(9, "Generating assertctl for a module: " << m_modp << endl); + FileLine* const fl = nodep->fileline(); + const string assertOnStmt + = string{"vlSymsp->_vm_contextp__->assertOn("} + + (nodep->ctlType() == VAssertCtlType::ON ? "true" : "false") + ");\n"; + nodep->replaceWith(new AstCExpr{fl, assertOnStmt, 1}); + break; + } + case VAssertCtlType::LOCK: + case VAssertCtlType::UNLOCK: + case VAssertCtlType::PASS_ON: + case VAssertCtlType::PASS_OFF: + case VAssertCtlType::FAIL_ON: + case VAssertCtlType::FAIL_OFF: + case VAssertCtlType::NONVACUOUS_ON: + case VAssertCtlType::VACUOUS_OFF: { + nodep->unlinkFrBack(); + nodep->v3warn(E_UNSUPPORTED, "Unsupported assertcontrol control_type"); + break; + } + default: { + nodep->unlinkFrBack(); + nodep->v3warn(EC_ERROR, "Bad assertcontrol control_type (IEEE 1800-2023 Table 20-5)"); + } + } + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } void visit(AstAssertIntrinsic* nodep) override { iterateChildren(nodep); newPslAssertion(nodep, nodep->failsp()); diff --git a/src/V3Ast.h b/src/V3Ast.h index b03d983b3..1392176d3 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -1102,6 +1102,61 @@ constexpr bool operator==(VAlwaysKwd::en lhs, const VAlwaysKwd& rhs) { return lh // ###################################################################### +class VAssertCtlType final { +public: + // IEEE 1800-2023 Table 20-5 + enum en : uint8_t { + _TO_BE_EVALUATED = 0, + LOCK = 1, + UNLOCK = 2, + ON = 3, + OFF = 4, + KILL = 5, + PASS_ON = 6, + PASS_OFF = 7, + FAIL_ON = 8, + FAIL_OFF = 9, + NONVACUOUS_ON = 10, + VACUOUS_OFF = 11 + }; + enum en m_e; + VAssertCtlType() + : m_e{_TO_BE_EVALUATED} {} + // cppcheck-suppress noExplicitConstructor + constexpr VAssertCtlType(en _e) + : m_e{_e} {} + explicit VAssertCtlType(int _e) + : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning + constexpr operator en() const { return m_e; } + const char* ascii() const { + // IEEE 1800-2023 20.11 + static const char* const names[] = {"", + "", + "", + "$asserton", + "$assertoff", + "$assertkill", + "$assertpasson", + "$assertpassoff", + "$assertfailon", + "$assertfailoff", + "$assertnonvacuouson", + "$assertvacuousoff"}; + return names[m_e]; + } +}; +constexpr bool operator==(const VAssertCtlType& lhs, const VAssertCtlType& rhs) { + return lhs.m_e == rhs.m_e; +} +constexpr bool operator==(const VAssertCtlType& lhs, VAssertCtlType::en rhs) { + return lhs.m_e == rhs; +} +constexpr bool operator==(VAssertCtlType::en lhs, const VAssertCtlType& rhs) { + return lhs == rhs.m_e; +} + +// ###################################################################### + class VCaseType final { public: enum en : uint8_t { CT_CASE, CT_CASEX, CT_CASEZ, CT_CASEINSIDE }; diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index 0151132b8..01aa910f3 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -2578,6 +2578,31 @@ public: bool isJustOneBodyStmt() const { return stmtsp() && !stmtsp()->nextp(); } bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); } }; +class AstAssertCtl final : public AstNodeStmt { + // @astgen op1 := controlTypep : AstNodeExpr + // @astgen op2 := levelp : AstNodeExpr + // @astgen op3 := itemsp : List[AstNodeExpr] + // Type of assertcontrol task; either known from parser or from evaluated + // controlTypep expression. + VAssertCtlType m_ctlType; // $assert keyword type + +public: + AstAssertCtl(FileLine* fl, VAssertCtlType ctlType, AstNodeExpr* levelp = nullptr, + AstNodeExpr* itemsp = nullptr); + AstAssertCtl(FileLine* fl, AstNodeExpr* controlTypep, AstNodeExpr* assertionTypep = nullptr, + AstNodeExpr* directiveTypep = nullptr, AstNodeExpr* levelp = nullptr, + AstNodeExpr* itemsp = nullptr); + ASTGEN_MEMBERS_AstAssertCtl; + string verilogKwd() const override { return m_ctlType.ascii(); } + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + bool isPure() override { return false; } + bool isOutputter() override { return true; } + VAssertCtlType ctlType() const { return m_ctlType; } + void ctlType(int32_t type) { m_ctlType = VAssertCtlType{type}; } + void dump(std::ostream& str = std::cout) const override; + void dumpJson(std::ostream& str = std::cout) const override; +}; class AstBreak final : public AstNodeStmt { public: explicit AstBreak(FileLine* fl) diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index df2b8fd51..35202d35b 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -1458,7 +1458,32 @@ void AstAlways::dumpJson(std::ostream& str) const { dumpJsonStr(str, "keyword", keyword().ascii()); dumpJsonGen(str); } - +AstAssertCtl::AstAssertCtl(FileLine* fl, VAssertCtlType ctlType, AstNodeExpr* levelp, + AstNodeExpr* itemsp) + : ASTGEN_SUPER_AssertCtl(fl) + , m_ctlType{ctlType} { + controlTypep(new AstConst{fl, ctlType}); + if (!levelp) levelp = new AstConst{fl, 0}; + this->levelp(levelp); + addItemsp(itemsp); +} +AstAssertCtl::AstAssertCtl(FileLine* fl, AstNodeExpr* controlTypep, AstNodeExpr*, AstNodeExpr*, + AstNodeExpr* levelp, AstNodeExpr* itemsp) + : ASTGEN_SUPER_AssertCtl(fl) + , m_ctlType{VAssertCtlType::_TO_BE_EVALUATED} { + this->controlTypep(controlTypep); + if (!levelp) levelp = new AstConst{fl, 0}; + this->levelp(levelp); + addItemsp(itemsp); +} +void AstAssertCtl::dump(std::ostream& str) const { + this->AstNode::dump(str); + str << " [" << ctlType().ascii() << "]"; +} +void AstAssertCtl::dumpJson(std::ostream& str) const { + dumpJsonStr(str, "ctlType", ctlType().ascii()); + dumpJsonGen(str); +} void AstAttrOf::dump(std::ostream& str) const { this->AstNode::dump(str); str << " [" << attrType().ascii() << "]"; diff --git a/src/V3EmitCConstPool.cpp b/src/V3EmitCConstPool.cpp index 27313bacb..513d94e2e 100644 --- a/src/V3EmitCConstPool.cpp +++ b/src/V3EmitCConstPool.cpp @@ -84,6 +84,7 @@ class EmitCConstPool final : public EmitCConstInit { putns(varp, "extern const "); putns(varp, varp->dtypep()->cType(nameProtect, false, false)); putns(varp, " = "); + UASSERT_OBJ(varp, varp->valuep(), "Var without value"); iterateConst(varp->valuep()); putns(varp, ";\n"); // Keep track of stats diff --git a/src/verilog.l b/src/verilog.l index 8e7c56bcb..5ee0af1b9 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -618,6 +618,11 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} /* System Verilog 2012 */ { + /* System Tasks */ + "$assertcontrol" { FL; return yD_ASSERTCTL; } + "$assertkill" { FL; return yD_ASSERTKILL; } + "$assertoff" { FL; return yD_ASSERTOFF; } + "$asserton" { FL; return yD_ASSERTON; } /* Keywords */ "implements" { FL; return yIMPLEMENTS; } "interconnect" { FL; return yINTERCONNECT; } diff --git a/src/verilog.y b/src/verilog.y index b840de673..f73ec9104 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -807,6 +807,10 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yD_ACOSH "$acosh" %token yD_ASIN "$asin" %token yD_ASINH "$asinh" +%token yD_ASSERTCTL "$assertcontrol" +%token yD_ASSERTKILL "$assertkill" +%token yD_ASSERTOFF "$assertoff" +%token yD_ASSERTON "$asserton" %token yD_ATAN "$atan" %token yD_ATAN2 "$atan2" %token yD_ATANH "$atanh" @@ -4224,6 +4228,21 @@ system_t_call: // IEEE: system_tf_call (as task) { $$ = new AstDisplay{$1, VDisplayType::DT_FATAL, nullptr, $5}; $$->addNext(new AstStop{$1, false}); DEL($3); } // + | yD_ASSERTCTL '(' expr ')' { $$ = new AstAssertCtl{$1, $3}; } + | yD_ASSERTCTL '(' expr ',' exprE ')' { $$ = new AstAssertCtl{$1, $3, $5}; } + | yD_ASSERTCTL '(' expr ',' exprE ',' exprE ')' { $$ = new AstAssertCtl{$1, $3, $5, $7}; } + | yD_ASSERTCTL '(' expr ',' exprE ',' exprE ',' exprE ')' { $$ = new AstAssertCtl{$1, $3, $5, $7, $9}; } + | yD_ASSERTCTL '(' expr ',' exprE ',' exprE ',' exprE ',' exprList ')' { $$ = new AstAssertCtl{$1, $3, $5, $7, $9, $11}; } + | yD_ASSERTKILL parenE { $$ = new AstAssertCtl{$1, VAssertCtlType::KILL}; } + | yD_ASSERTKILL '(' expr ')' { $$ = new AstAssertCtl{$1, VAssertCtlType::KILL, $3}; } + | yD_ASSERTKILL '(' exprE ',' exprList ')' { $$ = new AstAssertCtl{$1, VAssertCtlType::KILL, $3, $5}; } + | yD_ASSERTOFF parenE { $$ = new AstAssertCtl{$1, VAssertCtlType::OFF}; } + | yD_ASSERTOFF '(' expr ')' { $$ = new AstAssertCtl{$1, VAssertCtlType::OFF, $3}; } + | yD_ASSERTOFF '(' exprE ',' exprList ')' { $$ = new AstAssertCtl{$1, VAssertCtlType::OFF, $3, $5}; } + | yD_ASSERTON parenE { $$ = new AstAssertCtl{$1, VAssertCtlType::ON}; } + | yD_ASSERTON '(' expr ')' { $$ = new AstAssertCtl{$1, VAssertCtlType::ON, $3}; } + | yD_ASSERTON '(' exprE ',' exprList ')' { $$ = new AstAssertCtl{$1, VAssertCtlType::ON, $3, $5}; } + // | yD_MONITOROFF parenE { $$ = new AstMonitorOff{$1, true}; } | yD_MONITORON parenE { $$ = new AstMonitorOff{$1, false}; } // @@ -4799,7 +4818,7 @@ constExpr: expr { $$ = $1; } ; -exprE: // IEEE: optional expression +exprE: // IEEE: optional expression /*empty*/ { $$ = nullptr; } | expr { $$ = $1; } ; diff --git a/test_regress/t/t_assert_ctl_concurrent.pl b/test_regress/t/t_assert_ctl_concurrent.pl new file mode 100755 index 000000000..c82d5093e --- /dev/null +++ b/test_regress/t/t_assert_ctl_concurrent.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 2024 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 --assert"], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_assert_ctl_concurrent.v b/test_regress/t/t_assert_ctl_concurrent.v new file mode 100644 index 000000000..a327b541a --- /dev/null +++ b/test_regress/t/t_assert_ctl_concurrent.v @@ -0,0 +1,44 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2024 by Antmicro. +// SPDX-License-Identifier: CC0-1.0 + +module t; + + bit clock = 1'b0; + bit reset = 1'b0; + + initial begin + $assertkill; + + #10 + + reset = 1'b1; + $display("%t: deassert reset %d", $time, reset); + + #40 + + $asserton; + + reset = 1'b0; + $display("%t: deassert reset %d", $time, reset); + + #200 + + $display("%t: finish", $time); + $write("*-* All Finished *-*\n"); + $finish; + + end + + always #10 clock = ~clock; + reg r = 1'b0; + + always @(posedge clock) if (reset) r <= 1'b1; + + assert_test: + assert property (@(posedge clock) (reset | r)) + else $error("%t: assertion triggered", $time); + +endmodule diff --git a/test_regress/t/t_assert_ctl_concurrent_noinl.pl b/test_regress/t/t_assert_ctl_concurrent_noinl.pl new file mode 100755 index 000000000..2339bbf25 --- /dev/null +++ b/test_regress/t/t_assert_ctl_concurrent_noinl.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 2024 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 + +top_filename("t_assert_ctl_concurrent.v"); +scenarios(vlt => 1); + +compile( + verilator_flags2 => ["--exe --main --timing --assert --fno-inline"], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_assert_ctl_immediate_bad.out b/test_regress/t/t_assert_ctl_immediate_bad.out new file mode 100644 index 000000000..a11c872ed --- /dev/null +++ b/test_regress/t/t_assert_ctl_immediate_bad.out @@ -0,0 +1,10 @@ +[0] %Error: t_assert_ctl_immediate_bad.v:50: Assertion failed in top.t.module_with_assertctl: 'assert' failed. +-Info: t/t_assert_ctl_immediate_bad.v:50: Verilog $stop, ignored due to +verilator+error+limit +[0] %Error: t_assert_ctl_immediate_bad.v:54: Assertion failed in top.t.module_with_assertctl: 'assert' failed. +[0] %Error: t_assert_ctl_immediate_bad.v:59: Assertion failed in top.t.module_with_assertctl: 'assert' failed. +[0] %Error: t_assert_ctl_immediate_bad.v:63: Assertion failed in top.t.module_with_assertctl: 'assert' failed. +[0] %Error: t_assert_ctl_immediate_bad.v:68: Assertion failed in top.t.module_with_assertctl: 'assert' failed. +[0] %Error: t_assert_ctl_immediate_bad.v:74: Assertion failed in top.t.module_with_assertctl: 'assert' failed. +[0] %Error: t_assert_ctl_immediate_bad.v:45: Assertion failed in top.t.module_with_assertctl.f_assert: 'assert' failed. +[0] %Error: t_assert_ctl_immediate_bad.v:45: Assertion failed in top.t.module_with_assertctl.f_assert: 'assert' failed. +*-* All Finished *-* diff --git a/test_regress/t/t_assert_ctl_immediate_bad.pl b/test_regress/t/t_assert_ctl_immediate_bad.pl new file mode 100755 index 000000000..55081d509 --- /dev/null +++ b/test_regress/t/t_assert_ctl_immediate_bad.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 2024 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 => ['--assert', '--timing'], + ); + +execute( + all_run_flags => ["+verilator+error+limit+100"], + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_assert_ctl_immediate_bad.v b/test_regress/t/t_assert_ctl_immediate_bad.v new file mode 100644 index 000000000..3268f9e46 --- /dev/null +++ b/test_regress/t/t_assert_ctl_immediate_bad.v @@ -0,0 +1,82 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2024 by Antmicro. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + + module_with_assert module_with_assert(clk); + module_with_assertctl module_with_assertctl(clk); + + always @ (posedge clk) begin + assert(0); + end + + always @ (negedge clk) begin + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule + +module module_with_assert(input clk); + always @(posedge clk) assert(0); +endmodule + +module module_with_assertctl(input clk); + let ON = 3; + let OFF = 4; + let KILL = 5; + + function void assert_off; begin + $assertoff; + end + endfunction + function void assert_on; begin + $asserton; + end + endfunction + function void f_assert; begin + assert(0); + end + endfunction + + initial begin + assert(0); + $assertoff; + assert(0); + $asserton; + assert(0); + $assertkill; + assert(0); + + $assertcontrol(ON); + assert(0); + $assertcontrol(OFF); + assert(0); + $assertcontrol(ON); + assert(0); + $assertcontrol(KILL); + assert(0); + + assert_on(); + assert(0); + assert_off(); + assert_off(); + assert(0); + assert_on(); + assert_on(); + assert(0); + + f_assert(); + f_assert(); + assert_off(); + f_assert(); + f_assert(); + end +endmodule diff --git a/test_regress/t/t_assert_ctl_immediate_noinl_bad.pl b/test_regress/t/t_assert_ctl_immediate_noinl_bad.pl new file mode 100755 index 000000000..125955db7 --- /dev/null +++ b/test_regress/t/t_assert_ctl_immediate_noinl_bad.pl @@ -0,0 +1,25 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 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 + +top_filename("t_assert_ctl_immediate_bad.v"); +golden_filename("t/t_assert_ctl_immediate_bad.out"); +scenarios(vlt => 1); + +compile( + verilator_flags2 => ['--assert --timing --fno-inline'], + ); + +execute( + all_run_flags => ["+verilator+error+limit+100"], + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_assert_ctl_unsup.out b/test_regress/t/t_assert_ctl_unsup.out new file mode 100644 index 000000000..eccea03d3 --- /dev/null +++ b/test_regress/t/t_assert_ctl_unsup.out @@ -0,0 +1,56 @@ +%Error-UNSUPPORTED: t/t_assert_ctl_unsup.v:18:7: Unsupported assertcontrol control_type + 18 | $assertcontrol(1); + | ^~~~~~~~~~~~~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error-UNSUPPORTED: t/t_assert_ctl_unsup.v:19:7: Unsupported assertcontrol control_type + 19 | $assertcontrol(2); + | ^~~~~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_assert_ctl_unsup.v:20:7: Unsupported assertcontrol control_type + 20 | $assertcontrol(6); + | ^~~~~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_assert_ctl_unsup.v:21:7: Unsupported assertcontrol control_type + 21 | $assertcontrol(7); + | ^~~~~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_assert_ctl_unsup.v:22:7: Unsupported assertcontrol control_type + 22 | $assertcontrol(8); + | ^~~~~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_assert_ctl_unsup.v:23:7: Unsupported assertcontrol control_type + 23 | $assertcontrol(9); + | ^~~~~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_assert_ctl_unsup.v:24:7: Unsupported assertcontrol control_type + 24 | $assertcontrol(10); + | ^~~~~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_assert_ctl_unsup.v:25:7: Unsupported assertcontrol control_type + 25 | $assertcontrol(11); + | ^~~~~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_assert_ctl_unsup.v:32:7: Unsupported: non-const assert control type expression + : ... note: In instance 't.unsupported_ctl_type_expr' + 32 | $assertcontrol(ctl_type); + | ^~~~~~~~~~~~~~ +%Error: t/t_assert_ctl_unsup.v:38:7: Bad assertcontrol control_type (IEEE 1800-2023 Table 20-5) + 38 | $assertcontrol(0); + | ^~~~~~~~~~~~~~ +%Error: t/t_assert_ctl_unsup.v:39:7: Bad assertcontrol control_type (IEEE 1800-2023 Table 20-5) + 39 | $assertcontrol(100); + | ^~~~~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_assert_ctl_unsup.v:68:10: Unsupported: assertcontrols in classes or interfaces + : ... note: In instance 't.assert_class' + 68 | $asserton; + | ^~~~~~~~~ +%Error-UNSUPPORTED: t/t_assert_ctl_unsup.v:74:10: Unsupported: assertcontrols in classes or interfaces + : ... note: In instance 't.assert_class' + 74 | $assertoff; + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_assert_ctl_unsup.v:147:7: Unsupported: assertcontrols in classes or interfaces + : ... note: In instance 't.assert_iface' + 147 | $assertoff; + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_assert_ctl_unsup.v:113:7: Unsupported: assertcontrols in classes or interfaces + : ... note: In instance 't.assert_iface_class' + 113 | $assertoff; + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_assert_ctl_unsup.v:120:7: Unsupported: assertcontrols in classes or interfaces + : ... note: In instance 't.assert_iface_class' + 120 | $asserton; + | ^~~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_assert_ctl_unsup.pl b/test_regress/t/t_assert_ctl_unsup.pl new file mode 100755 index 000000000..b3b9ca877 --- /dev/null +++ b/test_regress/t/t_assert_ctl_unsup.pl @@ -0,0 +1,20 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 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); + +lint( + verilator_flags2 => ['--assert'], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_assert_ctl_unsup.v b/test_regress/t/t_assert_ctl_unsup.v new file mode 100755 index 000000000..44a3179e7 --- /dev/null +++ b/test_regress/t/t_assert_ctl_unsup.v @@ -0,0 +1,160 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2024 by Antmicro. +// SPDX-License-Identifier: CC0-1.0 + +module t; + unsupported_ctl_type unsupported_ctl_type(); + unsupported_ctl_type_expr unsupported_ctl_type_expr(); + bad_assertcontrol_ctl_type bad_assertcontrol_ctl_type(); + assert_class assert_class(); + assert_iface assert_iface(); + assert_iface_class assert_iface_class(); +endmodule + +module unsupported_ctl_type; + initial begin + $assertcontrol(1); + $assertcontrol(2); + $assertcontrol(6); + $assertcontrol(7); + $assertcontrol(8); + $assertcontrol(9); + $assertcontrol(10); + $assertcontrol(11); + end +endmodule + +module unsupported_ctl_type_expr; + int ctl_type = 1; + initial begin + $assertcontrol(ctl_type); + end +endmodule + +module bad_assertcontrol_ctl_type; + initial begin + $assertcontrol(0); + $assertcontrol(100); + end +endmodule + +module assert_class; + virtual class AssertCtl; + pure virtual function void virtual_assert_ctl(); + endclass + + class AssertCls; + static function void static_function(); + assert(0); + endfunction + static task static_task(); + assert(0); + endtask + function void assert_function(); + assert(0); + endfunction + task assert_task(); + assert(0); + endtask + virtual function void virtual_assert(); + assert(0); + endfunction + endclass + + class AssertOn extends AssertCtl; + virtual function void virtual_assert_ctl(); + $asserton; + endfunction + endclass + + class AssertOff extends AssertCtl; + virtual function void virtual_assert_ctl(); + $assertoff; + endfunction + endclass + + AssertCls assertCls; + AssertOn assertOn; + AssertOff assertOff; + initial begin + $assertoff; + AssertCls::static_function(); + AssertCls::static_task(); + $asserton; + AssertCls::static_function(); + AssertCls::static_task(); + + assertCls = new; + assertOn = new; + assertOff = new; + + assertOff.virtual_assert_ctl(); + assertCls.assert_function(); + assertCls.assert_task(); + assertCls.virtual_assert(); + + assertOn.virtual_assert_ctl(); + assertCls.assert_function(); + assertCls.assert_task(); + assertCls.virtual_assert(); + assertOff.virtual_assert_ctl(); + assertCls.assert_function(); + end +endmodule + +interface Iface; + function void assert_func(); + assert(0); + endfunction + + function void assertoff_func(); + $assertoff; + endfunction + + initial begin + assertoff_func(); + assert(0); + assert_func(); + $asserton; + assert(0); + assert_func(); + end +endinterface + +module assert_iface; + Iface iface(); + virtual Iface vIface = iface; + initial begin + vIface.assert_func(); + vIface.assertoff_func(); + vIface.assert_func(); + + iface.assert_func(); + iface.assertoff_func(); + iface.assert_func(); + end +endmodule + +interface class IfaceClass; + pure virtual function void assertoff_func(); + pure virtual function void assert_func(); +endclass + +class IfaceClassImpl implements IfaceClass; + virtual function void assertoff_func(); + $assertoff; + endfunction + virtual function void assert_func(); + assert(0); + endfunction +endclass + +module assert_iface_class; + IfaceClassImpl ifaceClassImpl = new; + initial begin + ifaceClassImpl.assertoff_func(); + ifaceClassImpl.assert_func(); + end +endmodule diff --git a/test_regress/t/t_dump.v b/test_regress/t/t_dump.v index 2467605e5..8c70095e9 100644 --- a/test_regress/t/t_dump.v +++ b/test_regress/t/t_dump.v @@ -81,5 +81,11 @@ module Test(/*AUTOARG*/ always @(posedge clk) begin out <= in; + + // Assert control dump test. + $assertoff; + $assertkill; + assert(0); + $asserton; end endmodule diff --git a/test_regress/t/t_dump_json.out b/test_regress/t/t_dump_json.out index c29d4315a..b220a11e3 100644 --- a/test_regress/t/t_dump_json.out +++ b/test_regress/t/t_dump_json.out @@ -487,22 +487,47 @@ ], "lhsp": [ {"type":"PARSEREF","name":"out","addr":"(VH)","loc":"d,83:7,83:10","dtypep":"UNLINKED","expect":"TEXT","lhsp": [],"ftaskrefp": []} - ],"timingControlp": []} + ],"timingControlp": []}, + {"type":"ASSERTCTL","name":"","addr":"(WH)","loc":"d,86:7,86:17","ctlType":"$assertoff", + "controlTypep": [ + {"type":"CONST","name":"32'h4","addr":"(XH)","loc":"d,86:7,86:17","dtypep":"(MC)"} + ], + "levelp": [ + {"type":"CONST","name":"32'h0","addr":"(YH)","loc":"d,86:7,86:17","dtypep":"(MC)"} + ],"itemsp": []}, + {"type":"ASSERTCTL","name":"","addr":"(ZH)","loc":"d,87:7,87:18","ctlType":"$assertkill", + "controlTypep": [ + {"type":"CONST","name":"32'h5","addr":"(AI)","loc":"d,87:7,87:18","dtypep":"(MC)"} + ], + "levelp": [ + {"type":"CONST","name":"32'h0","addr":"(BI)","loc":"d,87:7,87:18","dtypep":"(MC)"} + ],"itemsp": []}, + {"type":"ASSERT","name":"","addr":"(CI)","loc":"d,88:7,88:13","immediate":true, + "propp": [ + {"type":"CONST","name":"?32?sh0","addr":"(DI)","loc":"d,88:14,88:15","dtypep":"(L)"} + ],"sentreep": [],"failsp": [],"passsp": []}, + {"type":"ASSERTCTL","name":"","addr":"(EI)","loc":"d,89:7,89:16","ctlType":"$asserton", + "controlTypep": [ + {"type":"CONST","name":"32'h3","addr":"(FI)","loc":"d,89:7,89:16","dtypep":"(MC)"} + ], + "levelp": [ + {"type":"CONST","name":"32'h0","addr":"(GI)","loc":"d,89:7,89:16","dtypep":"(MC)"} + ],"itemsp": []} ]} ]} ]} ],"activesp": []} ],"filesp": [], "miscsp": [ - {"type":"TYPETABLE","name":"","addr":"(C)","loc":"a,0:0,0:0","constraintRefp":"UNLINKED","emptyQueuep":"UNLINKED","queueIndexp":"UNLINKED","streamp":"UNLINKED","voidp":"(WH)", + {"type":"TYPETABLE","name":"","addr":"(C)","loc":"a,0:0,0:0","constraintRefp":"UNLINKED","emptyQueuep":"UNLINKED","queueIndexp":"UNLINKED","streamp":"UNLINKED","voidp":"(HI)", "typesp": [ - {"type":"BASICDTYPE","name":"integer","addr":"(XH)","loc":"c,31:27,31:28","dtypep":"(XH)","keyword":"integer","range":"31:0","generic":true,"rangep": []}, + {"type":"BASICDTYPE","name":"integer","addr":"(II)","loc":"c,31:27,31:28","dtypep":"(II)","keyword":"integer","range":"31:0","generic":true,"rangep": []}, {"type":"BASICDTYPE","name":"logic","addr":"(L)","loc":"c,33:32,33:33","dtypep":"(L)","keyword":"logic","range":"31:0","generic":true,"rangep": []}, {"type":"BASICDTYPE","name":"logic","addr":"(UE)","loc":"c,50:22,50:24","dtypep":"(UE)","keyword":"logic","generic":true,"rangep": []}, - {"type":"VOIDDTYPE","name":"","addr":"(WH)","loc":"c,51:21,51:30","dtypep":"(WH)","generic":false}, + {"type":"VOIDDTYPE","name":"","addr":"(HI)","loc":"c,51:21,51:30","dtypep":"(HI)","generic":false}, {"type":"BASICDTYPE","name":"logic","addr":"(QD)","loc":"c,119:22,119:23","dtypep":"(QD)","keyword":"logic","range":"31:0","generic":true,"rangep": []}, - {"type":"BASICDTYPE","name":"logic","addr":"(YH)","loc":"c,121:22,121:23","dtypep":"(YH)","keyword":"logic","range":"31:0","generic":true,"rangep": []}, - {"type":"BASICDTYPE","name":"logic","addr":"(ZH)","loc":"c,156:17,156:56","dtypep":"(ZH)","keyword":"logic","range":"295:0","generic":true,"rangep": []}, + {"type":"BASICDTYPE","name":"logic","addr":"(JI)","loc":"c,121:22,121:23","dtypep":"(JI)","keyword":"logic","range":"31:0","generic":true,"rangep": []}, + {"type":"BASICDTYPE","name":"logic","addr":"(KI)","loc":"c,156:17,156:56","dtypep":"(KI)","keyword":"logic","range":"295:0","generic":true,"rangep": []}, {"type":"BASICDTYPE","name":"string","addr":"(BG)","loc":"c,156:10,156:16","dtypep":"(BG)","keyword":"string","generic":true,"rangep": []}, {"type":"BASICDTYPE","name":"logic","addr":"(Q)","loc":"d,14:9,14:11","dtypep":"(Q)","keyword":"logic","range":"31:0","generic":true,"rangep": []}, {"type":"BASICDTYPE","name":"logic","addr":"(BB)","loc":"d,18:10,18:12","dtypep":"(BB)","keyword":"logic","range":"31:0","generic":true,"rangep": []}, @@ -517,9 +542,9 @@ ]}, {"type":"CONSTPOOL","name":"","addr":"(D)","loc":"a,0:0,0:0", "modulep": [ - {"type":"MODULE","name":"@CONST-POOL@","addr":"(AI)","loc":"a,0:0,0:0","origName":"@CONST-POOL@","level":0,"modPublic":false,"inLibrary":false,"dead":false,"recursiveClone":false,"recursive":false,"timeunit":"NONE","inlinesp": [], + {"type":"MODULE","name":"@CONST-POOL@","addr":"(LI)","loc":"a,0:0,0:0","origName":"@CONST-POOL@","level":0,"modPublic":false,"inLibrary":false,"dead":false,"recursiveClone":false,"recursive":false,"timeunit":"NONE","inlinesp": [], "stmtsp": [ - {"type":"SCOPE","name":"@CONST-POOL@","addr":"(BI)","loc":"a,0:0,0:0","aboveScopep":"UNLINKED","aboveCellp":"UNLINKED","modp":"(AI)","varsp": [],"blocksp": [],"inlinesp": []} + {"type":"SCOPE","name":"@CONST-POOL@","addr":"(MI)","loc":"a,0:0,0:0","aboveScopep":"UNLINKED","aboveCellp":"UNLINKED","modp":"(LI)","varsp": [],"blocksp": [],"inlinesp": []} ],"activesp": []} ]} ]}