From 8bd1c63b32e6cc2ea33bbdb419b45462b96bc19c Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 16 Sep 2023 17:37:25 -0400 Subject: [PATCH] Support function non-constant default arguments (#4470). --- Changes | 1 + src/V3AstNodeOther.h | 29 ++++- src/V3Task.cpp | 166 +++++++++++++++++++++++---- src/V3Task.h | 23 +++- src/V3Width.cpp | 6 +- src/V3WidthCommit.h | 9 ++ test_regress/t/t_func_arg_complex.pl | 23 ++++ test_regress/t/t_func_arg_complex.v | 106 +++++++++++++++++ test_regress/t/t_uvm_pkg_todo.vh | 31 ++--- 9 files changed, 345 insertions(+), 49 deletions(-) create mode 100755 test_regress/t/t_func_arg_complex.pl create mode 100644 test_regress/t/t_func_arg_complex.v diff --git a/Changes b/Changes index 5b2c2f8ea..6d82938f2 100644 --- a/Changes +++ b/Changes @@ -21,6 +21,7 @@ Verilator 5.015 devel * Support no-parentheses calls to static methods (#4432). [Krzysztof Boroński] * Support block_item_declaration in forks (#4455). [Krzysztof Boroński] * Support assignments of stream expressions on queues to packed values (#4458). [Ryszard Rozak, Antmicro Ltd] +* Support function non-constant default arguments (#4470). * Support 'let'. * Optimize Verilator executable size by refactoring error reporting routines (#4446). [Anthony Donlon] * Optimize Verilation runtime pointers and graphs (#4396) (#4397) (#4398). [Krzysztof Bieganski, Antmicro Ltd] diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index bcf4bbe14..0d9da1d1e 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -119,6 +119,7 @@ protected: public: ASTGEN_MEMBERS_AstNodeFTask; + virtual AstNodeFTask* cloneType(const string& name) = 0; void dump(std::ostream& str = std::cout) const override; string name() const override VL_MT_STABLE { return m_name; } // * = Var name bool maybePointedTo() const override { return true; } @@ -179,6 +180,15 @@ public: void lifetime(const VLifetime& flag) { m_lifetime = flag; } VLifetime lifetime() const { return m_lifetime; } bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); } + void propagateAttrFrom(const AstNodeFTask* fromp) { + // Creating a wrapper with e.g. cloneType(); preserve some attributes + classMethod(fromp->classMethod()); + isHideLocal(fromp->isHideLocal()); + isHideProtected(fromp->isHideProtected()); + isVirtual(fromp->isVirtual()); + lifetime(fromp->lifetime()); + underGenerate(fromp->underGenerate()); + } }; class AstNodeFile VL_NOT_FINAL : public AstNode { // Emitted Output file @@ -1964,18 +1974,25 @@ public: string verilogKwd() const override; void lifetime(const VLifetime& flag) { m_lifetime = flag; } VLifetime lifetime() const { return m_lifetime; } - void propagateAttrFrom(AstVar* fromp) { + void propagateAttrFrom(const AstVar* fromp) { // This is getting connected to fromp; keep attributes // Note the method below too if (fromp->attrFileDescr()) attrFileDescr(true); if (fromp->attrIsolateAssign()) attrIsolateAssign(true); if (fromp->isContinuously()) isContinuously(true); } + void propagateWrapAttrFrom(const AstVar* fromp) { + // Creating a function wrapper; keep attributes + propagateAttrFrom(fromp); + direction(fromp->direction()); + declDirection(fromp->declDirection()); + lifetime(fromp->lifetime()); + } bool gateMultiInputOptimizable() const { // Ok to gate optimize; must return false if propagateAttrFrom would do anything return !isUsedClock(); } - void combineType(AstVar* typevarp) { + void combineType(const AstVar* typevarp) { // This is same as typevarp (for combining input & reg decls) // "this" is the input var. typevarp is the reg var. propagateAttrFrom(typevarp); @@ -2094,6 +2111,9 @@ public: } ASTGEN_MEMBERS_AstFunc; bool hasDType() const override { return true; } + AstNodeFTask* cloneType(const string& name) { + return new AstFunc{fileline(), name, nullptr, nullptr}; + } }; class AstLet final : public AstNodeFTask { // Verilog "let" statement @@ -2108,6 +2128,7 @@ public: BROKEN_RTN(!VN_IS(stmtsp(), StmtExpr)); return nullptr; } + AstNodeFTask* cloneType(const string& name) { return new AstLet{fileline(), name}; } }; class AstProperty final : public AstNodeFTask { // A property inside a module @@ -2116,6 +2137,9 @@ public: : ASTGEN_SUPER_Property(fl, name, stmtp) {} ASTGEN_MEMBERS_AstProperty; bool hasDType() const override { return true; } + AstNodeFTask* cloneType(const string& name) { + return new AstProperty{fileline(), name, nullptr}; + } }; class AstTask final : public AstNodeFTask { // A task inside a module @@ -2123,6 +2147,7 @@ public: AstTask(FileLine* fl, const string& name, AstNode* stmtp) : ASTGEN_SUPER_Task(fl, name, stmtp) {} ASTGEN_MEMBERS_AstTask; + AstNodeFTask* cloneType(const string& name) { return new AstTask{fileline(), name, nullptr}; } }; // === AstNodeFile === diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 53137c807..6dff27044 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -1379,13 +1379,15 @@ private: nodep->replaceWith(cnewp); VL_DO_DANGLING(nodep->deleteTree(), nodep); } else if (VN_IS(nodep->backp(), NodeAssign)) { - UASSERT_OBJ(nodep->taskp()->isFunction(), nodep, "func reference to non-function"); + UASSERT_OBJ(nodep->taskp()->isFunction(), nodep, + "funcref-like assign to non-function"); insertBeforeStmt(nodep, beginp); AstVarRef* const outrefp = new AstVarRef{nodep->fileline(), outvscp, VAccess::READ}; nodep->replaceWith(outrefp); VL_DO_DANGLING(nodep->deleteTree(), nodep); } else if (!VN_IS(nodep->backp(), StmtExpr)) { - UASSERT_OBJ(nodep->taskp()->isFunction(), nodep, "func reference to non-function"); + UASSERT_OBJ(nodep->taskp()->isFunction(), nodep, + "funcref-like expression to non-function"); AstVarRef* const outrefp = new AstVarRef{nodep->fileline(), outvscp, VAccess::READ}; beginp = new AstExprStmt{nodep->fileline(), beginp, outrefp}; nodep->replaceWith(beginp); @@ -1493,13 +1495,6 @@ private: iterateChildren(nodep); m_insStmtp = nullptr; // Next thing should be new statement } - void visit(AstVar* nodep) override { - if (nodep->isFuncLocal() && nodep->direction() == VDirection::INPUT && nodep->valuep()) { - // It's the default value of optional argument. - // Such values are added to function calls on this stage and aren't needed here. - pushDeletep(nodep->valuep()->unlinkFrBack()); - } - } void visit(AstStmtExpr* nodep) override { m_insStmtp = nodep; iterateChildren(nodep); @@ -1529,13 +1524,15 @@ public: const char* const V3Task::s_dpiTemporaryVarSuffix = "__Vcvt"; -V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp) { +V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp, + V3TaskConnectState* statep) { // Output list will be in order of the port declaration variables (so // func calls are made right in C) // Missing pin/expr? We return (pinvar, nullptr) // Extra pin/expr? We clean it up - + UINFO(9, "taskConnects " << nodep << endl); std::map nameToIndex; + std::set argWrap; // Which ports are defaulted, forcing arg wrapper creation V3TaskConnects tconnects; UASSERT_OBJ(nodep->taskp(), nodep, "unlinked"); @@ -1624,16 +1621,24 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp) // The default value for this port might be a constant // expression that hasn't been folded yet. Try folding it // now; we don't have much to lose if it fails. - newvaluep = V3Const::constifyParamsEdit(VN_AS(portp->valuep(), NodeExpr)); + newvaluep = V3Const::constifyEdit(VN_AS(portp->valuep(), NodeExpr)); if (!VN_IS(newvaluep, Const)) { - // Problem otherwise is we might have a varref, task - // call, or something else that only makes sense in the - // domain of the function, not the callee. - nodep->v3warn(E_UNSUPPORTED, - "Unsupported: Non-constant default value in missing argument " - << portp->prettyNameQ() << " in function call to " - << nodep->taskp()->prettyTypeName()); - newvaluep = new AstConst{nodep->fileline(), AstConst::Unsized32{}, 0}; + if (statep) { + portp->pinNum(i + 1); // Make sure correct, will use to build name + UINFO(9, "taskConnects arg wrapper needed " << portp->valuep() << endl); + argWrap.emplace(portp); + } else { // statep = nullptr, called too late or otherwise to handle args + // Problem otherwise is we might have a varref, task + // call, or something else that only makes sense in the + // domain of the function (or class containing the method), + // versus that of the callee. + nodep->v3warn( + E_UNSUPPORTED, + "Unsupported: Non-constant default value in missing argument " + << portp->prettyNameQ() << " in function call to " + << nodep->taskp()->prettyTypeName()); + newvaluep = new AstConst{nodep->fileline(), AstConst::Unsized32{}, 0}; + } } } newvaluep = newvaluep->cloneTree(true); @@ -1671,12 +1676,131 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp) if (debug() >= 9) { // LCOV_EXCL_START nodep->dumpTree("- ftref-out: "); for (int i = 0; i < tpinnum; ++i) { - UINFO(0, " pin " << i << " conn=" << cvtToHex(tconnects[i].second) << endl); + UINFO(0, " pin " << i << " pin=" << cvtToHex(tconnects[i].first) + << " conn=" << cvtToHex(tconnects[i].second) << endl); } } // LCOV_EXCL_STOP + + if (!argWrap.empty()) { + UINFO(9, "Arg wrapper generation " << nodep << endl); + // Create wrapper function with default argument settings. + // Needed because the default needs symbol table of the called function. + taskConnectWrap(nodep, tconnects, statep, argWrap); + // Regenerate all connections, this time connecting to the wrapper + return taskConnects(nodep, nodep->taskp()->stmtsp(), + // statep null, so can't recurse forever + nullptr); + } return tconnects; } +void V3Task::taskConnectWrap(AstNodeFTaskRef* nodep, const V3TaskConnects& tconnects, + V3TaskConnectState* statep, const std::set& argWrap) { + statep->setDidWrap(); + // Make wrapper name such that is same iff same args are defaulted + std::string newname = nodep->name() + "__Vtcwrap"; + for (const AstVar* varp : argWrap) newname += "_" + cvtToStr(varp->pinNum()); + const auto namekey = std::make_pair(nodep->taskp(), newname); + auto& wrapMapr = statep->wrapMap(); + const auto it = wrapMapr.find(namekey); + AstNodeFTask* newTaskp; + if (it != wrapMapr.end()) { + newTaskp = it->second; + } else { + newTaskp = taskConnectWrapNew(nodep->taskp(), newname, tconnects, argWrap); + wrapMapr.emplace(namekey, newTaskp); + } + + // Remove the defaulted arguments from original outside call + for (const auto& tconnect : tconnects) { + const AstVar* const portp = tconnect.first; + AstArg* const argp = tconnect.second; + if (argWrap.find(portp) != argWrap.end()) { // Removed arg + statep->pushDeletep(argp->unlinkFrBack()); + } + } + // Change outside call to connect to new function + nodep->taskp(newTaskp); + nodep->name(newTaskp->name()); + // if (debug() >= 9) nodep->dumpTree("-taskConnectWrap-call "); +} + +AstNodeFTask* V3Task::taskConnectWrapNew(AstNodeFTask* taskp, const string& newname, + const V3TaskConnects& tconnects, + const std::set& argWrap) { + std::map oldNewVars; // Old -> new var mappings + + AstNodeFTask* const newTaskp = taskp->cloneType(newname); + newTaskp->propagateAttrFrom(taskp); + taskp->addNextHere(newTaskp); + + AstNodeFTaskRef* newCallp = nullptr; + AstNode* newCallInsertp = nullptr; + if (VN_IS(taskp, Func)) { + AstVar* const fvarp = VN_AS(taskp->fvarp(), Var); + UASSERT(fvarp, "FuncRef without fvar"); + AstVar* const newFVarp = fvarp->cloneTree(true); + oldNewVars.emplace(fvarp, newFVarp); + newFVarp->name(newTaskp->name()); + newTaskp->fvarp(newFVarp); + newTaskp->dtypeFrom(newFVarp); + newCallp = new AstFuncRef{taskp->fileline(), taskp->name(), nullptr}; + newCallp->taskp(taskp); + newCallp->dtypeFrom(newFVarp); + newCallInsertp + = new AstAssign{taskp->fileline(), + new AstVarRef{fvarp->fileline(), newFVarp, VAccess::WRITE}, newCallp}; + newCallInsertp->dtypeFrom(newFVarp); + } else if (VN_IS(taskp, Task)) { + newCallp = new AstTaskRef{taskp->fileline(), taskp->name(), nullptr}; + newCallp->taskp(taskp); + newCallInsertp = new AstStmtExpr{taskp->fileline(), newCallp}; + } else { + taskp->v3fatalSrc("Unsupported: Non-constant default value in missing argument in a " + << taskp->prettyTypeName()); + } + + // Create wrapper's ports matching original's + for (const auto& tconnect : tconnects) { + AstVar* const portp = tconnect.first; + AstVar* newPortp; + if (argWrap.find(portp) == argWrap.end()) { // Not removed arg + newPortp = new AstVar{portp->fileline(), portp->varType(), portp->name(), portp}; + newPortp->propagateWrapAttrFrom(portp); + newPortp->funcLocal(true); + if (newPortp->valuep()) newPortp->valuep()->unlinkFrBack()->deleteTree(); + newTaskp->addStmtsp(newPortp); + } else { // Defaulting arg + AstNodeExpr* const valuep = VN_AS(portp->valuep(), NodeExpr); + // Create local temporary + newPortp = new AstVar{portp->fileline(), VVarType::BLOCKTEMP, portp->name(), + portp->dtypep()}; + newPortp->propagateAttrFrom(portp); + newPortp->funcLocal(true); + newTaskp->addStmtsp(newPortp); + // Runtime-assign it to the default + AstAssign* const newAssignp = new AstAssign{ + valuep->fileline(), new AstVarRef{valuep->fileline(), newPortp, VAccess::WRITE}, + valuep->cloneTree(true)}; + newTaskp->addStmtsp(newAssignp); + } + oldNewVars.emplace(portp, newPortp); + AstArg* const newArgp + = new AstArg{portp->fileline(), portp->name(), + new AstVarRef{portp->fileline(), newPortp, VAccess::READ}}; + newCallp->addPinsp(newArgp); + } + // Create wrapper call to original, passing arguments, adding setting of return value + newTaskp->addStmtsp(newCallInsertp); + // Replace any varref's to original to new ports (e.g. in argument equations) + newTaskp->foreach([=](AstVarRef* refp) { + const auto it = oldNewVars.find(refp->varp()); + if (it != oldNewVars.end()) refp->varp(it->second); + }); + // if (debug() >= 9) newTaskp->dumpTree("-taskConnectWrap-new "); + return newTaskp; +} + string V3Task::assignInternalToDpi(AstVar* portp, bool isPtr, const string& frSuffix, const string& toSuffix, const string& frPrefix) { // Create assignment from internal format into DPI temporary diff --git a/src/V3Task.h b/src/V3Task.h index 1d7397da6..8dea5bee7 100644 --- a/src/V3Task.h +++ b/src/V3Task.h @@ -31,6 +31,20 @@ using V3TaskConnect = std::pair; // [port, pin-connects-to] using V3TaskConnects = std::vector; // [ [port, pin-connects-to] ... ] +class V3TaskConnectState final { + VNDeleter m_deleter; // Allow delayed deletion of nodes + bool m_didWrap = false; // Made a wrapper + using WrapMap = std::map, AstNodeFTask*>; + WrapMap m_wrapMap; // Map of {old function, arguments} -> new function +public: + V3TaskConnectState() {} + ~V3TaskConnectState() = default; + void pushDeletep(AstNode* nodep) { m_deleter.pushDeletep(nodep); } + bool didWrap() const { return m_didWrap; } + void setDidWrap() { m_didWrap = true; } + WrapMap& wrapMap() { return m_wrapMap; } +}; + //============================================================================ class V3Task final { @@ -39,7 +53,14 @@ class V3Task final { public: static void taskAll(AstNetlist* nodep); /// Return vector of [port, pin-connects-to] (SLOW) - static V3TaskConnects taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp); + static V3TaskConnects taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp, + V3TaskConnectState* statep = nullptr); + static void taskConnectWrap(AstNodeFTaskRef* nodep, const V3TaskConnects& tconnects, + V3TaskConnectState* statep, + const std::set& argWrap); + static AstNodeFTask* taskConnectWrapNew(AstNodeFTask* taskp, const string& newname, + const V3TaskConnects& tconnects, + const std::set& argWrap); static string assignInternalToDpi(AstVar* portp, bool isPtr, const string& frSuffix, const string& toSuffix, const string& frPrefix = ""); static string assignDpiToInternal(const string& lhsName, AstVar* rhsp); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index eb3e38dfe..e1c0edff1 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -224,6 +224,7 @@ private: // STATE VMemberMap m_memberMap; // Member names cached for fast lookup + V3TaskConnectState m_taskConnectState; // State to cache V3Task::taskConnects WidthVP* m_vup = nullptr; // Current node state const AstCell* m_cellp = nullptr; // Current cell for arrayed instantiations const AstEnumItem* m_enumItemp = nullptr; // Current enum item @@ -5483,7 +5484,10 @@ private: // And do the arguments to the task/function too do { reloop: - const V3TaskConnects tconnects = V3Task::taskConnects(nodep, nodep->taskp()->stmtsp()); + // taskConnects may create a new task, and change nodep->taskp() + const V3TaskConnects tconnects + = V3Task::taskConnects(nodep, nodep->taskp()->stmtsp(), &m_taskConnectState); + if (m_taskConnectState.didWrap()) m_memberMap.clear(); // As added a member for (const auto& tconnect : tconnects) { const AstVar* const portp = tconnect.first; AstArg* const argp = tconnect.second; diff --git a/src/V3WidthCommit.h b/src/V3WidthCommit.h index 135b559a6..959bde51b 100644 --- a/src/V3WidthCommit.h +++ b/src/V3WidthCommit.h @@ -237,6 +237,15 @@ private: classEncapCheck(nodep, nodep->varp(), classrefp->classp()); } // else might be struct, etc } + void visit(AstVar* nodep) override { + iterateChildren(nodep); + editDType(nodep); + if (nodep->isFuncLocal() && nodep->direction() == VDirection::INPUT && nodep->valuep()) { + // It's the default value of optional argument. + // Such values are added to function calls in V3Width so can be removed now + pushDeletep(nodep->valuep()->unlinkFrBack()); + } + } void visit(AstNodePreSel* nodep) override { // LCOV_EXCL_LINE // This check could go anywhere after V3Param nodep->v3fatalSrc("Presels should have been removed before this point"); diff --git a/test_regress/t/t_func_arg_complex.pl b/test_regress/t/t_func_arg_complex.pl new file mode 100755 index 000000000..02e61ae8f --- /dev/null +++ b/test_regress/t/t_func_arg_complex.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 2023 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( + v_flags2 => ["-Wno-PKGNODECL -Wno-UNPACKED -Wno-RANDC -Wno-IMPLICITSTATIC -Wno-CONSTRAINTIGN -Wno-MISINDENT", + "--error-limit 200"], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_func_arg_complex.v b/test_regress/t/t_func_arg_complex.v new file mode 100644 index 000000000..728e8b426 --- /dev/null +++ b/test_regress/t/t_func_arg_complex.v @@ -0,0 +1,106 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 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); + +class Cls; + enum { ONEK = 1000, TWOK = 2000 } sev_t; + int m_default_data; + function int trigger(int data=get_default_data()); + return data; + endfunction + + task triggert(output int o, input int data=get_default_data()); + o = data; + endtask + + virtual function int get_default_data(); + return m_default_data; + endfunction + + function int uvm_report(int severity, + int verbosity = (severity == 1) ? ONEK : TWOK); + return verbosity; + endfunction + +endclass + +module t(/*AUTOARG*/); + + function int mod_trigger(int data=mod_data()); + return data; + endfunction + + task mod_triggert(output int o, input int data=mod_data()); + o = data; + endtask + + int mod_default_data; + function int mod_data(); + return mod_default_data; + endfunction + + int v; + + initial begin + begin + mod_triggert(v, 1234); + `checkd(v, 1234); + + mod_default_data = 42; + v = mod_trigger(); + `checkd(v, 42); + v = mod_trigger(11); + `checkd(v, 11); + mod_default_data = 43; + v = mod_trigger(); + `checkd(v, 43); + v = mod_trigger(); // Multiple to test look up of duplicates + `checkd(v, 43); + + mod_default_data = 52; + mod_triggert(v); + `checkd(v, 52); + mod_triggert(v); // Multiple to test look up of duplicates + `checkd(v, 52); + end + begin + Cls c = new; + + c.m_default_data = 42; + v = c.trigger(); + `checkd(v, 42); + v = c.trigger(11); + `checkd(v, 11); + c.m_default_data = 43; + v = c.trigger(); + `checkd(v, 43); + v = c.trigger(); // Multiple to test look up of duplicates + `checkd(v, 43); + v = c.trigger(); // Multiple to test look up of duplicates + `checkd(v, 43); + + c.m_default_data = 52; + c.triggert(v); + `checkd(v, 52); + c.triggert(v); // Multiple to test look up of duplicates + `checkd(v, 52); + + v = c.uvm_report(1); + `checkd(v, 1000); + v = c.uvm_report(2); + `checkd(v, 2000); + v = c.uvm_report(1, 111); + `checkd(v, 111); + v = c.uvm_report(1, 222); + `checkd(v, 222); + end + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_uvm_pkg_todo.vh b/test_regress/t/t_uvm_pkg_todo.vh index 7f7c8b075..dceffefad 100644 --- a/test_regress/t/t_uvm_pkg_todo.vh +++ b/test_regress/t/t_uvm_pkg_todo.vh @@ -687,12 +687,8 @@ endfunction function void uvm_report( uvm_severity severity, string id, string message, -//TODO issue #4470 - Fix UVM function non-constant default arguments -//TODO %Error: Internal Error: t/t_uvm_pkg_todo.vh:9957:54: ../V3Broken.cpp:262: VarRef missing VarScope pointer -//TODO int verbosity = (severity == uvm_severity'(UVM_ERROR)) ? UVM_LOW : -//TODO (severity == uvm_severity'(UVM_FATAL)) ? UVM_NONE : UVM_MEDIUM, -//TODO remove next line: - int verbosity = UVM_LOW, + int verbosity = (severity == uvm_severity'(UVM_ERROR)) ? UVM_LOW : + (severity == uvm_severity'(UVM_FATAL)) ? UVM_NONE : UVM_MEDIUM, string filename = "", int line = 0, string context_name = "", @@ -7554,11 +7550,7 @@ class uvm_event#(type T=uvm_object) extends uvm_event_base; wait_ptrigger(); data = get_trigger_data(); endtask -//TODO issue #4470 - Fix UVM function non-constant default arguments -//TODO %Error: t/t_uvm_pkg_todo.vh:7549:47: Expecting expression to be constant, but can't determine constant for FUNCREF 'get_default_data' -//TODO virtual function void trigger (T data=get_default_data()); -//TODO remove next line: - virtual function void trigger (T data=null); + virtual function void trigger (T data=get_default_data()); int skip; cb_type cb_q[$]; skip=0; @@ -9958,12 +9950,8 @@ class uvm_report_object extends uvm_object; virtual function void uvm_report( uvm_severity severity, string id, string message, -//TODO issue #4470 - Fix UVM function non-constant default arguments -//TODO %Error: Internal Error: t/t_uvm_pkg_todo.vh:9957:54: ../V3Broken.cpp:262: VarRef missing VarScope pointer -//TODO int verbosity = (severity == uvm_severity'(UVM_ERROR)) ? UVM_LOW : -//TODO (severity == uvm_severity'(UVM_FATAL)) ? UVM_NONE : UVM_MEDIUM, -//TODO remove next line: - int verbosity = UVM_ERROR, + int verbosity = (severity == uvm_severity'(UVM_ERROR)) ? UVM_LOW : + (severity == uvm_severity'(UVM_FATAL)) ? UVM_NONE : UVM_MEDIUM, string filename = "", int line = 0, string context_name = "", @@ -18797,13 +18785,8 @@ class uvm_sequence_item extends uvm_transaction; virtual function void uvm_report( uvm_severity severity, string id, string message, - -//TODO issue #4470 - Fix UVM function non-constant default arguments -//TODO %Error: Internal Error: t/t_uvm_pkg_todo.vh:18800:54: ../V3Broken.cpp:262: VarRef missing VarScope pointer -//TODO int verbosity = (severity == uvm_severity'(UVM_ERROR)) ? UVM_LOW : -//TODO (severity == uvm_severity'(UVM_FATAL)) ? UVM_NONE : UVM_MEDIUM, -//TODO remove next line: - int verbosity = UVM_LOW, + int verbosity = (severity == uvm_severity'(UVM_ERROR)) ? UVM_LOW : + (severity == uvm_severity'(UVM_FATAL)) ? UVM_NONE : UVM_MEDIUM, string filename = "", int line = 0, string context_name = "",