From 665e8edaff70f1d3d3946b81aa8b8ada6fda92b7 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 29 Nov 2020 11:31:38 -0500 Subject: [PATCH] Support $monitor and $strobe. --- Changes | 2 + bin/verilator | 5 --- src/V3Active.cpp | 8 ++++ src/V3Assert.cpp | 74 ++++++++++++++++++++++++++++++- src/V3Ast.h | 17 +++++-- src/V3AstNodes.h | 42 ++++++++++++++---- src/V3Clock.cpp | 9 ++++ src/V3MergeCond.cpp | 2 +- src/V3Order.cpp | 9 +++- src/verilog.l | 20 ++++++++- src/verilog.y | 37 ++++++++++++++++ test_regress/t/t_sys_fmonitor.out | 15 +++++++ test_regress/t/t_sys_fmonitor.pl | 24 ++++++++++ test_regress/t/t_sys_fmonitor.v | 57 ++++++++++++++++++++++++ test_regress/t/t_sys_fstrobe.out | 6 +++ test_regress/t/t_sys_fstrobe.pl | 24 ++++++++++ test_regress/t/t_sys_fstrobe.v | 55 +++++++++++++++++++++++ test_regress/t/t_sys_monitor.out | 20 +++++++++ test_regress/t/t_sys_monitor.pl | 23 ++++++++++ test_regress/t/t_sys_monitor.v | 45 +++++++++++++++++++ test_regress/t/t_sys_strobe.out | 7 +++ test_regress/t/t_sys_strobe.pl | 23 ++++++++++ test_regress/t/t_sys_strobe.v | 46 +++++++++++++++++++ 23 files changed, 548 insertions(+), 22 deletions(-) create mode 100644 test_regress/t/t_sys_fmonitor.out create mode 100755 test_regress/t/t_sys_fmonitor.pl create mode 100644 test_regress/t/t_sys_fmonitor.v create mode 100644 test_regress/t/t_sys_fstrobe.out create mode 100755 test_regress/t/t_sys_fstrobe.pl create mode 100644 test_regress/t/t_sys_fstrobe.v create mode 100644 test_regress/t/t_sys_monitor.out create mode 100755 test_regress/t/t_sys_monitor.pl create mode 100644 test_regress/t/t_sys_monitor.v create mode 100644 test_regress/t/t_sys_strobe.out create mode 100755 test_regress/t/t_sys_strobe.pl create mode 100644 test_regress/t/t_sys_strobe.v diff --git a/Changes b/Changes index b2a3a5f9b..e2d2f61f4 100644 --- a/Changes +++ b/Changes @@ -11,6 +11,8 @@ The contributors that suggested a given feature are shown in []. Thanks! *** Support $random and $urandom seeds. +*** Support $monitor and $strobe. + *** Support complex function arguments. *** Support 'super'. diff --git a/bin/verilator b/bin/verilator index ac88b8e2a..2df1ec7aa 100755 --- a/bin/verilator +++ b/bin/verilator @@ -4107,11 +4107,6 @@ $setup, $setuphold, $skew, $timeskew, $width All specify blocks and timing checks are ignored. -=item $monitor, $strobe - -Monitor and strobe are not supported, convert to always_comb $display or -similar. - =item $random, $urandom, $urandom_range Use +verilator+seed argument to set the seed if there is no $random or diff --git a/src/V3Active.cpp b/src/V3Active.cpp index c2ab0f7cd..50aa672c2 100644 --- a/src/V3Active.cpp +++ b/src/V3Active.cpp @@ -364,6 +364,14 @@ private: } visitAlways(nodep, nodep->sensesp(), nodep->keyword()); } + virtual void visit(AstAlwaysPostponed* nodep) override { + UINFO(4, " ALW " << nodep << endl); + if (!nodep->bodysp()) { + VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); + return; + } + visitAlways(nodep, nullptr, VAlwaysKwd::ALWAYS); + } virtual void visit(AstAlwaysPublic* nodep) override { // Move always to appropriate ACTIVE based on its sense list UINFO(4, " ALWPub " << nodep << endl); diff --git a/src/V3Assert.cpp b/src/V3Assert.cpp index de633e7ef..8af7193cc 100644 --- a/src/V3Assert.cpp +++ b/src/V3Assert.cpp @@ -36,7 +36,11 @@ private: // STATE AstNodeModule* m_modp = nullptr; // Last module AstBegin* m_beginp = nullptr; // Last begin + unsigned m_monitorNum = 0; // Global $monitor numbering (not per module) + AstVar* m_monitorNumVarp = nullptr; // $monitor number variable + AstVar* m_monitorOffVarp = nullptr; // $monitoroff variable unsigned m_modPastNum = 0; // Module past numbering + unsigned m_modStrobeNum = 0; // Module $strobe numbering VDouble0 m_statCover; // Statistic tracking VDouble0 m_statAsNotImm; // Statistic tracking VDouble0 m_statAsImm; // Statistic tracking @@ -62,7 +66,26 @@ private: nodep->fmtp()->scopeNamep(new AstScopeName(nodep->fileline())); } } - + AstVarRef* newMonitorNumVarRefp(AstNode* nodep, VAccess access) { + if (!m_monitorNumVarp) { + m_monitorNumVarp = new AstVar{nodep->fileline(), AstVarType::MODULETEMP, + "__VmonitorNum", nodep->findUInt64DType()}; + v3Global.rootp()->dollarUnitPkgAddp()->addStmtp(m_monitorNumVarp); + } + const auto varrefp = new AstVarRef(nodep->fileline(), m_monitorNumVarp, access); + varrefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp()); + return varrefp; + } + AstVarRef* newMonitorOffVarRefp(AstNode* nodep, VAccess access) { + if (!m_monitorOffVarp) { + m_monitorOffVarp = new AstVar{nodep->fileline(), AstVarType::MODULETEMP, + "__VmonitorOff", nodep->findBitDType()}; + v3Global.rootp()->dollarUnitPkgAddp()->addStmtp(m_monitorOffVarp); + } + const auto varrefp = new AstVarRef(nodep->fileline(), m_monitorOffVarp, access); + varrefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp()); + return varrefp; + } AstNode* newIfAssertOn(AstNode* nodep) { // Add a internal if to check assertions are on. // Don't make this a AND term, as it's unlikely to need to test this. @@ -342,9 +365,54 @@ private: } else if (nodep->displayType() == AstDisplayType::DT_ERROR || nodep->displayType() == AstDisplayType::DT_FATAL) { replaceDisplay(nodep, "%%Error"); + } else if (nodep->displayType() == AstDisplayType::DT_MONITOR) { + nodep->displayType(AstDisplayType::DT_DISPLAY); + const auto fl = nodep->fileline(); + const auto monNum = ++m_monitorNum; + // Where $monitor was we do "__VmonitorNum = N;" + const auto newsetp = new AstAssign{fl, newMonitorNumVarRefp(nodep, VAccess::WRITE), + new AstConst{fl, monNum}}; + nodep->replaceWith(newsetp); + // Add "always_comb if (__VmonitorOn && __VmonitorNum==N) $display(...);" + AstNode* stmtsp = nodep; + AstIf* ifp = new AstIf{ + fl, + new AstLogAnd{fl, new AstLogNot{fl, newMonitorOffVarRefp(nodep, VAccess::READ)}, + new AstEq{fl, new AstConst{fl, monNum}, + newMonitorNumVarRefp(nodep, VAccess::READ)}}, + stmtsp, nullptr}; + ifp->branchPred(VBranchPred::BP_UNLIKELY); + AstNode* newp = new AstAlwaysPostponed{fl, ifp}; + m_modp->addStmtp(newp); + } else if (nodep->displayType() == AstDisplayType::DT_STROBE) { + nodep->displayType(AstDisplayType::DT_DISPLAY); + // Need one-shot + const auto fl = nodep->fileline(); + const auto varp + = new AstVar{fl, AstVarType::MODULETEMP, "__Vstrobe" + cvtToStr(m_modStrobeNum++), + nodep->findBitDType()}; + m_modp->addStmtp(varp); + // Where $strobe was we do "__Vstrobe = '1;" + const auto newsetp = new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE}, + new AstConst{fl, AstConst::BitTrue{}}}; + nodep->replaceWith(newsetp); + // Add "always_comb if (__Vstrobe) begin $display(...); __Vstrobe = '0; end" + AstNode* stmtsp = nodep; + AstIf* ifp = new AstIf{fl, new AstVarRef{fl, varp, VAccess::READ}, stmtsp, nullptr}; + ifp->branchPred(VBranchPred::BP_UNLIKELY); + AstNode* newp = new AstAlwaysPostponed{fl, ifp}; + stmtsp->addNext(new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE}, + new AstConst{fl, AstConst::BitFalse{}}}); + m_modp->addStmtp(newp); } } - + virtual void visit(AstMonitorOff* nodep) override { + const auto newp + = new AstAssign(nodep->fileline(), newMonitorOffVarRefp(nodep, VAccess::WRITE), + new AstConst(nodep->fileline(), AstConst::BitTrue{}, nodep->off())); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } virtual void visit(AstAssert* nodep) override { iterateChildren(nodep); newPslAssertion(nodep, nodep->failsp()); @@ -362,9 +430,11 @@ private: virtual void visit(AstNodeModule* nodep) override { VL_RESTORER(m_modp); VL_RESTORER(m_modPastNum); + VL_RESTORER(m_modStrobeNum); { m_modp = nodep; m_modPastNum = 0; + m_modStrobeNum = 0; iterateChildren(nodep); } } diff --git a/src/V3Ast.h b/src/V3Ast.h index 969ea9da2..90c54a434 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -879,12 +879,21 @@ inline bool operator==(VCaseType::en lhs, const VCaseType& rhs) { return lhs == class AstDisplayType final { public: - enum en : uint8_t { DT_DISPLAY, DT_WRITE, DT_INFO, DT_ERROR, DT_WARNING, DT_FATAL }; + enum en : uint8_t { + DT_DISPLAY, + DT_WRITE, + DT_MONITOR, + DT_STROBE, + DT_INFO, + DT_ERROR, + DT_WARNING, + DT_FATAL + }; enum en m_e; - inline AstDisplayType() + AstDisplayType() : m_e{DT_DISPLAY} {} // cppcheck-suppress noExplicitConstructor - inline AstDisplayType(en _e) + AstDisplayType(en _e) : m_e{_e} {} explicit inline AstDisplayType(int _e) : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning @@ -893,7 +902,7 @@ public: bool needScopeTracking() const { return m_e != DT_DISPLAY && m_e != DT_WRITE; } const char* ascii() const { static const char* const names[] - = {"display", "write", "info", "error", "warning", "fatal"}; + = {"display", "write", "monitor", "strobe", "info", "error", "warning", "fatal"}; return names[m_e]; } }; diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index f93d968d7..032cee3ee 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -146,16 +146,11 @@ public: , m_num(this, 1, 0) { dtypeSetBit(); } + // Shorthand const 1 (or with argument 0/1), dtype should be a logic of size 1 class BitTrue {}; - AstConst(FileLine* fl, BitTrue) // Shorthand const 1, dtype should be a logic of size 1 + AstConst(FileLine* fl, BitTrue, bool on = true) : ASTGEN_SUPER(fl) - , m_num(this, 1, 1) { - dtypeSetBit(); - } - class BitTrueFalse {}; - AstConst(FileLine* fl, BitTrueFalse, bool on) - : ASTGEN_SUPER(fl) - , m_num(this, 1, on ? 1 : 0) { + , m_num(this, 1, on) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(Const) @@ -3296,6 +3291,14 @@ public: void sensesp(AstSenTree* nodep) { setOp1p(nodep); } VAlwaysKwd keyword() const { return m_keyword; } }; +class AstAlwaysPostponed final : public AstNodeProcedure { + // Like always but postponement scheduling region + +public: + AstAlwaysPostponed(FileLine* fl, AstNode* bodysp) + : ASTGEN_SUPER(fl, bodysp) {} + ASTNODE_NODE_FUNCS(AlwaysPostponed) +}; class AstAlwaysPublic final : public AstNodeStmt { // "Fake" sensitivity created by /*verilator public_flat_rw @(edgelist)*/ @@ -4282,6 +4285,29 @@ public: virtual const char* cFuncPrefixp() const override { return "VL_WRITEMEM_"; } }; +class AstMonitorOff final : public AstNodeStmt { + bool m_off; // Monitor off. Using 0=on allows faster init and comparison + +public: + AstMonitorOff(FileLine* fl, bool off) + : ASTGEN_SUPER(fl) + , m_off{off} {} + ASTNODE_NODE_FUNCS(MonitorOff) + virtual string verilogKwd() const override { return m_off ? "$monitoroff" : "$monitoron"; } + virtual bool isGateOptimizable() const override { return false; } // Though deleted before opt + virtual bool isPredictOptimizable() const override { + return false; + } // Though deleted before opt + virtual bool isPure() const override { return false; } // Though deleted before opt + virtual bool isOutputter() const override { return true; } // Though deleted before opt + virtual int instrCount() const override { return instrCountPli(); } + virtual V3Hash sameHash() const override { return V3Hash(m_off); } + virtual bool same(const AstNode* samep) const override { + return m_off == static_cast(samep)->m_off; + } + bool off() const { return m_off; } +}; + class AstSystemT final : public AstNodeStmt { // $system used as task public: diff --git a/src/V3Clock.cpp b/src/V3Clock.cpp index 31128c4f7..e4a5da09f 100644 --- a/src/V3Clock.cpp +++ b/src/V3Clock.cpp @@ -311,6 +311,15 @@ private: } VL_DO_DANGLING(nodep->deleteTree(), nodep); } + virtual void visit(AstAlwaysPostponed* nodep) override { + AstNode* cmtp = new AstComment(nodep->fileline(), nodep->typeName(), true); + nodep->replaceWith(cmtp); + if (AstNode* stmtsp = nodep->bodysp()) { + stmtsp->unlinkFrBackWithNext(); + cmtp->addNextHere(stmtsp); + } + VL_DO_DANGLING(nodep->deleteTree(), nodep); + } virtual void visit(AstCoverToggle* nodep) override { // nodep->dumpTree(cout, "ct:"); // COVERTOGGLE(INC, ORIG, CHANGE) -> diff --git a/src/V3MergeCond.cpp b/src/V3MergeCond.cpp index d0d23b7bc..771096200 100644 --- a/src/V3MergeCond.cpp +++ b/src/V3MergeCond.cpp @@ -170,7 +170,7 @@ private: // of the RHS is expected to be deleted by the caller. AstNode* foldAndUnlink(AstNode* rhsp, bool condTrue) { if (rhsp->sameTree(m_mgCondp)) { - return new AstConst(rhsp->fileline(), AstConst::BitTrueFalse(), condTrue); + return new AstConst(rhsp->fileline(), AstConst::BitTrue{}, condTrue); } else if (AstNodeCond* const condp = extractCond(rhsp)) { AstNode* const resp = condTrue ? condp->expr1p()->unlinkFrBack() : condp->expr2p()->unlinkFrBack(); diff --git a/src/V3Order.cpp b/src/V3Order.cpp index cca5359fe..4060c3c54 100644 --- a/src/V3Order.cpp +++ b/src/V3Order.cpp @@ -673,6 +673,7 @@ private: bool m_inClkAss = false; // Underneath AstAssign bool m_inPre = false; // Underneath AstAssignPre bool m_inPost = false; // Underneath AstAssignPost + bool m_inPostponed = false; // Underneath AstAssignPostponed OrderLogicVertex* m_activeSenVxp = nullptr; // Sensitivity vertex std::deque m_orderUserps; // All created OrderUser's for later deletion. // STATE... for inside process @@ -1044,7 +1045,8 @@ private: // We don't want to add extra edges if the logic block has many usages of same var bool gen = false; bool con = false; - if (nodep->access().isWriteOrRW()) gen = !(varscp->user4() & VU_GEN); + if (nodep->access().isWriteOrRW() && !m_inPostponed) + gen = !(varscp->user4() & VU_GEN); if (nodep->access().isReadOrRW()) { con = !(varscp->user4() & VU_CON); if ((varscp->user4() & VU_GEN) && !m_inClocked) { @@ -1174,6 +1176,11 @@ private: iterateNewStmt(nodep); m_inPost = false; } + virtual void visit(AstAlwaysPostponed* nodep) override { + VL_RESTORER(m_inPostponed); + m_inPostponed = true; + iterateNewStmt(nodep); + } virtual void visit(AstAlways* nodep) override { iterateNewStmt(nodep); } virtual void visit(AstAlwaysPublic* nodep) override { iterateNewStmt(nodep); } virtual void visit(AstAssignAlias* nodep) override { iterateNewStmt(nodep); } diff --git a/src/verilog.l b/src/verilog.l index 0b7301475..422af9538 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -205,11 +205,19 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "$fgets" { FL; return yD_FGETS; } "$finish" { FL; return yD_FINISH; } "$floor" { FL; return yD_FLOOR; } + "$fmonitor" { FL; return yD_FMONITOR; } + "$fmonitorb" { FL; return yD_FMONITORB; } + "$fmonitorh" { FL; return yD_FMONITORH; } + "$fmonitoro" { FL; return yD_FMONITORO; } "$fopen" { FL; return yD_FOPEN; } "$fread" { FL; return yD_FREAD; } "$frewind" { FL; return yD_FREWIND; } "$fscanf" { FL; return yD_FSCANF; } "$fseek" { FL; return yD_FSEEK; } + "$fstrobe" { FL; return yD_FSTROBE; } + "$fstrobeb" { FL; return yD_FSTROBEB; } + "$fstrobeh" { FL; return yD_FSTROBEH; } + "$fstrobeo" { FL; return yD_FSTROBEO; } "$ftell" { FL; return yD_FTELL; } "$fullskew" { FL; return yaTIMINGSPEC; } "$fwrite" { FL; return yD_FWRITE; } @@ -221,6 +229,12 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "$itor" { FL; return yD_ITOR; } "$ln" { FL; return yD_LN; } "$log10" { FL; return yD_LOG10; } + "$monitor" { FL; return yD_MONITOR; } + "$monitorb" { FL; return yD_MONITORB; } + "$monitorh" { FL; return yD_MONITORH; } + "$monitoro" { FL; return yD_MONITORO; } + "$monitoroff" { FL; return yD_MONITOROFF; } + "$monitoron" { FL; return yD_MONITORON; } "$nochange" { FL; return yaTIMINGSPEC; } "$period" { FL; return yaTIMINGSPEC; } "$pow" { FL; return yD_POW; } @@ -248,6 +262,10 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "$sscanf" { FL; return yD_SSCANF; } "$stime" { FL; return yD_STIME; } "$stop" { FL; return yD_STOP; } + "$strobe" { FL; return yD_STROBE; } + "$strobeb" { FL; return yD_STROBEB; } + "$strobeh" { FL; return yD_STROBEH; } + "$strobeo" { FL; return yD_STROBEO; } "$swrite" { FL; return yD_SWRITE; } "$swriteb" { FL; return yD_SWRITEB; } "$swriteh" { FL; return yD_SWRITEH; } @@ -268,9 +286,9 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "$write" { FL; return yD_WRITE; } "$writeb" { FL; return yD_WRITEB; } "$writeh" { FL; return yD_WRITEH; } - "$writeo" { FL; return yD_WRITEO; } "$writememb" { FL; return yD_WRITEMEMB; } "$writememh" { FL; return yD_WRITEMEMH; } + "$writeo" { FL; return yD_WRITEO; } /* Keywords */ "always" { FL; return yALWAYS; } "and" { FL; return yAND; } diff --git a/src/verilog.y b/src/verilog.y index b56ea343f..fdace335b 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -740,11 +740,19 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yD_FGETS "$fgets" %token yD_FINISH "$finish" %token yD_FLOOR "$floor" +%token yD_FMONITOR "$fmonitor" +%token yD_FMONITORB "$fmonitorb" +%token yD_FMONITORH "$fmonitorh" +%token yD_FMONITORO "$fmonitoro" %token yD_FOPEN "$fopen" %token yD_FREAD "$fread" %token yD_FREWIND "$frewind" %token yD_FSCANF "$fscanf" %token yD_FSEEK "$fseek" +%token yD_FSTROBE "$fstrobe" +%token yD_FSTROBEB "$fstrobeb" +%token yD_FSTROBEH "$fstrobeh" +%token yD_FSTROBEO "$fstrobeo" %token yD_FTELL "$ftell" %token yD_FWRITE "$fwrite" %token yD_FWRITEB "$fwriteb" @@ -761,6 +769,12 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yD_LN "$ln" %token yD_LOG10 "$log10" %token yD_LOW "$low" +%token yD_MONITOR "$monitor" +%token yD_MONITORB "$monitorb" +%token yD_MONITORH "$monitorh" +%token yD_MONITORO "$monitoro" +%token yD_MONITOROFF "$monitoroff" +%token yD_MONITORON "$monitoron" %token yD_ONEHOT "$onehot" %token yD_ONEHOT0 "$onehot0" %token yD_PAST "$past" @@ -789,6 +803,10 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yD_STABLE "$stable" %token yD_STIME "$stime" %token yD_STOP "$stop" +%token yD_STROBE "$strobe" +%token yD_STROBEB "$strobeb" +%token yD_STROBEH "$strobeh" +%token yD_STROBEO "$strobeo" %token yD_SWRITE "$swrite" %token yD_SWRITEB "$swriteb" %token yD_SWRITEH "$swriteh" @@ -3580,6 +3598,14 @@ system_t_call: // IEEE: system_tf_call (as task) | yD_DISPLAYH '(' exprDispList ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, nullptr, $3, 'h'); } | yD_DISPLAYO parenE { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, nullptr, nullptr, 'o'); } | yD_DISPLAYO '(' exprDispList ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, nullptr, $3, 'o'); } + | yD_MONITOR '(' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_MONITOR, nullptr, $3); } + | yD_MONITORB '(' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_MONITOR, nullptr, $3, 'b'); } + | yD_MONITORH '(' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_MONITOR, nullptr, $3, 'h'); } + | yD_MONITORO '(' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_MONITOR, nullptr, $3, 'o'); } + | yD_STROBE '(' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_STROBE, nullptr, $3); } + | yD_STROBEB '(' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_STROBE, nullptr, $3, 'b'); } + | yD_STROBEH '(' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_STROBE, nullptr, $3, 'h'); } + | yD_STROBEO '(' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_STROBE, nullptr, $3, 'o'); } | yD_WRITE parenE { $$ = nullptr; } // NOP | yD_WRITE '(' exprDispList ')' { $$ = new AstDisplay($1,AstDisplayType::DT_WRITE, nullptr, $3); } | yD_WRITEB parenE { $$ = nullptr; } // NOP @@ -3596,6 +3622,14 @@ system_t_call: // IEEE: system_tf_call (as task) | yD_FDISPLAYH '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, $3, $5, 'h'); } | yD_FDISPLAYO '(' expr ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, $3, nullptr, 'o'); } | yD_FDISPLAYO '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, $3, $5, 'o'); } + | yD_FMONITOR '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_MONITOR, $3, $5); } + | yD_FMONITORB '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_MONITOR, $3, $5, 'b'); } + | yD_FMONITORH '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_MONITOR, $3, $5, 'h'); } + | yD_FMONITORO '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_MONITOR, $3, $5, 'o'); } + | yD_FSTROBE '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_STROBE, $3, $5); } + | yD_FSTROBEB '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_STROBE, $3, $5, 'b'); } + | yD_FSTROBEH '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_STROBE, $3, $5, 'h'); } + | yD_FSTROBEO '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_STROBE, $3, $5, 'o'); } | yD_FWRITE '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_WRITE, $3, $5); } | yD_FWRITEB '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_WRITE, $3, $5, 'b'); } | yD_FWRITEH '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_WRITE, $3, $5, 'h'); } @@ -3610,6 +3644,9 @@ system_t_call: // IEEE: system_tf_call (as task) | yD_FATAL '(' expr ')' { $$ = new AstDisplay($1,AstDisplayType::DT_FATAL, nullptr, nullptr); $$->addNext(new AstStop($1, false)); DEL($3); } | yD_FATAL '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1,AstDisplayType::DT_FATAL, nullptr, $5); $$->addNext(new AstStop($1, false)); DEL($3); } // + | 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); } diff --git a/test_regress/t/t_sys_fmonitor.out b/test_regress/t/t_sys_fmonitor.out new file mode 100644 index 000000000..4d75640c2 --- /dev/null +++ b/test_regress/t/t_sys_fmonitor.out @@ -0,0 +1,15 @@ +[110] cyc=11 also +[120] cyc=12 also +[130] cyc=13 also +[140] cyc=14 also +[150] cyc=15 also +[160] cyc=16 also +[170] cyc=17 also +00000000000000000000000000010010b +00000013h +00000000024o +00000000025o +00000000026o +[230] cyc=23 new-monitor +[240] cyc=24 new-monitor +[270] cyc=27 new-monitor diff --git a/test_regress/t/t_sys_fmonitor.pl b/test_regress/t/t_sys_fmonitor.pl new file mode 100755 index 000000000..6bbedacab --- /dev/null +++ b/test_regress/t/t_sys_fmonitor.pl @@ -0,0 +1,24 @@ +#!/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, + ); + +files_identical("$Self->{obj_dir}/open.log", $Self->{golden_filename}); + +ok(1); + +1; diff --git a/test_regress/t/t_sys_fmonitor.v b/test_regress/t/t_sys_fmonitor.v new file mode 100644 index 000000000..dd7f1329f --- /dev/null +++ b/test_regress/t/t_sys_fmonitor.v @@ -0,0 +1,57 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`define STRINGIFY(x) `"x`" + +module t(/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + + int cyc = 0; + int fd; + + // Test loop + always @ (posedge clk) begin + cyc <= cyc + 1; + if (cyc == 5) begin + fd = $fopen({`STRINGIFY(`TEST_OBJ_DIR),"/open.log"}, "w"); + end + else if (cyc == 10) begin + $fmonitor(fd, "[%0t] cyc=%0d", $time, cyc); + $fmonitor(fd, "[%0t] cyc=%0d also", $time, cyc); + end + else if (cyc == 17) begin + $fmonitorb(fd, cyc, "b"); + end + else if (cyc == 18) begin + $fmonitorh(fd, cyc, "h"); + end + else if (cyc == 19) begin + $fmonitoro(fd, cyc, "o"); + end + else if (cyc == 22) begin + $fmonitor(fd, "[%0t] cyc=%0d new-monitor", $time, cyc); + end + else if (cyc == 24) begin + // IEEE suggests $monitoroff doesn't affect $fmonitor, but + // other simulators believe it does + $monitoroff; + end + else if (cyc == 26) begin + $monitoron; + end + else if (cyc == 27) begin + $fclose(fd); + end + else if (cyc == 30) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule diff --git a/test_regress/t/t_sys_fstrobe.out b/test_regress/t/t_sys_fstrobe.out new file mode 100644 index 000000000..7f9c034de --- /dev/null +++ b/test_regress/t/t_sys_fstrobe.out @@ -0,0 +1,6 @@ +[110] cyc=11 +[110] cyc=11 also +00000000000000000000000000010010b +00000013h +00000000024o +[230] cyc=23 new-strobe diff --git a/test_regress/t/t_sys_fstrobe.pl b/test_regress/t/t_sys_fstrobe.pl new file mode 100755 index 000000000..6bbedacab --- /dev/null +++ b/test_regress/t/t_sys_fstrobe.pl @@ -0,0 +1,24 @@ +#!/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, + ); + +files_identical("$Self->{obj_dir}/open.log", $Self->{golden_filename}); + +ok(1); + +1; diff --git a/test_regress/t/t_sys_fstrobe.v b/test_regress/t/t_sys_fstrobe.v new file mode 100644 index 000000000..de5c664b1 --- /dev/null +++ b/test_regress/t/t_sys_fstrobe.v @@ -0,0 +1,55 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`define STRINGIFY(x) `"x`" + +module t(/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + + int cyc = 0; + int fd; + + // Test loop + always @ (posedge clk) begin + cyc <= cyc + 1; + if (cyc == 5) begin + fd = $fopen({`STRINGIFY(`TEST_OBJ_DIR),"/open.log"}, "w"); + end + else if (cyc == 10) begin + $fstrobe(fd, "[%0t] cyc=%0d", $time, cyc); + $fstrobe(fd, "[%0t] cyc=%0d also", $time, cyc); + end + else if (cyc == 17) begin + $fstrobeb(fd, cyc, "b"); + end + else if (cyc == 18) begin + $fstrobeh(fd, cyc, "h"); + end + else if (cyc == 19) begin + $fstrobeo(fd, cyc, "o"); + end + else if (cyc == 22) begin + $fstrobe(fd, "[%0t] cyc=%0d new-strobe", $time, cyc); + end + else if (cyc == 24) begin + $monitoroff; + end + else if (cyc == 26) begin + $monitoron; + end + else if (cyc == 27) begin + $fclose(fd); + end + else if (cyc == 30) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule diff --git a/test_regress/t/t_sys_monitor.out b/test_regress/t/t_sys_monitor.out new file mode 100644 index 000000000..50f6f4d16 --- /dev/null +++ b/test_regress/t/t_sys_monitor.out @@ -0,0 +1,20 @@ +[110] cyc=11 +[120] cyc=12 +[130] cyc=13 +[140] cyc=14 +[150] cyc=15 +[160] cyc=16 +[170] cyc=17 +00000000000000000000000000010010b +00000013h +00000000024o +00000000025o +00000000026o +[230] cyc=23 new-monitor +[240] cyc=24 new-monitor +[270] cyc=27 new-monitor +[280] cyc=28 new-monitor +[290] cyc=29 new-monitor +[300] cyc=30 new-monitor +*-* All Finished *-* +[310] cyc=31 new-monitor diff --git a/test_regress/t/t_sys_monitor.pl b/test_regress/t/t_sys_monitor.pl new file mode 100755 index 000000000..88b7809fc --- /dev/null +++ b/test_regress/t/t_sys_monitor.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 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, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); + +1; diff --git a/test_regress/t/t_sys_monitor.v b/test_regress/t/t_sys_monitor.v new file mode 100644 index 000000000..21df4071f --- /dev/null +++ b/test_regress/t/t_sys_monitor.v @@ -0,0 +1,45 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + + int cyc = 0; + + // Test loop + always @ (posedge clk) begin + cyc <= cyc + 1; + if (cyc == 10) begin + $monitor("[%0t] cyc=%0d", $time, cyc); + end + else if (cyc == 17) begin + $monitorb(cyc, "b"); + end + else if (cyc == 18) begin + $monitorh(cyc, "h"); + end + else if (cyc == 19) begin + $monitoro(cyc, "o"); + end + else if (cyc == 22) begin + $monitor("[%0t] cyc=%0d new-monitor", $time, cyc); + end + else if (cyc == 24) begin + $monitoroff; + end + else if (cyc == 26) begin + $monitoron; + end + else if (cyc == 30) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule diff --git a/test_regress/t/t_sys_strobe.out b/test_regress/t/t_sys_strobe.out new file mode 100644 index 000000000..c38db0c3f --- /dev/null +++ b/test_regress/t/t_sys_strobe.out @@ -0,0 +1,7 @@ +[110] cyc=11 +[110] cyc=11 also +00000000000000000000000000010010b +00000013h +00000000024o +[230] cyc=23 new-strobe +*-* All Finished *-* diff --git a/test_regress/t/t_sys_strobe.pl b/test_regress/t/t_sys_strobe.pl new file mode 100755 index 000000000..88b7809fc --- /dev/null +++ b/test_regress/t/t_sys_strobe.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 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, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); + +1; diff --git a/test_regress/t/t_sys_strobe.v b/test_regress/t/t_sys_strobe.v new file mode 100644 index 000000000..4365344d5 --- /dev/null +++ b/test_regress/t/t_sys_strobe.v @@ -0,0 +1,46 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + + int cyc = 0; + + // Test loop + always @ (posedge clk) begin + cyc <= cyc + 1; + if (cyc == 10) begin + $strobe("[%0t] cyc=%0d", $time, cyc); + $strobe("[%0t] cyc=%0d also", $time, cyc); + end + else if (cyc == 17) begin + $strobeb(cyc, "b"); + end + else if (cyc == 18) begin + $strobeh(cyc, "h"); + end + else if (cyc == 19) begin + $strobeo(cyc, "o"); + end + else if (cyc == 22) begin + $strobe("[%0t] cyc=%0d new-strobe", $time, cyc); + end + else if (cyc == 24) begin + $monitoroff; + end + else if (cyc == 26) begin + $monitoron; + end + else if (cyc == 30) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule