From b1c1aa53a918557499cb7633b0ccb48e68d1d538 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 6 Aug 2023 10:53:16 -0400 Subject: [PATCH 001/111] devel release --- CMakeLists.txt | 2 +- Changes | 7 +++++++ configure.ac | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bc8ee7900..32c6c9698 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ cmake_minimum_required(VERSION 3.15) cmake_policy(SET CMP0091 NEW) # Use MSVC_RUNTIME_LIBRARY to select the runtime project(Verilator - VERSION 5.014 + VERSION 5.015 HOMEPAGE_URL https://verilator.org LANGUAGES CXX ) diff --git a/Changes b/Changes index 2cd2678df..a688968f4 100644 --- a/Changes +++ b/Changes @@ -8,6 +8,13 @@ The changes in each Verilator version are described below. The contributors that suggested a given feature are shown in []. Thanks! +Verilator 5.015 devel +========================== + +**Minor:** + + + Verilator 5.014 2023-08-06 ========================== diff --git a/configure.ac b/configure.ac index b20979c00..e0886a557 100644 --- a/configure.ac +++ b/configure.ac @@ -10,7 +10,7 @@ # Then 'make maintainer-dist' #AC_INIT([Verilator],[#.### YYYY-MM-DD]) #AC_INIT([Verilator],[#.### devel]) -AC_INIT([Verilator],[5.014 2023-08-06], +AC_INIT([Verilator],[5.015 devel], [https://verilator.org], [verilator],[https://verilator.org]) From b0942ed8c71c9b6854b5ae760c57e868af1d5215 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Mon, 7 Aug 2023 11:35:44 +0200 Subject: [PATCH 002/111] Fix detection of mixed blocking and nonblocking assignment in nested assignments (#4404) --- src/V3Delayed.cpp | 6 ++++ .../t_assign_on_rhs_of_nonblocking_unsup.out | 11 +++++++ .../t/t_assign_on_rhs_of_nonblocking_unsup.pl | 19 +++++++++++ .../t/t_assign_on_rhs_of_nonblocking_unsup.v | 33 +++++++++++++++++++ test_regress/t/t_enum_huge_methods.v | 6 ++++ 5 files changed, 75 insertions(+) create mode 100644 test_regress/t/t_assign_on_rhs_of_nonblocking_unsup.out create mode 100755 test_regress/t/t_assign_on_rhs_of_nonblocking_unsup.pl create mode 100644 test_regress/t/t_assign_on_rhs_of_nonblocking_unsup.v diff --git a/src/V3Delayed.cpp b/src/V3Delayed.cpp index 760026163..a744b31fa 100644 --- a/src/V3Delayed.cpp +++ b/src/V3Delayed.cpp @@ -623,6 +623,12 @@ private: m_inLoop = true; iterateChildren(nodep); } + void visit(AstNodeAssign* nodep) override { + VL_RESTORER(m_inDly); + // Restoring is needed in nested assignments, like a <= (x = y); + m_inDly = false; + iterateChildren(nodep); + } //-------------------- void visit(AstNode* nodep) override { iterateChildren(nodep); } diff --git a/test_regress/t/t_assign_on_rhs_of_nonblocking_unsup.out b/test_regress/t/t_assign_on_rhs_of_nonblocking_unsup.out new file mode 100644 index 000000000..d4fd4ace8 --- /dev/null +++ b/test_regress/t/t_assign_on_rhs_of_nonblocking_unsup.out @@ -0,0 +1,11 @@ +%Error-BLKANDNBLK: t/t_assign_on_rhs_of_nonblocking_unsup.v:15:8: Unsupported: Blocked and non-blocking assignments to same variable: 't.x' + 15 | int x; + | ^ + t/t_assign_on_rhs_of_nonblocking_unsup.v:24:18: ... Location of blocking assignment + 24 | y <= (x = 2); + | ^ + t/t_assign_on_rhs_of_nonblocking_unsup.v:21:10: ... Location of nonblocking assignment + 21 | x <= 1; + | ^ + ... For error description see https://verilator.org/warn/BLKANDNBLK?v=latest +%Error: Exiting due to diff --git a/test_regress/t/t_assign_on_rhs_of_nonblocking_unsup.pl b/test_regress/t/t_assign_on_rhs_of_nonblocking_unsup.pl new file mode 100755 index 000000000..35d749208 --- /dev/null +++ b/test_regress/t/t_assign_on_rhs_of_nonblocking_unsup.pl @@ -0,0 +1,19 @@ +#!/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-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. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_assign_on_rhs_of_nonblocking_unsup.v b/test_regress/t/t_assign_on_rhs_of_nonblocking_unsup.v new file mode 100644 index 000000000..ed6d0ee84 --- /dev/null +++ b/test_regress/t/t_assign_on_rhs_of_nonblocking_unsup.v @@ -0,0 +1,33 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + integer cyc = 0; + + int x; + int y; + + always @ (posedge clk) begin + cyc <= cyc + 1; + if (cyc == 0) begin + x <= 1; + end + else if (cyc == 1) begin + y <= (x = 2); + end else begin + if (x != 2) $stop; + if (y != 2) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule diff --git a/test_regress/t/t_enum_huge_methods.v b/test_regress/t/t_enum_huge_methods.v index 951c57d1b..3dba73251 100644 --- a/test_regress/t/t_enum_huge_methods.v +++ b/test_regress/t/t_enum_huge_methods.v @@ -48,15 +48,21 @@ module t (/*AUTOARG*/ end // else if (cyc == 10) begin + /* verilator lint_off BLKANDNBLK */ i_cast <= $cast(e, 60'h1234); + /* verilator lint_on BLKANDNBLK */ end else if (cyc == 11) begin `checkh(i_cast, 0); + /* verilator lint_off BLKANDNBLK */ i_cast <= $cast(e, 60'h1); + /* verilator lint_on BLKANDNBLK */ end else if (cyc == 12) begin `checkh(i_cast, 1); + /* verilator lint_off BLKANDNBLK */ i_cast <= $cast(e, 60'h1234_4567_abcd); + /* verilator lint_on BLKANDNBLK */ end else if (cyc == 13) begin `checkh(i_cast, 1); From 2d9bc7370920492193cc857c6fc5e997aef4fe93 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Mon, 7 Aug 2023 11:54:30 +0200 Subject: [PATCH 003/111] Fix dtype of condition operation on class objects (#4345) (#4352) --- src/V3AstNodeExpr.h | 10 +--- src/V3AstNodes.cpp | 15 ++++++ src/V3Width.cpp | 71 +++++++++++++++-------------- src/V3Width.h | 3 ++ test_regress/t/t_class_if_assign.pl | 21 +++++++++ test_regress/t/t_class_if_assign.v | 43 +++++++++++++++++ 6 files changed, 122 insertions(+), 41 deletions(-) create mode 100755 test_regress/t/t_class_if_assign.pl create mode 100644 test_regress/t/t_class_if_assign.v diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index c59775da1..9e198b39e 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -360,14 +360,8 @@ class AstNodeCond VL_NOT_FINAL : public AstNodeTriop { // @astgen alias op2 := thenp // @astgen alias op3 := elsep protected: - AstNodeCond(VNType t, FileLine* fl, AstNodeExpr* condp, AstNodeExpr* thenp, AstNodeExpr* elsep) - : AstNodeTriop{t, fl, condp, thenp, elsep} { - if (thenp) { - dtypeFrom(thenp); - } else if (elsep) { - dtypeFrom(elsep); - } - } + AstNodeCond(VNType t, FileLine* fl, AstNodeExpr* condp, AstNodeExpr* thenp, + AstNodeExpr* elsep); public: ASTGEN_MEMBERS_AstNodeCond; diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index ad31bc0f4..704932733 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -25,6 +25,7 @@ #include "V3Hasher.h" #include "V3PartitionGraph.h" // Just for mtask dumping #include "V3String.h" +#include "V3Width.h" #include "V3Ast__gen_macros.h" // Generated by 'astgen' @@ -134,6 +135,20 @@ string AstCCall::selfPointerProtect(bool useSelfForThis) const { return VIdProtect::protectWordsIf(sp, protect()); } +AstNodeCond::AstNodeCond(VNType t, FileLine* fl, AstNodeExpr* condp, AstNodeExpr* thenp, + AstNodeExpr* elsep) + : AstNodeTriop{t, fl, condp, thenp, elsep} { + UASSERT_OBJ(thenp, this, "No thenp expression"); + UASSERT_OBJ(elsep, this, "No elsep expression"); + if (thenp->isClassHandleValue() && elsep->isClassHandleValue()) { + // Get the most-deriving class type that both arguments can be casted to. + AstNodeDType* const commonClassTypep = V3Width::getCommonClassTypep(thenp, elsep); + UASSERT_OBJ(commonClassTypep, this, "No common base class exists"); + dtypep(commonClassTypep); + } else { + dtypeFrom(thenp); + } +} void AstNodeCond::numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, const V3Number& ths) { if (lhs.isNeqZero()) { diff --git a/src/V3Width.cpp b/src/V3Width.cpp index aa3ee6581..965c511d8 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -513,7 +513,8 @@ private: AstNodeDType* commonClassTypep = nullptr; if (nodep->thenp()->isClassHandleValue() && nodep->elsep()->isClassHandleValue()) { // Get the most-deriving class type that both arguments can be casted to. - commonClassTypep = getCommonClassTypep(nodep->thenp(), nodep->elsep()); + commonClassTypep + = V3Width::getCommonClassTypep(nodep->thenp(), nodep->elsep()); } if (commonClassTypep) { nodep->dtypep(commonClassTypep); @@ -7337,41 +7338,9 @@ private: if (nodep->subDTypep()) return hasOpenArrayIterateDType(nodep->subDTypep()->skipRefp()); return false; } - AstNodeDType* getCommonClassTypep(AstNode* nodep1, AstNode* nodep2) { - // Return the class type that both nodep1 and nodep2 are castable to. - // If both are null, return the type of null constant. - // If one is a class and one is null, return AstClassRefDType that points to that class. - // If no common class type exists, return nullptr. - - // First handle cases with null values and when one class is a super class of the other. - if (VN_IS(nodep1, Const)) std::swap(nodep1, nodep2); - const Castable castable = computeCastable(nodep1->dtypep(), nodep2->dtypep(), nodep2); - if (castable == SAMEISH || castable == COMPATIBLE) { - return nodep1->dtypep()->cloneTree(false); - } else if (castable == DYNAMIC_CLASS) { - return nodep2->dtypep()->cloneTree(false); - } - - AstClassRefDType* classDtypep1 = VN_CAST(nodep1->dtypep(), ClassRefDType); - while (classDtypep1) { - const Castable castable = computeCastable(classDtypep1, nodep2->dtypep(), nodep2); - if (castable == COMPATIBLE) return classDtypep1->cloneTree(false); - AstClassExtends* const extendsp = classDtypep1->classp()->extendsp(); - classDtypep1 = extendsp ? VN_AS(extendsp->dtypep(), ClassRefDType) : nullptr; - } - return nullptr; - } //---------------------------------------------------------------------- // METHODS - casting - static Castable computeCastable(const AstNodeDType* toDtp, const AstNodeDType* fromDtp, - const AstNode* fromConstp) { - const auto castable = computeCastableImp(toDtp, fromDtp, fromConstp); - UINFO(9, " castable=" << castable << " for " << toDtp << endl); - UINFO(9, " =?= " << fromDtp << endl); - UINFO(9, " const= " << fromConstp << endl); - return castable; - } static Castable computeCastableImp(const AstNodeDType* toDtp, const AstNodeDType* fromDtp, const AstNode* fromConstp) { const Castable castable = UNSUPPORTED; @@ -7536,6 +7505,15 @@ public: return userIterateSubtreeReturnEdits(nodep, WidthVP{SELF, BOTH}.p()); } ~WidthVisitor() override = default; + + static Castable computeCastable(const AstNodeDType* toDtp, const AstNodeDType* fromDtp, + const AstNode* fromConstp) { + const auto castable = computeCastableImp(toDtp, fromDtp, fromConstp); + UINFO(9, " castable=" << castable << " for " << toDtp << endl); + UINFO(9, " =?= " << fromDtp << endl); + UINFO(9, " const= " << fromConstp << endl); + return castable; + } }; //###################################################################### @@ -7554,6 +7532,33 @@ void V3Width::width(AstNetlist* nodep) { V3Global::dumpCheckGlobalTree("width", 0, dumpTreeLevel() >= 3); } +AstNodeDType* V3Width::getCommonClassTypep(AstNode* nodep1, AstNode* nodep2) { + // Return the class type that both nodep1 and nodep2 are castable to. + // If both are null, return the type of null constant. + // If one is a class and one is null, return AstClassRefDType that points to that class. + // If no common class type exists, return nullptr. + + // First handle cases with null values and when one class is a super class of the other. + if (VN_IS(nodep1, Const)) std::swap(nodep1, nodep2); + const Castable castable + = WidthVisitor::computeCastable(nodep1->dtypep(), nodep2->dtypep(), nodep2); + if (castable == SAMEISH || castable == COMPATIBLE) { + return nodep1->dtypep(); + } else if (castable == DYNAMIC_CLASS) { + return nodep2->dtypep(); + } + + AstClassRefDType* classDtypep1 = VN_CAST(nodep1->dtypep(), ClassRefDType); + while (classDtypep1) { + const Castable castable + = WidthVisitor::computeCastable(classDtypep1, nodep2->dtypep(), nodep2); + if (castable == COMPATIBLE) return classDtypep1; + AstClassExtends* const extendsp = classDtypep1->classp()->extendsp(); + classDtypep1 = extendsp ? VN_AS(extendsp->dtypep(), ClassRefDType) : nullptr; + } + return nullptr; +} + //! Single node parameter propagation //! Smaller step... Only do a single node for parameter propagation AstNode* V3Width::widthParamsEdit(AstNode* nodep) { diff --git a/src/V3Width.h b/src/V3Width.h index 857ca1dc1..497c0bd23 100644 --- a/src/V3Width.h +++ b/src/V3Width.h @@ -22,6 +22,7 @@ class AstNetlist; class AstNode; +class AstNodeDType; //============================================================================ @@ -33,6 +34,8 @@ public: // Final step... Mark all widths as equal static void widthCommit(AstNetlist* nodep); + static AstNodeDType* getCommonClassTypep(AstNode* nodep1, AstNode* nodep2); + // For use only in WidthVisitor // Replace AstSelBit, etc with AstSel/AstArraySel // Returns replacement node if nodep was deleted, or null if none. diff --git a/test_regress/t/t_class_if_assign.pl b/test_regress/t/t_class_if_assign.pl new file mode 100755 index 000000000..1aa73f80a --- /dev/null +++ b/test_regress/t/t_class_if_assign.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_if_assign.v b/test_regress/t/t_class_if_assign.v new file mode 100644 index 000000000..e92a9628b --- /dev/null +++ b/test_regress/t/t_class_if_assign.v @@ -0,0 +1,43 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +class Cls; + int x; + function new; + x = 1; + endfunction +endclass + +class ExtendCls extends Cls; + function new; + x = 2; + endfunction +endclass + +class AnotherExtendCls extends Cls; + function new; + x = 3; + endfunction +endclass + +module t (/*AUTOARG*/); + initial begin + Cls cls = new; + ExtendCls ext_cls = new; + AnotherExtendCls an_ext_cls = new; + + if (cls.x == 1) cls = ext_cls; + else cls = an_ext_cls; + if (cls.x != 2) $stop; + + if (cls.x == 1) cls = ext_cls; + else cls = an_ext_cls; + if (cls.x != 3) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule From 8d512c31870ff90d27a5e830ca9272502f3b248c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Boro=C5=84ski?= <94375110+kboronski-ant@users.noreply.github.com> Date: Fri, 11 Aug 2023 16:52:59 +0200 Subject: [PATCH 004/111] Fix variable lifetimes in extern methods (#4414) --- src/V3LinkParse.cpp | 12 +++++-- .../t/t_var_extern_method_lifetime.pl | 23 ++++++++++++ test_regress/t/t_var_extern_method_lifetime.v | 35 +++++++++++++++++++ 3 files changed, 68 insertions(+), 2 deletions(-) create mode 100755 test_regress/t/t_var_extern_method_lifetime.pl create mode 100644 test_regress/t/t_var_extern_method_lifetime.v diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index 117104a30..a7b6b9923 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -296,8 +296,16 @@ private: nodep->v3warn(STATICVAR, "Static variable with assignment declaration declared in a " "loop converted to automatic"); } - if (m_ftaskp && m_ftaskp->classMethod() && nodep->lifetime().isNone()) { - nodep->lifetime(VLifetime::AUTOMATIC); + if (m_ftaskp) { + bool classMethod = m_ftaskp->classMethod(); + if (!classMethod) { + AstClassOrPackageRef* const pkgrefp + = VN_CAST(m_ftaskp->classOrPackagep(), ClassOrPackageRef); + if (pkgrefp && VN_IS(pkgrefp->classOrPackagep(), Class)) classMethod = true; + } + if (classMethod && nodep->lifetime().isNone()) { + nodep->lifetime(VLifetime::AUTOMATIC); + } } if (nodep->lifetime().isNone() && nodep->varType() != VVarType::PORT) { nodep->lifetime(m_lifetime); diff --git a/test_regress/t/t_var_extern_method_lifetime.pl b/test_regress/t/t_var_extern_method_lifetime.pl new file mode 100755 index 000000000..b8493bd06 --- /dev/null +++ b/test_regress/t/t_var_extern_method_lifetime.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(simulator => 1); + +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_var_extern_method_lifetime.v b/test_regress/t/t_var_extern_method_lifetime.v new file mode 100644 index 000000000..899faae30 --- /dev/null +++ b/test_regress/t/t_var_extern_method_lifetime.v @@ -0,0 +1,35 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +class Foo; + int m_v; + + function new(int v); + m_v = v; + endfunction + + extern task add_in_fork_delayed(int delay, Foo arg); +endclass + +task automatic Foo::add_in_fork_delayed(int delay, Foo arg); + fork + #delay m_v = m_v + arg.m_v; + join_none +endtask + +module t(); + initial begin + Foo foo1, foo2; + foo1 = new(1); + foo2 = new(2); + foo1.add_in_fork_delayed(10, foo2); + #20; + if (foo1.m_v != 3) + $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule From b752faa10713e0b6b017b67e6b2a6a05d8b37343 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Boro=C5=84ski?= <94375110+kboronski-ant@users.noreply.github.com> Date: Fri, 11 Aug 2023 18:28:37 +0200 Subject: [PATCH 005/111] Fix jumping over object initialization (#4411) --- src/V3AstNodeOther.h | 10 +++++ src/V3Const.cpp | 7 +++ src/V3EmitCFunc.h | 5 +++ src/V3Timing.cpp | 20 +++++++++ .../t/t_jumps_uninit_destructor_call.pl | 23 ++++++++++ .../t/t_jumps_uninit_destructor_call.v | 45 +++++++++++++++++++ 6 files changed, 110 insertions(+) create mode 100755 test_regress/t/t_jumps_uninit_destructor_call.pl create mode 100644 test_regress/t/t_jumps_uninit_destructor_call.v diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index dc5f038e1..fb3c31789 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -699,6 +699,16 @@ public: && finalsp() == nullptr; } }; +class AstCLocalScope final : public AstNode { + // Pack statements into an unnamed scope when generating C++ + // @astgen op1 := stmtsp : List[AstNode] +public: + AstCLocalScope(FileLine* fl, AstNode* stmtsp) + : ASTGEN_SUPER_CLocalScope(fl) { + this->addStmtsp(stmtsp); + } + ASTGEN_MEMBERS_AstCLocalScope; +}; class AstCUse final : public AstNode { // C++ use of a class or #include; indicates need of forward declaration // Parents: NODEMODULE diff --git a/src/V3Const.cpp b/src/V3Const.cpp index c8448ff6c..8eca1a198 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -2288,6 +2288,13 @@ private: iterateChildren(nodep); } } + void visit(AstCLocalScope* nodep) override { + iterateChildren(nodep); + if (!nodep->stmtsp()) { + nodep->unlinkFrBack(); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + } + } void visit(AstScope* nodep) override { // No ASSIGNW removals under scope, we've long eliminated INITIALs VL_RESTORER(m_wremove); diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index ba7c10e54..351fd956a 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -883,6 +883,11 @@ public: iterateAndNextConstNull(nodep->endStmtsp()); puts("}\n"); } + void visit(AstCLocalScope* nodep) override { + puts("{\n"); + iterateAndNextConstNull(nodep->stmtsp()); + puts("}\n"); + } void visit(AstJumpGo* nodep) override { puts("goto __Vlabel" + cvtToStr(nodep->labelp()->blockp()->labelNum()) + ";\n"); } diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp index ab099d647..0cca7835a 100644 --- a/src/V3Timing.cpp +++ b/src/V3Timing.cpp @@ -52,6 +52,7 @@ #include "V3Ast.h" #include "V3Const.h" #include "V3EmitV.h" +#include "V3Global.h" #include "V3Graph.h" #include "V3MemberMap.h" #include "V3SenExprBuilder.h" @@ -388,6 +389,7 @@ private: AstNode* m_procp = nullptr; // NodeProcedure/CFunc/Begin we're under double m_timescaleFactor = 1.0; // Factor to scale delays by int m_forkCnt = 0; // Number of forks inside a module + bool m_underJumpBlock = false; // True if we are inside of a jump-block // Unique names V3UniqueNames m_contAssignVarNames{"__VassignWtmp"}; // Names for temp AssignW vars @@ -594,6 +596,17 @@ private: m_netlistp->typeTablep()->addTypesp(m_forkDtp); return m_forkDtp; } + // Move `insertBeforep` into `AstCLocalScope` if necessary to avoid jumping over + // a variable initialization that whould be inserted before `insertBeforep`. All + // access to this variable shoule be contained within returned `AstCLocalScope`. + AstCLocalScope* addCLocalScope(FileLine* const flp, AstNode* const insertBeforep) const { + if (!insertBeforep || !m_underJumpBlock) return nullptr; + VNRelinker handle; + insertBeforep->unlinkFrBack(&handle); + AstCLocalScope* const cscopep = new AstCLocalScope{flp, insertBeforep}; + handle.relink(cscopep); + return cscopep; + } // Create a temp variable and optionally put it before the specified node (mark local if so) AstVarScope* createTemp(FileLine* const flp, const std::string& name, AstNodeDType* const dtypep, AstNode* const insertBeforep = nullptr) { @@ -625,6 +638,7 @@ private: FileLine* const flp = forkp->fileline(); // If we're in a function, insert the sync var directly before the fork AstNode* const insertBeforep = m_classp ? forkp : nullptr; + addCLocalScope(flp, insertBeforep); AstVarScope* forkVscp = createTemp(flp, forkp->name() + "__sync", getCreateForkSyncDTypep(), insertBeforep); unsigned joinCount = 0; // Needed for join counter @@ -691,6 +705,11 @@ private: new AstCStmt{nodep->fileline(), "vlProcess->state(VlProcess::FINISHED);\n"}); } } + void visit(AstJumpBlock* nodep) override { + VL_RESTORER(m_underJumpBlock); + m_underJumpBlock = true; + visit(static_cast(nodep)); + } void visit(AstAlways* nodep) override { if (nodep->user1SetOnce()) return; VL_RESTORER(m_procp); @@ -908,6 +927,7 @@ private: // Insert new vars before the timing control if we're in a function; in a process we can't // do that. These intra-assignment vars will later be passed to forked processes by value. AstNode* const insertBeforep = m_classp ? controlp : nullptr; + addCLocalScope(flp, insertBeforep); // Function for replacing values with intermediate variables const auto replaceWithIntermediate = [&](AstNodeExpr* const valuep, const std::string& name) { diff --git a/test_regress/t/t_jumps_uninit_destructor_call.pl b/test_regress/t/t_jumps_uninit_destructor_call.pl new file mode 100755 index 000000000..b8493bd06 --- /dev/null +++ b/test_regress/t/t_jumps_uninit_destructor_call.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(simulator => 1); + +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_jumps_uninit_destructor_call.v b/test_regress/t/t_jumps_uninit_destructor_call.v new file mode 100644 index 000000000..9354f989e --- /dev/null +++ b/test_regress/t/t_jumps_uninit_destructor_call.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, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 +class Foo; + string arra[2]; + string arrb[string]; + + function new(); + arra = '{"baz", "boo"}; + arrb = '{"baz": "inga!", "boo": "..."}; + endfunction + + task automatic return_before_fork(bit b); + if (b) begin + // This is going to translate to a `goto` statement. + return; + end + // This will instantiate a `VlForkSync` object (local to the call, as we are under a class) + fork + #10 $display("forked process"); + join + // This is where we jump to from the aforementioned goto. If we don't wrap the `VlForkSync` + // object in a scope that ends before that point, we will end up calling its destructor + // without having it initialized first. + endtask + task automatic return_before_select(bit b, int idx); + if (b) return; // goto + // This will create two temporary strings used to select from `arrb` and assign to it. + arrb[arra[idx]] = #10 "yah!"; + // jump here + endtask +endclass + +module t(); + initial begin + Foo foo; + foo = new; + foo.return_before_fork(1'b1); + foo.return_before_select(1'b1, 1); + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule From 709db5c648d8a511266e62f60de0e24d79bedb2e Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 12 Aug 2023 08:46:25 -0400 Subject: [PATCH 006/111] Internals: Avoid unordered_set --- src/V3Broken.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/V3Broken.cpp b/src/V3Broken.cpp index 14c01d029..cc8c4e780 100644 --- a/src/V3Broken.cpp +++ b/src/V3Broken.cpp @@ -156,9 +156,9 @@ class BrokenCheckVisitor final : public VNVisitorConst { // Current CFunc, if any const AstCFunc* m_cfuncp = nullptr; // All local variables declared in current function - std::unordered_set m_localVars; + std::set m_localVars; // Variable references in current function that do not reference an in-scope local - std::unordered_map m_suspectRefs; + std::map m_suspectRefs; // Local variables declared in the scope of the current statement std::vector> m_localsStack; From bc97319402a1a79e2783f675e0e9f3f52c0f2892 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 12 Aug 2023 08:55:08 -0400 Subject: [PATCH 007/111] Internals: State commentary. No functional change. --- src/V3Broken.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/V3Broken.cpp b/src/V3Broken.cpp index cc8c4e780..f8db359ba 100644 --- a/src/V3Broken.cpp +++ b/src/V3Broken.cpp @@ -147,14 +147,11 @@ bool V3Broken::isLinkable(const AstNode* nodep) { return s_linkableTable.isLinka // Check every node in tree class BrokenCheckVisitor final : public VNVisitorConst { - bool m_inScope = false; // Under AstScope - // Constants for marking we are under/not under a node const uint8_t m_brokenCntCurrentNotUnder = s_brokenCntGlobal.get(); // Top bit is clear const uint8_t m_brokenCntCurrentUnder = m_brokenCntCurrentNotUnder | 0x80; // Top bit is set - // Current CFunc, if any - const AstCFunc* m_cfuncp = nullptr; + // STATE - across all visitors // All local variables declared in current function std::set m_localVars; // Variable references in current function that do not reference an in-scope local @@ -162,7 +159,12 @@ class BrokenCheckVisitor final : public VNVisitorConst { // Local variables declared in the scope of the current statement std::vector> m_localsStack; + // STATE - for current visit position (use VL_RESTORER) + const AstCFunc* m_cfuncp = nullptr; // Current CFunc, if any + bool m_inScope = false; // Under AstScope + private: + // METHODS static void checkWidthMin(const AstNode* nodep) { UASSERT_OBJ(nodep->width() == nodep->widthMin() || v3Global.widthMinUsage() != VWidthMinUsage::MATCHES_WIDTH, @@ -220,6 +222,7 @@ private: } return false; } + // VISITORS void visit(AstNodeAssign* nodep) override { processAndIterate(nodep); UASSERT_OBJ(!(v3Global.assertDTypesResolved() && nodep->brokeLhsMustBeLvalue() @@ -235,10 +238,8 @@ private: } void visit(AstScope* nodep) override { VL_RESTORER(m_inScope); - { - m_inScope = true; - processAndIterate(nodep); - } + m_inScope = true; + processAndIterate(nodep); } void visit(AstNodeVarRef* nodep) override { processAndIterate(nodep); @@ -260,6 +261,7 @@ private: } void visit(AstCFunc* nodep) override { UASSERT_OBJ(!m_cfuncp, nodep, "Nested AstCFunc"); + VL_RESTORER(m_cfuncp); m_cfuncp = nodep; m_localVars.clear(); m_suspectRefs.clear(); @@ -273,8 +275,6 @@ private: UASSERT_OBJ(m_localVars.count(pair.first) == 0, pair.second, "Local variable not in scope where referenced: " << pair.first); } - - m_cfuncp = nullptr; } void visit(AstNodeIf* nodep) override { // Each branch is a separate local variable scope From 9eba61018a4ca451a30bc0b3ab88b3ea25a2ec81 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 12 Aug 2023 09:39:02 -0400 Subject: [PATCH 008/111] Tests: Ignore debug message in error line --- test_regress/driver.pl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 76f394231..69c8cccb4 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -1680,8 +1680,12 @@ sub _run { if (!$param{fails} && $status) { my $firstline = ""; if (my $fh = IO::File->new("<$param{logfile}")) { - $firstline = $fh->getline || ''; - chomp $firstline; + while (defined(my $line = $fh->getline)) { + next if $line =~ /^- /; # Debug message + $firstline = $line; + chomp $firstline; + last; + } } $self->error("Exec of $param{cmd}[0] failed: $firstline\n"); } From 5447ed26293aced38ee97c8b190b4fb913b0e512 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 12 Aug 2023 10:41:44 -0400 Subject: [PATCH 009/111] Fix multple function definitions in V3Sched (#4416). --- Changes | 1 + src/V3Sched.cpp | 36 +++++++++++++++++++----------------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/Changes b/Changes index a688968f4..8b0bb6653 100644 --- a/Changes +++ b/Changes @@ -13,6 +13,7 @@ Verilator 5.015 devel **Minor:** +* Fix multple function definitions in V3Sched (#4416). [Hennadii Chernyshchyk] Verilator 5.014 2023-08-06 diff --git a/src/V3Sched.cpp b/src/V3Sched.cpp index 28c561c95..8948730bf 100644 --- a/src/V3Sched.cpp +++ b/src/V3Sched.cpp @@ -119,29 +119,29 @@ void invertAndMergeSenTreeMap( //============================================================================ // Split large function according to --output-split-cfuncs +std::map s_funcNums; // What split number to attach to a function + +AstCFunc* splitCheckCreateNewSubFunc(AstCFunc* ofuncp) { + auto funcNumItMatch = s_funcNums.emplace(std::make_pair(ofuncp, 0)); + AstCFunc* const subFuncp = new AstCFunc{ + ofuncp->fileline(), ofuncp->name() + "__" + cvtToStr(funcNumItMatch.first->second++), + ofuncp->scopep()}; + subFuncp->dontCombine(true); + subFuncp->isStatic(false); + subFuncp->isLoose(true); + subFuncp->slow(ofuncp->slow()); + subFuncp->declPrivate(ofuncp->declPrivate()); + return subFuncp; +}; + void splitCheck(AstCFunc* ofuncp) { if (!v3Global.opt.outputSplitCFuncs() || !ofuncp->stmtsp()) return; if (ofuncp->nodeCount() < v3Global.opt.outputSplitCFuncs()) return; - int funcnum = 0; int func_stmts = 0; const bool is_ofuncp_coroutine = ofuncp->isCoroutine(); AstCFunc* funcp = nullptr; - const auto createNewSubFuncp = [&]() { - AstCFunc* const subFuncp = new AstCFunc{ - ofuncp->fileline(), ofuncp->name() + "__" + cvtToStr(funcnum++), ofuncp->scopep()}; - subFuncp->dontCombine(true); - subFuncp->isStatic(false); - subFuncp->isLoose(true); - subFuncp->slow(ofuncp->slow()); - subFuncp->declPrivate(ofuncp->declPrivate()); - - func_stmts = 0; - - return subFuncp; - }; - const auto finishSubFuncp = [&](AstCFunc* subFuncp) { ofuncp->scopep()->addBlocksp(subFuncp); AstCCall* const callp = new AstCCall{subFuncp->fileline(), subFuncp}; @@ -160,7 +160,8 @@ void splitCheck(AstCFunc* ofuncp) { } }; - funcp = createNewSubFuncp(); + funcp = splitCheckCreateNewSubFunc(ofuncp); + func_stmts = 0; // Unlink all statements, then add item by item to new sub-functions AstBegin* const tempp = new AstBegin{ofuncp->fileline(), "[EditWrapper]", @@ -173,7 +174,8 @@ void splitCheck(AstCFunc* ofuncp) { if ((func_stmts + stmts) > v3Global.opt.outputSplitCFuncs()) { finishSubFuncp(funcp); - funcp = createNewSubFuncp(); + funcp = splitCheckCreateNewSubFunc(ofuncp); + func_stmts = 0; } funcp->addStmtsp(itemp); From 16008acdf146a8d8d4707e676ba3662906fc8c18 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 12 Aug 2023 10:51:35 -0400 Subject: [PATCH 010/111] Internals: Add disabled duplicate function check (#4418) --- src/V3Broken.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/V3Broken.cpp b/src/V3Broken.cpp index f8db359ba..961d243ec 100644 --- a/src/V3Broken.cpp +++ b/src/V3Broken.cpp @@ -162,6 +162,7 @@ class BrokenCheckVisitor final : public VNVisitorConst { // STATE - for current visit position (use VL_RESTORER) const AstCFunc* m_cfuncp = nullptr; // Current CFunc, if any bool m_inScope = false; // Under AstScope + std::set m_cFuncNames; // CFunc by name in current class/module private: // METHODS @@ -239,6 +240,18 @@ private: void visit(AstScope* nodep) override { VL_RESTORER(m_inScope); m_inScope = true; + VL_RESTORER(m_cFuncNames); + m_cFuncNames.clear(); + processAndIterate(nodep); + } + void visit(AstNodeModule* nodep) override { + VL_RESTORER(m_cFuncNames); + m_cFuncNames.clear(); + processAndIterate(nodep); + } + void visit(AstNodeUOrStructDType* nodep) override { + VL_RESTORER(m_cFuncNames); + m_cFuncNames.clear(); processAndIterate(nodep); } void visit(AstNodeVarRef* nodep) override { @@ -268,6 +281,14 @@ private: m_localsStack.clear(); pushLocalScope(); + // Check for duplicate names, otherwise linker might just ignore them + string nameArgs = nodep->name(); + if (!nodep->argTypes().empty()) nameArgs += "(" + nodep->argTypes() + ")"; + if (false) { // bug4418 + UASSERT_OBJ(m_cFuncNames.emplace(nameArgs).second, nodep, + "Duplicate cfunc name: '" << nameArgs << "'"); + } + processAndIterate(nodep); // Check suspect references are all to non-locals From 6c80457262198f0b2e9433698c42441cba6d505f Mon Sep 17 00:00:00 2001 From: Jose Loyola Date: Mon, 14 Aug 2023 23:45:07 -0500 Subject: [PATCH 011/111] CI: Refactor docker build action to define DOCKER_HUB_NAMESPACE as repo variable (#4419) --- .github/workflows/docker.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 312b59474..759421e35 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -1,6 +1,7 @@ # Build and push verilator docker image when tags are pushed to the repository. -# The following secrets must be configured in the github repository: +# The following variable(s) must be configured in the github repository: # DOCKER_HUB_NAMESPACE: docker hub namespace. +# The following secrets must be configured in the github repository: # DOCKER_HUB_USER: user name for logging into docker hub # DOCKER_HUB_ACCESS_TOKEN: docker hub access token. name: Build Verilator Container @@ -52,7 +53,7 @@ jobs: uses: docker/metadata-action@v4 with: images: | - ${{ secrets.DOCKER_HUB_NAMESPACE }}/${{ env.image_name }} + ${{ vars.DOCKER_HUB_NAMESPACE }}/${{ env.image_name }} tags: | type=match,pattern=(v.*),group=1,enable=${{ startsWith(github.ref, 'refs/tags/v') }} type=raw,value=${{ inputs.manual_tag }},enable=${{ inputs.manual_tag != '' }} From 0f66262fa1fc0f955265190ed2e469d07d1ad208 Mon Sep 17 00:00:00 2001 From: Anthony Donlon <4056887+donlon@users.noreply.github.com> Date: Wed, 16 Aug 2023 19:32:39 +0800 Subject: [PATCH 012/111] Internals: Refactor AstNode::checkTreeIter for better stack size (#4420) --- src/V3Ast.cpp | 62 ++++++++++++++++++++++--- src/V3Ast.h | 14 ++++++ src/astgen | 122 +++++++++++++++----------------------------------- 3 files changed, 106 insertions(+), 92 deletions(-) diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index 4242138db..0224ff574 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -55,12 +55,16 @@ bool VNUser5InUse::s_userBusy = false; int AstNodeDType::s_uniqueNum = 0; //###################################################################### -// V3AstType +// VNType + +const VNTypeInfo VNType::typeInfoTable[] = { +#include "V3Ast__gen_type_info.h" // From ./astgen +}; std::ostream& operator<<(std::ostream& os, VNType rhs); //###################################################################### -// Creators +// AstNode AstNode::AstNode(VNType t, FileLine* fl) : m_type{t} @@ -1098,9 +1102,57 @@ bool AstNode::sameTreeIter(const AstNode* node1p, const AstNode* node2p, bool ig void AstNode::checkTreeIter(const AstNode* prevBackp) const VL_MT_STABLE { // private: Check a tree and children UASSERT_OBJ(prevBackp == this->backp(), this, "Back node inconsistent"); - switch (this->type()) { -#include "V3Ast__gen_op_checks.h" - default: VL_UNREACHABLE; // LCOV_EXCL_LINE + const VNTypeInfo& typeInfo = *type().typeInfo(); + for (int i = 1; i <= 4; i++) { + AstNode* nodep = nullptr; + switch (i) { + case 1: nodep = op1p(); break; + case 2: nodep = op2p(); break; + case 3: nodep = op3p(); break; + case 4: nodep = op4p(); break; + default: this->v3fatalSrc("Bad case"); break; + } + const char* opName = typeInfo.m_opNamep[i - 1]; + switch (typeInfo.m_opType[i - 1]) { + case VNTypeInfo::OP_UNUSED: + UASSERT_OBJ(!nodep, this, typeInfo.m_namep << " must not use " << opName << "()"); + break; + case VNTypeInfo::OP_USED: + UASSERT_OBJ(nodep, this, + typeInfo.m_namep << " must have non nullptr " << opName << "()"); + UASSERT_OBJ(!nodep->nextp(), this, + typeInfo.m_namep << "::" << opName + << "() cannot have a non nullptr nextp()"); + nodep->checkTreeIter(this); + break; + case VNTypeInfo::OP_LIST: + if (const AstNode* const headp = nodep) { + const AstNode* backp = this; + const AstNode* tailp = headp; + const AstNode* opp = headp; + do { + opp->checkTreeIter(backp); + UASSERT_OBJ(opp == headp || !opp->nextp() || !opp->m_headtailp, opp, + "Headtailp should be null in middle of lists"); + backp = tailp = opp; + opp = opp->nextp(); + } while (opp); + UASSERT_OBJ(headp->m_headtailp == tailp, headp, + "Tail in headtailp is inconsistent"); + UASSERT_OBJ(tailp->m_headtailp == headp, tailp, + "Head in headtailp is inconsistent"); + } + break; + case VNTypeInfo::OP_OPTIONAL: + if (nodep) { + UASSERT_OBJ(!nodep->nextp(), this, + typeInfo.m_namep << "::" << opName + << "() cannot have a non-nullptr nextp()"); + nodep->checkTreeIter(this); + } + break; + default: this->v3fatalSrc("Bad case"); break; + } } } diff --git a/src/V3Ast.h b/src/V3Ast.h index f763284ca..8fc42582e 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -98,7 +98,20 @@ using MTaskIdSet = std::set; // Set of mtaskIds for Var sorting //###################################################################### +struct VNTypeInfo { + const char* m_namep; + enum uint8_t { + OP_UNUSED, + OP_USED, + OP_LIST, + OP_OPTIONAL, + } m_opType[4]; + const char* m_opNamep[4]; +}; + class VNType final { + static const VNTypeInfo typeInfoTable[]; + public: #include "V3Ast__gen_type_enum.h" // From ./astgen // Above include has: @@ -111,6 +124,7 @@ public: constexpr VNType(en _e) VL_MT_SAFE : m_e{_e} {} explicit VNType(int _e) : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning + const VNTypeInfo* typeInfo() const VL_MT_SAFE { return &typeInfoTable[m_e]; } constexpr operator en() const VL_MT_SAFE { return m_e; } }; constexpr bool operator==(const VNType& lhs, const VNType& rhs) VL_PURE { diff --git a/src/astgen b/src/astgen index a7f12ef14..3a9b65785 100755 --- a/src/astgen +++ b/src/astgen @@ -246,7 +246,7 @@ class Cpt: with open_file(self.out_filename) as fho: togen = self.out_lines for line in togen: - if type(line) is str: + if isinstance(line, str): self.out_lines = [line] else: self.out_lines = [] @@ -908,6 +908,39 @@ def write_type_tests(prefix, nodeList): ################################################################################ +def write_ast_type_info(filename): + with open_file(filename) as fh: + for node in sorted(filter(lambda _: _.isLeaf, AstNodeList), + key=lambda _: _.typeId): + opTypeList = [] + opNameList = [] + for n in range(1, 5): + op = node.getOp(n) + if not op: + opTypeList.append('OP_UNUSED') + opNameList.append('op{0}p'.format(n)) + else: + name, monad, _ = op + if not monad: + opTypeList.append('OP_USED') + elif monad == "Optional": + opTypeList.append('OP_OPTIONAL') + elif monad == "List": + opTypeList.append('OP_LIST') + opNameList.append(name) + # opTypeStr = ', '.join(opTypeList) + opTypeStr = ', '.join( + ['VNTypeInfo::{0}'.format(s) for s in opTypeList]) + opNameStr = ', '.join(['"{0}"'.format(s) for s in opNameList]) + fh.write( + ' {{ "Ast{name}", {{{opTypeStr}}}, {{{opNameStr}}} }},\n'. + format( + name=node.name, + opTypeStr=opTypeStr, + opNameStr=opNameStr, + )) + + def write_ast_macros(filename): with open_file(filename) as fh: @@ -998,91 +1031,6 @@ def write_ast_yystype(filename): node.name[1:])) -def write_ast_op_checks(filename): - with open_file(filename) as fh: - - indent = "" - - def emitBlock(pattern, **fmt): - fh.write( - textwrap.indent(textwrap.dedent(pattern), - indent).format(**fmt)) - - for node in AstNodeList: - if not node.isLeaf: - continue - - emitBlock('''\ - case VNType::at{nodeName}: {{ - const Ast{nodeName}* const currp = static_cast(this); - ''', - nodeName=node.name) - indent = " " - for n in range(1, 5): - op = node.getOp(n) - emitBlock("// Checking op{n}p\n", n=n) - if op: - name, monad, kind = op - if not monad: - emitBlock('''\ - UASSERT_OBJ(currp->{opName}(), currp, "Ast{nodeName} must have non nullptr {opName}()"); - UASSERT_OBJ(!currp->{opName}()->nextp(), currp, "Ast{nodeName}::{opName}() cannot have a non nullptr nextp()"); - currp->{opName}()->checkTreeIter(currp); - ''', - n=n, - nodeName=node.name, - opName=name) - elif monad == "Optional": - emitBlock('''\ - if (Ast{kind}* const opp = currp->{opName}()) {{ - UASSERT_OBJ(!currp->{opName}()->nextp(), currp, "Ast{nodeName}::{opName}() cannot have a non nullptr nextp()"); - opp->checkTreeIter(currp); - }} - ''', - n=n, - nodeName=node.name, - opName=name, - kind=kind) - elif monad == "List": - emitBlock('''\ - if (const Ast{kind}* const headp = currp->{opName}()) {{ - const AstNode* backp = currp; - const Ast{kind}* tailp = headp; - const Ast{kind}* opp = headp; - do {{ - opp->checkTreeIter(backp); - UASSERT_OBJ(opp == headp || !opp->nextp() || !opp->m_headtailp, opp, "Headtailp should be null in middle of lists"); - backp = tailp = opp; - opp = {next}; - }} while (opp); - // cppcheck-suppress knownConditionTrueFalse - if (false && headp && tailp) {{}} // Prevent unused - UASSERT_OBJ(headp->m_headtailp == tailp, headp, "Tail in headtailp is inconsistent"); - UASSERT_OBJ(tailp->m_headtailp == headp, tailp, "Head in headtailp is inconsistent"); - }} - ''', - n=n, - nodeName=node.name, - opName=name, - kind=kind, - next="VN_AS(opp->nextp(), {kind})".format( - kind=kind) - if kind != "Node" else "opp->nextp()") - else: - sys.exit("Unknown operand type") - else: - emitBlock('''\ - UASSERT_OBJ(!currp->op{n}p(), currp, "Ast{nodeName} does not use op{n}p()"); - ''', - n=n, - nodeName=node.name) - indent = "" - emitBlock('''\ - break; - }} - ''') - - ################################################################################ # DFG code genaration ################################################################################ @@ -1346,9 +1294,9 @@ if Args.classes: write_visitor_defns("Ast", AstNodeList, "VNVisitorConst") write_type_enum("Ast", AstNodeList) write_type_tests("Ast", AstNodeList) + write_ast_type_info("V3Ast__gen_type_info.h") write_ast_macros("V3Ast__gen_macros.h") write_ast_yystype("V3Ast__gen_yystype.h") - write_ast_op_checks("V3Ast__gen_op_checks.h") # Write Dfg code write_forward_class_decls("Dfg", DfgVertexList) write_visitor_decls("Dfg", DfgVertexList) From cbdee5a80499aaae049e955b7b45d5d8abc5b8ef Mon Sep 17 00:00:00 2001 From: Anthony Donlon <4056887+donlon@users.noreply.github.com> Date: Wed, 16 Aug 2023 19:34:57 +0800 Subject: [PATCH 013/111] Fix Windows filename format, etc. (#3873) (#4421) * Ignore CLion project files and CMake outputs * Supporting stripping file path that contains backslash * Set /bigobj flag and increase stack size for windows platform * Fix MSVC warnings --- .gitignore | 2 ++ include/verilatedos.h | 4 ++-- src/CMakeLists.txt | 2 ++ src/V3Expand.cpp | 4 +++- src/V3FileLine.cpp | 8 ++------ src/V3MergeCond.cpp | 1 + src/V3Options.cpp | 4 ++-- src/V3Os.cpp | 48 +++++++++++++++++++++++++++---------------- src/V3Os.h | 14 +++++++------ src/V3Table.cpp | 2 +- 10 files changed, 53 insertions(+), 36 deletions(-) diff --git a/.gitignore b/.gitignore index 48859af2b..e7e3d788a 100644 --- a/.gitignore +++ b/.gitignore @@ -41,3 +41,5 @@ verilator-config-version.cmake **/_build/* **/obj_dir/* /.vscode/ +/.idea/ +/cmake-build-*/ diff --git a/include/verilatedos.h b/include/verilatedos.h index 113d8cd2d..f065ed6f6 100644 --- a/include/verilatedos.h +++ b/include/verilatedos.h @@ -577,8 +577,8 @@ static inline double VL_ROUND(double n) { //========================================================================= // Stringify macros -#define VL_STRINGIFY(x) VL_STRINGIFY2(x) -#define VL_STRINGIFY2(x) #x +#define VL_STRINGIFY(...) VL_STRINGIFY2(__VA_ARGS__) +#define VL_STRINGIFY2(...) #__VA_ARGS__ //========================================================================= // Offset of field in type diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ba230d891..47471a1bd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -490,11 +490,13 @@ target_include_directories(${verilator} ) if (WIN32) + target_compile_options(${verilator} PRIVATE /bigobj) target_compile_definitions(${verilator} PRIVATE YY_NO_UNISTD_H ) target_include_directories(${verilator} PRIVATE ../platform/win32) target_link_libraries(${verilator} PRIVATE bcrypt psapi) + target_link_options(${verilator} PRIVATE /STACK:10000000) endif() install(TARGETS ${verilator}) diff --git a/src/V3Expand.cpp b/src/V3Expand.cpp index 812ac86fd..54cb31068 100644 --- a/src/V3Expand.cpp +++ b/src/V3Expand.cpp @@ -202,7 +202,9 @@ private: new AstShiftR{fl, lhip, new AstConst{fl, static_cast(nbitsonright)}, VL_EDATASIZE}}, - new AstAnd{fl, new AstConst{fl, AstConst::SizedEData{}, ~VL_MASK_E(loffset)}, + new AstAnd{fl, + new AstConst{fl, AstConst::SizedEData{}, + static_cast(~VL_MASK_E(loffset))}, new AstShiftL{fl, llowp, new AstConst{fl, static_cast(loffset)}, VL_EDATASIZE}}}; diff --git a/src/V3FileLine.cpp b/src/V3FileLine.cpp index 5de357085..be4a7cd25 100644 --- a/src/V3FileLine.cpp +++ b/src/V3FileLine.cpp @@ -20,6 +20,7 @@ // clang-format off #include "V3Error.h" #include "V3FileLine.h" +#include "V3Os.h" #include "V3String.h" #ifndef V3ERROR_NO_GLOBAL_ # include "V3Global.h" @@ -286,12 +287,7 @@ FileLine* FileLine::copyOrSameFileLine() { return newp; } -string FileLine::filebasename() const VL_MT_SAFE { - string name = filename(); - string::size_type pos; - if ((pos = name.rfind('/')) != string::npos) name.erase(0, pos + 1); - return name; -} +string FileLine::filebasename() const VL_MT_SAFE { return V3Os::filenameNonDir(filename()); } string FileLine::filebasenameNoExt() const { string name = filebasename(); diff --git a/src/V3MergeCond.cpp b/src/V3MergeCond.cpp index 5f57e82c5..8a237c8ba 100644 --- a/src/V3MergeCond.cpp +++ b/src/V3MergeCond.cpp @@ -620,6 +620,7 @@ private: // LCOV_EXCL_START if (debug()) rhsp->dumpTree("Don't know how to fold expression: "); rhsp->v3fatalSrc("Should not try to fold this during conditional merging"); + return nullptr; // LCOV_EXCL_STOP } diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 8d0d3e26f..611f62b20 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -548,8 +548,8 @@ string V3Options::filePath(FileLine* fl, const string& modname, const string& la // Find a filename to read the specified module name, // using the incdir and libext's. // Return "" if not found. - if (modname[0] == '/') { - // If leading /, obey existing absolute path, so can find getStdPackagePath() + if (!V3Os::filenameIsRel(modname)) { + // modname is an absolute path, so can find getStdPackagePath() string exists = filePathCheckOneDir(modname, ""); if (exists != "") return exists; } diff --git a/src/V3Os.cpp b/src/V3Os.cpp index 3fb7ec5ee..01d9db383 100644 --- a/src/V3Os.cpp +++ b/src/V3Os.cpp @@ -124,7 +124,9 @@ void V3Os::setenvStr(const string& envvar, const string& value, const string& wh //###################################################################### // Generic filename utilities -string V3Os::filenameFromDirBase(const string& dir, const string& basename) { +static bool isSlash(char ch) VL_PURE { return ch == '/' || ch == '\\'; } + +string V3Os::filenameFromDirBase(const string& dir, const string& basename) VL_PURE { // Don't return ./{filename} because if filename was absolute, that makes it relative if (dir.empty() || dir == ".") { return basename; @@ -133,22 +135,26 @@ string V3Os::filenameFromDirBase(const string& dir, const string& basename) { } } -string V3Os::filenameDir(const string& filename) { - string::size_type pos; - if ((pos = filename.rfind('/')) != string::npos) { - return filename.substr(0, pos); - } else { +string V3Os::filenameDir(const string& filename) VL_PURE { + // std::filesystem::path::parent_path + auto it = filename.rbegin(); + for (; it != filename.rend(); ++it) { + if (isSlash(*it)) break; + } + if (it.base() == filename.begin()) { return "."; + } else { + return {filename.begin(), (++it).base()}; } } string V3Os::filenameNonDir(const string& filename) VL_PURE { - string::size_type pos; - if ((pos = filename.rfind('/')) != string::npos) { - return filename.substr(pos + 1); - } else { - return filename; + // std::filesystem::path::filename + auto it = filename.rbegin(); + for (; it != filename.rend(); ++it) { + if (isSlash(*it)) break; } + return string{it.base(), filename.end()}; } string V3Os::filenameNonExt(const string& filename) VL_PURE { @@ -202,7 +208,7 @@ string V3Os::filenameSubstitute(const string& filename) { return result; } -string V3Os::filenameRealPath(const string& filename) { +string V3Os::filenameRealPath(const string& filename) VL_PURE { // Get rid of all the ../ behavior in the middle of the paths. // If there is a ../ that goes down from the 'root' of this path it is preserved. char retpath[PATH_MAX]; @@ -219,8 +225,12 @@ string V3Os::filenameRealPath(const string& filename) { } } -bool V3Os::filenameIsRel(const string& filename) { +bool V3Os::filenameIsRel(const string& filename) VL_PURE { +#if defined(_MSC_VER) + return std::filesystem::path(filename).is_relative(); +#else return (filename.length() > 0 && filename[0] != '/'); +#endif } //###################################################################### @@ -251,12 +261,14 @@ void V3Os::createDir(const string& dirname) { void V3Os::unlinkRegexp(const string& dir, const string& regexp) { #ifdef _MSC_VER - for (const auto& dirEntry : std::filesystem::directory_iterator(dir.c_str())) { - if (VString::wildmatch(dirEntry.path().filename().string(), regexp.c_str())) { - const string fullname = dir + "/" + dirEntry.path().filename().string(); - _unlink(fullname.c_str()); + try { + for (const auto& dirEntry : std::filesystem::directory_iterator(dir.c_str())) { + if (VString::wildmatch(dirEntry.path().filename().string(), regexp.c_str())) { + const string fullname = dir + "/" + dirEntry.path().filename().string(); + _unlink(fullname.c_str()); + } } - } + } catch (std::filesystem::filesystem_error const& ex) {} #else if (DIR* const dirp = opendir(dir.c_str())) { while (struct dirent* const direntp = readdir(dirp)) { diff --git a/src/V3Os.h b/src/V3Os.h index 4f4d44bb9..da1bcb1d0 100644 --- a/src/V3Os.h +++ b/src/V3Os.h @@ -35,20 +35,22 @@ public: static void setenvStr(const string& envvar, const string& value, const string& why); // METHODS (generic filename utilities) - static string filenameFromDirBase(const string& dir, const string& basename); - /// Return non-directory part of filename + static string filenameFromDirBase(const string& dir, const string& basename) VL_PURE; + ///< Return non-directory part of filename static string filenameNonDir(const string& filename) VL_PURE; - /// Return non-extensioned (no .) part of filename + ///< Return non-extensioned (no .) part of filename static string filenameNonExt(const string& filename) VL_PURE; ///< Return basename of filename static string filenameNonDirExt(const string& filename) VL_PURE { return filenameNonExt(filenameNonDir(filename)); } - static string filenameDir(const string& filename); ///< Return directory part of filename + ///< Return directory part of filename + static string filenameDir(const string& filename) VL_PURE; /// Return filename with env vars removed static string filenameSubstitute(const string& filename); - static string filenameRealPath(const string& filename); ///< Return realpath of filename - static bool filenameIsRel(const string& filename); ///< True if relative + ///< Return realpath of filename + static string filenameRealPath(const string& filename) VL_PURE; + static bool filenameIsRel(const string& filename) VL_PURE; ///< True if relative // METHODS (file utilities) static string getline(std::istream& is, char delim = '\n'); diff --git a/src/V3Table.cpp b/src/V3Table.cpp index 26f37f970..6e1c4d6db 100644 --- a/src/V3Table.cpp +++ b/src/V3Table.cpp @@ -181,7 +181,7 @@ public: // We'll make the table with a separate natural alignment for each output var, so // always have 8, 16 or 32 bit widths, so use widthTotalBytes m_outWidthBytes += nodep->varp()->dtypeSkipRefp()->widthTotalBytes(); - m_outVarps.emplace_back(vscp, m_outVarps.size()); + m_outVarps.emplace_back(vscp, static_cast(m_outVarps.size())); } if (nodep->access().isReadOrRW()) { m_inWidthBits += nodep->varp()->width(); From e9cc2786b7537963abea9db78c851f9ec78f364a Mon Sep 17 00:00:00 2001 From: Frans Skarman Date: Sat, 19 Aug 2023 08:51:29 +0000 Subject: [PATCH 014/111] Add --no-trace-top option (#4422) --- bin/verilator | 1 + docs/CONTRIBUTORS | 1 + docs/guide/exe_verilator.rst | 12 + src/V3LinkLevel.cpp | 4 + src/V3Options.cpp | 1 + src/V3Options.h | 2 + test_regress/t/t_no_trace_top.cpp | 44 + test_regress/t/t_no_trace_top.out | 4762 +++++++++++++++++++++++++++++ test_regress/t/t_no_trace_top.pl | 29 + 9 files changed, 4856 insertions(+) create mode 100644 test_regress/t/t_no_trace_top.cpp create mode 100644 test_regress/t/t_no_trace_top.out create mode 100755 test_regress/t/t_no_trace_top.pl diff --git a/bin/verilator b/bin/verilator index 65acaf2f8..92ba9dde5 100755 --- a/bin/verilator +++ b/bin/verilator @@ -440,6 +440,7 @@ detailed descriptions of these arguments. --trace-params Enable tracing of parameters --trace-structs Enable tracing structure names --trace-threads Enable FST waveform creation on separate threads + --no-trace-top Do not emit traces for signals in the top module generated by verilator --trace-underscore Enable tracing of _signals -U Undefine preprocessor define --no-unlimited-stack Don't disable stack size limit diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index b9b184379..f066d9bef 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -40,6 +40,7 @@ Fan Shupei february cozzocrea Felix Neumärker Felix Yan +Frans Skarman G-A. Kamendje Garrett Smith Geza Lore diff --git a/docs/guide/exe_verilator.rst b/docs/guide/exe_verilator.rst index 6ec962e1e..87f9db880 100644 --- a/docs/guide/exe_verilator.rst +++ b/docs/guide/exe_verilator.rst @@ -1314,6 +1314,7 @@ Summary: This is not needed with standard designs with only one top. See also :option:`MULTITOP` warning. + .. option:: --trace Adds waveform tracing code to the model using VCD format. This overrides @@ -1392,6 +1393,17 @@ Summary: This option is accepted, but has absolutely no effect with :vlopt:`--trace`, which respects :vlopt:`--threads` instead. +.. option:: --no-trace-top + + Disables tracing for the input and output signals in the top wrapper which + Verilator adds to the design. The signals are still traced in the original + verilog top modules. + + When combined with :option:`--main-top-name` set to "-" or when the name of + the top module is set to "" in its constructor, the generated trace file + will have the verilog top module as its root, rather than another module + added by Verilator. + .. option:: --trace-underscore Enable tracing of signals or modules that start with an diff --git a/src/V3LinkLevel.cpp b/src/V3LinkLevel.cpp index 609563b99..cd0f0a195 100644 --- a/src/V3LinkLevel.cpp +++ b/src/V3LinkLevel.cpp @@ -289,6 +289,10 @@ void V3LinkLevel::wrapTopCell(AstNetlist* rootp) { varp->trace(false); } + if (v3Global.opt.noTraceTop() && varp->isIO()) { + varp->trace(false); + } + AstPin* const pinp = new AstPin{ oldvarp->fileline(), 0, varp->name(), new AstVarRef{varp->fileline(), varp, diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 611f62b20..47ac50329 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -1496,6 +1496,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char DECL_OPTION("-timing", OnOff, &m_timing); DECL_OPTION("-top-module", Set, &m_topModule); DECL_OPTION("-top", Set, &m_topModule); + DECL_OPTION("-no-trace-top", Set, &m_noTraceTop); DECL_OPTION("-trace", OnOff, &m_trace); DECL_OPTION("-trace-coverage", OnOff, &m_traceCoverage); DECL_OPTION("-trace-depth", Set, &m_traceDepth); diff --git a/src/V3Options.h b/src/V3Options.h index dcdf0d96b..f68c32d11 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -280,6 +280,7 @@ private: bool m_traceCoverage = false; // main switch: --trace-coverage bool m_traceParams = true; // main switch: --trace-params bool m_traceStructs = false; // main switch: --trace-structs + bool m_noTraceTop; // main switch: --no-trace-top bool m_traceUnderscore = false; // main switch: --trace-underscore bool m_underlineZero = false; // main switch: --underline-zero; undocumented old Verilator 2 bool m_verilate = true; // main switch: --verilate @@ -578,6 +579,7 @@ public: bool protectKeyProvided() const { return !m_protectKey.empty(); } string protectKeyDefaulted() VL_MT_SAFE; // Set default key if not set by user string topModule() const { return m_topModule; } + bool noTraceTop() const { return m_noTraceTop; } string unusedRegexp() const { return m_unusedRegexp; } string waiverOutput() const { return m_waiverOutput; } bool isWaiverOutput() const { return !m_waiverOutput.empty(); } diff --git a/test_regress/t/t_no_trace_top.cpp b/test_regress/t/t_no_trace_top.cpp new file mode 100644 index 000000000..e53cd583d --- /dev/null +++ b/test_regress/t/t_no_trace_top.cpp @@ -0,0 +1,44 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +// +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2008 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +#include +#include + +#include + +#include VM_PREFIX_INCLUDE + +unsigned long long main_time = 0; +double sc_time_stamp() { return (double)main_time; } + +int main(int argc, char** argv) { + Verilated::debug(0); + Verilated::traceEverOn(true); + Verilated::commandArgs(argc, argv); + + std::unique_ptr top{new VM_PREFIX{"top"}}; + + std::unique_ptr tfp{new VerilatedVcdC}; + top->trace(tfp.get(), 99); + tfp->open(VL_STRINGIFY(TEST_OBJ_DIR) "/simno_trace_top.vcd"); + + top->clk = 0; + + while (main_time < 1900) { // Creates 2 files + top->clk = !top->clk; + top->eval(); + tfp->dump((unsigned int)(main_time)); + ++main_time; + } + tfp->close(); + top->final(); + tfp.reset(); + top.reset(); + printf("*-* All Finished *-*\n"); + return 0; +} diff --git a/test_regress/t/t_no_trace_top.out b/test_regress/t/t_no_trace_top.out new file mode 100644 index 000000000..0d64685ff --- /dev/null +++ b/test_regress/t/t_no_trace_top.out @@ -0,0 +1,4762 @@ +$version Generated by VerilatedVcd $end +$timescale 1ps $end + + $scope module top $end + $scope module t $end + $var wire 1 # clk $end + $var wire 32 $ cyc [31:0] $end + $upscope $end + $upscope $end +$enddefinitions $end + + +#0 +1# +b00000000000000000000000000000000 $ +#1 +0# +#2 +1# +b00000000000000000000000000000001 $ +#3 +0# +#4 +1# +b00000000000000000000000000000010 $ +#5 +0# +#6 +1# +b00000000000000000000000000000011 $ +#7 +0# +#8 +1# +b00000000000000000000000000000100 $ +#9 +0# +#10 +1# +b00000000000000000000000000000101 $ +#11 +0# +#12 +1# +b00000000000000000000000000000110 $ +#13 +0# +#14 +1# +b00000000000000000000000000000111 $ +#15 +0# +#16 +1# +b00000000000000000000000000001000 $ +#17 +0# +#18 +1# +b00000000000000000000000000001001 $ +#19 +0# +#20 +1# +b00000000000000000000000000001010 $ +#21 +0# +#22 +1# +b00000000000000000000000000001011 $ +#23 +0# +#24 +1# +b00000000000000000000000000001100 $ +#25 +0# +#26 +1# +b00000000000000000000000000001101 $ +#27 +0# +#28 +1# +b00000000000000000000000000001110 $ +#29 +0# +#30 +1# +b00000000000000000000000000001111 $ +#31 +0# +#32 +1# +b00000000000000000000000000010000 $ +#33 +0# +#34 +1# +b00000000000000000000000000010001 $ +#35 +0# +#36 +1# +b00000000000000000000000000010010 $ +#37 +0# +#38 +1# +b00000000000000000000000000010011 $ +#39 +0# +#40 +1# +b00000000000000000000000000010100 $ +#41 +0# +#42 +1# +b00000000000000000000000000010101 $ +#43 +0# +#44 +1# +b00000000000000000000000000010110 $ +#45 +0# +#46 +1# +b00000000000000000000000000010111 $ +#47 +0# +#48 +1# +b00000000000000000000000000011000 $ +#49 +0# +#50 +1# +b00000000000000000000000000011001 $ +#51 +0# +#52 +1# +b00000000000000000000000000011010 $ +#53 +0# +#54 +1# +b00000000000000000000000000011011 $ +#55 +0# +#56 +1# +b00000000000000000000000000011100 $ +#57 +0# +#58 +1# +b00000000000000000000000000011101 $ +#59 +0# +#60 +1# +b00000000000000000000000000011110 $ +#61 +0# +#62 +1# +b00000000000000000000000000011111 $ +#63 +0# +#64 +1# +b00000000000000000000000000100000 $ +#65 +0# +#66 +1# +b00000000000000000000000000100001 $ +#67 +0# +#68 +1# +b00000000000000000000000000100010 $ +#69 +0# +#70 +1# +b00000000000000000000000000100011 $ +#71 +0# +#72 +1# +b00000000000000000000000000100100 $ +#73 +0# +#74 +1# +b00000000000000000000000000100101 $ +#75 +0# +#76 +1# +b00000000000000000000000000100110 $ +#77 +0# +#78 +1# +b00000000000000000000000000100111 $ +#79 +0# +#80 +1# +b00000000000000000000000000101000 $ +#81 +0# +#82 +1# +b00000000000000000000000000101001 $ +#83 +0# +#84 +1# +b00000000000000000000000000101010 $ +#85 +0# +#86 +1# +b00000000000000000000000000101011 $ +#87 +0# +#88 +1# +b00000000000000000000000000101100 $ +#89 +0# +#90 +1# +b00000000000000000000000000101101 $ +#91 +0# +#92 +1# +b00000000000000000000000000101110 $ +#93 +0# +#94 +1# +b00000000000000000000000000101111 $ +#95 +0# +#96 +1# +b00000000000000000000000000110000 $ +#97 +0# +#98 +1# +b00000000000000000000000000110001 $ +#99 +0# +#100 +1# +b00000000000000000000000000110010 $ +#101 +0# +#102 +1# +b00000000000000000000000000110011 $ +#103 +0# +#104 +1# +b00000000000000000000000000110100 $ +#105 +0# +#106 +1# +b00000000000000000000000000110101 $ +#107 +0# +#108 +1# +b00000000000000000000000000110110 $ +#109 +0# +#110 +1# +b00000000000000000000000000110111 $ +#111 +0# +#112 +1# +b00000000000000000000000000111000 $ +#113 +0# +#114 +1# +b00000000000000000000000000111001 $ +#115 +0# +#116 +1# +b00000000000000000000000000111010 $ +#117 +0# +#118 +1# +b00000000000000000000000000111011 $ +#119 +0# +#120 +1# +b00000000000000000000000000111100 $ +#121 +0# +#122 +1# +b00000000000000000000000000111101 $ +#123 +0# +#124 +1# +b00000000000000000000000000111110 $ +#125 +0# +#126 +1# +b00000000000000000000000000111111 $ +#127 +0# +#128 +1# +b00000000000000000000000001000000 $ +#129 +0# +#130 +1# +b00000000000000000000000001000001 $ +#131 +0# +#132 +1# +b00000000000000000000000001000010 $ +#133 +0# +#134 +1# +b00000000000000000000000001000011 $ +#135 +0# +#136 +1# +b00000000000000000000000001000100 $ +#137 +0# +#138 +1# +b00000000000000000000000001000101 $ +#139 +0# +#140 +1# +b00000000000000000000000001000110 $ +#141 +0# +#142 +1# +b00000000000000000000000001000111 $ +#143 +0# +#144 +1# +b00000000000000000000000001001000 $ +#145 +0# +#146 +1# +b00000000000000000000000001001001 $ +#147 +0# +#148 +1# +b00000000000000000000000001001010 $ +#149 +0# +#150 +1# +b00000000000000000000000001001011 $ +#151 +0# +#152 +1# +b00000000000000000000000001001100 $ +#153 +0# +#154 +1# +b00000000000000000000000001001101 $ +#155 +0# +#156 +1# +b00000000000000000000000001001110 $ +#157 +0# +#158 +1# +b00000000000000000000000001001111 $ +#159 +0# +#160 +1# +b00000000000000000000000001010000 $ +#161 +0# +#162 +1# +b00000000000000000000000001010001 $ +#163 +0# +#164 +1# +b00000000000000000000000001010010 $ +#165 +0# +#166 +1# +b00000000000000000000000001010011 $ +#167 +0# +#168 +1# +b00000000000000000000000001010100 $ +#169 +0# +#170 +1# +b00000000000000000000000001010101 $ +#171 +0# +#172 +1# +b00000000000000000000000001010110 $ +#173 +0# +#174 +1# +b00000000000000000000000001010111 $ +#175 +0# +#176 +1# +b00000000000000000000000001011000 $ +#177 +0# +#178 +1# +b00000000000000000000000001011001 $ +#179 +0# +#180 +1# +b00000000000000000000000001011010 $ +#181 +0# +#182 +1# +b00000000000000000000000001011011 $ +#183 +0# +#184 +1# +b00000000000000000000000001011100 $ +#185 +0# +#186 +1# +b00000000000000000000000001011101 $ +#187 +0# +#188 +1# +b00000000000000000000000001011110 $ +#189 +0# +#190 +1# +b00000000000000000000000001011111 $ +#191 +0# +#192 +1# +b00000000000000000000000001100000 $ +#193 +0# +#194 +1# +b00000000000000000000000001100001 $ +#195 +0# +#196 +1# +b00000000000000000000000001100010 $ +#197 +0# +#198 +1# +b00000000000000000000000001100011 $ +#199 +0# +#200 +1# +b00000000000000000000000001100100 $ +#201 +0# +#202 +1# +b00000000000000000000000001100101 $ +#203 +0# +#204 +1# +b00000000000000000000000001100110 $ +#205 +0# +#206 +1# +b00000000000000000000000001100111 $ +#207 +0# +#208 +1# +b00000000000000000000000001101000 $ +#209 +0# +#210 +1# +b00000000000000000000000001101001 $ +#211 +0# +#212 +1# +b00000000000000000000000001101010 $ +#213 +0# +#214 +1# +b00000000000000000000000001101011 $ +#215 +0# +#216 +1# +b00000000000000000000000001101100 $ +#217 +0# +#218 +1# +b00000000000000000000000001101101 $ +#219 +0# +#220 +1# +b00000000000000000000000001101110 $ +#221 +0# +#222 +1# +b00000000000000000000000001101111 $ +#223 +0# +#224 +1# +b00000000000000000000000001110000 $ +#225 +0# +#226 +1# +b00000000000000000000000001110001 $ +#227 +0# +#228 +1# +b00000000000000000000000001110010 $ +#229 +0# +#230 +1# +b00000000000000000000000001110011 $ +#231 +0# +#232 +1# +b00000000000000000000000001110100 $ +#233 +0# +#234 +1# +b00000000000000000000000001110101 $ +#235 +0# +#236 +1# +b00000000000000000000000001110110 $ +#237 +0# +#238 +1# +b00000000000000000000000001110111 $ +#239 +0# +#240 +1# +b00000000000000000000000001111000 $ +#241 +0# +#242 +1# +b00000000000000000000000001111001 $ +#243 +0# +#244 +1# +b00000000000000000000000001111010 $ +#245 +0# +#246 +1# +b00000000000000000000000001111011 $ +#247 +0# +#248 +1# +b00000000000000000000000001111100 $ +#249 +0# +#250 +1# +b00000000000000000000000001111101 $ +#251 +0# +#252 +1# +b00000000000000000000000001111110 $ +#253 +0# +#254 +1# +b00000000000000000000000001111111 $ +#255 +0# +#256 +1# +b00000000000000000000000010000000 $ +#257 +0# +#258 +1# +b00000000000000000000000010000001 $ +#259 +0# +#260 +1# +b00000000000000000000000010000010 $ +#261 +0# +#262 +1# +b00000000000000000000000010000011 $ +#263 +0# +#264 +1# +b00000000000000000000000010000100 $ +#265 +0# +#266 +1# +b00000000000000000000000010000101 $ +#267 +0# +#268 +1# +b00000000000000000000000010000110 $ +#269 +0# +#270 +1# +b00000000000000000000000010000111 $ +#271 +0# +#272 +1# +b00000000000000000000000010001000 $ +#273 +0# +#274 +1# +b00000000000000000000000010001001 $ +#275 +0# +#276 +1# +b00000000000000000000000010001010 $ +#277 +0# +#278 +1# +b00000000000000000000000010001011 $ +#279 +0# +#280 +1# +b00000000000000000000000010001100 $ +#281 +0# +#282 +1# +b00000000000000000000000010001101 $ +#283 +0# +#284 +1# +b00000000000000000000000010001110 $ +#285 +0# +#286 +1# +b00000000000000000000000010001111 $ +#287 +0# +#288 +1# +b00000000000000000000000010010000 $ +#289 +0# +#290 +1# +b00000000000000000000000010010001 $ +#291 +0# +#292 +1# +b00000000000000000000000010010010 $ +#293 +0# +#294 +1# +b00000000000000000000000010010011 $ +#295 +0# +#296 +1# +b00000000000000000000000010010100 $ +#297 +0# +#298 +1# +b00000000000000000000000010010101 $ +#299 +0# +#300 +1# +b00000000000000000000000010010110 $ +#301 +0# +#302 +1# +b00000000000000000000000010010111 $ +#303 +0# +#304 +1# +b00000000000000000000000010011000 $ +#305 +0# +#306 +1# +b00000000000000000000000010011001 $ +#307 +0# +#308 +1# +b00000000000000000000000010011010 $ +#309 +0# +#310 +1# +b00000000000000000000000010011011 $ +#311 +0# +#312 +1# +b00000000000000000000000010011100 $ +#313 +0# +#314 +1# +b00000000000000000000000010011101 $ +#315 +0# +#316 +1# +b00000000000000000000000010011110 $ +#317 +0# +#318 +1# +b00000000000000000000000010011111 $ +#319 +0# +#320 +1# +b00000000000000000000000010100000 $ +#321 +0# +#322 +1# +b00000000000000000000000010100001 $ +#323 +0# +#324 +1# +b00000000000000000000000010100010 $ +#325 +0# +#326 +1# +b00000000000000000000000010100011 $ +#327 +0# +#328 +1# +b00000000000000000000000010100100 $ +#329 +0# +#330 +1# +b00000000000000000000000010100101 $ +#331 +0# +#332 +1# +b00000000000000000000000010100110 $ +#333 +0# +#334 +1# +b00000000000000000000000010100111 $ +#335 +0# +#336 +1# +b00000000000000000000000010101000 $ +#337 +0# +#338 +1# +b00000000000000000000000010101001 $ +#339 +0# +#340 +1# +b00000000000000000000000010101010 $ +#341 +0# +#342 +1# +b00000000000000000000000010101011 $ +#343 +0# +#344 +1# +b00000000000000000000000010101100 $ +#345 +0# +#346 +1# +b00000000000000000000000010101101 $ +#347 +0# +#348 +1# +b00000000000000000000000010101110 $ +#349 +0# +#350 +1# +b00000000000000000000000010101111 $ +#351 +0# +#352 +1# +b00000000000000000000000010110000 $ +#353 +0# +#354 +1# +b00000000000000000000000010110001 $ +#355 +0# +#356 +1# +b00000000000000000000000010110010 $ +#357 +0# +#358 +1# +b00000000000000000000000010110011 $ +#359 +0# +#360 +1# +b00000000000000000000000010110100 $ +#361 +0# +#362 +1# +b00000000000000000000000010110101 $ +#363 +0# +#364 +1# +b00000000000000000000000010110110 $ +#365 +0# +#366 +1# +b00000000000000000000000010110111 $ +#367 +0# +#368 +1# +b00000000000000000000000010111000 $ +#369 +0# +#370 +1# +b00000000000000000000000010111001 $ +#371 +0# +#372 +1# +b00000000000000000000000010111010 $ +#373 +0# +#374 +1# +b00000000000000000000000010111011 $ +#375 +0# +#376 +1# +b00000000000000000000000010111100 $ +#377 +0# +#378 +1# +b00000000000000000000000010111101 $ +#379 +0# +#380 +1# +b00000000000000000000000010111110 $ +#381 +0# +#382 +1# +b00000000000000000000000010111111 $ +#383 +0# +#384 +1# +b00000000000000000000000011000000 $ +#385 +0# +#386 +1# +b00000000000000000000000011000001 $ +#387 +0# +#388 +1# +b00000000000000000000000011000010 $ +#389 +0# +#390 +1# +b00000000000000000000000011000011 $ +#391 +0# +#392 +1# +b00000000000000000000000011000100 $ +#393 +0# +#394 +1# +b00000000000000000000000011000101 $ +#395 +0# +#396 +1# +b00000000000000000000000011000110 $ +#397 +0# +#398 +1# +b00000000000000000000000011000111 $ +#399 +0# +#400 +1# +b00000000000000000000000011001000 $ +#401 +0# +#402 +1# +b00000000000000000000000011001001 $ +#403 +0# +#404 +1# +b00000000000000000000000011001010 $ +#405 +0# +#406 +1# +b00000000000000000000000011001011 $ +#407 +0# +#408 +1# +b00000000000000000000000011001100 $ +#409 +0# +#410 +1# +b00000000000000000000000011001101 $ +#411 +0# +#412 +1# +b00000000000000000000000011001110 $ +#413 +0# +#414 +1# +b00000000000000000000000011001111 $ +#415 +0# +#416 +1# +b00000000000000000000000011010000 $ +#417 +0# +#418 +1# +b00000000000000000000000011010001 $ +#419 +0# +#420 +1# +b00000000000000000000000011010010 $ +#421 +0# +#422 +1# +b00000000000000000000000011010011 $ +#423 +0# +#424 +1# +b00000000000000000000000011010100 $ +#425 +0# +#426 +1# +b00000000000000000000000011010101 $ +#427 +0# +#428 +1# +b00000000000000000000000011010110 $ +#429 +0# +#430 +1# +b00000000000000000000000011010111 $ +#431 +0# +#432 +1# +b00000000000000000000000011011000 $ +#433 +0# +#434 +1# +b00000000000000000000000011011001 $ +#435 +0# +#436 +1# +b00000000000000000000000011011010 $ +#437 +0# +#438 +1# +b00000000000000000000000011011011 $ +#439 +0# +#440 +1# +b00000000000000000000000011011100 $ +#441 +0# +#442 +1# +b00000000000000000000000011011101 $ +#443 +0# +#444 +1# +b00000000000000000000000011011110 $ +#445 +0# +#446 +1# +b00000000000000000000000011011111 $ +#447 +0# +#448 +1# +b00000000000000000000000011100000 $ +#449 +0# +#450 +1# +b00000000000000000000000011100001 $ +#451 +0# +#452 +1# +b00000000000000000000000011100010 $ +#453 +0# +#454 +1# +b00000000000000000000000011100011 $ +#455 +0# +#456 +1# +b00000000000000000000000011100100 $ +#457 +0# +#458 +1# +b00000000000000000000000011100101 $ +#459 +0# +#460 +1# +b00000000000000000000000011100110 $ +#461 +0# +#462 +1# +b00000000000000000000000011100111 $ +#463 +0# +#464 +1# +b00000000000000000000000011101000 $ +#465 +0# +#466 +1# +b00000000000000000000000011101001 $ +#467 +0# +#468 +1# +b00000000000000000000000011101010 $ +#469 +0# +#470 +1# +b00000000000000000000000011101011 $ +#471 +0# +#472 +1# +b00000000000000000000000011101100 $ +#473 +0# +#474 +1# +b00000000000000000000000011101101 $ +#475 +0# +#476 +1# +b00000000000000000000000011101110 $ +#477 +0# +#478 +1# +b00000000000000000000000011101111 $ +#479 +0# +#480 +1# +b00000000000000000000000011110000 $ +#481 +0# +#482 +1# +b00000000000000000000000011110001 $ +#483 +0# +#484 +1# +b00000000000000000000000011110010 $ +#485 +0# +#486 +1# +b00000000000000000000000011110011 $ +#487 +0# +#488 +1# +b00000000000000000000000011110100 $ +#489 +0# +#490 +1# +b00000000000000000000000011110101 $ +#491 +0# +#492 +1# +b00000000000000000000000011110110 $ +#493 +0# +#494 +1# +b00000000000000000000000011110111 $ +#495 +0# +#496 +1# +b00000000000000000000000011111000 $ +#497 +0# +#498 +1# +b00000000000000000000000011111001 $ +#499 +0# +#500 +1# +b00000000000000000000000011111010 $ +#501 +0# +#502 +1# +b00000000000000000000000011111011 $ +#503 +0# +#504 +1# +b00000000000000000000000011111100 $ +#505 +0# +#506 +1# +b00000000000000000000000011111101 $ +#507 +0# +#508 +1# +b00000000000000000000000011111110 $ +#509 +0# +#510 +1# +b00000000000000000000000011111111 $ +#511 +0# +#512 +1# +b00000000000000000000000100000000 $ +#513 +0# +#514 +1# +b00000000000000000000000100000001 $ +#515 +0# +#516 +1# +b00000000000000000000000100000010 $ +#517 +0# +#518 +1# +b00000000000000000000000100000011 $ +#519 +0# +#520 +1# +b00000000000000000000000100000100 $ +#521 +0# +#522 +1# +b00000000000000000000000100000101 $ +#523 +0# +#524 +1# +b00000000000000000000000100000110 $ +#525 +0# +#526 +1# +b00000000000000000000000100000111 $ +#527 +0# +#528 +1# +b00000000000000000000000100001000 $ +#529 +0# +#530 +1# +b00000000000000000000000100001001 $ +#531 +0# +#532 +1# +b00000000000000000000000100001010 $ +#533 +0# +#534 +1# +b00000000000000000000000100001011 $ +#535 +0# +#536 +1# +b00000000000000000000000100001100 $ +#537 +0# +#538 +1# +b00000000000000000000000100001101 $ +#539 +0# +#540 +1# +b00000000000000000000000100001110 $ +#541 +0# +#542 +1# +b00000000000000000000000100001111 $ +#543 +0# +#544 +1# +b00000000000000000000000100010000 $ +#545 +0# +#546 +1# +b00000000000000000000000100010001 $ +#547 +0# +#548 +1# +b00000000000000000000000100010010 $ +#549 +0# +#550 +1# +b00000000000000000000000100010011 $ +#551 +0# +#552 +1# +b00000000000000000000000100010100 $ +#553 +0# +#554 +1# +b00000000000000000000000100010101 $ +#555 +0# +#556 +1# +b00000000000000000000000100010110 $ +#557 +0# +#558 +1# +b00000000000000000000000100010111 $ +#559 +0# +#560 +1# +b00000000000000000000000100011000 $ +#561 +0# +#562 +1# +b00000000000000000000000100011001 $ +#563 +0# +#564 +1# +b00000000000000000000000100011010 $ +#565 +0# +#566 +1# +b00000000000000000000000100011011 $ +#567 +0# +#568 +1# +b00000000000000000000000100011100 $ +#569 +0# +#570 +1# +b00000000000000000000000100011101 $ +#571 +0# +#572 +1# +b00000000000000000000000100011110 $ +#573 +0# +#574 +1# +b00000000000000000000000100011111 $ +#575 +0# +#576 +1# +b00000000000000000000000100100000 $ +#577 +0# +#578 +1# +b00000000000000000000000100100001 $ +#579 +0# +#580 +1# +b00000000000000000000000100100010 $ +#581 +0# +#582 +1# +b00000000000000000000000100100011 $ +#583 +0# +#584 +1# +b00000000000000000000000100100100 $ +#585 +0# +#586 +1# +b00000000000000000000000100100101 $ +#587 +0# +#588 +1# +b00000000000000000000000100100110 $ +#589 +0# +#590 +1# +b00000000000000000000000100100111 $ +#591 +0# +#592 +1# +b00000000000000000000000100101000 $ +#593 +0# +#594 +1# +b00000000000000000000000100101001 $ +#595 +0# +#596 +1# +b00000000000000000000000100101010 $ +#597 +0# +#598 +1# +b00000000000000000000000100101011 $ +#599 +0# +#600 +1# +b00000000000000000000000100101100 $ +#601 +0# +#602 +1# +b00000000000000000000000100101101 $ +#603 +0# +#604 +1# +b00000000000000000000000100101110 $ +#605 +0# +#606 +1# +b00000000000000000000000100101111 $ +#607 +0# +#608 +1# +b00000000000000000000000100110000 $ +#609 +0# +#610 +1# +b00000000000000000000000100110001 $ +#611 +0# +#612 +1# +b00000000000000000000000100110010 $ +#613 +0# +#614 +1# +b00000000000000000000000100110011 $ +#615 +0# +#616 +1# +b00000000000000000000000100110100 $ +#617 +0# +#618 +1# +b00000000000000000000000100110101 $ +#619 +0# +#620 +1# +b00000000000000000000000100110110 $ +#621 +0# +#622 +1# +b00000000000000000000000100110111 $ +#623 +0# +#624 +1# +b00000000000000000000000100111000 $ +#625 +0# +#626 +1# +b00000000000000000000000100111001 $ +#627 +0# +#628 +1# +b00000000000000000000000100111010 $ +#629 +0# +#630 +1# +b00000000000000000000000100111011 $ +#631 +0# +#632 +1# +b00000000000000000000000100111100 $ +#633 +0# +#634 +1# +b00000000000000000000000100111101 $ +#635 +0# +#636 +1# +b00000000000000000000000100111110 $ +#637 +0# +#638 +1# +b00000000000000000000000100111111 $ +#639 +0# +#640 +1# +b00000000000000000000000101000000 $ +#641 +0# +#642 +1# +b00000000000000000000000101000001 $ +#643 +0# +#644 +1# +b00000000000000000000000101000010 $ +#645 +0# +#646 +1# +b00000000000000000000000101000011 $ +#647 +0# +#648 +1# +b00000000000000000000000101000100 $ +#649 +0# +#650 +1# +b00000000000000000000000101000101 $ +#651 +0# +#652 +1# +b00000000000000000000000101000110 $ +#653 +0# +#654 +1# +b00000000000000000000000101000111 $ +#655 +0# +#656 +1# +b00000000000000000000000101001000 $ +#657 +0# +#658 +1# +b00000000000000000000000101001001 $ +#659 +0# +#660 +1# +b00000000000000000000000101001010 $ +#661 +0# +#662 +1# +b00000000000000000000000101001011 $ +#663 +0# +#664 +1# +b00000000000000000000000101001100 $ +#665 +0# +#666 +1# +b00000000000000000000000101001101 $ +#667 +0# +#668 +1# +b00000000000000000000000101001110 $ +#669 +0# +#670 +1# +b00000000000000000000000101001111 $ +#671 +0# +#672 +1# +b00000000000000000000000101010000 $ +#673 +0# +#674 +1# +b00000000000000000000000101010001 $ +#675 +0# +#676 +1# +b00000000000000000000000101010010 $ +#677 +0# +#678 +1# +b00000000000000000000000101010011 $ +#679 +0# +#680 +1# +b00000000000000000000000101010100 $ +#681 +0# +#682 +1# +b00000000000000000000000101010101 $ +#683 +0# +#684 +1# +b00000000000000000000000101010110 $ +#685 +0# +#686 +1# +b00000000000000000000000101010111 $ +#687 +0# +#688 +1# +b00000000000000000000000101011000 $ +#689 +0# +#690 +1# +b00000000000000000000000101011001 $ +#691 +0# +#692 +1# +b00000000000000000000000101011010 $ +#693 +0# +#694 +1# +b00000000000000000000000101011011 $ +#695 +0# +#696 +1# +b00000000000000000000000101011100 $ +#697 +0# +#698 +1# +b00000000000000000000000101011101 $ +#699 +0# +#700 +1# +b00000000000000000000000101011110 $ +#701 +0# +#702 +1# +b00000000000000000000000101011111 $ +#703 +0# +#704 +1# +b00000000000000000000000101100000 $ +#705 +0# +#706 +1# +b00000000000000000000000101100001 $ +#707 +0# +#708 +1# +b00000000000000000000000101100010 $ +#709 +0# +#710 +1# +b00000000000000000000000101100011 $ +#711 +0# +#712 +1# +b00000000000000000000000101100100 $ +#713 +0# +#714 +1# +b00000000000000000000000101100101 $ +#715 +0# +#716 +1# +b00000000000000000000000101100110 $ +#717 +0# +#718 +1# +b00000000000000000000000101100111 $ +#719 +0# +#720 +1# +b00000000000000000000000101101000 $ +#721 +0# +#722 +1# +b00000000000000000000000101101001 $ +#723 +0# +#724 +1# +b00000000000000000000000101101010 $ +#725 +0# +#726 +1# +b00000000000000000000000101101011 $ +#727 +0# +#728 +1# +b00000000000000000000000101101100 $ +#729 +0# +#730 +1# +b00000000000000000000000101101101 $ +#731 +0# +#732 +1# +b00000000000000000000000101101110 $ +#733 +0# +#734 +1# +b00000000000000000000000101101111 $ +#735 +0# +#736 +1# +b00000000000000000000000101110000 $ +#737 +0# +#738 +1# +b00000000000000000000000101110001 $ +#739 +0# +#740 +1# +b00000000000000000000000101110010 $ +#741 +0# +#742 +1# +b00000000000000000000000101110011 $ +#743 +0# +#744 +1# +b00000000000000000000000101110100 $ +#745 +0# +#746 +1# +b00000000000000000000000101110101 $ +#747 +0# +#748 +1# +b00000000000000000000000101110110 $ +#749 +0# +#750 +1# +b00000000000000000000000101110111 $ +#751 +0# +#752 +1# +b00000000000000000000000101111000 $ +#753 +0# +#754 +1# +b00000000000000000000000101111001 $ +#755 +0# +#756 +1# +b00000000000000000000000101111010 $ +#757 +0# +#758 +1# +b00000000000000000000000101111011 $ +#759 +0# +#760 +1# +b00000000000000000000000101111100 $ +#761 +0# +#762 +1# +b00000000000000000000000101111101 $ +#763 +0# +#764 +1# +b00000000000000000000000101111110 $ +#765 +0# +#766 +1# +b00000000000000000000000101111111 $ +#767 +0# +#768 +1# +b00000000000000000000000110000000 $ +#769 +0# +#770 +1# +b00000000000000000000000110000001 $ +#771 +0# +#772 +1# +b00000000000000000000000110000010 $ +#773 +0# +#774 +1# +b00000000000000000000000110000011 $ +#775 +0# +#776 +1# +b00000000000000000000000110000100 $ +#777 +0# +#778 +1# +b00000000000000000000000110000101 $ +#779 +0# +#780 +1# +b00000000000000000000000110000110 $ +#781 +0# +#782 +1# +b00000000000000000000000110000111 $ +#783 +0# +#784 +1# +b00000000000000000000000110001000 $ +#785 +0# +#786 +1# +b00000000000000000000000110001001 $ +#787 +0# +#788 +1# +b00000000000000000000000110001010 $ +#789 +0# +#790 +1# +b00000000000000000000000110001011 $ +#791 +0# +#792 +1# +b00000000000000000000000110001100 $ +#793 +0# +#794 +1# +b00000000000000000000000110001101 $ +#795 +0# +#796 +1# +b00000000000000000000000110001110 $ +#797 +0# +#798 +1# +b00000000000000000000000110001111 $ +#799 +0# +#800 +1# +b00000000000000000000000110010000 $ +#801 +0# +#802 +1# +b00000000000000000000000110010001 $ +#803 +0# +#804 +1# +b00000000000000000000000110010010 $ +#805 +0# +#806 +1# +b00000000000000000000000110010011 $ +#807 +0# +#808 +1# +b00000000000000000000000110010100 $ +#809 +0# +#810 +1# +b00000000000000000000000110010101 $ +#811 +0# +#812 +1# +b00000000000000000000000110010110 $ +#813 +0# +#814 +1# +b00000000000000000000000110010111 $ +#815 +0# +#816 +1# +b00000000000000000000000110011000 $ +#817 +0# +#818 +1# +b00000000000000000000000110011001 $ +#819 +0# +#820 +1# +b00000000000000000000000110011010 $ +#821 +0# +#822 +1# +b00000000000000000000000110011011 $ +#823 +0# +#824 +1# +b00000000000000000000000110011100 $ +#825 +0# +#826 +1# +b00000000000000000000000110011101 $ +#827 +0# +#828 +1# +b00000000000000000000000110011110 $ +#829 +0# +#830 +1# +b00000000000000000000000110011111 $ +#831 +0# +#832 +1# +b00000000000000000000000110100000 $ +#833 +0# +#834 +1# +b00000000000000000000000110100001 $ +#835 +0# +#836 +1# +b00000000000000000000000110100010 $ +#837 +0# +#838 +1# +b00000000000000000000000110100011 $ +#839 +0# +#840 +1# +b00000000000000000000000110100100 $ +#841 +0# +#842 +1# +b00000000000000000000000110100101 $ +#843 +0# +#844 +1# +b00000000000000000000000110100110 $ +#845 +0# +#846 +1# +b00000000000000000000000110100111 $ +#847 +0# +#848 +1# +b00000000000000000000000110101000 $ +#849 +0# +#850 +1# +b00000000000000000000000110101001 $ +#851 +0# +#852 +1# +b00000000000000000000000110101010 $ +#853 +0# +#854 +1# +b00000000000000000000000110101011 $ +#855 +0# +#856 +1# +b00000000000000000000000110101100 $ +#857 +0# +#858 +1# +b00000000000000000000000110101101 $ +#859 +0# +#860 +1# +b00000000000000000000000110101110 $ +#861 +0# +#862 +1# +b00000000000000000000000110101111 $ +#863 +0# +#864 +1# +b00000000000000000000000110110000 $ +#865 +0# +#866 +1# +b00000000000000000000000110110001 $ +#867 +0# +#868 +1# +b00000000000000000000000110110010 $ +#869 +0# +#870 +1# +b00000000000000000000000110110011 $ +#871 +0# +#872 +1# +b00000000000000000000000110110100 $ +#873 +0# +#874 +1# +b00000000000000000000000110110101 $ +#875 +0# +#876 +1# +b00000000000000000000000110110110 $ +#877 +0# +#878 +1# +b00000000000000000000000110110111 $ +#879 +0# +#880 +1# +b00000000000000000000000110111000 $ +#881 +0# +#882 +1# +b00000000000000000000000110111001 $ +#883 +0# +#884 +1# +b00000000000000000000000110111010 $ +#885 +0# +#886 +1# +b00000000000000000000000110111011 $ +#887 +0# +#888 +1# +b00000000000000000000000110111100 $ +#889 +0# +#890 +1# +b00000000000000000000000110111101 $ +#891 +0# +#892 +1# +b00000000000000000000000110111110 $ +#893 +0# +#894 +1# +b00000000000000000000000110111111 $ +#895 +0# +#896 +1# +b00000000000000000000000111000000 $ +#897 +0# +#898 +1# +b00000000000000000000000111000001 $ +#899 +0# +#900 +1# +b00000000000000000000000111000010 $ +#901 +0# +#902 +1# +b00000000000000000000000111000011 $ +#903 +0# +#904 +1# +b00000000000000000000000111000100 $ +#905 +0# +#906 +1# +b00000000000000000000000111000101 $ +#907 +0# +#908 +1# +b00000000000000000000000111000110 $ +#909 +0# +#910 +1# +b00000000000000000000000111000111 $ +#911 +0# +#912 +1# +b00000000000000000000000111001000 $ +#913 +0# +#914 +1# +b00000000000000000000000111001001 $ +#915 +0# +#916 +1# +b00000000000000000000000111001010 $ +#917 +0# +#918 +1# +b00000000000000000000000111001011 $ +#919 +0# +#920 +1# +b00000000000000000000000111001100 $ +#921 +0# +#922 +1# +b00000000000000000000000111001101 $ +#923 +0# +#924 +1# +b00000000000000000000000111001110 $ +#925 +0# +#926 +1# +b00000000000000000000000111001111 $ +#927 +0# +#928 +1# +b00000000000000000000000111010000 $ +#929 +0# +#930 +1# +b00000000000000000000000111010001 $ +#931 +0# +#932 +1# +b00000000000000000000000111010010 $ +#933 +0# +#934 +1# +b00000000000000000000000111010011 $ +#935 +0# +#936 +1# +b00000000000000000000000111010100 $ +#937 +0# +#938 +1# +b00000000000000000000000111010101 $ +#939 +0# +#940 +1# +b00000000000000000000000111010110 $ +#941 +0# +#942 +1# +b00000000000000000000000111010111 $ +#943 +0# +#944 +1# +b00000000000000000000000111011000 $ +#945 +0# +#946 +1# +b00000000000000000000000111011001 $ +#947 +0# +#948 +1# +b00000000000000000000000111011010 $ +#949 +0# +#950 +1# +b00000000000000000000000111011011 $ +#951 +0# +#952 +1# +b00000000000000000000000111011100 $ +#953 +0# +#954 +1# +b00000000000000000000000111011101 $ +#955 +0# +#956 +1# +b00000000000000000000000111011110 $ +#957 +0# +#958 +1# +b00000000000000000000000111011111 $ +#959 +0# +#960 +1# +b00000000000000000000000111100000 $ +#961 +0# +#962 +1# +b00000000000000000000000111100001 $ +#963 +0# +#964 +1# +b00000000000000000000000111100010 $ +#965 +0# +#966 +1# +b00000000000000000000000111100011 $ +#967 +0# +#968 +1# +b00000000000000000000000111100100 $ +#969 +0# +#970 +1# +b00000000000000000000000111100101 $ +#971 +0# +#972 +1# +b00000000000000000000000111100110 $ +#973 +0# +#974 +1# +b00000000000000000000000111100111 $ +#975 +0# +#976 +1# +b00000000000000000000000111101000 $ +#977 +0# +#978 +1# +b00000000000000000000000111101001 $ +#979 +0# +#980 +1# +b00000000000000000000000111101010 $ +#981 +0# +#982 +1# +b00000000000000000000000111101011 $ +#983 +0# +#984 +1# +b00000000000000000000000111101100 $ +#985 +0# +#986 +1# +b00000000000000000000000111101101 $ +#987 +0# +#988 +1# +b00000000000000000000000111101110 $ +#989 +0# +#990 +1# +b00000000000000000000000111101111 $ +#991 +0# +#992 +1# +b00000000000000000000000111110000 $ +#993 +0# +#994 +1# +b00000000000000000000000111110001 $ +#995 +0# +#996 +1# +b00000000000000000000000111110010 $ +#997 +0# +#998 +1# +b00000000000000000000000111110011 $ +#999 +0# +#1000 +1# +b00000000000000000000000111110100 $ +#1001 +0# +#1002 +1# +b00000000000000000000000111110101 $ +#1003 +0# +#1004 +1# +b00000000000000000000000111110110 $ +#1005 +0# +#1006 +1# +b00000000000000000000000111110111 $ +#1007 +0# +#1008 +1# +b00000000000000000000000111111000 $ +#1009 +0# +#1010 +1# +b00000000000000000000000111111001 $ +#1011 +0# +#1012 +1# +b00000000000000000000000111111010 $ +#1013 +0# +#1014 +1# +b00000000000000000000000111111011 $ +#1015 +0# +#1016 +1# +b00000000000000000000000111111100 $ +#1017 +0# +#1018 +1# +b00000000000000000000000111111101 $ +#1019 +0# +#1020 +1# +b00000000000000000000000111111110 $ +#1021 +0# +#1022 +1# +b00000000000000000000000111111111 $ +#1023 +0# +#1024 +1# +b00000000000000000000001000000000 $ +#1025 +0# +#1026 +1# +b00000000000000000000001000000001 $ +#1027 +0# +#1028 +1# +b00000000000000000000001000000010 $ +#1029 +0# +#1030 +1# +b00000000000000000000001000000011 $ +#1031 +0# +#1032 +1# +b00000000000000000000001000000100 $ +#1033 +0# +#1034 +1# +b00000000000000000000001000000101 $ +#1035 +0# +#1036 +1# +b00000000000000000000001000000110 $ +#1037 +0# +#1038 +1# +b00000000000000000000001000000111 $ +#1039 +0# +#1040 +1# +b00000000000000000000001000001000 $ +#1041 +0# +#1042 +1# +b00000000000000000000001000001001 $ +#1043 +0# +#1044 +1# +b00000000000000000000001000001010 $ +#1045 +0# +#1046 +1# +b00000000000000000000001000001011 $ +#1047 +0# +#1048 +1# +b00000000000000000000001000001100 $ +#1049 +0# +#1050 +1# +b00000000000000000000001000001101 $ +#1051 +0# +#1052 +1# +b00000000000000000000001000001110 $ +#1053 +0# +#1054 +1# +b00000000000000000000001000001111 $ +#1055 +0# +#1056 +1# +b00000000000000000000001000010000 $ +#1057 +0# +#1058 +1# +b00000000000000000000001000010001 $ +#1059 +0# +#1060 +1# +b00000000000000000000001000010010 $ +#1061 +0# +#1062 +1# +b00000000000000000000001000010011 $ +#1063 +0# +#1064 +1# +b00000000000000000000001000010100 $ +#1065 +0# +#1066 +1# +b00000000000000000000001000010101 $ +#1067 +0# +#1068 +1# +b00000000000000000000001000010110 $ +#1069 +0# +#1070 +1# +b00000000000000000000001000010111 $ +#1071 +0# +#1072 +1# +b00000000000000000000001000011000 $ +#1073 +0# +#1074 +1# +b00000000000000000000001000011001 $ +#1075 +0# +#1076 +1# +b00000000000000000000001000011010 $ +#1077 +0# +#1078 +1# +b00000000000000000000001000011011 $ +#1079 +0# +#1080 +1# +b00000000000000000000001000011100 $ +#1081 +0# +#1082 +1# +b00000000000000000000001000011101 $ +#1083 +0# +#1084 +1# +b00000000000000000000001000011110 $ +#1085 +0# +#1086 +1# +b00000000000000000000001000011111 $ +#1087 +0# +#1088 +1# +b00000000000000000000001000100000 $ +#1089 +0# +#1090 +1# +b00000000000000000000001000100001 $ +#1091 +0# +#1092 +1# +b00000000000000000000001000100010 $ +#1093 +0# +#1094 +1# +b00000000000000000000001000100011 $ +#1095 +0# +#1096 +1# +b00000000000000000000001000100100 $ +#1097 +0# +#1098 +1# +b00000000000000000000001000100101 $ +#1099 +0# +#1100 +1# +b00000000000000000000001000100110 $ +#1101 +0# +#1102 +1# +b00000000000000000000001000100111 $ +#1103 +0# +#1104 +1# +b00000000000000000000001000101000 $ +#1105 +0# +#1106 +1# +b00000000000000000000001000101001 $ +#1107 +0# +#1108 +1# +b00000000000000000000001000101010 $ +#1109 +0# +#1110 +1# +b00000000000000000000001000101011 $ +#1111 +0# +#1112 +1# +b00000000000000000000001000101100 $ +#1113 +0# +#1114 +1# +b00000000000000000000001000101101 $ +#1115 +0# +#1116 +1# +b00000000000000000000001000101110 $ +#1117 +0# +#1118 +1# +b00000000000000000000001000101111 $ +#1119 +0# +#1120 +1# +b00000000000000000000001000110000 $ +#1121 +0# +#1122 +1# +b00000000000000000000001000110001 $ +#1123 +0# +#1124 +1# +b00000000000000000000001000110010 $ +#1125 +0# +#1126 +1# +b00000000000000000000001000110011 $ +#1127 +0# +#1128 +1# +b00000000000000000000001000110100 $ +#1129 +0# +#1130 +1# +b00000000000000000000001000110101 $ +#1131 +0# +#1132 +1# +b00000000000000000000001000110110 $ +#1133 +0# +#1134 +1# +b00000000000000000000001000110111 $ +#1135 +0# +#1136 +1# +b00000000000000000000001000111000 $ +#1137 +0# +#1138 +1# +b00000000000000000000001000111001 $ +#1139 +0# +#1140 +1# +b00000000000000000000001000111010 $ +#1141 +0# +#1142 +1# +b00000000000000000000001000111011 $ +#1143 +0# +#1144 +1# +b00000000000000000000001000111100 $ +#1145 +0# +#1146 +1# +b00000000000000000000001000111101 $ +#1147 +0# +#1148 +1# +b00000000000000000000001000111110 $ +#1149 +0# +#1150 +1# +b00000000000000000000001000111111 $ +#1151 +0# +#1152 +1# +b00000000000000000000001001000000 $ +#1153 +0# +#1154 +1# +b00000000000000000000001001000001 $ +#1155 +0# +#1156 +1# +b00000000000000000000001001000010 $ +#1157 +0# +#1158 +1# +b00000000000000000000001001000011 $ +#1159 +0# +#1160 +1# +b00000000000000000000001001000100 $ +#1161 +0# +#1162 +1# +b00000000000000000000001001000101 $ +#1163 +0# +#1164 +1# +b00000000000000000000001001000110 $ +#1165 +0# +#1166 +1# +b00000000000000000000001001000111 $ +#1167 +0# +#1168 +1# +b00000000000000000000001001001000 $ +#1169 +0# +#1170 +1# +b00000000000000000000001001001001 $ +#1171 +0# +#1172 +1# +b00000000000000000000001001001010 $ +#1173 +0# +#1174 +1# +b00000000000000000000001001001011 $ +#1175 +0# +#1176 +1# +b00000000000000000000001001001100 $ +#1177 +0# +#1178 +1# +b00000000000000000000001001001101 $ +#1179 +0# +#1180 +1# +b00000000000000000000001001001110 $ +#1181 +0# +#1182 +1# +b00000000000000000000001001001111 $ +#1183 +0# +#1184 +1# +b00000000000000000000001001010000 $ +#1185 +0# +#1186 +1# +b00000000000000000000001001010001 $ +#1187 +0# +#1188 +1# +b00000000000000000000001001010010 $ +#1189 +0# +#1190 +1# +b00000000000000000000001001010011 $ +#1191 +0# +#1192 +1# +b00000000000000000000001001010100 $ +#1193 +0# +#1194 +1# +b00000000000000000000001001010101 $ +#1195 +0# +#1196 +1# +b00000000000000000000001001010110 $ +#1197 +0# +#1198 +1# +b00000000000000000000001001010111 $ +#1199 +0# +#1200 +1# +b00000000000000000000001001011000 $ +#1201 +0# +#1202 +1# +b00000000000000000000001001011001 $ +#1203 +0# +#1204 +1# +b00000000000000000000001001011010 $ +#1205 +0# +#1206 +1# +b00000000000000000000001001011011 $ +#1207 +0# +#1208 +1# +b00000000000000000000001001011100 $ +#1209 +0# +#1210 +1# +b00000000000000000000001001011101 $ +#1211 +0# +#1212 +1# +b00000000000000000000001001011110 $ +#1213 +0# +#1214 +1# +b00000000000000000000001001011111 $ +#1215 +0# +#1216 +1# +b00000000000000000000001001100000 $ +#1217 +0# +#1218 +1# +b00000000000000000000001001100001 $ +#1219 +0# +#1220 +1# +b00000000000000000000001001100010 $ +#1221 +0# +#1222 +1# +b00000000000000000000001001100011 $ +#1223 +0# +#1224 +1# +b00000000000000000000001001100100 $ +#1225 +0# +#1226 +1# +b00000000000000000000001001100101 $ +#1227 +0# +#1228 +1# +b00000000000000000000001001100110 $ +#1229 +0# +#1230 +1# +b00000000000000000000001001100111 $ +#1231 +0# +#1232 +1# +b00000000000000000000001001101000 $ +#1233 +0# +#1234 +1# +b00000000000000000000001001101001 $ +#1235 +0# +#1236 +1# +b00000000000000000000001001101010 $ +#1237 +0# +#1238 +1# +b00000000000000000000001001101011 $ +#1239 +0# +#1240 +1# +b00000000000000000000001001101100 $ +#1241 +0# +#1242 +1# +b00000000000000000000001001101101 $ +#1243 +0# +#1244 +1# +b00000000000000000000001001101110 $ +#1245 +0# +#1246 +1# +b00000000000000000000001001101111 $ +#1247 +0# +#1248 +1# +b00000000000000000000001001110000 $ +#1249 +0# +#1250 +1# +b00000000000000000000001001110001 $ +#1251 +0# +#1252 +1# +b00000000000000000000001001110010 $ +#1253 +0# +#1254 +1# +b00000000000000000000001001110011 $ +#1255 +0# +#1256 +1# +b00000000000000000000001001110100 $ +#1257 +0# +#1258 +1# +b00000000000000000000001001110101 $ +#1259 +0# +#1260 +1# +b00000000000000000000001001110110 $ +#1261 +0# +#1262 +1# +b00000000000000000000001001110111 $ +#1263 +0# +#1264 +1# +b00000000000000000000001001111000 $ +#1265 +0# +#1266 +1# +b00000000000000000000001001111001 $ +#1267 +0# +#1268 +1# +b00000000000000000000001001111010 $ +#1269 +0# +#1270 +1# +b00000000000000000000001001111011 $ +#1271 +0# +#1272 +1# +b00000000000000000000001001111100 $ +#1273 +0# +#1274 +1# +b00000000000000000000001001111101 $ +#1275 +0# +#1276 +1# +b00000000000000000000001001111110 $ +#1277 +0# +#1278 +1# +b00000000000000000000001001111111 $ +#1279 +0# +#1280 +1# +b00000000000000000000001010000000 $ +#1281 +0# +#1282 +1# +b00000000000000000000001010000001 $ +#1283 +0# +#1284 +1# +b00000000000000000000001010000010 $ +#1285 +0# +#1286 +1# +b00000000000000000000001010000011 $ +#1287 +0# +#1288 +1# +b00000000000000000000001010000100 $ +#1289 +0# +#1290 +1# +b00000000000000000000001010000101 $ +#1291 +0# +#1292 +1# +b00000000000000000000001010000110 $ +#1293 +0# +#1294 +1# +b00000000000000000000001010000111 $ +#1295 +0# +#1296 +1# +b00000000000000000000001010001000 $ +#1297 +0# +#1298 +1# +b00000000000000000000001010001001 $ +#1299 +0# +#1300 +1# +b00000000000000000000001010001010 $ +#1301 +0# +#1302 +1# +b00000000000000000000001010001011 $ +#1303 +0# +#1304 +1# +b00000000000000000000001010001100 $ +#1305 +0# +#1306 +1# +b00000000000000000000001010001101 $ +#1307 +0# +#1308 +1# +b00000000000000000000001010001110 $ +#1309 +0# +#1310 +1# +b00000000000000000000001010001111 $ +#1311 +0# +#1312 +1# +b00000000000000000000001010010000 $ +#1313 +0# +#1314 +1# +b00000000000000000000001010010001 $ +#1315 +0# +#1316 +1# +b00000000000000000000001010010010 $ +#1317 +0# +#1318 +1# +b00000000000000000000001010010011 $ +#1319 +0# +#1320 +1# +b00000000000000000000001010010100 $ +#1321 +0# +#1322 +1# +b00000000000000000000001010010101 $ +#1323 +0# +#1324 +1# +b00000000000000000000001010010110 $ +#1325 +0# +#1326 +1# +b00000000000000000000001010010111 $ +#1327 +0# +#1328 +1# +b00000000000000000000001010011000 $ +#1329 +0# +#1330 +1# +b00000000000000000000001010011001 $ +#1331 +0# +#1332 +1# +b00000000000000000000001010011010 $ +#1333 +0# +#1334 +1# +b00000000000000000000001010011011 $ +#1335 +0# +#1336 +1# +b00000000000000000000001010011100 $ +#1337 +0# +#1338 +1# +b00000000000000000000001010011101 $ +#1339 +0# +#1340 +1# +b00000000000000000000001010011110 $ +#1341 +0# +#1342 +1# +b00000000000000000000001010011111 $ +#1343 +0# +#1344 +1# +b00000000000000000000001010100000 $ +#1345 +0# +#1346 +1# +b00000000000000000000001010100001 $ +#1347 +0# +#1348 +1# +b00000000000000000000001010100010 $ +#1349 +0# +#1350 +1# +b00000000000000000000001010100011 $ +#1351 +0# +#1352 +1# +b00000000000000000000001010100100 $ +#1353 +0# +#1354 +1# +b00000000000000000000001010100101 $ +#1355 +0# +#1356 +1# +b00000000000000000000001010100110 $ +#1357 +0# +#1358 +1# +b00000000000000000000001010100111 $ +#1359 +0# +#1360 +1# +b00000000000000000000001010101000 $ +#1361 +0# +#1362 +1# +b00000000000000000000001010101001 $ +#1363 +0# +#1364 +1# +b00000000000000000000001010101010 $ +#1365 +0# +#1366 +1# +b00000000000000000000001010101011 $ +#1367 +0# +#1368 +1# +b00000000000000000000001010101100 $ +#1369 +0# +#1370 +1# +b00000000000000000000001010101101 $ +#1371 +0# +#1372 +1# +b00000000000000000000001010101110 $ +#1373 +0# +#1374 +1# +b00000000000000000000001010101111 $ +#1375 +0# +#1376 +1# +b00000000000000000000001010110000 $ +#1377 +0# +#1378 +1# +b00000000000000000000001010110001 $ +#1379 +0# +#1380 +1# +b00000000000000000000001010110010 $ +#1381 +0# +#1382 +1# +b00000000000000000000001010110011 $ +#1383 +0# +#1384 +1# +b00000000000000000000001010110100 $ +#1385 +0# +#1386 +1# +b00000000000000000000001010110101 $ +#1387 +0# +#1388 +1# +b00000000000000000000001010110110 $ +#1389 +0# +#1390 +1# +b00000000000000000000001010110111 $ +#1391 +0# +#1392 +1# +b00000000000000000000001010111000 $ +#1393 +0# +#1394 +1# +b00000000000000000000001010111001 $ +#1395 +0# +#1396 +1# +b00000000000000000000001010111010 $ +#1397 +0# +#1398 +1# +b00000000000000000000001010111011 $ +#1399 +0# +#1400 +1# +b00000000000000000000001010111100 $ +#1401 +0# +#1402 +1# +b00000000000000000000001010111101 $ +#1403 +0# +#1404 +1# +b00000000000000000000001010111110 $ +#1405 +0# +#1406 +1# +b00000000000000000000001010111111 $ +#1407 +0# +#1408 +1# +b00000000000000000000001011000000 $ +#1409 +0# +#1410 +1# +b00000000000000000000001011000001 $ +#1411 +0# +#1412 +1# +b00000000000000000000001011000010 $ +#1413 +0# +#1414 +1# +b00000000000000000000001011000011 $ +#1415 +0# +#1416 +1# +b00000000000000000000001011000100 $ +#1417 +0# +#1418 +1# +b00000000000000000000001011000101 $ +#1419 +0# +#1420 +1# +b00000000000000000000001011000110 $ +#1421 +0# +#1422 +1# +b00000000000000000000001011000111 $ +#1423 +0# +#1424 +1# +b00000000000000000000001011001000 $ +#1425 +0# +#1426 +1# +b00000000000000000000001011001001 $ +#1427 +0# +#1428 +1# +b00000000000000000000001011001010 $ +#1429 +0# +#1430 +1# +b00000000000000000000001011001011 $ +#1431 +0# +#1432 +1# +b00000000000000000000001011001100 $ +#1433 +0# +#1434 +1# +b00000000000000000000001011001101 $ +#1435 +0# +#1436 +1# +b00000000000000000000001011001110 $ +#1437 +0# +#1438 +1# +b00000000000000000000001011001111 $ +#1439 +0# +#1440 +1# +b00000000000000000000001011010000 $ +#1441 +0# +#1442 +1# +b00000000000000000000001011010001 $ +#1443 +0# +#1444 +1# +b00000000000000000000001011010010 $ +#1445 +0# +#1446 +1# +b00000000000000000000001011010011 $ +#1447 +0# +#1448 +1# +b00000000000000000000001011010100 $ +#1449 +0# +#1450 +1# +b00000000000000000000001011010101 $ +#1451 +0# +#1452 +1# +b00000000000000000000001011010110 $ +#1453 +0# +#1454 +1# +b00000000000000000000001011010111 $ +#1455 +0# +#1456 +1# +b00000000000000000000001011011000 $ +#1457 +0# +#1458 +1# +b00000000000000000000001011011001 $ +#1459 +0# +#1460 +1# +b00000000000000000000001011011010 $ +#1461 +0# +#1462 +1# +b00000000000000000000001011011011 $ +#1463 +0# +#1464 +1# +b00000000000000000000001011011100 $ +#1465 +0# +#1466 +1# +b00000000000000000000001011011101 $ +#1467 +0# +#1468 +1# +b00000000000000000000001011011110 $ +#1469 +0# +#1470 +1# +b00000000000000000000001011011111 $ +#1471 +0# +#1472 +1# +b00000000000000000000001011100000 $ +#1473 +0# +#1474 +1# +b00000000000000000000001011100001 $ +#1475 +0# +#1476 +1# +b00000000000000000000001011100010 $ +#1477 +0# +#1478 +1# +b00000000000000000000001011100011 $ +#1479 +0# +#1480 +1# +b00000000000000000000001011100100 $ +#1481 +0# +#1482 +1# +b00000000000000000000001011100101 $ +#1483 +0# +#1484 +1# +b00000000000000000000001011100110 $ +#1485 +0# +#1486 +1# +b00000000000000000000001011100111 $ +#1487 +0# +#1488 +1# +b00000000000000000000001011101000 $ +#1489 +0# +#1490 +1# +b00000000000000000000001011101001 $ +#1491 +0# +#1492 +1# +b00000000000000000000001011101010 $ +#1493 +0# +#1494 +1# +b00000000000000000000001011101011 $ +#1495 +0# +#1496 +1# +b00000000000000000000001011101100 $ +#1497 +0# +#1498 +1# +b00000000000000000000001011101101 $ +#1499 +0# +#1500 +1# +b00000000000000000000001011101110 $ +#1501 +0# +#1502 +1# +b00000000000000000000001011101111 $ +#1503 +0# +#1504 +1# +b00000000000000000000001011110000 $ +#1505 +0# +#1506 +1# +b00000000000000000000001011110001 $ +#1507 +0# +#1508 +1# +b00000000000000000000001011110010 $ +#1509 +0# +#1510 +1# +b00000000000000000000001011110011 $ +#1511 +0# +#1512 +1# +b00000000000000000000001011110100 $ +#1513 +0# +#1514 +1# +b00000000000000000000001011110101 $ +#1515 +0# +#1516 +1# +b00000000000000000000001011110110 $ +#1517 +0# +#1518 +1# +b00000000000000000000001011110111 $ +#1519 +0# +#1520 +1# +b00000000000000000000001011111000 $ +#1521 +0# +#1522 +1# +b00000000000000000000001011111001 $ +#1523 +0# +#1524 +1# +b00000000000000000000001011111010 $ +#1525 +0# +#1526 +1# +b00000000000000000000001011111011 $ +#1527 +0# +#1528 +1# +b00000000000000000000001011111100 $ +#1529 +0# +#1530 +1# +b00000000000000000000001011111101 $ +#1531 +0# +#1532 +1# +b00000000000000000000001011111110 $ +#1533 +0# +#1534 +1# +b00000000000000000000001011111111 $ +#1535 +0# +#1536 +1# +b00000000000000000000001100000000 $ +#1537 +0# +#1538 +1# +b00000000000000000000001100000001 $ +#1539 +0# +#1540 +1# +b00000000000000000000001100000010 $ +#1541 +0# +#1542 +1# +b00000000000000000000001100000011 $ +#1543 +0# +#1544 +1# +b00000000000000000000001100000100 $ +#1545 +0# +#1546 +1# +b00000000000000000000001100000101 $ +#1547 +0# +#1548 +1# +b00000000000000000000001100000110 $ +#1549 +0# +#1550 +1# +b00000000000000000000001100000111 $ +#1551 +0# +#1552 +1# +b00000000000000000000001100001000 $ +#1553 +0# +#1554 +1# +b00000000000000000000001100001001 $ +#1555 +0# +#1556 +1# +b00000000000000000000001100001010 $ +#1557 +0# +#1558 +1# +b00000000000000000000001100001011 $ +#1559 +0# +#1560 +1# +b00000000000000000000001100001100 $ +#1561 +0# +#1562 +1# +b00000000000000000000001100001101 $ +#1563 +0# +#1564 +1# +b00000000000000000000001100001110 $ +#1565 +0# +#1566 +1# +b00000000000000000000001100001111 $ +#1567 +0# +#1568 +1# +b00000000000000000000001100010000 $ +#1569 +0# +#1570 +1# +b00000000000000000000001100010001 $ +#1571 +0# +#1572 +1# +b00000000000000000000001100010010 $ +#1573 +0# +#1574 +1# +b00000000000000000000001100010011 $ +#1575 +0# +#1576 +1# +b00000000000000000000001100010100 $ +#1577 +0# +#1578 +1# +b00000000000000000000001100010101 $ +#1579 +0# +#1580 +1# +b00000000000000000000001100010110 $ +#1581 +0# +#1582 +1# +b00000000000000000000001100010111 $ +#1583 +0# +#1584 +1# +b00000000000000000000001100011000 $ +#1585 +0# +#1586 +1# +b00000000000000000000001100011001 $ +#1587 +0# +#1588 +1# +b00000000000000000000001100011010 $ +#1589 +0# +#1590 +1# +b00000000000000000000001100011011 $ +#1591 +0# +#1592 +1# +b00000000000000000000001100011100 $ +#1593 +0# +#1594 +1# +b00000000000000000000001100011101 $ +#1595 +0# +#1596 +1# +b00000000000000000000001100011110 $ +#1597 +0# +#1598 +1# +b00000000000000000000001100011111 $ +#1599 +0# +#1600 +1# +b00000000000000000000001100100000 $ +#1601 +0# +#1602 +1# +b00000000000000000000001100100001 $ +#1603 +0# +#1604 +1# +b00000000000000000000001100100010 $ +#1605 +0# +#1606 +1# +b00000000000000000000001100100011 $ +#1607 +0# +#1608 +1# +b00000000000000000000001100100100 $ +#1609 +0# +#1610 +1# +b00000000000000000000001100100101 $ +#1611 +0# +#1612 +1# +b00000000000000000000001100100110 $ +#1613 +0# +#1614 +1# +b00000000000000000000001100100111 $ +#1615 +0# +#1616 +1# +b00000000000000000000001100101000 $ +#1617 +0# +#1618 +1# +b00000000000000000000001100101001 $ +#1619 +0# +#1620 +1# +b00000000000000000000001100101010 $ +#1621 +0# +#1622 +1# +b00000000000000000000001100101011 $ +#1623 +0# +#1624 +1# +b00000000000000000000001100101100 $ +#1625 +0# +#1626 +1# +b00000000000000000000001100101101 $ +#1627 +0# +#1628 +1# +b00000000000000000000001100101110 $ +#1629 +0# +#1630 +1# +b00000000000000000000001100101111 $ +#1631 +0# +#1632 +1# +b00000000000000000000001100110000 $ +#1633 +0# +#1634 +1# +b00000000000000000000001100110001 $ +#1635 +0# +#1636 +1# +b00000000000000000000001100110010 $ +#1637 +0# +#1638 +1# +b00000000000000000000001100110011 $ +#1639 +0# +#1640 +1# +b00000000000000000000001100110100 $ +#1641 +0# +#1642 +1# +b00000000000000000000001100110101 $ +#1643 +0# +#1644 +1# +b00000000000000000000001100110110 $ +#1645 +0# +#1646 +1# +b00000000000000000000001100110111 $ +#1647 +0# +#1648 +1# +b00000000000000000000001100111000 $ +#1649 +0# +#1650 +1# +b00000000000000000000001100111001 $ +#1651 +0# +#1652 +1# +b00000000000000000000001100111010 $ +#1653 +0# +#1654 +1# +b00000000000000000000001100111011 $ +#1655 +0# +#1656 +1# +b00000000000000000000001100111100 $ +#1657 +0# +#1658 +1# +b00000000000000000000001100111101 $ +#1659 +0# +#1660 +1# +b00000000000000000000001100111110 $ +#1661 +0# +#1662 +1# +b00000000000000000000001100111111 $ +#1663 +0# +#1664 +1# +b00000000000000000000001101000000 $ +#1665 +0# +#1666 +1# +b00000000000000000000001101000001 $ +#1667 +0# +#1668 +1# +b00000000000000000000001101000010 $ +#1669 +0# +#1670 +1# +b00000000000000000000001101000011 $ +#1671 +0# +#1672 +1# +b00000000000000000000001101000100 $ +#1673 +0# +#1674 +1# +b00000000000000000000001101000101 $ +#1675 +0# +#1676 +1# +b00000000000000000000001101000110 $ +#1677 +0# +#1678 +1# +b00000000000000000000001101000111 $ +#1679 +0# +#1680 +1# +b00000000000000000000001101001000 $ +#1681 +0# +#1682 +1# +b00000000000000000000001101001001 $ +#1683 +0# +#1684 +1# +b00000000000000000000001101001010 $ +#1685 +0# +#1686 +1# +b00000000000000000000001101001011 $ +#1687 +0# +#1688 +1# +b00000000000000000000001101001100 $ +#1689 +0# +#1690 +1# +b00000000000000000000001101001101 $ +#1691 +0# +#1692 +1# +b00000000000000000000001101001110 $ +#1693 +0# +#1694 +1# +b00000000000000000000001101001111 $ +#1695 +0# +#1696 +1# +b00000000000000000000001101010000 $ +#1697 +0# +#1698 +1# +b00000000000000000000001101010001 $ +#1699 +0# +#1700 +1# +b00000000000000000000001101010010 $ +#1701 +0# +#1702 +1# +b00000000000000000000001101010011 $ +#1703 +0# +#1704 +1# +b00000000000000000000001101010100 $ +#1705 +0# +#1706 +1# +b00000000000000000000001101010101 $ +#1707 +0# +#1708 +1# +b00000000000000000000001101010110 $ +#1709 +0# +#1710 +1# +b00000000000000000000001101010111 $ +#1711 +0# +#1712 +1# +b00000000000000000000001101011000 $ +#1713 +0# +#1714 +1# +b00000000000000000000001101011001 $ +#1715 +0# +#1716 +1# +b00000000000000000000001101011010 $ +#1717 +0# +#1718 +1# +b00000000000000000000001101011011 $ +#1719 +0# +#1720 +1# +b00000000000000000000001101011100 $ +#1721 +0# +#1722 +1# +b00000000000000000000001101011101 $ +#1723 +0# +#1724 +1# +b00000000000000000000001101011110 $ +#1725 +0# +#1726 +1# +b00000000000000000000001101011111 $ +#1727 +0# +#1728 +1# +b00000000000000000000001101100000 $ +#1729 +0# +#1730 +1# +b00000000000000000000001101100001 $ +#1731 +0# +#1732 +1# +b00000000000000000000001101100010 $ +#1733 +0# +#1734 +1# +b00000000000000000000001101100011 $ +#1735 +0# +#1736 +1# +b00000000000000000000001101100100 $ +#1737 +0# +#1738 +1# +b00000000000000000000001101100101 $ +#1739 +0# +#1740 +1# +b00000000000000000000001101100110 $ +#1741 +0# +#1742 +1# +b00000000000000000000001101100111 $ +#1743 +0# +#1744 +1# +b00000000000000000000001101101000 $ +#1745 +0# +#1746 +1# +b00000000000000000000001101101001 $ +#1747 +0# +#1748 +1# +b00000000000000000000001101101010 $ +#1749 +0# +#1750 +1# +b00000000000000000000001101101011 $ +#1751 +0# +#1752 +1# +b00000000000000000000001101101100 $ +#1753 +0# +#1754 +1# +b00000000000000000000001101101101 $ +#1755 +0# +#1756 +1# +b00000000000000000000001101101110 $ +#1757 +0# +#1758 +1# +b00000000000000000000001101101111 $ +#1759 +0# +#1760 +1# +b00000000000000000000001101110000 $ +#1761 +0# +#1762 +1# +b00000000000000000000001101110001 $ +#1763 +0# +#1764 +1# +b00000000000000000000001101110010 $ +#1765 +0# +#1766 +1# +b00000000000000000000001101110011 $ +#1767 +0# +#1768 +1# +b00000000000000000000001101110100 $ +#1769 +0# +#1770 +1# +b00000000000000000000001101110101 $ +#1771 +0# +#1772 +1# +b00000000000000000000001101110110 $ +#1773 +0# +#1774 +1# +b00000000000000000000001101110111 $ +#1775 +0# +#1776 +1# +b00000000000000000000001101111000 $ +#1777 +0# +#1778 +1# +b00000000000000000000001101111001 $ +#1779 +0# +#1780 +1# +b00000000000000000000001101111010 $ +#1781 +0# +#1782 +1# +b00000000000000000000001101111011 $ +#1783 +0# +#1784 +1# +b00000000000000000000001101111100 $ +#1785 +0# +#1786 +1# +b00000000000000000000001101111101 $ +#1787 +0# +#1788 +1# +b00000000000000000000001101111110 $ +#1789 +0# +#1790 +1# +b00000000000000000000001101111111 $ +#1791 +0# +#1792 +1# +b00000000000000000000001110000000 $ +#1793 +0# +#1794 +1# +b00000000000000000000001110000001 $ +#1795 +0# +#1796 +1# +b00000000000000000000001110000010 $ +#1797 +0# +#1798 +1# +b00000000000000000000001110000011 $ +#1799 +0# +#1800 +1# +b00000000000000000000001110000100 $ +#1801 +0# +#1802 +1# +b00000000000000000000001110000101 $ +#1803 +0# +#1804 +1# +b00000000000000000000001110000110 $ +#1805 +0# +#1806 +1# +b00000000000000000000001110000111 $ +#1807 +0# +#1808 +1# +b00000000000000000000001110001000 $ +#1809 +0# +#1810 +1# +b00000000000000000000001110001001 $ +#1811 +0# +#1812 +1# +b00000000000000000000001110001010 $ +#1813 +0# +#1814 +1# +b00000000000000000000001110001011 $ +#1815 +0# +#1816 +1# +b00000000000000000000001110001100 $ +#1817 +0# +#1818 +1# +b00000000000000000000001110001101 $ +#1819 +0# +#1820 +1# +b00000000000000000000001110001110 $ +#1821 +0# +#1822 +1# +b00000000000000000000001110001111 $ +#1823 +0# +#1824 +1# +b00000000000000000000001110010000 $ +#1825 +0# +#1826 +1# +b00000000000000000000001110010001 $ +#1827 +0# +#1828 +1# +b00000000000000000000001110010010 $ +#1829 +0# +#1830 +1# +b00000000000000000000001110010011 $ +#1831 +0# +#1832 +1# +b00000000000000000000001110010100 $ +#1833 +0# +#1834 +1# +b00000000000000000000001110010101 $ +#1835 +0# +#1836 +1# +b00000000000000000000001110010110 $ +#1837 +0# +#1838 +1# +b00000000000000000000001110010111 $ +#1839 +0# +#1840 +1# +b00000000000000000000001110011000 $ +#1841 +0# +#1842 +1# +b00000000000000000000001110011001 $ +#1843 +0# +#1844 +1# +b00000000000000000000001110011010 $ +#1845 +0# +#1846 +1# +b00000000000000000000001110011011 $ +#1847 +0# +#1848 +1# +b00000000000000000000001110011100 $ +#1849 +0# +#1850 +1# +b00000000000000000000001110011101 $ +#1851 +0# +#1852 +1# +b00000000000000000000001110011110 $ +#1853 +0# +#1854 +1# +b00000000000000000000001110011111 $ +#1855 +0# +#1856 +1# +b00000000000000000000001110100000 $ +#1857 +0# +#1858 +1# +b00000000000000000000001110100001 $ +#1859 +0# +#1860 +1# +b00000000000000000000001110100010 $ +#1861 +0# +#1862 +1# +b00000000000000000000001110100011 $ +#1863 +0# +#1864 +1# +b00000000000000000000001110100100 $ +#1865 +0# +#1866 +1# +b00000000000000000000001110100101 $ +#1867 +0# +#1868 +1# +b00000000000000000000001110100110 $ +#1869 +0# +#1870 +1# +b00000000000000000000001110100111 $ +#1871 +0# +#1872 +1# +b00000000000000000000001110101000 $ +#1873 +0# +#1874 +1# +b00000000000000000000001110101001 $ +#1875 +0# +#1876 +1# +b00000000000000000000001110101010 $ +#1877 +0# +#1878 +1# +b00000000000000000000001110101011 $ +#1879 +0# +#1880 +1# +b00000000000000000000001110101100 $ +#1881 +0# +#1882 +1# +b00000000000000000000001110101101 $ +#1883 +0# +#1884 +1# +b00000000000000000000001110101110 $ +#1885 +0# +#1886 +1# +b00000000000000000000001110101111 $ +#1887 +0# +#1888 +1# +b00000000000000000000001110110000 $ +#1889 +0# +#1890 +1# +b00000000000000000000001110110001 $ +#1891 +0# +#1892 +1# +b00000000000000000000001110110010 $ +#1893 +0# +#1894 +1# +b00000000000000000000001110110011 $ +#1895 +0# +#1896 +1# +b00000000000000000000001110110100 $ +#1897 +0# +#1898 +1# +b00000000000000000000001110110101 $ +#1899 +0# diff --git a/test_regress/t/t_no_trace_top.pl b/test_regress/t/t_no_trace_top.pl new file mode 100755 index 000000000..100fef756 --- /dev/null +++ b/test_regress/t/t_no_trace_top.pl @@ -0,0 +1,29 @@ +#!/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-2013 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_all => 1); + +top_filename("t_trace_cat.v"); + +compile( + make_top_shell => 0, + make_main => 0, + v_flags2 => ["--trace --no-trace-top --exe $Self->{t_dir}/t_no_trace_top.cpp"], + ); + +execute( + check_finished => 1, + ); + +vcd_identical("$Self->{obj_dir}/simno_trace_top.vcd", + $Self->{golden_filename}); + +ok(1); +1; From 7479db6ffcbbc9b4a5a4669c77fdee3f233ac28d Mon Sep 17 00:00:00 2001 From: github action Date: Sat, 19 Aug 2023 08:52:38 +0000 Subject: [PATCH 015/111] Apply 'make format' --- src/V3LinkLevel.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/V3LinkLevel.cpp b/src/V3LinkLevel.cpp index cd0f0a195..36ee13044 100644 --- a/src/V3LinkLevel.cpp +++ b/src/V3LinkLevel.cpp @@ -289,9 +289,7 @@ void V3LinkLevel::wrapTopCell(AstNetlist* rootp) { varp->trace(false); } - if (v3Global.opt.noTraceTop() && varp->isIO()) { - varp->trace(false); - } + if (v3Global.opt.noTraceTop() && varp->isIO()) { varp->trace(false); } AstPin* const pinp = new AstPin{ oldvarp->fileline(), 0, varp->name(), From af3aba78217e4d168522eb5db89714577c7cc620 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 19 Aug 2023 04:56:29 -0400 Subject: [PATCH 016/111] Commentary: Changes update --- Changes | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Changes b/Changes index 8b0bb6653..f8d51a059 100644 --- a/Changes +++ b/Changes @@ -13,6 +13,12 @@ Verilator 5.015 devel **Minor:** +* Add --no-trace-top to not trace top signals (#4412) (#4422). [Frans Skarman] +* Fix Windows filename format, etc (#3873) (#4421). [Anthony Donlon]. +* Fix dtype of condition operation on class objects (#4345) (#4352). [Ryszard Rozak, Antmicro Ltd] +* Fix detection of mixed blocking and nonblocking assignment in nested assignments (#4404). [Ryszard Rozak, Antmicro Ltd] +* Fix jumping over object initialization (#4411). [Krzysztof Boroński] +* Fix variable lifetimes in extern methods (#4414). [Krzysztof Boroński] * Fix multple function definitions in V3Sched (#4416). [Hennadii Chernyshchyk] From 436f72582b669ad625b64ca41d6c5f06c4414b0a Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 19 Aug 2023 06:57:43 -0400 Subject: [PATCH 017/111] Update GTKWave from upstream. --- include/gtkwave/fstapi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/gtkwave/fstapi.c b/include/gtkwave/fstapi.c index 205e43952..1405878cb 100644 --- a/include/gtkwave/fstapi.c +++ b/include/gtkwave/fstapi.c @@ -4181,7 +4181,7 @@ if(!(isfeof=feof(xc->fh))) if((xc->hier.u.attr.subtype == FST_MT_SOURCESTEM)||(xc->hier.u.attr.subtype == FST_MT_SOURCEISTEM)) { int sidx_skiplen_dummy = 0; - xc->hier.u.attr.arg_from_name = fstGetVarint64((unsigned char *)xc->str_scope_nam, &sidx_skiplen_dummy); + xc->hier.u.attr.arg_from_name = fstGetVarint64((unsigned char *)xc->str_scope_attr, &sidx_skiplen_dummy); } } break; From 4370254e733c46d20e71d52725af6f4c2d2ec8d4 Mon Sep 17 00:00:00 2001 From: Aleksander Kiryk Date: Sat, 19 Aug 2023 13:03:21 +0200 Subject: [PATCH 018/111] Fix ++/-- under statements (#4399) --- src/V3LinkInc.cpp | 43 +++++++++++++++++++++++++--------- test_regress/t/t_inc_relink.pl | 18 ++++++++++++++ test_regress/t/t_inc_relink.v | 37 +++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 11 deletions(-) create mode 100755 test_regress/t/t_inc_relink.pl create mode 100644 test_regress/t/t_inc_relink.v diff --git a/src/V3LinkInc.cpp b/src/V3LinkInc.cpp index 904fd423f..eeb339af1 100644 --- a/src/V3LinkInc.cpp +++ b/src/V3LinkInc.cpp @@ -61,13 +61,30 @@ private: // STATE AstNodeFTask* m_ftaskp = nullptr; // Function or task we're inside + AstNodeModule* m_modp = nullptr; // Module we're inside int m_modIncrementsNum = 0; // Var name counter InsertMode m_insMode = IM_BEFORE; // How to insert AstNode* m_insStmtp = nullptr; // Where to insert statement bool m_unsupportedHere = false; // Used to detect where it's not supported yet // METHODS - void insertBeforeStmt(AstNode* nodep, AstNode* newp) { + void insertOnTop(AstNode* newp) { + // Add the thing directly under the current TFunc/Module + AstNode* stmtsp = nullptr; + if (m_ftaskp) { + stmtsp = m_ftaskp->stmtsp(); + } else if (m_modp) { + stmtsp = m_modp->stmtsp(); + } + UASSERT(stmtsp, "Variable not under FTASK/MODULE"); + newp->addNext(stmtsp->unlinkFrBackWithNext()); + if (m_ftaskp) { + m_ftaskp->addStmtsp(newp); + } else if (m_modp) { + m_modp->addStmtsp(newp); + } + } + void insertNextToStmt(AstNode* nodep, AstNode* newp) { // Return node that must be visited, if any if (debug() >= 9) newp->dumpTree("- newstmt: "); UASSERT_OBJ(m_insStmtp, nodep, "Function not underneath a statement"); @@ -88,7 +105,9 @@ private: // VISITORS void visit(AstNodeModule* nodep) override { + VL_RESTORER(m_modp); VL_RESTORER(m_modIncrementsNum); + m_modp = nodep; m_modIncrementsNum = 0; iterateChildren(nodep); } @@ -248,11 +267,10 @@ private: AstConst* const constp = VN_AS(nodep->lhsp(), Const); UASSERT_OBJ(nodep, constp, "Expecting CONST"); - const AstNode* const backp = nodep->backp(); AstConst* const newconstp = constp->cloneTree(true); // Prepare a temporary variable - FileLine* const fl = backp->fileline(); + FileLine* const fl = nodep->fileline(); const string name = string{"__Vincrement"} + cvtToStr(++m_modIncrementsNum); AstVar* const varp = new AstVar{ fl, VVarType::BLOCKTEMP, name, VFlagChildDType{}, @@ -260,7 +278,7 @@ private: if (m_ftaskp) varp->funcLocal(true); // Declare the variable - insertBeforeStmt(nodep, varp); + insertOnTop(varp); // Define what operation will we be doing AstNodeExpr* operp; @@ -273,17 +291,20 @@ private: if (VN_IS(nodep, PreAdd) || VN_IS(nodep, PreSub)) { // PreAdd/PreSub operations // Immediately after declaration - increment it by one - varp->addNextHere(new AstAssign{fl, writep->cloneTree(true), - new AstVarRef{fl, varp, VAccess::READ}}); + AstAssign* const assignp + = new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE}, operp}; + insertNextToStmt(nodep, assignp); // Immediately after incrementing - assign it to the original variable - varp->addNextHere(new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE}, operp}); + assignp->addNextHere(new AstAssign{fl, writep->cloneTree(true), + new AstVarRef{fl, varp, VAccess::READ}}); } else { // PostAdd/PostSub operations - // assign the original variable to the temporary one - varp->addNextHere(new AstAssign{fl, writep->cloneTree(true), operp}); + // Assign the original variable to the temporary one + AstAssign* const assignp = new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE}, + readp->cloneTree(true)}; + insertNextToStmt(nodep, assignp); // Increment the original variable by one - varp->addNextHere(new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE}, - readp->cloneTree(true)}); + assignp->addNextHere(new AstAssign{fl, writep->cloneTree(true), operp}); } // Replace the node with the temporary diff --git a/test_regress/t/t_inc_relink.pl b/test_regress/t/t_inc_relink.pl new file mode 100755 index 000000000..92b300018 --- /dev/null +++ b/test_regress/t/t_inc_relink.pl @@ -0,0 +1,18 @@ +#!/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(simulator => 1); + +compile( + verilator_flags2 => ["-Wno-WIDTHTRUNC"], + ); + +ok(1); +1; diff --git a/test_regress/t/t_inc_relink.v b/test_regress/t/t_inc_relink.v new file mode 100644 index 000000000..fcaf80289 --- /dev/null +++ b/test_regress/t/t_inc_relink.v @@ -0,0 +1,37 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +// Test if temporary vars are relinked if not used directly under FTASK. + +package A; // Create JUMPBLOCK; use n++ in it + task t; + automatic int n; + if ($random) return; + n = n++; + endtask +endpackage + +package B; // Create IF; use n++ in it + int n; + task t; + if ($random) n = n++; + endtask +endpackage + +module C; // Like above but in a module + int n = 0; + + initial if ($random) n = n++; +endmodule + +module t; // Actually use those to test relinking + C c; + + initial begin + A::t(); + B::t(); + end +endmodule From 768b78e7d08dba4ae856b0de59f961e0e8929e66 Mon Sep 17 00:00:00 2001 From: Anthony Donlon <4056887+donlon@users.noreply.github.com> Date: Sun, 20 Aug 2023 20:55:16 +0800 Subject: [PATCH 019/111] Fix checking for parameter and port connections in the wrong place (#4428) --- src/V3Ast.h | 1 + src/V3AstNodeOther.h | 4 +-- src/V3EmitCImp.cpp | 2 +- src/V3LinkDot.cpp | 46 +++++++++++++++++-------- test_regress/t/t_inst_pin_place_bad.out | 12 +++++++ test_regress/t/t_inst_pin_place_bad.pl | 19 ++++++++++ test_regress/t/t_inst_pin_place_bad.v | 24 +++++++++++++ 7 files changed, 90 insertions(+), 18 deletions(-) create mode 100644 test_regress/t/t_inst_pin_place_bad.out create mode 100755 test_regress/t/t_inst_pin_place_bad.pl create mode 100644 test_regress/t/t_inst_pin_place_bad.v diff --git a/src/V3Ast.h b/src/V3Ast.h index 8fc42582e..d49d60f1e 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -816,6 +816,7 @@ public: "BLOCKTEMP", "MODULETEMP", "STMTTEMP", "XTEMP", "IFACEREF", "MEMBER"}; return names[m_e]; } + bool isParam() const { return m_e == GPARAM || m_e == LPARAM; } bool isSignal() const { return (m_e == WIRE || m_e == WREAL || m_e == IMPLICITWIRE || m_e == TRIWIRE || m_e == TRI0 || m_e == TRI1 || m_e == PORT || m_e == SUPPLY0 || m_e == SUPPLY1 || m_e == VAR); diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index fb3c31789..7e7199427 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -1922,9 +1922,7 @@ public: bool isClassMember() const { return varType() == VVarType::MEMBER; } bool isStatementTemp() const { return (varType() == VVarType::STMTTEMP); } bool isXTemp() const { return (varType() == VVarType::XTEMP); } - bool isParam() const VL_MT_SAFE { - return (varType() == VVarType::LPARAM || varType() == VVarType::GPARAM); - } + bool isParam() const { return varType().isParam(); } bool isGParam() const { return (varType() == VVarType::GPARAM); } bool isGenVar() const { return (varType() == VVarType::GENVAR); } bool isBitLogic() const { diff --git a/src/V3EmitCImp.cpp b/src/V3EmitCImp.cpp index e11daab55..18f75acc4 100644 --- a/src/V3EmitCImp.cpp +++ b/src/V3EmitCImp.cpp @@ -677,7 +677,7 @@ class EmitCTrace final : EmitCFunc { string fstvt; // Doubles have special decoding properties, so must indicate if a double if (nodep->dtypep()->basicp()->isDouble()) { - if (vartype == VVarType::GPARAM || vartype == VVarType::LPARAM) { + if (vartype.isParam()) { fstvt = "FST_VT_VCD_REAL_PARAMETER"; } else { fstvt = "FST_VT_VCD_REAL"; diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 283e15206..8b81802aa 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -1616,6 +1616,7 @@ private: AstPin* const pinp = new AstPin{nodep->fileline(), -1, // Pin# not relevant nodep->name(), exprp}; + pinp->param(true); cellp->addParamsp(pinp); } VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); @@ -2250,6 +2251,11 @@ private: if (classp->isInterfaceClass()) importImplementsClass(nodep, srcp, classp); if (!cextp->isImplements()) m_curSymp->importFromClass(m_statep->symsp(), srcp); } + bool checkPinRef(AstPin* pinp, VVarType refVarType) { + // In instantiations of modules/ifaces, we shouldn't connect port pins to submodule's + // parameters or vice versa + return pinp->param() == refVarType.isParam(); + } // VISITs void visit(AstNetlist* nodep) override { @@ -2344,7 +2350,32 @@ private: UASSERT_OBJ(m_pinSymp, nodep, "Pin not under instance?"); VSymEnt* const foundp = m_pinSymp->findIdFlat(nodep->name()); const char* const whatp = nodep->param() ? "parameter pin" : "pin"; - if (!foundp) { + bool pinCheckFail = false; + if (foundp) { + if (AstVar* const refp = VN_CAST(foundp->nodep(), Var)) { + if (!refp->isIO() && !refp->isParam() && !refp->isIfaceRef()) { + nodep->v3error(ucfirst(whatp) + << " is not an in/out/inout/param/interface: " + << nodep->prettyNameQ()); + } else if (!checkPinRef(nodep, refp->varType())) { + pinCheckFail = true; + } else { + nodep->modVarp(refp); + markAndCheckPinDup(nodep, refp, whatp); + } + } else if (AstParamTypeDType* const refp + = VN_CAST(foundp->nodep(), ParamTypeDType)) { + if (!checkPinRef(nodep, refp->varType())) { + pinCheckFail = true; + } else { + nodep->modPTypep(refp); + markAndCheckPinDup(nodep, refp, whatp); + } + } else { + nodep->v3error(ucfirst(whatp) << " not found: " << nodep->prettyNameQ()); + } + } + if (!foundp || pinCheckFail) { if (nodep->name() == "__paramNumber1" && m_cellp && VN_IS(m_cellp->modp(), Primitive)) { // Primitive parameter is really a delay we can just ignore @@ -2360,19 +2391,6 @@ private: ucfirst(whatp) << " not found: " << nodep->prettyNameQ() << '\n' << (suggest.empty() ? "" : nodep->warnMore() + suggest)); - } else if (AstVar* const refp = VN_CAST(foundp->nodep(), Var)) { - if (!refp->isIO() && !refp->isParam() && !refp->isIfaceRef()) { - nodep->v3error(ucfirst(whatp) << " is not an in/out/inout/param/interface: " - << nodep->prettyNameQ()); - } else { - nodep->modVarp(refp); - markAndCheckPinDup(nodep, refp, whatp); - } - } else if (AstParamTypeDType* const refp = VN_CAST(foundp->nodep(), ParamTypeDType)) { - nodep->modPTypep(refp); - markAndCheckPinDup(nodep, refp, whatp); - } else { - nodep->v3error(ucfirst(whatp) << " not found: " << nodep->prettyNameQ()); } } // Early return() above when deleted diff --git a/test_regress/t/t_inst_pin_place_bad.out b/test_regress/t/t_inst_pin_place_bad.out new file mode 100644 index 000000000..0d3f845a6 --- /dev/null +++ b/test_regress/t/t_inst_pin_place_bad.out @@ -0,0 +1,12 @@ +%Warning-PINMISSING: t/t_inst_pin_place_bad.v:21:7: Cell has missing pin: 'pin_1' + 21 | ) i_sub ( + | ^~~~~ + ... For warning description see https://verilator.org/warn/PINMISSING?v=latest + ... Use "/* verilator lint_off PINMISSING */" and lint_on around source to disable this message. +%Error-PINNOTFOUND: t/t_inst_pin_place_bad.v:22:10: Pin not found: 'PARAM_A' + 22 | .PARAM_A(1) + | ^~~~~~~ +%Error-PINNOTFOUND: t/t_inst_pin_place_bad.v:20:10: Parameter pin not found: 'pin_1' + 20 | .pin_1(1) + | ^~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_inst_pin_place_bad.pl b/test_regress/t/t_inst_pin_place_bad.pl new file mode 100755 index 000000000..376c2d2ee --- /dev/null +++ b/test_regress/t/t_inst_pin_place_bad.pl @@ -0,0 +1,19 @@ +#!/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(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_inst_pin_place_bad.v b/test_regress/t/t_inst_pin_place_bad.v new file mode 100644 index 000000000..cac3e4f4c --- /dev/null +++ b/test_regress/t/t_inst_pin_place_bad.v @@ -0,0 +1,24 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2023 by Anthony Donlon. +// SPDX-License-Identifier: CC0-1.0 + +module sub # ( + parameter PARAM_A = 1, + parameter type PARAM_B = logic +) ( + input pin_1 +); +endmodule + +module t; + parameter type PARAM_B = string; + + sub #( + .PARAM_B(PARAM_B), + .pin_1(1) + ) i_sub ( + .PARAM_A(1) + ); +endmodule From 95f3dd053523a430d2561868ecd79265917564e5 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 21 Aug 2023 06:23:35 -0400 Subject: [PATCH 020/111] Commentary (#4429) --- docs/guide/overview.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/overview.rst b/docs/guide/overview.rst index cecbfab14..101c97faa 100644 --- a/docs/guide/overview.rst +++ b/docs/guide/overview.rst @@ -44,7 +44,7 @@ The best place to get started is to try the :ref:`Examples`. .. [#] Verilog is defined by the `Institute of Electrical and Electronics Engineers (IEEE) Standard for Verilog Hardware Description Language`, Std. 1364, released in 1995, 2001, and 2005. The - Verilator documentation uses the shorthand, e.g., "IEEE 1394-2005", + Verilator documentation uses the shorthand, e.g., "IEEE 1364-2005", to refer to the, e.g., 2005 version of this standard. .. [#] SystemVerilog is defined by the `Institute of Electrical and From 7c7c92d2ddaf8db3d62b34774e04e4287026e9c6 Mon Sep 17 00:00:00 2001 From: Aleksander Kiryk Date: Mon, 21 Aug 2023 16:22:09 +0200 Subject: [PATCH 021/111] Fix coroutine handle movement during queue manipulation (#4431) --- include/verilated_timing.h | 4 +- test_regress/t/t_timing_debug1.out | 344 ++++++++++++------------ test_regress/t/t_timing_debug2.out | 414 ++++++++++++++--------------- 3 files changed, 382 insertions(+), 380 deletions(-) diff --git a/include/verilated_timing.h b/include/verilated_timing.h index 6ddd0b115..c7684fe5a 100644 --- a/include/verilated_timing.h +++ b/include/verilated_timing.h @@ -116,7 +116,7 @@ public: // Move the handle, leaving a nullptr VlCoroutineHandle(VlCoroutineHandle&& moved) : m_coro{std::exchange(moved.m_coro, nullptr)} - , m_process{moved.m_process} + , m_process{std::exchange(moved.m_process, nullptr)} , m_fileline{moved.m_fileline} {} // Destroy if the handle isn't null ~VlCoroutineHandle() { @@ -133,6 +133,8 @@ public: // Move the handle, leaving a null handle auto& operator=(VlCoroutineHandle&& moved) { m_coro = std::exchange(moved.m_coro, nullptr); + m_process = std::exchange(moved.m_process, nullptr); + m_fileline = moved.m_fileline; return *this; } // Resume the coroutine if the handle isn't null and the process isn't killed diff --git a/test_regress/t/t_timing_debug1.out b/test_regress/t/t_timing_debug1.out index 11a893850..2740c8bd0 100644 --- a/test_regress/t/t_timing_debug1.out +++ b/test_regress/t/t_timing_debug1.out @@ -74,13 +74,13 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 3: Process waiting at t/t_timing_sched.v:52 +-V{t#,#} Awaiting time 3: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 3: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 11: Process waiting at t/t_timing_sched.v:13 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 11: Process waiting at t/t_timing_sched.v:13 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 @@ -134,13 +134,13 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 6: Process waiting at t/t_timing_sched.v:52 --V{t#,#} Awaiting time 7: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:13 --V{t#,#} Awaiting time 11: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 11: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Awaiting time 6: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 7: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 +-V{t#,#} Awaiting time 11: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 11: Process waiting at t/t_timing_sched.v:13 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act @@ -173,13 +173,13 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 7: Process waiting at t/t_timing_sched.v:52 +-V{t#,#} Awaiting time 7: Process waiting at t/t_timing_sched.v:17 -V{t#,#} Awaiting time 9: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:13 --V{t#,#} Awaiting time 11: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 11: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 +-V{t#,#} Awaiting time 11: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 11: Process waiting at t/t_timing_sched.v:13 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 -V{t#,#} Suspending process waiting for @(posedge t.clk1) at t/t_timing_sched.v:17 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 @@ -207,10 +207,10 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 9: Process waiting at t/t_timing_sched.v:52 --V{t#,#} Awaiting time 11: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:13 --V{t#,#} Awaiting time 11: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 9: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 11: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 +-V{t#,#} Awaiting time 11: Process waiting at t/t_timing_sched.v:13 -V{t#,#} Resuming delayed processes -V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 -V{t#,#}+ Vt_timing_debug1___024root___eval_act @@ -259,14 +259,14 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 11: Process waiting at t/t_timing_sched.v:52 --V{t#,#} Awaiting time 11: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 11: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 11: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 12: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 13: Process waiting at t/t_timing_sched.v:17 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:13 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act @@ -324,14 +324,14 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 12: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 12: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 12: Process waiting at t/t_timing_sched.v:50 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 22: Process waiting at t/t_timing_sched.v:13 --V{t#,#} Awaiting time 13: Process waiting at t/t_timing_sched.v:50 +-V{t#,#} Awaiting time 13: Process waiting at t/t_timing_sched.v:17 -V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:50 --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:13 -V{t#,#} Suspending process waiting for @(posedge t.clk2) at t/t_timing_sched.v:50 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 @@ -367,12 +367,12 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 13: Process waiting at t/t_timing_sched.v:52 +-V{t#,#} Awaiting time 13: Process waiting at t/t_timing_sched.v:17 -V{t#,#} Awaiting time 15: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:13 --V{t#,#} Awaiting time 22: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 +-V{t#,#} Awaiting time 22: Process waiting at t/t_timing_sched.v:13 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 -V{t#,#} Suspending process waiting for @(posedge t.clk1) at t/t_timing_sched.v:17 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 @@ -400,11 +400,11 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 15: Process waiting at t/t_timing_sched.v:52 --V{t#,#} Awaiting time 22: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 15: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 22: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act @@ -457,12 +457,12 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 18: Process waiting at t/t_timing_sched.v:52 --V{t#,#} Awaiting time 19: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 22: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Awaiting time 18: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 19: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Awaiting time 22: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act @@ -495,12 +495,12 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 19: Process waiting at t/t_timing_sched.v:52 +-V{t#,#} Awaiting time 19: Process waiting at t/t_timing_sched.v:17 -V{t#,#} Awaiting time 21: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 22: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 22: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 -V{t#,#} Suspending process waiting for @(posedge t.clk1) at t/t_timing_sched.v:17 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 @@ -528,9 +528,9 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 21: Process waiting at t/t_timing_sched.v:52 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 22: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 21: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 +-V{t#,#} Awaiting time 22: Process waiting at t/t_timing_sched.v:13 -V{t#,#} Resuming delayed processes -V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 -V{t#,#}+ Vt_timing_debug1___024root___eval_act @@ -579,12 +579,12 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 22: Process waiting at t/t_timing_sched.v:52 --V{t#,#} Awaiting time 25: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 22: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 25: Process waiting at t/t_timing_sched.v:17 -V{t#,#} Awaiting time 24: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:13 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act @@ -617,12 +617,12 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 24: Process waiting at t/t_timing_sched.v:52 --V{t#,#} Awaiting time 25: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 24: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 25: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 33: Process waiting at t/t_timing_sched.v:13 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act @@ -655,12 +655,12 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 25: Process waiting at t/t_timing_sched.v:52 +-V{t#,#} Awaiting time 25: Process waiting at t/t_timing_sched.v:17 -V{t#,#} Awaiting time 27: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 33: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 +-V{t#,#} Awaiting time 33: Process waiting at t/t_timing_sched.v:13 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 -V{t#,#} Suspending process waiting for @(posedge t.clk1) at t/t_timing_sched.v:17 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 @@ -688,9 +688,9 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 27: Process waiting at t/t_timing_sched.v:52 --V{t#,#} Awaiting time 33: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 27: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 33: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Resuming delayed processes -V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 -V{t#,#}+ Vt_timing_debug1___024root___eval_act @@ -739,12 +739,12 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 30: Process waiting at t/t_timing_sched.v:52 --V{t#,#} Awaiting time 31: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 33: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Awaiting time 30: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 31: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Awaiting time 33: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act @@ -777,12 +777,12 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 31: Process waiting at t/t_timing_sched.v:52 +-V{t#,#} Awaiting time 31: Process waiting at t/t_timing_sched.v:17 -V{t#,#} Awaiting time 33: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 33: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 33: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 -V{t#,#} Suspending process waiting for @(posedge t.clk1) at t/t_timing_sched.v:17 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 @@ -810,11 +810,11 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 33: Process waiting at t/t_timing_sched.v:52 +-V{t#,#} Awaiting time 33: Process waiting at t/t_timing_sched.v:13 -V{t#,#} Awaiting time 33: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:13 -V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 @@ -883,11 +883,11 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 34: Process waiting at t/t_timing_sched.v:52 +-V{t#,#} Awaiting time 34: Process waiting at t/t_timing_sched.v:50 -V{t#,#} Awaiting time 36: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 44: Process waiting at t/t_timing_sched.v:13 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:17 --V{t#,#} Awaiting time 37: Process waiting at t/t_timing_sched.v:50 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 +-V{t#,#} Awaiting time 37: Process waiting at t/t_timing_sched.v:17 -V{t#,#} Resuming delayed processes -V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:50 -V{t#,#} Suspending process waiting for @(posedge t.clk2) at t/t_timing_sched.v:50 @@ -917,12 +917,12 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 36: Process waiting at t/t_timing_sched.v:52 --V{t#,#} Awaiting time 37: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 36: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 37: Process waiting at t/t_timing_sched.v:17 -V{t#,#} Awaiting time 44: Process waiting at t/t_timing_sched.v:13 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act @@ -955,12 +955,12 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 37: Process waiting at t/t_timing_sched.v:52 +-V{t#,#} Awaiting time 37: Process waiting at t/t_timing_sched.v:17 -V{t#,#} Awaiting time 39: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 44: Process waiting at t/t_timing_sched.v:13 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 -V{t#,#} Suspending process waiting for @(posedge t.clk1) at t/t_timing_sched.v:17 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 @@ -988,11 +988,11 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 39: Process waiting at t/t_timing_sched.v:52 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 39: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 44: Process waiting at t/t_timing_sched.v:13 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act @@ -1045,12 +1045,12 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 42: Process waiting at t/t_timing_sched.v:52 --V{t#,#} Awaiting time 43: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 44: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Awaiting time 42: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 43: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Awaiting time 44: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act @@ -1083,12 +1083,12 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 43: Process waiting at t/t_timing_sched.v:52 +-V{t#,#} Awaiting time 43: Process waiting at t/t_timing_sched.v:17 -V{t#,#} Awaiting time 45: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 44: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 44: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 -V{t#,#} Suspending process waiting for @(posedge t.clk1) at t/t_timing_sched.v:17 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 @@ -1116,11 +1116,11 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 44: Process waiting at t/t_timing_sched.v:52 +-V{t#,#} Awaiting time 44: Process waiting at t/t_timing_sched.v:13 -V{t#,#} Awaiting time 45: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:13 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act @@ -1153,11 +1153,11 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 45: Process waiting at t/t_timing_sched.v:52 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 45: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 55: Process waiting at t/t_timing_sched.v:13 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act @@ -1204,12 +1204,12 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 48: Process waiting at t/t_timing_sched.v:52 --V{t#,#} Awaiting time 49: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 55: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Awaiting time 48: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 49: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Awaiting time 55: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act @@ -1242,12 +1242,12 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 49: Process waiting at t/t_timing_sched.v:52 +-V{t#,#} Awaiting time 49: Process waiting at t/t_timing_sched.v:17 -V{t#,#} Awaiting time 51: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 55: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 55: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 -V{t#,#} Suspending process waiting for @(posedge t.clk1) at t/t_timing_sched.v:17 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 @@ -1275,9 +1275,9 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 51: Process waiting at t/t_timing_sched.v:52 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 55: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 51: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 +-V{t#,#} Awaiting time 55: Process waiting at t/t_timing_sched.v:13 -V{t#,#} Resuming delayed processes -V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 -V{t#,#}+ Vt_timing_debug1___024root___eval_act @@ -1326,12 +1326,12 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 54: Process waiting at t/t_timing_sched.v:52 --V{t#,#} Awaiting time 55: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 55: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Awaiting time 54: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 55: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Awaiting time 55: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act @@ -1364,13 +1364,13 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 55: Process waiting at t/t_timing_sched.v:52 --V{t#,#} Awaiting time 55: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 55: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 55: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 57: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 -V{t#,#} Suspending process waiting for @(posedge t.clk1) at t/t_timing_sched.v:17 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 @@ -1431,10 +1431,10 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 56: Process waiting at t/t_timing_sched.v:52 +-V{t#,#} Awaiting time 56: Process waiting at t/t_timing_sched.v:50 -V{t#,#} Awaiting time 57: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 66: Process waiting at t/t_timing_sched.v:13 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:50 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Resuming delayed processes -V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:50 -V{t#,#} Suspending process waiting for @(posedge t.clk2) at t/t_timing_sched.v:50 @@ -1464,11 +1464,11 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 57: Process waiting at t/t_timing_sched.v:52 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 57: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 66: Process waiting at t/t_timing_sched.v:13 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act @@ -1521,12 +1521,12 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 60: Process waiting at t/t_timing_sched.v:52 --V{t#,#} Awaiting time 61: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 66: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Awaiting time 60: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 61: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Awaiting time 66: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act @@ -1559,12 +1559,12 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 61: Process waiting at t/t_timing_sched.v:52 +-V{t#,#} Awaiting time 61: Process waiting at t/t_timing_sched.v:17 -V{t#,#} Awaiting time 63: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 66: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 66: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 -V{t#,#} Suspending process waiting for @(posedge t.clk1) at t/t_timing_sched.v:17 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 @@ -1592,9 +1592,9 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 63: Process waiting at t/t_timing_sched.v:52 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 66: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 63: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 +-V{t#,#} Awaiting time 66: Process waiting at t/t_timing_sched.v:13 -V{t#,#} Resuming delayed processes -V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 -V{t#,#}+ Vt_timing_debug1___024root___eval_act @@ -1643,12 +1643,12 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 66: Process waiting at t/t_timing_sched.v:52 --V{t#,#} Awaiting time 67: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 66: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 67: Process waiting at t/t_timing_sched.v:17 -V{t#,#} Awaiting time 66: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:13 -V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 @@ -1685,12 +1685,12 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 67: Process waiting at t/t_timing_sched.v:52 --V{t#,#} Awaiting time 77: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 67: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Awaiting time 77: Process waiting at t/t_timing_sched.v:13 -V{t#,#} Awaiting time 69: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 -V{t#,#} Suspending process waiting for @(posedge t.clk1) at t/t_timing_sched.v:17 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 @@ -1718,9 +1718,9 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 69: Process waiting at t/t_timing_sched.v:52 --V{t#,#} Awaiting time 77: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 69: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 77: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Resuming delayed processes -V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 -V{t#,#}+ Vt_timing_debug1___024root___eval_act @@ -1769,12 +1769,12 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 72: Process waiting at t/t_timing_sched.v:52 --V{t#,#} Awaiting time 73: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 77: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Awaiting time 72: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 73: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Awaiting time 77: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act @@ -1807,12 +1807,12 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 73: Process waiting at t/t_timing_sched.v:52 +-V{t#,#} Awaiting time 73: Process waiting at t/t_timing_sched.v:17 -V{t#,#} Awaiting time 75: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 77: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 77: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 -V{t#,#} Suspending process waiting for @(posedge t.clk1) at t/t_timing_sched.v:17 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 @@ -1840,9 +1840,9 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 75: Process waiting at t/t_timing_sched.v:52 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 77: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 75: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 +-V{t#,#} Awaiting time 77: Process waiting at t/t_timing_sched.v:13 -V{t#,#} Resuming delayed processes -V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 -V{t#,#}+ Vt_timing_debug1___024root___eval_act @@ -1891,12 +1891,12 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 77: Process waiting at t/t_timing_sched.v:52 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 77: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 79: Process waiting at t/t_timing_sched.v:17 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:13 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act @@ -1954,16 +1954,16 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Awaiting time 79: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 +-V{t#,#} Awaiting time 79: Process waiting at t/t_timing_sched.v:17 -V{t#,#} Awaiting time 88: Process waiting at t/t_timing_sched.v:13 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:50 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:50 --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:13 -*-* All Finished *-* -V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:52 +*-* All Finished *-* +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:50 -V{t#,#} Suspending process waiting for @(posedge t.clk2) at t/t_timing_sched.v:50 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 diff --git a/test_regress/t/t_timing_debug2.out b/test_regress/t/t_timing_debug2.out index 61e54e3b2..4bf0ad4c3 100644 --- a/test_regress/t/t_timing_debug2.out +++ b/test_regress/t/t_timing_debug2.out @@ -106,16 +106,16 @@ -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 5: Process waiting at t/t_timing_class.v:119 --V{t#,#} Awaiting time 10: Process waiting at t/t_timing_class.v:120 --V{t#,#} Awaiting time 10: Process waiting at t/t_timing_class.v:122 --V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:136 --V{t#,#} Awaiting time 20: Process waiting at t/t_timing_class.v:173 --V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:247 +-V{t#,#} Awaiting time 5: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Awaiting time 10: Process waiting at t/t_timing_class.v:173 +-V{t#,#} Awaiting time 10: Process waiting at t/t_timing_class.v:247 +-V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:257 +-V{t#,#} Awaiting time 20: Process waiting at t/t_timing_class.v:119 +-V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:122 -V{t#,#} Awaiting time 20: Process waiting at t/t_timing_class.v:252 --V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:257 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:136 -V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:274 --V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:120 -V{t#,#} Resuming delayed processes -V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 -V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip @@ -167,23 +167,23 @@ -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 10: Process waiting at t/t_timing_class.v:119 --V{t#,#} Awaiting time 10: Process waiting at t/t_timing_class.v:120 --V{t#,#} Awaiting time 20: Process waiting at t/t_timing_class.v:122 --V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:136 +-V{t#,#} Awaiting time 10: Process waiting at t/t_timing_class.v:247 -V{t#,#} Awaiting time 10: Process waiting at t/t_timing_class.v:173 --V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:247 --V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:252 --V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:257 +-V{t#,#} Awaiting time 20: Process waiting at t/t_timing_class.v:252 +-V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:257 +-V{t#,#} Awaiting time 10: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:122 +-V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:120 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:136 -V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:274 --V{t#,#} Awaiting time 20: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Awaiting time 20: Process waiting at t/t_timing_class.v:119 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:247 -V{t#,#} Process forked at t/t_timing_class.v:246 finished --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:274 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:173 -V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay10::__VnoInFunc_do_sth_else -V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay20::__VnoInFunc_do_delay --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:174 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 -V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act @@ -219,15 +219,15 @@ -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 15: Process waiting at t/t_timing_class.v:119 --V{t#,#} Awaiting time 20: Process waiting at t/t_timing_class.v:120 --V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:122 --V{t#,#} Awaiting time 20: Process waiting at t/t_timing_class.v:136 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:173 --V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:247 --V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:252 --V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:257 --V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Awaiting time 15: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Awaiting time 20: Process waiting at t/t_timing_class.v:252 +-V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:174 +-V{t#,#} Awaiting time 20: Process waiting at t/t_timing_class.v:119 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:274 +-V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:122 +-V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:120 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:136 +-V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:257 -V{t#,#} Resuming delayed processes -V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 -V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip @@ -279,23 +279,23 @@ -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 20: Process waiting at t/t_timing_class.v:252 -V{t#,#} Awaiting time 20: Process waiting at t/t_timing_class.v:119 --V{t#,#} Awaiting time 20: Process waiting at t/t_timing_class.v:120 --V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:122 --V{t#,#} Awaiting time 20: Process waiting at t/t_timing_class.v:136 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:173 --V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:247 --V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:252 --V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:257 --V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:174 +-V{t#,#} Awaiting time 20: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:274 +-V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:122 +-V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:120 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:136 +-V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:257 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:252 -V{t#,#}+ Vt_timing_debug2_t__03a__03aForkDelayClass::new -V{t#,#}+ Vt_timing_debug2_t__03a__03aForkDelayClass::_ctor_var_reset -V{t#,#} Process forked at t/t_timing_class.v:251 finished --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:257 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:119 -V{t#,#}+ Vt_timing_debug2_t__03a__03aEventClass::__VnoInFunc_wake --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:252 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 -V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act @@ -373,13 +373,13 @@ -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 25: Process waiting at t/t_timing_class.v:119 --V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:120 --V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:122 +-V{t#,#} Awaiting time 25: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:257 +-V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:174 -V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:136 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:173 --V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:247 --V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:274 +-V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:122 +-V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:120 -V{t#,#} Resuming delayed processes -V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 -V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip @@ -463,20 +463,20 @@ -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:119 --V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:120 --V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:122 +-V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:174 +-V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:257 +-V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:131 -V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:136 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:173 --V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:247 --V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:274 +-V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:122 +-V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:120 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:174 -V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay20::__VnoInFunc_do_sth_else -V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay40::__VnoInFunc_do_delay --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:175 --V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip -V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:257 -V{t#,#}+ Vt_timing_debug2_t__03a__03aForkDelayClass::__VnoInFunc_do_delay -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act @@ -536,15 +536,15 @@ -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 35: Process waiting at t/t_timing_class.v:119 --V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:120 --V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:122 +-V{t#,#} Awaiting time 35: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:175 +-V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:120 -V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:136 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:173 --V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:247 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:274 +-V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:122 -V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:238 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:238 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 -V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act @@ -626,16 +626,16 @@ -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:119 --V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:120 --V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:122 +-V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:120 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:175 +-V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:131 -V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:136 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:173 --V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:247 --V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:274 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:238 +-V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:122 -V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:120 -V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:247 -V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act @@ -721,12 +721,12 @@ -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 45: Process waiting at t/t_timing_class.v:119 --V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:120 +-V{t#,#} Awaiting time 45: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:175 -V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:122 -V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:136 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:173 --V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:274 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:238 -V{t#,#} Resuming delayed processes -V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 -V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip @@ -781,57 +781,101 @@ -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:119 --V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:120 -V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:122 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:175 +-V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:131 -V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:136 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:173 --V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:274 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:238 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:122 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip +-V{t#,#}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:58 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:58 +-V{t#,#} Suspending process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:58 +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+ Vt_timing_debug2___024root___eval_nba +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:58 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:58 +-V{t#,#} Suspending process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:58 +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}End-of-eval cleanup +-V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step +-V{t#,#}+ Vt_timing_debug2___024root___eval_debug_assertions +-V{t#,#}MTask0 starting +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug2___024root___eval +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:58 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:58 +-V{t#,#} Suspending process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:58 +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+ Vt_timing_debug2___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 55: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:175 +-V{t#,#} Awaiting time 60: Process waiting at t/t_timing_class.v:123 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:136 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:274 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:238 -V{t#,#} Resuming delayed processes -V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip +-V{t#,#}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:58 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:58 +-V{t#,#} Suspending process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:58 +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+ Vt_timing_debug2___024root___eval_nba +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:58 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:58 +-V{t#,#} Suspending process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:58 +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}End-of-eval cleanup +-V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step +-V{t#,#}+ Vt_timing_debug2___024root___eval_debug_assertions +-V{t#,#}MTask0 starting +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug2___024root___eval +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:58 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:58 +-V{t#,#} Suspending process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:58 +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+ Vt_timing_debug2___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 60: Process waiting at t/t_timing_class.v:123 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:175 +-V{t#,#} Awaiting time 60: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:136 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:274 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:238 +-V{t#,#} Resuming delayed processes -V{t#,#} Resuming: Process waiting at t/t_timing_class.v:123 --V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip --V{t#,#}+ Vt_timing_debug2___024root___eval_act --V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act --V{t#,#} Suspended processes waiting for dynamic trigger evaluation: --V{t#,#} - Process waiting at t/t_timing_class.v:58 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:58 --V{t#,#} Suspending process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:58 --V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act --V{t#,#} No triggers active --V{t#,#}+ Vt_timing_debug2___024root___timing_commit --V{t#,#}+ Vt_timing_debug2___024root___eval_nba --V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act --V{t#,#} Suspended processes waiting for dynamic trigger evaluation: --V{t#,#} - Process waiting at t/t_timing_class.v:58 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:58 --V{t#,#} Suspending process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:58 --V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act --V{t#,#} No triggers active --V{t#,#}+ Vt_timing_debug2___024root___timing_commit --V{t#,#}End-of-eval cleanup --V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step --V{t#,#}+ Vt_timing_debug2___024root___eval_debug_assertions --V{t#,#}MTask0 starting --V{t#,#}+ Eval --V{t#,#}+ Vt_timing_debug2___024root___eval --V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act --V{t#,#} Suspended processes waiting for dynamic trigger evaluation: --V{t#,#} - Process waiting at t/t_timing_class.v:58 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:58 --V{t#,#} Suspending process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:58 --V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act --V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime()) --V{t#,#}+ Vt_timing_debug2___024root___timing_commit --V{t#,#}+ Vt_timing_debug2___024root___timing_resume --V{t#,#} Delayed processes: --V{t#,#} Awaiting time 55: Process waiting at t/t_timing_class.v:119 --V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:120 --V{t#,#} Awaiting time 60: Process waiting at t/t_timing_class.v:122 --V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:136 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:173 --V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:131 --V{t#,#} Resuming delayed processes -V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 -V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip -V{t#,#}+ Vt_timing_debug2___024root___eval_act @@ -839,50 +883,6 @@ -V{t#,#} Suspended processes waiting for dynamic trigger evaluation: -V{t#,#} - Process waiting at t/t_timing_class.v:58 -V{t#,#} Resuming: Process waiting at t/t_timing_class.v:58 --V{t#,#} Suspending process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:58 --V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act --V{t#,#} No triggers active --V{t#,#}+ Vt_timing_debug2___024root___timing_commit --V{t#,#}+ Vt_timing_debug2___024root___eval_nba --V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act --V{t#,#} Suspended processes waiting for dynamic trigger evaluation: --V{t#,#} - Process waiting at t/t_timing_class.v:58 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:58 --V{t#,#} Suspending process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:58 --V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act --V{t#,#} No triggers active --V{t#,#}+ Vt_timing_debug2___024root___timing_commit --V{t#,#}End-of-eval cleanup --V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step --V{t#,#}+ Vt_timing_debug2___024root___eval_debug_assertions --V{t#,#}MTask0 starting --V{t#,#}+ Eval --V{t#,#}+ Vt_timing_debug2___024root___eval --V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act --V{t#,#} Suspended processes waiting for dynamic trigger evaluation: --V{t#,#} - Process waiting at t/t_timing_class.v:58 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:58 --V{t#,#} Suspending process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:58 --V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act --V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime()) --V{t#,#}+ Vt_timing_debug2___024root___timing_commit --V{t#,#}+ Vt_timing_debug2___024root___timing_resume --V{t#,#} Delayed processes: --V{t#,#} Awaiting time 60: Process waiting at t/t_timing_class.v:119 --V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:120 --V{t#,#} Awaiting time 60: Process waiting at t/t_timing_class.v:122 --V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:136 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:173 --V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:131 --V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:173 --V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip --V{t#,#}+ Vt_timing_debug2___024root___eval_act --V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act --V{t#,#} Suspended processes waiting for dynamic trigger evaluation: --V{t#,#} - Process waiting at t/t_timing_class.v:58 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:58 -V{t#,#} Process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:58 awaiting resumption -V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 2 is active: @([true] __VdynSched.evaluate()) @@ -930,14 +930,14 @@ -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 65: Process waiting at t/t_timing_class.v:119 --V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:120 --V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:122 +-V{t#,#} Awaiting time 65: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:238 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:76 -V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:136 --V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:131 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:76 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:175 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:274 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:76 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 -V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act @@ -973,23 +973,23 @@ -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:119 --V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:120 --V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:122 --V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:136 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:76 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:238 -V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:131 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:136 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:175 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:274 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:76 -V{t#,#} Process forked at t/t_timing_class.v:76 finished -V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 -V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:238 -V{t#,#} Process forked at t/t_timing_class.v:256 finished --V{t#,#} Resuming: Process waiting at (null):0 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:250 -V{t#,#} Process forked at t/t_timing_class.v:250 finished --V{t#,#} Resuming: Process waiting at (null):0 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:136 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:245 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:175 -V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay40::__VnoInFunc_do_sth_else -V{t#,#}+ Vt_timing_debug2_t__03a__03aNoDelay::__VnoInFunc_do_delay -V{t#,#}+ Vt_timing_debug2_t__03a__03aNoDelay::__VnoInFunc_do_sth_else @@ -1009,7 +1009,7 @@ -V{t#,#} - Process waiting at t/t_timing_class.v:75 -V{t#,#} Resuming: Process waiting at t/t_timing_class.v:75 -V{t#,#} Process forked at t/t_timing_class.v:75 finished --V{t#,#} Resuming: Process waiting at (null):0 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:74 -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} No suspended processes waiting for dynamic trigger evaluation @@ -1037,15 +1037,15 @@ -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 75: Process waiting at t/t_timing_class.v:119 --V{t#,#} Awaiting time 75: Process waiting at t/t_timing_class.v:120 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:122 --V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:224 +-V{t#,#} Awaiting time 75: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Awaiting time 75: Process waiting at t/t_timing_class.v:224 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:274 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:136 -V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:190 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:190 --V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip -V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:224 -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} No suspended processes waiting for dynamic trigger evaluation @@ -1071,16 +1071,16 @@ -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:119 --V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:120 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:122 --V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:224 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:136 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:190 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:274 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:131 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:224 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:122 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:136 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:190 -V{t#,#}+ Vt_timing_debug2_t____Vfork_2__0 -V{t#,#}+ Vt_timing_debug2_t__03a__03aAssignDelayClass::__VnoInFunc_do_assign --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:230 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 -V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act @@ -1107,13 +1107,13 @@ -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 85: Process waiting at t/t_timing_class.v:119 --V{t#,#} Awaiting time 85: Process waiting at t/t_timing_class.v:120 +-V{t#,#} Awaiting time 85: Process waiting at t/t_timing_class.v:230 +-V{t#,#} Awaiting time 85: Process waiting at t/t_timing_class.v:131 -V{t#,#} Awaiting time 90: Process waiting at t/t_timing_class.v:190 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:274 -V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:230 -V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:231 -V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act @@ -1140,13 +1140,13 @@ -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 90: Process waiting at t/t_timing_class.v:119 --V{t#,#} Awaiting time 90: Process waiting at t/t_timing_class.v:120 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:190 --V{t#,#} Awaiting time 100: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Awaiting time 90: Process waiting at t/t_timing_class.v:190 +-V{t#,#} Awaiting time 90: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:274 +-V{t#,#} Awaiting time 100: Process waiting at t/t_timing_class.v:231 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 -V{t#,#} Resuming: Process waiting at t/t_timing_class.v:190 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 -V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act @@ -1174,9 +1174,9 @@ -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 95: Process waiting at t/t_timing_class.v:119 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:120 --V{t#,#} Awaiting time 100: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Awaiting time 95: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:274 +-V{t#,#} Awaiting time 100: Process waiting at t/t_timing_class.v:231 -V{t#,#} Resuming delayed processes -V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 -V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip @@ -1205,13 +1205,13 @@ -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 100: Process waiting at t/t_timing_class.v:119 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:120 +-V{t#,#} Awaiting time 100: Process waiting at t/t_timing_class.v:231 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:274 -V{t#,#} Awaiting time 100: Process waiting at t/t_timing_class.v:131 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:231 *-* All Finished *-* --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:120 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 -V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act From ef4794e36df440be76779232bec8347ed5d4b52a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Boro=C5=84ski?= <94375110+kboronski-ant@users.noreply.github.com> Date: Tue, 22 Aug 2023 07:06:34 +0200 Subject: [PATCH 022/111] Support parenthesesless calls to static methods (#4432) --- src/V3LinkDot.cpp | 11 ++++++- test_regress/t/t_package_export_bad.out | 12 +++---- ...ction_in_class_call_without_parentheses.pl | 21 +++++++++++++ ...nction_in_class_call_without_parentheses.v | 31 +++++++++++++++++++ 4 files changed, 68 insertions(+), 7 deletions(-) create mode 100755 test_regress/t/t_static_function_in_class_call_without_parentheses.pl create mode 100644 test_regress/t/t_static_function_in_class_call_without_parentheses.v diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 8b81802aa..53ab2238a 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2573,13 +2573,15 @@ private: string expectWhat; bool allowScope = false; bool allowVar = false; + bool allowFTask = false; bool staticAccess = false; if (m_ds.m_dotPos == DP_PACKAGE) { // {package}::{a} AstNodeModule* classOrPackagep = nullptr; - expectWhat = "scope/variable"; + expectWhat = "scope/variable/func"; allowScope = true; allowVar = true; + allowFTask = true; staticAccess = true; UASSERT_OBJ(VN_IS(m_ds.m_dotp->lhsp(), ClassOrPackageRef), m_ds.m_dotp->lhsp(), "Bad package link"); @@ -2660,6 +2662,13 @@ private: << cellp->modp()->prettyNameQ()); } } + } else if (allowFTask && VN_IS(foundp->nodep(), NodeFTask)) { + AstTaskRef* const taskrefp + = new AstTaskRef{nodep->fileline(), nodep->name(), nullptr}; + nodep->replaceWith(taskrefp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + if (start) m_ds = lastStates; + return; } else if (AstVar* const varp = foundToVarp(foundp, nodep, VAccess::READ)) { AstIfaceRefDType* const ifacerefp = LinkDotState::ifaceRefFromArray(varp->subDTypep()); diff --git a/test_regress/t/t_package_export_bad.out b/test_regress/t/t_package_export_bad.out index 98c2ef9a9..caa0aa233 100644 --- a/test_regress/t/t_package_export_bad.out +++ b/test_regress/t/t_package_export_bad.out @@ -1,27 +1,27 @@ %Error: t/t_package_export.v:45:17: Export object not found: 'pkg1::BAD_DOES_NOT_EXIST' 45 | export pkg1::BAD_DOES_NOT_EXIST; | ^~~~~~~~~~~~~~~~~~ -%Error: t/t_package_export.v:60:16: Can't find definition of scope/variable: 'PARAM2' +%Error: t/t_package_export.v:60:16: Can't find definition of scope/variable/func: 'PARAM2' : ... Suggested alternative: 'PARAM1' 60 | reg [pkg11::PARAM2 : 0] bus12; | ^~~~~~ -%Error: t/t_package_export.v:61:16: Can't find definition of scope/variable: 'PARAM3' +%Error: t/t_package_export.v:61:16: Can't find definition of scope/variable/func: 'PARAM3' : ... Suggested alternative: 'PARAM1' 61 | reg [pkg11::PARAM3 : 0] bus13; | ^~~~~~ -%Error: t/t_package_export.v:64:16: Can't find definition of scope/variable: 'PARAM2' +%Error: t/t_package_export.v:64:16: Can't find definition of scope/variable/func: 'PARAM2' : ... Suggested alternative: 'PARAM1' 64 | reg [pkg21::PARAM2 : 0] bus22; | ^~~~~~ -%Error: t/t_package_export.v:65:16: Can't find definition of scope/variable: 'PARAM3' +%Error: t/t_package_export.v:65:16: Can't find definition of scope/variable/func: 'PARAM3' : ... Suggested alternative: 'PARAM1' 65 | reg [pkg21::PARAM3 : 0] bus23; | ^~~~~~ -%Error: t/t_package_export.v:68:16: Can't find definition of scope/variable: 'PARAM2' +%Error: t/t_package_export.v:68:16: Can't find definition of scope/variable/func: 'PARAM2' : ... Suggested alternative: 'PARAM1' 68 | reg [pkg31::PARAM2 : 0] bus32; | ^~~~~~ -%Error: t/t_package_export.v:69:16: Can't find definition of scope/variable: 'PARAM3' +%Error: t/t_package_export.v:69:16: Can't find definition of scope/variable/func: 'PARAM3' : ... Suggested alternative: 'PARAM1' 69 | reg [pkg31::PARAM3 : 0] bus33; | ^~~~~~ diff --git a/test_regress/t/t_static_function_in_class_call_without_parentheses.pl b/test_regress/t/t_static_function_in_class_call_without_parentheses.pl new file mode 100755 index 000000000..859050d63 --- /dev/null +++ b/test_regress/t/t_static_function_in_class_call_without_parentheses.pl @@ -0,0 +1,21 @@ +#!/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(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_static_function_in_class_call_without_parentheses.v b/test_regress/t/t_static_function_in_class_call_without_parentheses.v new file mode 100644 index 000000000..4c125d7ff --- /dev/null +++ b/test_regress/t/t_static_function_in_class_call_without_parentheses.v @@ -0,0 +1,31 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +class Foo; + static int m_v; + + static function void set_v(int v); + m_v = v; + endfunction + static function int get_v(); + // Let's see if referring to the implicit variable does not resolve into a call + get_v = m_v; + endfunction +endclass + +module t(); + initial begin + int v; + + Foo::set_v(3); + // Check if a parenthesesless call to static method works + v = Foo::get_v; + if (v != 3) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule From 967a8530dd02a20cb5e9c33dcb83d96a0cc349d8 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 22 Aug 2023 01:48:45 -0400 Subject: [PATCH 023/111] Fix errors on some $past cases (#4425) --- src/verilog.y | 22 +++++++++++++++++----- test_regress/t/t_past.v | 6 ++++-- test_regress/t/t_past_unsup.out | 11 +++++++++++ test_regress/t/t_past_unsup.pl | 19 +++++++++++++++++++ test_regress/t/t_past_unsup.v | 20 ++++++++++++++++++++ 5 files changed, 71 insertions(+), 7 deletions(-) create mode 100644 test_regress/t/t_past_unsup.out create mode 100755 test_regress/t/t_past_unsup.pl create mode 100644 test_regress/t/t_past_unsup.v diff --git a/src/verilog.y b/src/verilog.y index 08cd48cdc..076ea09fa 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -4254,11 +4254,13 @@ system_f_call_or_t: // IEEE: part of system_tf_call (can be task | yD_ONEHOT '(' expr ')' { $$ = new AstOneHot{$1, $3}; } | yD_ONEHOT0 '(' expr ')' { $$ = new AstOneHot0{$1, $3}; } | yD_PAST '(' expr ')' { $$ = new AstPast{$1, $3, nullptr}; } - | yD_PAST '(' expr ',' expr ')' { $$ = new AstPast{$1, $3, $5}; } - | yD_PAST '(' expr ',' expr ',' expr ')' - { $$ = $3; BBUNSUP($1, "Unsupported: $past expr2 and clock arguments"); } - | yD_PAST '(' expr ',' expr ',' expr ',' expr')' - { $$ = $3; BBUNSUP($1, "Unsupported: $past expr2 and clock arguments"); } + | yD_PAST '(' expr ',' exprE ')' { $$ = new AstPast{$1, $3, $5}; } + | yD_PAST '(' expr ',' exprE ',' exprE ')' + { if ($7) BBUNSUP($1, "Unsupported: $past expr2 and/or clock arguments"); + $$ = new AstPast{$1, $3, $5}; } + | yD_PAST '(' expr ',' exprE ',' exprE ',' clocking_eventE ')' + { if ($7 || $9) BBUNSUP($1, "Unsupported: $past expr2 and/or clock arguments"); + $$ = new AstPast{$1, $3, $5}; } | yD_POW '(' expr ',' expr ')' { $$ = new AstPowD{$1, $3, $5}; } | yD_RANDOM '(' expr ')' { $$ = new AstRand{$1, $3, false}; } | yD_RANDOM parenE { $$ = new AstRand{$1, nullptr, false}; } @@ -4683,6 +4685,11 @@ constExpr: expr { $$ = $1; } ; +exprE: // IEEE: optional expression + /*empty*/ { $$ = nullptr; } + | expr { $$ = $1; } + ; + expr: // IEEE: part of expression/constant_expression/primary // *SEE BELOW* // IEEE: primary/constant_primary // @@ -5665,6 +5672,11 @@ clocking_declaration: // IEEE: clocking_declaration { $$ = new AstClocking{$3, *$3, $4, $6, false, true}; } ; +clocking_eventE: // IEEE: optional clocking_event + /* empty */ { $$ = nullptr; } + | clocking_event { $$ = $1; } + ; + clocking_event: // IEEE: clocking_event '@' id { $$ = new AstSenItem{$2, VEdgeType::ET_CHANGED, new AstParseRef{$2, VParseRefExp::PX_TEXT, *$2, nullptr, nullptr}}; } diff --git a/test_regress/t/t_past.v b/test_regress/t/t_past.v index 250810185..24b82ad92 100644 --- a/test_regress/t/t_past.v +++ b/test_regress/t/t_past.v @@ -74,8 +74,10 @@ module Test (/*AUTOARG*/ // $past(expression, ticks, expression, clocking) // In clock expression if (dly0 != $past(in)) $stop; - if (dly0 != $past(in,1)) $stop; - if (dly1 != $past(in,2)) $stop; + if (dly0 != $past(in,)) $stop; + if (dly1 != $past(in, 2)) $stop; + if (dly1 != $past(in, 2, )) $stop; + if (dly1 != $past(in, 2, , )) $stop; // $sampled(expression) -> expression if (in != $sampled(in)) $stop; end diff --git a/test_regress/t/t_past_unsup.out b/test_regress/t/t_past_unsup.out new file mode 100644 index 000000000..888dec662 --- /dev/null +++ b/test_regress/t/t_past_unsup.out @@ -0,0 +1,11 @@ +%Error-UNSUPPORTED: t/t_past_unsup.v:16:11: Unsupported: $past expr2 and/or clock arguments + 16 | if ($past(d, 1, 1)) $stop; + | ^~~~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error-UNSUPPORTED: t/t_past_unsup.v:17:11: Unsupported: $past expr2 and/or clock arguments + 17 | if ($past(d, 1, 1, )) $stop; + | ^~~~~ +%Error-UNSUPPORTED: t/t_past_unsup.v:18:11: Unsupported: $past expr2 and/or clock arguments + 18 | if ($past(d, 1, 1, @(posedge clk))) $stop; + | ^~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_past_unsup.pl b/test_regress/t/t_past_unsup.pl new file mode 100755 index 000000000..a5846c699 --- /dev/null +++ b/test_regress/t/t_past_unsup.pl @@ -0,0 +1,19 @@ +#!/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(vlt => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_past_unsup.v b/test_regress/t/t_past_unsup.v new file mode 100644 index 000000000..58cbc84c5 --- /dev/null +++ b/test_regress/t/t_past_unsup.v @@ -0,0 +1,20 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2018 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + // Inputs + d, clk, num + ); + input d; + input clk; + input int num; + + always @ (posedge clk) begin + if ($past(d, 1, 1)) $stop; // Unsup + if ($past(d, 1, 1, )) $stop; // Unsup + if ($past(d, 1, 1, @(posedge clk))) $stop; // Unsup + end +endmodule From 90079c2974c40fb9758c3e5a5733f3255fe3435b Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Wed, 23 Aug 2023 12:08:22 +0200 Subject: [PATCH 024/111] Fix nested assignments on the LHS (#4435) --- src/V3Timing.cpp | 24 ++++++-------- .../t/t_timing_nested_assignment_on_lhs.pl | 25 +++++++++++++++ .../t/t_timing_nested_assignment_on_lhs.v | 31 +++++++++++++++++++ 3 files changed, 65 insertions(+), 15 deletions(-) create mode 100755 test_regress/t/t_timing_nested_assignment_on_lhs.pl create mode 100644 test_regress/t/t_timing_nested_assignment_on_lhs.v diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp index 0cca7835a..b886b2ed9 100644 --- a/src/V3Timing.cpp +++ b/src/V3Timing.cpp @@ -415,25 +415,19 @@ private: // METHODS // Find net delay on the LHS of an assignment - AstDelay* getLhsNetDelay(AstNodeAssign* nodep) const { - bool foundWrite = false; - AstDelay* delayp = nullptr; - nodep->lhsp()->foreach([&](const AstNodeVarRef* const refp) { - if (!refp->access().isWriteOrRW()) return; - UASSERT_OBJ(!foundWrite, nodep, "Should only be one variable written to on the LHS"); - foundWrite = true; - if (refp->varp()->delayp()) { - delayp = refp->varp()->delayp(); - delayp->unlinkFrBack(); - } - }); - return delayp; + AstDelay* getLhsNetDelayRecurse(const AstNodeExpr* const nodep) const { + if (const AstNodeVarRef* const refp = VN_CAST(nodep, NodeVarRef)) { + if (refp->varp()->delayp()) return refp->varp()->delayp()->unlinkFrBack(); + } else if (const AstSel* const selp = VN_CAST(nodep, Sel)) { + return getLhsNetDelayRecurse(selp->fromp()); + } + return nullptr; } // Transform an assignment with an intra timing control into a timing control with the // assignment under it AstNode* factorOutTimingControl(AstNodeAssign* nodep) const { AstNode* stmtp = nodep; - AstDelay* delayp = getLhsNetDelay(nodep); + AstDelay* delayp = getLhsNetDelayRecurse(nodep->lhsp()); FileLine* const flp = nodep->fileline(); AstNode* const controlp = nodep->timingControlp(); if (controlp) { @@ -955,7 +949,7 @@ private: replaceWithIntermediate(nodep->rhsp(), m_intraValueNames.get(nodep)); } void visit(AstAssignW* nodep) override { - AstDelay* const netDelayp = getLhsNetDelay(nodep); + AstDelay* const netDelayp = getLhsNetDelayRecurse(nodep->lhsp()); if (!netDelayp && !nodep->timingControlp()) return; // This assignment will be converted to an always. In some cases this may generate an // UNOPTFLAT, e.g.: assign #1 clk = ~clk. We create a temp var for the LHS of this diff --git a/test_regress/t/t_timing_nested_assignment_on_lhs.pl b/test_regress/t/t_timing_nested_assignment_on_lhs.pl new file mode 100755 index 000000000..0ebdb8a45 --- /dev/null +++ b/test_regress/t/t_timing_nested_assignment_on_lhs.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 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(simulator => 1); + +top_filename("t/t_net_delay.v"); + +compile( + timing_loop => 1, + verilator_flags2 => ["--timing"], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_timing_nested_assignment_on_lhs.v b/test_regress/t/t_timing_nested_assignment_on_lhs.v new file mode 100644 index 000000000..1bacb5579 --- /dev/null +++ b/test_regress/t/t_timing_nested_assignment_on_lhs.v @@ -0,0 +1,31 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +class uvm_object_wrapper; + function string get_type_name; + return "abcd"; + endfunction +endclass + +class uvm_default_factory; + int m_type_names[string]; + virtual function int register; + uvm_object_wrapper obj; + string name; + m_type_names[(name = obj.get_type_name())] = 1; + return m_type_names[name]; + endfunction +endclass + +module t; + initial begin + uvm_default_factory u = new; + if (u.register() != 1) $stop; + #1; // Needed only visit assignments in V3Timing + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule From e8e79128715faa12b73bcd79de54d477e5fe0855 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Wed, 23 Aug 2023 16:27:17 +0200 Subject: [PATCH 025/111] Tests: Fix t_net_delay test (#4436) --- test_regress/t/t_net_delay.out | 12 ++++++------ test_regress/t/t_net_delay.v | 21 +++++++++++++-------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/test_regress/t/t_net_delay.out b/test_regress/t/t_net_delay.out index afade27cb..d812684ed 100644 --- a/test_regress/t/t_net_delay.out +++ b/test_regress/t/t_net_delay.out @@ -1,15 +1,15 @@ -%Warning-STMTDLY: t/t_net_delay.v:13:14: Ignoring delay on this statement due to --no-timing +%Warning-STMTDLY: t/t_net_delay.v:15:14: Ignoring delay on this statement due to --no-timing : ... In instance t - 13 | wire[3:0] #4 val1 = cyc; + 15 | wire[3:0] #4 val1 = half_cyc; | ^ ... For warning description see https://verilator.org/warn/STMTDLY?v=latest ... Use "/* verilator lint_off STMTDLY */" and lint_on around source to disable this message. -%Warning-STMTDLY: t/t_net_delay.v:14:14: Ignoring delay on this statement due to --no-timing +%Warning-STMTDLY: t/t_net_delay.v:16:14: Ignoring delay on this statement due to --no-timing : ... In instance t - 14 | wire[3:0] #4 val2; + 16 | wire[3:0] #4 val2; | ^ -%Warning-ASSIGNDLY: t/t_net_delay.v:17:11: Ignoring timing control on this assignment/primitive due to --no-timing +%Warning-ASSIGNDLY: t/t_net_delay.v:19:11: Ignoring timing control on this assignment/primitive due to --no-timing : ... In instance t - 17 | assign #4 val2 = cyc; + 19 | assign #4 val2 = half_cyc; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_net_delay.v b/test_regress/t/t_net_delay.v index c9b524005..13fece4e5 100644 --- a/test_regress/t/t_net_delay.v +++ b/test_regress/t/t_net_delay.v @@ -4,25 +4,30 @@ // any use, without warranty, 2022 by Antmicro Ltd. // SPDX-License-Identifier: CC0-1.0 +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0) + module t (/*AUTOARG*/ // Inputs clk ); input clk; - wire[3:0] #4 val1 = cyc; + wire[3:0] #4 val1 = half_cyc; wire[3:0] #4 val2; - reg[3:0] cyc = 0; + reg[3:0] half_cyc = 0; - assign #4 val2 = cyc; + assign #4 val2 = half_cyc; - always @(posedge clk) begin - cyc <= cyc + 1; + always @(clk) begin + if ($time > 0) half_cyc <= half_cyc + 1; `ifdef TEST_VERBOSE - $write("[%0t] cyc=%0d, val1=%0d, val2=%0d\n", $time, cyc, val1, val2); + $strobe("[%0t] half_cyc=%0d, val1=%0d, val2=%0d", $time, half_cyc, val1, val2); `endif - if (cyc >= 7 && val1 != cyc-1 && val2 != cyc-7) $stop; - if (cyc == 15) begin + if (half_cyc >= 7) begin + `checkh(val1, half_cyc - 3); + `checkh(val2, half_cyc - 7); + end + if (half_cyc == 15) begin $write("*-* All Finished *-*\n"); $finish; end From 2daa32b98b27855a224ce4daea5a5b6702004af2 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Fri, 25 Aug 2023 11:24:12 +0200 Subject: [PATCH 026/111] Support assignments of packed values to stream expressions on queues (#4401) --- include/verilated_funcs.h | 8 + src/V3AstNodeExpr.h | 14 ++ src/V3Const.cpp | 30 ++-- src/V3EmitCFunc.h | 13 ++ src/V3Width.cpp | 10 +- test_regress/t/t_stream_bad.out | 5 + test_regress/t/t_stream_dynamic.pl | 21 +++ test_regress/t/t_stream_dynamic.v | 40 +++++ test_regress/t/t_stream_integer_type.out | 40 ----- .../t/t_stream_integer_type_unsup.out | 146 ++++++++++++++++++ ...type.pl => t_stream_integer_type_unsup.pl} | 0 ...r_type.v => t_stream_integer_type_unsup.v} | 0 12 files changed, 269 insertions(+), 58 deletions(-) create mode 100755 test_regress/t/t_stream_dynamic.pl create mode 100644 test_regress/t/t_stream_dynamic.v delete mode 100644 test_regress/t/t_stream_integer_type.out create mode 100644 test_regress/t/t_stream_integer_type_unsup.out rename test_regress/t/{t_stream_integer_type.pl => t_stream_integer_type_unsup.pl} (100%) rename test_regress/t/{t_stream_integer_type.v => t_stream_integer_type_unsup.v} (100%) diff --git a/include/verilated_funcs.h b/include/verilated_funcs.h index 63bcda06f..98e14738a 100644 --- a/include/verilated_funcs.h +++ b/include/verilated_funcs.h @@ -1526,6 +1526,14 @@ static inline WDataOutP VL_STREAML_WWI(int lbits, WDataOutP owp, WDataInP const return owp; } +template +static inline void VL_ASSIGN_DYN_Q(VlQueue& q, int elem_size, int lbits, QData from) { + const int size = (lbits + elem_size - 1) / elem_size; + q.renew(size); + const QData mask = VL_MASK_Q(elem_size); + for (int i = 0; i < size; ++i) q.at(i) = (T)((from >> (i * elem_size)) & mask); +} + // Because concats are common and wide, it's valuable to always have a clean output. // Thus we specify inputs must be clean, so we don't need to clean the output. // Note the bit shifts are always constants, so the adds in these constify out. diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 9e198b39e..302c74c6c 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -1013,6 +1013,20 @@ public: // May return nullptr on parse failure. static AstConst* parseParamLiteral(FileLine* fl, const string& literal); }; +class AstCvtPackedToDynArray final : public AstNodeExpr { + // Cast from packed array to dynamic queue data type + // @astgen op1 := fromp : AstNodeExpr +public: + AstCvtPackedToDynArray(FileLine* fl, AstNodeExpr* fromp, AstNodeDType* dtp) + : ASTGEN_SUPER_CvtPackedToDynArray(fl) { + this->fromp(fromp); + dtypeFrom(dtp); + } + ASTGEN_MEMBERS_AstCvtPackedToDynArray; + string emitVerilog() override { V3ERROR_NA_RETURN(""); } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return true; } +}; class AstDot final : public AstNodeExpr { // A dot separating paths in an AstVarXRef, AstFuncRef or AstTaskRef // These are eliminated in the link stage diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 8eca1a198..856a13b57 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -2158,12 +2158,11 @@ private: return true; } else if (m_doV && VN_IS(nodep->lhsp(), StreamL)) { // Push the stream operator to the rhs of the assignment statement - const int dWidth = VN_AS(nodep->lhsp(), StreamL)->lhsp()->width(); - const int sWidth = nodep->rhsp()->width(); - // Unlink the stuff - AstNodeExpr* const dstp = VN_AS(nodep->lhsp(), StreamL)->lhsp()->unlinkFrBack(); - AstNodeExpr* streamp = VN_AS(nodep->lhsp(), StreamL)->unlinkFrBack(); + AstNodeExpr* streamp = nodep->lhsp()->unlinkFrBack(); + AstNodeExpr* const dstp = VN_AS(streamp, StreamL)->lhsp()->unlinkFrBack(); AstNodeExpr* const srcp = nodep->rhsp()->unlinkFrBack(); + const int sWidth = srcp->width(); + const int dWidth = dstp->width(); // Connect the rhs to the stream operator and update its width VN_AS(streamp, StreamL)->lhsp(srcp); if (VN_IS(srcp->dtypep(), DynArrayDType) || VN_IS(srcp->dtypep(), QueueDType) @@ -2172,11 +2171,11 @@ private: } else { streamp->dtypeSetLogicUnsized(srcp->width(), srcp->widthMin(), VSigning::UNSIGNED); } - // Shrink the RHS if necessary - if (sWidth > dWidth) { + if (dWidth == 0) { + streamp = new AstCvtPackedToDynArray{nodep->fileline(), streamp, dstp->dtypep()}; + } else if (sWidth > dWidth) { streamp = new AstSel{streamp->fileline(), streamp, sWidth - dWidth, dWidth}; } - // Link the nodes back in nodep->lhsp(dstp); nodep->rhsp(streamp); return true; @@ -2184,14 +2183,15 @@ private: // The right stream operator on lhs of assignment statement does // not reorder bits. However, if the rhs is wider than the lhs, // then we select bits from the left-most, not the right-most. - const int dWidth = VN_AS(nodep->lhsp(), StreamR)->lhsp()->width(); - const int sWidth = nodep->rhsp()->width(); - // Unlink the stuff - AstNodeExpr* const dstp = VN_AS(nodep->lhsp(), StreamR)->lhsp()->unlinkFrBack(); - AstNode* const sizep = VN_AS(nodep->lhsp(), StreamR)->rhsp()->unlinkFrBack(); - AstNodeExpr* const streamp = VN_AS(nodep->lhsp(), StreamR)->unlinkFrBack(); + AstNodeExpr* const streamp = nodep->lhsp()->unlinkFrBack(); + AstNodeExpr* const dstp = VN_AS(streamp, StreamR)->lhsp()->unlinkFrBack(); + AstNode* const sizep = VN_AS(streamp, StreamR)->rhsp()->unlinkFrBack(); AstNodeExpr* srcp = nodep->rhsp()->unlinkFrBack(); - if (sWidth > dWidth) { + const int sWidth = srcp->width(); + const int dWidth = dstp->width(); + if (dWidth == 0) { + srcp = new AstCvtPackedToDynArray{nodep->fileline(), srcp, dstp->dtypep()}; + } else if (sWidth > dWidth) { srcp = new AstSel{streamp->fileline(), srcp, sWidth - dWidth, dWidth}; } nodep->lhsp(dstp); diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index 351fd956a..b4817ab8d 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -401,6 +401,19 @@ public: puts(cvtToStr(nodep->widthMin()) + ","); iterateAndNextConstNull(nodep->lhsp()); puts(", "); + } else if (const AstCvtPackedToDynArray* const castp + = VN_CAST(nodep->rhsp(), CvtPackedToDynArray)) { + puts("VL_ASSIGN_DYN_Q<"); + putbs(castp->dtypep()->subDTypep()->cType("", false, false)); + puts(">("); + iterateAndNextConstNull(nodep->lhsp()); + puts(", "); + puts(cvtToStr(castp->dtypep()->subDTypep()->widthMin())); + puts(", "); + puts(cvtToStr(castp->fromp()->widthMin())); + puts(", "); + rhs = false; + iterateAndNextConstNull(castp->fromp()); } else if (nodep->isWide() && VN_IS(nodep->lhsp(), VarRef) // && !VN_IS(nodep->rhsp(), CExpr) // && !VN_IS(nodep->rhsp(), CMethodHard) // diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 965c511d8..ab3f2267a 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -840,9 +840,13 @@ private: } else { nodep->v3error("Slice size isn't a constant or basic data type."); } - if (VN_IS(nodep->lhsp()->dtypep(), DynArrayDType) - || VN_IS(nodep->lhsp()->dtypep(), QueueDType) - || VN_IS(nodep->lhsp()->dtypep(), UnpackArrayDType)) { + const AstNodeDType* const lhsDtypep = nodep->lhsp()->dtypep(); + if (VN_IS(lhsDtypep, DynArrayDType) || VN_IS(lhsDtypep, QueueDType)) { + nodep->dtypeSetStream(); + } else if (VN_IS(lhsDtypep, UnpackArrayDType) || lhsDtypep->isCompound()) { + nodep->v3warn(E_UNSUPPORTED, + "Unsupported: Stream operation on a variable of a type " + << lhsDtypep->prettyDTypeNameQ()); nodep->dtypeSetStream(); } else { nodep->dtypeSetLogicUnsized(nodep->lhsp()->width(), nodep->lhsp()->widthMin(), diff --git a/test_regress/t/t_stream_bad.out b/test_regress/t/t_stream_bad.out index 6b4934e46..966297307 100644 --- a/test_regress/t/t_stream_bad.out +++ b/test_regress/t/t_stream_bad.out @@ -6,4 +6,9 @@ : ... In instance t 12 | initial packed_data_32 = {<<$random{byte_in}}; | ^~ +%Error-UNSUPPORTED: t/t_stream_bad.v:12:30: Unsupported: Stream operation on a variable of a type 'byte$[0:3]' + : ... In instance t + 12 | initial packed_data_32 = {<<$random{byte_in}}; + | ^~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest %Error: Exiting due to diff --git a/test_regress/t/t_stream_dynamic.pl b/test_regress/t/t_stream_dynamic.pl new file mode 100755 index 000000000..aabcde63e --- /dev/null +++ b/test_regress/t/t_stream_dynamic.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_stream_dynamic.v b/test_regress/t/t_stream_dynamic.v new file mode 100644 index 000000000..60c127bef --- /dev/null +++ b/test_regress/t/t_stream_dynamic.v @@ -0,0 +1,40 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +`define stop $stop +`define checks(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); + +module t (/*AUTOARG*/); + initial begin + bit arr[]; + bit [1:0] arr2[$]; + bit [4:0] arr5[]; + bit [5:0] arr6[$]; + string v; + bit [5:0] bit6 = 6'b111000; + + { >> bit {arr}} = bit6; + v = $sformatf("%p", arr); `checks(v, "'{'h0, 'h0, 'h0, 'h1, 'h1, 'h1} "); + + { << bit {arr}} = bit6; + v = $sformatf("%p", arr); `checks(v, "'{'h1, 'h1, 'h1, 'h0, 'h0, 'h0} "); + + { >> bit[1:0] {arr2}} = bit6; + v = $sformatf("%p", arr2); `checks(v, "'{'h0, 'h2, 'h3} "); + + { << bit[1:0] {arr2}} = bit6; + v = $sformatf("%p", arr2); `checks(v, "'{'h3, 'h2, 'h0} "); + + { >> bit [5:0] {arr6} } = bit6; + v = $sformatf("%p", arr6); `checks(v, "'{'h38} "); + + { << bit [5:0] {arr6} } = bit6; + v = $sformatf("%p", arr6); `checks(v, "'{'h38} "); + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_stream_integer_type.out b/test_regress/t/t_stream_integer_type.out deleted file mode 100644 index 05640a0f4..000000000 --- a/test_regress/t/t_stream_integer_type.out +++ /dev/null @@ -1,40 +0,0 @@ -%Error: t/t_stream_integer_type.v:128:11: SEL is not an unpacked array, but is in an unpacked array context - 128 | {<<8{byte_out}} = packed_data_32; - | ^~ -%Error: t/t_stream_integer_type.v:129:11: SEL is not an unpacked array, but is in an unpacked array context - 129 | {<<16{shortint_out}} = packed_data_64; - | ^~ -%Error: t/t_stream_integer_type.v:130:11: SEL is not an unpacked array, but is in an unpacked array context - 130 | {<<32{int_out}} = packed_data_128; - | ^~ -%Error: t/t_stream_integer_type.v:131:11: SEL is not an unpacked array, but is in an unpacked array context - 131 | {<<32{integer_out}} = packed_data_128_i; - | ^~ -%Error: t/t_stream_integer_type.v:132:11: SEL is not an unpacked array, but is in an unpacked array context - 132 | {<<64{longint_out}} = packed_data_256; - | ^~ -%Error: t/t_stream_integer_type.v:133:11: SEL is not an unpacked array, but is in an unpacked array context - 133 | {<<64{time_out}} = packed_time_256; - | ^~ -%Error: t/t_stream_integer_type.v:134:11: SEL is not an unpacked array, but is in an unpacked array context - 134 | {<<8{bit_out}} = v_packed_data_32; - | ^~ -%Error: t/t_stream_integer_type.v:135:11: SEL is not an unpacked array, but is in an unpacked array context - 135 | {<<16{logic_out}} = v_packed_data_64; - | ^~ -%Error: t/t_stream_integer_type.v:136:11: SEL is not an unpacked array, but is in an unpacked array context - 136 | {<<32{reg_out}} = v_packed_data_128; - | ^~ -%Error: t/t_stream_integer_type.v:160:11: SEL is not an unpacked array, but is in an unpacked array context - 160 | {< Date: Fri, 25 Aug 2023 07:59:29 -0400 Subject: [PATCH 027/111] Fix false UNUSEDPARAM on generate localparam (#4427). --- Changes | 1 + src/V3LinkDot.cpp | 8 ++++++++ test_regress/t/t_lint_unused_bad.v | 13 +++++++++++++ 3 files changed, 22 insertions(+) diff --git a/Changes b/Changes index f8d51a059..f0e862842 100644 --- a/Changes +++ b/Changes @@ -20,6 +20,7 @@ Verilator 5.015 devel * Fix jumping over object initialization (#4411). [Krzysztof Boroński] * Fix variable lifetimes in extern methods (#4414). [Krzysztof Boroński] * Fix multple function definitions in V3Sched (#4416). [Hennadii Chernyshchyk] +* Fix false UNUSEDPARAM on generate localparam (#4427). [Bill Pringlemeir] Verilator 5.014 2023-08-06 diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 53ab2238a..2718e5c37 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2256,6 +2256,11 @@ private: // parameters or vice versa return pinp->param() == refVarType.isParam(); } + void updateVarUse(AstVar* nodep) { + // Avoid dotted.PARAM false positive when in a parameter block + // that is if ()'ed off by same dotted name as another block + if (nodep && nodep->isParam()) nodep->usedParam(true); + } // VISITs void visit(AstNetlist* nodep) override { @@ -2922,6 +2927,7 @@ private: if (AstVar* const varp = foundp ? foundToVarp(foundp, nodep, nodep->access()) : nullptr) { nodep->varp(varp); + updateVarUse(nodep->varp()); // Generally set by parse, but might be an import nodep->classOrPackagep(foundp->classOrPackagep()); } @@ -2964,6 +2970,7 @@ private: AstVar* const varp = foundp ? foundToVarp(foundp, nodep, nodep->access()) : nullptr; nodep->varp(varp); + updateVarUse(nodep->varp()); UINFO(7, " Resolved " << nodep << endl); // Also prints varp if (!nodep->varp()) { nodep->v3error("Can't find definition of " @@ -3001,6 +3008,7 @@ private: // later optimizations to deal with VarXRef. nodep->varp(vscp->varp()); nodep->varScopep(vscp); + updateVarUse(nodep->varp()); UINFO(7, " Resolved " << nodep << endl); // Also prints taskp AstVarRef* const newvscp = new AstVarRef{nodep->fileline(), vscp, nodep->access()}; diff --git a/test_regress/t/t_lint_unused_bad.v b/test_regress/t/t_lint_unused_bad.v index cc837c4ec..abcd94e51 100644 --- a/test_regress/t/t_lint_unused_bad.v +++ b/test_regress/t/t_lint_unused_bad.v @@ -64,10 +64,23 @@ module sub; genvar linter_genvar4; // verilator lint_on UNUSED + case (2) + 1: begin : named + localparam BLOCK_PARAM = 10; + end + 2: begin : named + localparam BLOCK_PARAM = 20; + end + 3: begin : named + localparam BLOCK_PARAM = 30; + end + endcase + initial begin if (0 && assunu1[0] != 0 && udrb2 != 0) begin end if (0 && assunub2[THREE] && assunub2[1:0]!=0) begin end if (0 && mixed[1:0] != 0) begin end + if (named.BLOCK_PARAM != 20) $stop; end generate From 00d63883f887cb24f7b0404d97dca709cf2edd9e Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 25 Aug 2023 08:21:15 -0400 Subject: [PATCH 028/111] Fix false MULTITOP on bound interfaces (#4438). --- Changes | 1 + src/V3LinkLevel.cpp | 2 +- test_regress/t/t_bind_nfound.pl | 16 ++++++++++++++++ test_regress/t/t_bind_nfound.v | 27 +++++++++++++++++++++++++++ 4 files changed, 45 insertions(+), 1 deletion(-) create mode 100755 test_regress/t/t_bind_nfound.pl create mode 100644 test_regress/t/t_bind_nfound.v diff --git a/Changes b/Changes index f0e862842..7bd9516cc 100644 --- a/Changes +++ b/Changes @@ -21,6 +21,7 @@ Verilator 5.015 devel * Fix variable lifetimes in extern methods (#4414). [Krzysztof Boroński] * Fix multple function definitions in V3Sched (#4416). [Hennadii Chernyshchyk] * Fix false UNUSEDPARAM on generate localparam (#4427). [Bill Pringlemeir] +* Fix false MULTITOP on bound interfaces (#4438). [Alex Solomatnikov] Verilator 5.014 2023-08-06 diff --git a/src/V3LinkLevel.cpp b/src/V3LinkLevel.cpp index 36ee13044..1b0dc54cf 100644 --- a/src/V3LinkLevel.cpp +++ b/src/V3LinkLevel.cpp @@ -53,7 +53,7 @@ void V3LinkLevel::modSortByLevel() { ModVec tops; // Top level modules for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); nodep; nodep = VN_AS(nodep->nextp(), NodeModule)) { - if (nodep->level() <= 2) tops.push_back(nodep); + if (nodep->level() <= 2 && !VN_IS(nodep, NotFoundModule)) tops.push_back(nodep); mods.push_back(nodep); } if (tops.size() >= 2) { diff --git a/test_regress/t/t_bind_nfound.pl b/test_regress/t/t_bind_nfound.pl new file mode 100755 index 000000000..7918d5f13 --- /dev/null +++ b/test_regress/t/t_bind_nfound.pl @@ -0,0 +1,16 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2008 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(); + +ok(1); +1; diff --git a/test_regress/t/t_bind_nfound.v b/test_regress/t/t_bind_nfound.v new file mode 100644 index 000000000..505944b62 --- /dev/null +++ b/test_regress/t/t_bind_nfound.v @@ -0,0 +1,27 @@ +// 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 + +interface bound_if; +endinterface + +module t; + + sub sub(); + + initial begin + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule + +module sub_ext; + bind sub_inst bound_if i_bound(); +endmodule + +module sub; + sub_ext sub_ext(); +endmodule From 77bd565ef65c589472029c3f22cb0de57bdb9771 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 25 Aug 2023 08:28:26 -0400 Subject: [PATCH 029/111] Commentary: Changes update --- Changes | 10 ++++++++-- docs/spelling.txt | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Changes b/Changes index 7bd9516cc..6bba79b79 100644 --- a/Changes +++ b/Changes @@ -14,13 +14,19 @@ Verilator 5.015 devel **Minor:** * Add --no-trace-top to not trace top signals (#4412) (#4422). [Frans Skarman] +* Support assignments of packed values to stream expressions on queues (#4401). [Ryszard Rozak, Antmicro Ltd] +* Support no-parentheses calls to static methods (#4432). [Krzysztof Boroński] * Fix Windows filename format, etc (#3873) (#4421). [Anthony Donlon]. -* Fix dtype of condition operation on class objects (#4345) (#4352). [Ryszard Rozak, Antmicro Ltd] +* Fix data type of condition operation on class objects (#4345) (#4352). [Ryszard Rozak, Antmicro Ltd] +* Fix ++/-- under statements (#4399). [Aleksander Kiryk, Antmicro Ltd] * Fix detection of mixed blocking and nonblocking assignment in nested assignments (#4404). [Ryszard Rozak, Antmicro Ltd] * Fix jumping over object initialization (#4411). [Krzysztof Boroński] * Fix variable lifetimes in extern methods (#4414). [Krzysztof Boroński] -* Fix multple function definitions in V3Sched (#4416). [Hennadii Chernyshchyk] +* Fix multiple function definitions in V3Sched (#4416). [Hennadii Chernyshchyk] * Fix false UNUSEDPARAM on generate localparam (#4427). [Bill Pringlemeir] +* Fix checking for parameter and port connections in the wrong place (#4428). [Anthony Donlon] +* Fix coroutine handle movement during queue manipulation (#4431). [Aleksander Kiryk, Antmicro Ltd] +* Fix nested assignments on the LHS (#4435). [Ryszard Rozak, Antmicro Ltd] * Fix false MULTITOP on bound interfaces (#4438). [Alex Solomatnikov] diff --git a/docs/spelling.txt b/docs/spelling.txt index 46754fe66..49a5ed3b1 100644 --- a/docs/spelling.txt +++ b/docs/spelling.txt @@ -263,6 +263,7 @@ Pre Preprocess Pretet Pretl +Pringlemeir Priyadharshini Pullup Pulver From e66b28823dc96f808c97e0f03ec37290bd9d151a Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 26 Aug 2023 05:59:56 -0400 Subject: [PATCH 030/111] Internals: Cleanup some spacing. No functional change. --- src/V3Ast.h | 140 ++++++++++++++++++++++---------------------- src/V3EmitCFunc.h | 4 +- src/V3GraphTest.cpp | 2 - 3 files changed, 71 insertions(+), 75 deletions(-) diff --git a/src/V3Ast.h b/src/V3Ast.h index d49d60f1e..337d948a7 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -1329,55 +1329,55 @@ protected: class VNUser1InUse final : VNUserInUseBase { protected: friend class AstNode; - static uint32_t s_userCntGbl; // Count of which usage of userp() this is - static bool s_userBusy; // Count is in use + static uint32_t s_userCntGbl; // Count of which usage of userp() this is + static bool s_userBusy; // Count is in use public: - VNUser1InUse() { allocate(1, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } - ~VNUser1InUse() { free (1, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } + VNUser1InUse() { allocate(1, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } + ~VNUser1InUse() { free (1, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } static void clear() { clearcnt(1, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } static void check() { checkcnt(1, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } }; class VNUser2InUse final : VNUserInUseBase { protected: friend class AstNode; - static uint32_t s_userCntGbl; // Count of which usage of userp() this is - static bool s_userBusy; // Count is in use + static uint32_t s_userCntGbl; // Count of which usage of userp() this is + static bool s_userBusy; // Count is in use public: - VNUser2InUse() { allocate(2, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } - ~VNUser2InUse() { free (2, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } + VNUser2InUse() { allocate(2, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } + ~VNUser2InUse() { free (2, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } static void clear() { clearcnt(2, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } static void check() { checkcnt(2, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } }; class VNUser3InUse final : VNUserInUseBase { protected: friend class AstNode; - static uint32_t s_userCntGbl; // Count of which usage of userp() this is - static bool s_userBusy; // Count is in use + static uint32_t s_userCntGbl; // Count of which usage of userp() this is + static bool s_userBusy; // Count is in use public: - VNUser3InUse() { allocate(3, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } - ~VNUser3InUse() { free (3, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } + VNUser3InUse() { allocate(3, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } + ~VNUser3InUse() { free (3, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } static void clear() { clearcnt(3, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } static void check() { checkcnt(3, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } }; class VNUser4InUse final : VNUserInUseBase { protected: friend class AstNode; - static uint32_t s_userCntGbl; // Count of which usage of userp() this is - static bool s_userBusy; // Count is in use + static uint32_t s_userCntGbl; // Count of which usage of userp() this is + static bool s_userBusy; // Count is in use public: - VNUser4InUse() { allocate(4, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } - ~VNUser4InUse() { free (4, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } + VNUser4InUse() { allocate(4, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } + ~VNUser4InUse() { free (4, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } static void clear() { clearcnt(4, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } static void check() { checkcnt(4, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } }; class VNUser5InUse final : VNUserInUseBase { protected: friend class AstNode; - static uint32_t s_userCntGbl; // Count of which usage of userp() this is - static bool s_userBusy; // Count is in use + static uint32_t s_userCntGbl; // Count of which usage of userp() this is + static bool s_userBusy; // Count is in use public: - VNUser5InUse() { allocate(5, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } - ~VNUser5InUse() { free (5, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } + VNUser5InUse() { allocate(5, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } + ~VNUser5InUse() { free (5, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } static void clear() { clearcnt(5, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } static void check() { checkcnt(5, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } }; @@ -1768,74 +1768,74 @@ public: inline bool isString() const VL_MT_STABLE; // clang-format off - VNUser user1u() const VL_MT_STABLE { + VNUser user1u() const VL_MT_STABLE { // Slows things down measurably, so disabled by default - //UASSERT_STATIC(VNUser1InUse::s_userBusy, "userp set w/o busy"); - return ((m_user1Cnt==VNUser1InUse::s_userCntGbl) ? m_user1u : VNUser{0}); + //UASSERT_STATIC(VNUser1InUse::s_userBusy, "user1p used without AstUserInUse"); + return ((m_user1Cnt == VNUser1InUse::s_userCntGbl) ? m_user1u : VNUser{0}); } - AstNode* user1p() const VL_MT_STABLE { return user1u().toNodep(); } - void user1u(const VNUser& user) { m_user1u=user; m_user1Cnt=VNUser1InUse::s_userCntGbl; } - void user1p(void* userp) { user1u(VNUser{userp}); } - int user1() const { return user1u().toInt(); } - void user1(int val) { user1u(VNUser{val}); } - int user1Inc(int val=1) { int v=user1(); user1(v+val); return v; } - int user1SetOnce() { int v=user1(); if (!v) user1(1); return v; } // Better for cache than user1Inc() + AstNode* user1p() const VL_MT_STABLE { return user1u().toNodep(); } + void user1u(const VNUser& user) { m_user1u = user; m_user1Cnt = VNUser1InUse::s_userCntGbl; } + void user1p(void* userp) { user1u(VNUser{userp}); } + void user1(int val) { user1u(VNUser{val}); } + int user1() const { return user1u().toInt(); } + int user1Inc(int val = 1) { int v = user1(); user1(v + val); return v; } + int user1SetOnce() { int v = user1(); if (!v) user1(1); return v; } // Better for cache than user1Inc() static void user1ClearTree() { VNUser1InUse::clear(); } // Clear userp()'s across the entire tree - VNUser user2u() const VL_MT_STABLE { + VNUser user2u() const VL_MT_STABLE { // Slows things down measurably, so disabled by default - //UASSERT_STATIC(VNUser2InUse::s_userBusy, "userp set w/o busy"); - return ((m_user2Cnt==VNUser2InUse::s_userCntGbl) ? m_user2u : VNUser{0}); + //UASSERT_STATIC(VNUser2InUse::s_userBusy, "user2p used without AstUserInUse"); + return ((m_user2Cnt == VNUser2InUse::s_userCntGbl) ? m_user2u : VNUser{0}); } - AstNode* user2p() const VL_MT_STABLE { return user2u().toNodep(); } - void user2u(const VNUser& user) { m_user2u=user; m_user2Cnt=VNUser2InUse::s_userCntGbl; } - void user2p(void* userp) { user2u(VNUser{userp}); } - int user2() const { return user2u().toInt(); } - void user2(int val) { user2u(VNUser{val}); } - int user2Inc(int val=1) { int v=user2(); user2(v+val); return v; } - int user2SetOnce() { int v=user2(); if (!v) user2(1); return v; } // Better for cache than user2Inc() + AstNode* user2p() const VL_MT_STABLE { return user2u().toNodep(); } + void user2u(const VNUser& user) { m_user2u = user; m_user2Cnt = VNUser2InUse::s_userCntGbl; } + void user2p(void* userp) { user2u(VNUser{userp}); } + void user2(int val) { user2u(VNUser{val}); } + int user2() const { return user2u().toInt(); } + int user2Inc(int val = 1) { int v = user2(); user2(v + val); return v; } + int user2SetOnce() { int v = user2(); if (!v) user2(1); return v; } // Better for cache than user2Inc() static void user2ClearTree() { VNUser2InUse::clear(); } // Clear userp()'s across the entire tree - VNUser user3u() const VL_MT_STABLE { + VNUser user3u() const VL_MT_STABLE { // Slows things down measurably, so disabled by default - //UASSERT_STATIC(VNUser3InUse::s_userBusy, "userp set w/o busy"); - return ((m_user3Cnt==VNUser3InUse::s_userCntGbl) ? m_user3u : VNUser{0}); + //UASSERT_STATIC(VNUser3InUse::s_userBusy, "user3p used without AstUserInUse"); + return ((m_user3Cnt == VNUser3InUse::s_userCntGbl) ? m_user3u : VNUser{0}); } - AstNode* user3p() const VL_MT_STABLE { return user3u().toNodep(); } - void user3u(const VNUser& user) { m_user3u=user; m_user3Cnt=VNUser3InUse::s_userCntGbl; } - void user3p(void* userp) { user3u(VNUser{userp}); } - int user3() const { return user3u().toInt(); } - void user3(int val) { user3u(VNUser{val}); } - int user3Inc(int val=1) { int v=user3(); user3(v+val); return v; } - int user3SetOnce() { int v=user3(); if (!v) user3(1); return v; } // Better for cache than user3Inc() + AstNode* user3p() const VL_MT_STABLE { return user3u().toNodep(); } + void user3u(const VNUser& user) { m_user3u = user; m_user3Cnt = VNUser3InUse::s_userCntGbl; } + void user3p(void* userp) { user3u(VNUser{userp}); } + void user3(int val) { user3u(VNUser{val}); } + int user3() const { return user3u().toInt(); } + int user3Inc(int val = 1) { int v = user3(); user3(v + val); return v; } + int user3SetOnce() { int v = user3(); if (!v) user3(1); return v; } // Better for cache than user3Inc() static void user3ClearTree() { VNUser3InUse::clear(); } // Clear userp()'s across the entire tree - VNUser user4u() const VL_MT_STABLE { + VNUser user4u() const VL_MT_STABLE { // Slows things down measurably, so disabled by default - //UASSERT_STATIC(VNUser4InUse::s_userBusy, "userp set w/o busy"); - return ((m_user4Cnt==VNUser4InUse::s_userCntGbl) ? m_user4u : VNUser{0}); + //UASSERT_STATIC(VNUser4InUse::s_userBusy, "user4p used without AstUserInUse"); + return ((m_user4Cnt == VNUser4InUse::s_userCntGbl) ? m_user4u : VNUser{0}); } - AstNode* user4p() const VL_MT_STABLE { return user4u().toNodep(); } - void user4u(const VNUser& user) { m_user4u=user; m_user4Cnt=VNUser4InUse::s_userCntGbl; } - void user4p(void* userp) { user4u(VNUser{userp}); } - int user4() const { return user4u().toInt(); } - void user4(int val) { user4u(VNUser{val}); } - int user4Inc(int val=1) { int v=user4(); user4(v+val); return v; } - int user4SetOnce() { int v=user4(); if (!v) user4(1); return v; } // Better for cache than user4Inc() + AstNode* user4p() const VL_MT_STABLE { return user4u().toNodep(); } + void user4u(const VNUser& user) { m_user4u = user; m_user4Cnt = VNUser4InUse::s_userCntGbl; } + void user4p(void* userp) { user4u(VNUser{userp}); } + void user4(int val) { user4u(VNUser{val}); } + int user4() const { return user4u().toInt(); } + int user4Inc(int val = 1) { int v = user4(); user4(v + val); return v; } + int user4SetOnce() { int v = user4(); if (!v) user4(1); return v; } // Better for cache than user4Inc() static void user4ClearTree() { VNUser4InUse::clear(); } // Clear userp()'s across the entire tree - VNUser user5u() const VL_MT_STABLE { + VNUser user5u() const VL_MT_STABLE { // Slows things down measurably, so disabled by default - //UASSERT_STATIC(VNUser5InUse::s_userBusy, "userp set w/o busy"); - return ((m_user5Cnt==VNUser5InUse::s_userCntGbl) ? m_user5u : VNUser{0}); + //UASSERT_STATIC(VNUser5InUse::s_userBusy, "user5p used without AstUserInUse"); + return ((m_user5Cnt == VNUser5InUse::s_userCntGbl) ? m_user5u : VNUser{0}); } - AstNode* user5p() const VL_MT_STABLE { return user5u().toNodep(); } - void user5u(const VNUser& user) { m_user5u=user; m_user5Cnt=VNUser5InUse::s_userCntGbl; } - void user5p(void* userp) { user5u(VNUser{userp}); } - int user5() const { return user5u().toInt(); } - void user5(int val) { user5u(VNUser{val}); } - int user5Inc(int val=1) { int v=user5(); user5(v+val); return v; } - int user5SetOnce() { int v=user5(); if (!v) user5(1); return v; } // Better for cache than user5Inc() + AstNode* user5p() const VL_MT_STABLE { return user5u().toNodep(); } + void user5u(const VNUser& user) { m_user5u = user; m_user5Cnt = VNUser5InUse::s_userCntGbl; } + void user5p(void* userp) { user5u(VNUser{userp}); } + void user5(int val) { user5u(VNUser{val}); } + int user5() const { return user5u().toInt(); } + int user5Inc(int val = 1) { int v = user5(); user5(v + val); return v; } + int user5SetOnce() { int v = user5(); if (!v) user5(1); return v; } // Better for cache than user5Inc() static void user5ClearTree() { VNUser5InUse::clear(); } // Clear userp()'s across the entire tree // clang-format on diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index b4817ab8d..db2bf9e40 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -192,12 +192,10 @@ public: } void emitScIQW(AstVar* nodep) { UASSERT_OBJ(nodep->isSc(), nodep, "emitting SystemC operator on non-SC variable"); - // clang-format off puts(nodep->isScBigUint() ? "SB" : nodep->isScUint() ? "SU" : nodep->isScBv() ? "SW" - : (nodep->isScQuad() ? "SQ" : "SI")); - // clang-format on + : (nodep->isScQuad() ? "SQ" : "SI")); } void emitDatap(AstNode* nodep) { // When passing to a function with va_args the compiler doesn't diff --git a/src/V3GraphTest.cpp b/src/V3GraphTest.cpp index e90251a58..93ed93b89 100644 --- a/src/V3GraphTest.cpp +++ b/src/V3GraphTest.cpp @@ -293,10 +293,8 @@ public: void V3Graph::selfTest() { // Execute all of the tests UINFO(2, __FUNCTION__ << ": " << endl); - // clang-format off { V3GraphTestStrong{}.run(); } { V3GraphTestAcyc{}.run(); } { V3GraphTestVars{}.run(); } { V3GraphTestImport{}.run(); } - // clang-format on } From 63db60f64618798796482595e8174544d00cf5dd Mon Sep 17 00:00:00 2001 From: Anthony Donlon <4056887+donlon@users.noreply.github.com> Date: Sat, 26 Aug 2023 21:06:26 +0800 Subject: [PATCH 031/111] Fix using type in parameterized classes without #() (#4281) (#4440) * Check whether a class is parameterized or not with AstClass::isParameterized method * Fix usage conflict of user2 pointer in V3Param.cpp --- src/V3LinkDot.cpp | 3 +- src/V3Param.cpp | 28 +++++------ test_regress/t/t_class_param.v | 4 +- test_regress/t/t_class_param_mod.v | 4 +- test_regress/t/t_class_param_subtype.v | 49 +++++++++++++++++++ .../t/t_class_param_subtype_bad_paren.out | 5 ++ .../t/t_class_param_subtype_bad_paren.pl | 22 +++++++++ .../t/t_class_param_subtype_constsim.pl | 24 +++++++++ 8 files changed, 120 insertions(+), 19 deletions(-) create mode 100644 test_regress/t/t_class_param_subtype.v create mode 100644 test_regress/t/t_class_param_subtype_bad_paren.out create mode 100755 test_regress/t/t_class_param_subtype_bad_paren.pl create mode 100755 test_regress/t/t_class_param_subtype_constsim.pl diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 2718e5c37..3a1819911 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -3553,7 +3553,8 @@ private: if (nodep->user3SetOnce()) return; if (AstNode* const cpackagep = nodep->classOrPackageOpp()) { if (AstClassOrPackageRef* const cpackagerefp = VN_CAST(cpackagep, ClassOrPackageRef)) { - if (cpackagerefp->paramsp()) { + const AstClass* const clsp = VN_CAST(cpackagerefp->classOrPackageNodep(), Class); + if (clsp && clsp->isParameterized()) { // Unable to link before the instantiation of parameter classes. // The class reference node has to be visited to properly link parameters. iterate(cpackagep); diff --git a/src/V3Param.cpp b/src/V3Param.cpp index 2502bc459..1539ce3c4 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -18,7 +18,7 @@ // For each cell: // If parameterized, // Determine all parameter widths, constant values. -// (Interfaces also matter, as if an interface is parameterized +// (Interfaces also matter, as if a module is parameterized // this effectively changes the width behavior of all that // reference the iface.) // Clone module cell calls, renaming with __{par1}_{par2}_... @@ -227,6 +227,10 @@ class ParamProcessor final : public VNDeleter { // // (0=not processed, 1=iterated, but no number, // // 65+ parameter numbered) // NODE STATE - Shared with ParamVisitor + // AstClass::user4p() // AstClass* Unchanged copy of the parameterized class node. + // The class node may be modified according to parameter + // values and an unchanged copy is needed to instantiate + // classes with different parameters. // AstNodeModule::user5() // bool True if processed // AstGenFor::user5() // bool True if processed // AstVar::user5() // bool True if constant propagated @@ -574,8 +578,8 @@ class ParamProcessor final : public VNDeleter { // Note all module internal variables will be re-linked to the new modules by clone // However links outside the module (like on the upper cells) will not. AstNodeModule* newmodp; - if (srcModp->user2p()) { - newmodp = VN_CAST(srcModp->user2p()->cloneTree(false), NodeModule); + if (srcModp->user4p()) { + newmodp = VN_CAST(srcModp->user4p()->cloneTree(false), NodeModule); } else { newmodp = srcModp->cloneTree(false); } @@ -617,7 +621,7 @@ class ParamProcessor final : public VNDeleter { // Grab all I/O so we can remap our pins later // Note we allow multiple users of a parameterized model, // thus we need to stash this info. - collectPins(clonemapp, newmodp, srcModp->user2p()); + collectPins(clonemapp, newmodp, srcModp->user4p()); // Relink parameter vars to the new module relinkPins(clonemapp, paramsp); // Fix any interface references @@ -856,14 +860,14 @@ class ParamProcessor final : public VNDeleter { if (!any_overrides) { UINFO(8, "Cell parameters all match original values, skipping expansion.\n"); - // If it's the first use of the default instance, create a copy and store it in user2p. - // user2p will also be used to check if the default instance is used. - if (!srcModpr->user2p() && VN_IS(srcModpr, Class)) { + // If it's the first use of the default instance, create a copy and store it in user4p. + // user4p will also be used to check if the default instance is used. + if (!srcModpr->user4p() && VN_IS(srcModpr, Class)) { AstClass* classCopyp = VN_AS(srcModpr, Class)->cloneTree(false); // It is a temporary copy of the original class node, stored in order to create // another instances. It is needed only during class instantiation. pushDeletep(classCopyp); - srcModpr->user2p(classCopyp); + srcModpr->user4p(classCopyp); storeOriginalParams(classCopyp); } } else if (AstNodeModule* const paramedModp @@ -972,11 +976,7 @@ public: class ParamVisitor final : public VNVisitor { // NODE STATE - // AstNodeModule::user1 -> bool: already fixed level - // AstClass::user2p -> AstClass*: Unchanged copy of the parameterized class node. - // The class node may be modified according to parameter - // values and an unchanged copy is needed to instantiate - // classes with different parameters. + // AstNodeModule::user1 -> bool: already fixed level (temporary) // STATE ParamProcessor m_processor; // De-parameterize a cell, build modules @@ -1435,7 +1435,7 @@ public: for (AstNodeModule* const modp : modps) netlistp->addModulesp(modp); for (AstClass* const classp : m_paramClasses) { - if (!classp->user2p()) { + if (!classp->user4p()) { // The default value isn't referenced, so it can be removed VL_DO_DANGLING(pushDeletep(classp->unlinkFrBack()), classp); } else { diff --git a/test_regress/t/t_class_param.v b/test_regress/t/t_class_param.v index e16f409a6..ae0a4386a 100644 --- a/test_regress/t/t_class_param.v +++ b/test_regress/t/t_class_param.v @@ -138,9 +138,9 @@ module t (/*AUTOARG*/); Wrap #(.P(16)) w16; Wrap2 #(.P(32)) w32; SelfRefClassTypeParam src_logic; - SelfRefClassTypeParam::self_int_t src_int; + SelfRefClassTypeParam#()::self_int_t src_int; SelfRefClassIntParam src1; - SelfRefClassIntParam::self_int_t src10; + SelfRefClassIntParam#()::self_int_t src10; IntQueue qi; ClsWithParamField cls_param_field; DictOperator #(DictWrapper) dict_op; diff --git a/test_regress/t/t_class_param_mod.v b/test_regress/t/t_class_param_mod.v index e117fa2ec..93ebe28e6 100644 --- a/test_regress/t/t_class_param_mod.v +++ b/test_regress/t/t_class_param_mod.v @@ -60,9 +60,9 @@ endclass Wrap #(.P(16)) w16; Wrap2 #(.P(32)) w32; SelfRefClassTypeParam src_logic; - SelfRefClassTypeParam::self_int_t src_int; + SelfRefClassTypeParam#()::self_int_t src_int; SelfRefClassIntParam src1; - SelfRefClassIntParam::self_int_t src10; + SelfRefClassIntParam#()::self_int_t src10; initial begin c12 = new; c4 = new; diff --git a/test_regress/t/t_class_param_subtype.v b/test_regress/t/t_class_param_subtype.v new file mode 100644 index 000000000..6799c43e6 --- /dev/null +++ b/test_regress/t/t_class_param_subtype.v @@ -0,0 +1,49 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2023 by Anthony Donlon. +// SPDX-License-Identifier: CC0-1.0 + +// Test for bug4281 + +class CParam #(parameter PARAM=10); + typedef int type_t; +endclass + +class CParam2 #(parameter PARAM=10); + typedef int type_t; + + typedef logic [PARAM-1:0] type2_t; +endclass + +`ifdef CONSTSIM +module sub(); + parameter N = 32; + for (genvar i = 0; i < N/8; i = i + 1) begin + initial begin + end + end + // Test for bug4281, usage conflict of user2 with constant simulator in V3Param.cpp +endmodule +`endif + +module t; +`ifdef BAD_PAREN + CParam::type_t val_0 = 100; +`else + CParam#()::type_t val_0 = 100; +`endif + CParam2#()::type_t val_2 = 200; + +`ifdef CONSTSIM + + sub i_sub(); +`endif + + initial begin + if (val_0 != 100) $stop; + if (val_2 != 200) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class_param_subtype_bad_paren.out b/test_regress/t/t_class_param_subtype_bad_paren.out new file mode 100644 index 000000000..a9ec2d035 --- /dev/null +++ b/test_regress/t/t_class_param_subtype_bad_paren.out @@ -0,0 +1,5 @@ +%Error: t/t_class_param_subtype.v:32:5: Reference to parameterized class without #() (IEEE 1800-2017 8.25.1) + : ... Suggest use 'CParam#()' + 32 | CParam::type_t val_0 = 100; + | ^~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_class_param_subtype_bad_paren.pl b/test_regress/t/t_class_param_subtype_bad_paren.pl new file mode 100755 index 000000000..13944a9e5 --- /dev/null +++ b/test_regress/t/t_class_param_subtype_bad_paren.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 2022 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); + +top_filename("t/t_class_param_subtype.v"); + +lint( + fails => 1, + v_flags2 => ['+define+BAD_PAREN'], + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_param_subtype_constsim.pl b/test_regress/t/t_class_param_subtype_constsim.pl new file mode 100755 index 000000000..2336fb402 --- /dev/null +++ b/test_regress/t/t_class_param_subtype_constsim.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 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(simulator => 1); + +top_filename("t/t_class_param_subtype.v"); + +compile( + v_flags2 => ['+define+CONSTSIM'], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; From e24197fd16e63b4dede06d46adc33129d38db67c Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Mon, 28 Aug 2023 15:44:41 +0200 Subject: [PATCH 032/111] Don't move function calls before the expression (#4413) --- src/V3AstNodeExpr.h | 1 + src/V3Dead.cpp | 1 - src/V3Delayed.cpp | 8 ++++--- src/V3EmitCFunc.h | 3 ++- src/V3EmitV.cpp | 6 ++++++ src/V3Gate.cpp | 13 +++-------- src/V3Premit.cpp | 13 ++++++----- src/V3Reloop.cpp | 1 + src/V3SchedTiming.cpp | 2 ++ src/V3Task.cpp | 13 +++++++++-- src/V3Timing.cpp | 5 ++++- test_regress/t/t_dpi_shortcircuit.out | 2 -- test_regress/t/t_unopt_combo_isolate.pl | 2 +- test_regress/t/t_unopt_combo_isolate_vlt.pl | 2 +- test_regress/t/t_xml_debugcheck.out | 24 ++++++++++----------- 15 files changed, 55 insertions(+), 41 deletions(-) diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 302c74c6c..648779532 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -1110,6 +1110,7 @@ public: string emitVerilog() override { V3ERROR_NA_RETURN(""); } string emitC() override { V3ERROR_NA_RETURN(""); } bool cleanOut() const override { return true; } + bool isPure() const override { return false; } bool same(const AstNode*) const override { return true; } }; class AstFError final : public AstNodeExpr { diff --git a/src/V3Dead.cpp b/src/V3Dead.cpp index 197b6658c..dd91a542d 100644 --- a/src/V3Dead.cpp +++ b/src/V3Dead.cpp @@ -288,7 +288,6 @@ private: VL_RESTORER(m_sideEffect); m_inAssign = true; m_sideEffect = false; - if (assignInAssign) m_sideEffect = true; iterateAndNextNull(nodep->rhsp()); checkAll(nodep); // Has to be direct assignment without any EXTRACTing. diff --git a/src/V3Delayed.cpp b/src/V3Delayed.cpp index a744b31fa..226185e89 100644 --- a/src/V3Delayed.cpp +++ b/src/V3Delayed.cpp @@ -551,7 +551,9 @@ private: } if (!lhsp->backp()) VL_DO_DANGLING(pushDeletep(lhsp), lhsp); } else { - iterateChildren(nodep); + iterate(nodep->lhsp()); + m_inDly = false; + iterate(nodep->rhsp()); } } @@ -623,9 +625,9 @@ private: m_inLoop = true; iterateChildren(nodep); } - void visit(AstNodeAssign* nodep) override { + void visit(AstExprStmt* nodep) override { VL_RESTORER(m_inDly); - // Restoring is needed in nested assignments, like a <= (x = y); + // Restoring is needed, because AstExprStmt may contain assignments m_inDly = false; iterateChildren(nodep); } diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index db2bf9e40..459618ff7 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -419,7 +419,8 @@ public: && !VN_IS(nodep->rhsp(), AssocSel) // && !VN_IS(nodep->rhsp(), MemberSel) // && !VN_IS(nodep->rhsp(), StructSel) // - && !VN_IS(nodep->rhsp(), ArraySel)) { + && !VN_IS(nodep->rhsp(), ArraySel) // + && !VN_IS(nodep->rhsp(), ExprStmt)) { // Wide functions assign into the array directly, don't need separate assign statement m_wideTempRefp = VN_AS(nodep->lhsp(), VarRef); paren = false; diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index 8314ec15c..953a3d937 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -664,6 +664,12 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst { iterateAndNextConstNull(nodep->pinsp()); puts(")"); } + void visit(AstCCall* nodep) override { + puts(nodep->funcp()->name()); + puts("("); + iterateAndNextConstNull(nodep->argsp()); + puts(")"); + } void visit(AstArg* nodep) override { iterateAndNextConstNull(nodep->exprp()); } void visit(AstPrintTimeScale* nodep) override { puts(nodep->verilogKwd()); diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index 09ff35046..e1a9375a4 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -331,7 +331,6 @@ private: AstActive* m_activep = nullptr; // Current active bool m_activeReducible = true; // Is activation block reducible? bool m_inSenItem = false; // Underneath AstSenItem; any varrefs are clocks - bool m_inExprStmt = false; // Underneath ExprStmt; don't optimize LHS vars bool m_inSlow = false; // Inside a slow structure std::vector m_optimized; // Logic blocks optimized @@ -497,10 +496,6 @@ private: // the weight will increase if (nodep->access().isWriteOrRW()) { new V3GraphEdge{&m_graph, m_logicVertexp, vvertexp, 1}; - if (m_inExprStmt) { - m_logicVertexp->clearReducibleAndDedupable("LHS var in ExprStmt"); - m_logicVertexp->setConsumed("LHS var in ExprStmt"); - } } if (nodep->access().isReadOrRW()) { new V3GraphEdge{&m_graph, vvertexp, m_logicVertexp, 1}; @@ -516,11 +511,6 @@ private: iterateNewStmt(nodep, "User C Function", "User C Function"); } void visit(AstClocking* nodep) override { iterateNewStmt(nodep, nullptr, nullptr); } - void visit(AstExprStmt* nodep) override { - VL_RESTORER(m_inExprStmt); - m_inExprStmt = true; - iterateChildren(nodep); - } void visit(AstSenItem* nodep) override { VL_RESTORER(m_inSenItem); m_inSenItem = true; @@ -905,6 +895,7 @@ class GateDedupeVarVisitor final : public VNVisitor { // (Note, the IF must be the only node under the always, // and the assign must be the only node under the if, other than the ifcond) // Any other ordering or node type, except for an AstComment, makes it not dedupable + // AstExprStmt in the subtree of a node also makes the node not dedupable. private: // STATE GateDedupeHash m_ghash; // Hash used to find dupes of rhs of assign @@ -920,6 +911,7 @@ private: // non-blocking statements, but erring on side of caution here if (!m_assignp) { m_assignp = assignp; + m_dedupable = !assignp->exists([&](AstExprStmt*) { return true; }); } else { m_dedupable = false; } @@ -944,6 +936,7 @@ private: if (m_always && !m_ifCondp && !ifp->elsesp()) { // we're under an always, this is the first IF, and there's no else m_ifCondp = ifp->condp(); + m_dedupable = !m_ifCondp->exists([&](AstExprStmt*) { return true; }); iterateAndNextNull(ifp->thensp()); } else { m_dedupable = false; diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp index 2a3d09db1..6a134cd89 100644 --- a/src/V3Premit.cpp +++ b/src/V3Premit.cpp @@ -54,11 +54,11 @@ private: const VNUser2InUse m_inuser2; // STATE - across all visitors - V3UniqueNames m_tempNames; // For generating unique temporary variable names VDouble0 m_extractedToConstPool; // Statistic tracking // STATE - for current visit position (use VL_RESTORER) AstCFunc* m_cfuncp = nullptr; // Current block + int m_tmpVarCnt = 0; // Number of temporary variables created inside a function AstNode* m_stmtp = nullptr; // Current statement AstCCall* m_callp = nullptr; // Current AstCCall AstWhile* m_inWhilep = nullptr; // Inside while loop, special statement additions @@ -138,7 +138,8 @@ private: ++m_extractedToConstPool; } else { // Keep as local temporary. Name based on hash of node for output stability. - varp = new AstVar{fl, VVarType::STMTTEMP, m_tempNames.get(nodep), nodep->dtypep()}; + varp = new AstVar{fl, VVarType::STMTTEMP, "__Vtemp_" + cvtToStr(++m_tmpVarCnt), + nodep->dtypep()}; m_cfuncp->addInitsp(varp); // Put assignment before the referencing statement insertBeforeStmt(new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE}, nodep}); @@ -158,8 +159,9 @@ private: } void visit(AstCFunc* nodep) override { VL_RESTORER(m_cfuncp); + VL_RESTORER(m_tmpVarCnt); m_cfuncp = nodep; - m_tempNames.reset(); + m_tmpVarCnt = 0; iterateChildren(nodep); } @@ -391,10 +393,7 @@ private: public: // CONSTRUCTORS - explicit PremitVisitor(AstNetlist* nodep) - : m_tempNames{"__Vtemp"} { - iterate(nodep); - } + explicit PremitVisitor(AstNetlist* nodep) { iterate(nodep); } ~PremitVisitor() override { V3Stats::addStat("Optimizations, Prelim extracted value to ConstPool", m_extractedToConstPool); diff --git a/src/V3Reloop.cpp b/src/V3Reloop.cpp index f71d8913b..284c0df36 100644 --- a/src/V3Reloop.cpp +++ b/src/V3Reloop.cpp @@ -253,6 +253,7 @@ private: m_mgIndexHi = lindex; UINFO(9, "Start merge i=" << lindex << " o=" << m_mgOffset << nodep << endl); } + void visit(AstExprStmt* nodep) override { iterateChildren(nodep); } //-------------------- void visit(AstVar*) override {} // Accelerate void visit(AstNodeExpr*) override {} // Accelerate diff --git a/src/V3SchedTiming.cpp b/src/V3SchedTiming.cpp index 1c80c3736..f52870299 100644 --- a/src/V3SchedTiming.cpp +++ b/src/V3SchedTiming.cpp @@ -236,6 +236,7 @@ TimingKit prepareTiming(AstNetlist* const netlistp) { m_writtenBySuspendable.push_back(nodep->varScopep()); } } + void visit(AstExprStmt* nodep) override { iterateChildren(nodep); } //-------------------- void visit(AstNodeExpr*) override {} // Accelerate @@ -405,6 +406,7 @@ void transformForks(AstNetlist* const netlistp) { if (nodep->funcp()->needProcess()) m_beginNeedProcess = true; iterateChildrenConst(nodep); } + void visit(AstExprStmt* nodep) override { iterateChildren(nodep); } //-------------------- void visit(AstNodeExpr*) override {} // Accelerate diff --git a/src/V3Task.cpp b/src/V3Task.cpp index fd4cb172b..e1435a43b 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -1420,18 +1420,27 @@ private: beginp = createInlinedFTask(nodep, namePrefix, outvscp); } // Replace the ref - AstNode* const visitp = insertBeforeStmt(nodep, beginp); + AstNode* visitp = nullptr; if (VN_IS(nodep, New)) { + visitp = insertBeforeStmt(nodep, beginp); UASSERT_OBJ(cnewp, nodep, "didn't create cnew for new"); 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"); + visitp = 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"); AstVarRef* const outrefp = new AstVarRef{nodep->fileline(), outvscp, VAccess::READ}; - nodep->replaceWith(outrefp); + beginp = new AstExprStmt{nodep->fileline(), beginp, outrefp}; + nodep->replaceWith(beginp); VL_DO_DANGLING(nodep->deleteTree(), nodep); } else { + visitp = insertBeforeStmt(nodep, beginp); if (nodep->taskp()->isFunction()) { nodep->v3warn( IGNOREDRETURN, diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp index b886b2ed9..5b8651d20 100644 --- a/src/V3Timing.cpp +++ b/src/V3Timing.cpp @@ -550,7 +550,10 @@ private: ss << '"'; V3EmitV::verilogForTree(sensesp, ss); ss << '"'; - auto* const commentp = new AstCExpr{sensesp->fileline(), ss.str(), 0}; + // possibly a multiline string + std::string comment = ss.str(); + std::replace(comment.begin(), comment.end(), '\n', ' '); + AstCExpr* const commentp = new AstCExpr{sensesp->fileline(), comment, 0}; commentp->dtypeSetString(); sensesp->user2p(commentp); return commentp; diff --git a/test_regress/t/t_dpi_shortcircuit.out b/test_regress/t/t_dpi_shortcircuit.out index 53f6dc0e8..2cc554bcf 100644 --- a/test_regress/t/t_dpi_shortcircuit.out +++ b/test_regress/t/t_dpi_shortcircuit.out @@ -10,8 +10,6 @@ %Error: Line 136: Bad result, got=0 expect=1 %Error: Line 148: Bad result, got=1 expect=0 %Error: Line 152: Bad result, got=1 expect=0 -%Error: Line 166: Bad result, got=1 expect=0 -%Error: Line 170: Bad result, got=1 expect=0 %Error: Line 179: Bad result, got=0 expect=1 %Error: Line 219: Bad result, got=64 expect=32 %Error: Line 220: Bad result, got=64 expect=16 diff --git a/test_regress/t/t_unopt_combo_isolate.pl b/test_regress/t/t_unopt_combo_isolate.pl index c875fbf2b..a6196c6d9 100755 --- a/test_regress/t/t_unopt_combo_isolate.pl +++ b/test_regress/t/t_unopt_combo_isolate.pl @@ -18,7 +18,7 @@ compile( ); if ($Self->{vlt_all}) { - file_grep($Self->{stats}, qr/Optimizations, isolate_assignments blocks\s+5/i); + file_grep($Self->{stats}, qr/Optimizations, isolate_assignments blocks\s+3/i); file_grep("$out_filename", qr/\/i); file_grep("$out_filename", qr/\/i); file_grep("$out_filename", qr/\/i); diff --git a/test_regress/t/t_unopt_combo_isolate_vlt.pl b/test_regress/t/t_unopt_combo_isolate_vlt.pl index dedfa5e76..0d44d64e2 100755 --- a/test_regress/t/t_unopt_combo_isolate_vlt.pl +++ b/test_regress/t/t_unopt_combo_isolate_vlt.pl @@ -18,7 +18,7 @@ compile( ); if ($Self->{vlt_all}) { - file_grep($Self->{stats}, qr/Optimizations, isolate_assignments blocks\s+5/i); + file_grep($Self->{stats}, qr/Optimizations, isolate_assignments blocks\s+3/i); file_grep("$out_filename", qr/\/i); file_grep("$out_filename", qr/\/i); file_grep("$out_filename", qr/\/i); diff --git a/test_regress/t/t_xml_debugcheck.out b/test_regress/t/t_xml_debugcheck.out index 9e7447c4c..b50189df9 100644 --- a/test_regress/t/t_xml_debugcheck.out +++ b/test_regress/t/t_xml_debugcheck.out @@ -61,7 +61,7 @@ - + @@ -510,11 +510,11 @@ - + - + @@ -700,9 +700,9 @@ - - - + + + @@ -762,11 +762,11 @@ - + - + @@ -1012,11 +1012,11 @@ - + - + @@ -1262,11 +1262,11 @@ - + - + From c3e19f282179180b2b284c34737ed11853c12854 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Boro=C5=84ski?= <94375110+kboronski-ant@users.noreply.github.com> Date: Tue, 29 Aug 2023 20:01:00 +0200 Subject: [PATCH 033/111] Move variables mutated under fork..join_none/join_any blocks into anonymous objects (#4356) --- src/V3CUse.cpp | 4 +- src/V3Fork.cpp | 389 ++++++++++++++++-- src/V3Fork.h | 7 +- src/Verilator.cpp | 6 +- .../t/t_clocking_sched_timing_forkproc.out | 63 ++- .../t/t_clocking_sched_timing_forkproc.pl | 14 +- ...iming_fork_unsup.pl => t_fork_dynscope.pl} | 15 +- test_regress/t/t_fork_dynscope.v | 59 +++ test_regress/t/t_timing_dynscope.pl | 23 ++ test_regress/t/t_timing_dynscope.v | 41 ++ test_regress/t/t_timing_fork_unsup.out | 17 - test_regress/t/t_timing_fork_unsup.v | 24 -- 12 files changed, 575 insertions(+), 87 deletions(-) rename test_regress/t/{t_timing_fork_unsup.pl => t_fork_dynscope.pl} (65%) create mode 100644 test_regress/t/t_fork_dynscope.v create mode 100755 test_regress/t/t_timing_dynscope.pl create mode 100644 test_regress/t/t_timing_dynscope.v delete mode 100644 test_regress/t/t_timing_fork_unsup.out delete mode 100644 test_regress/t/t_timing_fork_unsup.v diff --git a/src/V3CUse.cpp b/src/V3CUse.cpp index 0bbab0886..e53c8b3d1 100644 --- a/src/V3CUse.cpp +++ b/src/V3CUse.cpp @@ -64,7 +64,9 @@ class CUseVisitor final : public VNVisitor { // VISITORS void visit(AstClassRefDType* nodep) override { - if (nodep->user1SetOnce()) return; // Process once + if (nodep->user1()) return; // Process once + if (!m_dtypesImplOnly) // We might need to revisit this type for interface + nodep->user1(true); addNewUse(nodep, VUseType::INT_FWD_CLASS, nodep->classp()->name()); } void visit(AstCFunc* nodep) override { diff --git a/src/V3Fork.cpp b/src/V3Fork.cpp index 427775cdc..d0829181a 100644 --- a/src/V3Fork.cpp +++ b/src/V3Fork.cpp @@ -18,11 +18,23 @@ // // Each module: // Look for FORKs [JOIN_NONE]/[JOIN_ANY] +// VARREF(var) -> MEMBERSEL(var->name, VARREF(dynscope)) (for write/RW refs) // FORK(stmts) -> TASK(stmts), FORK(TASKREF(inits)) // // FORKs that spawn tasks which might outlive their parents require those // tasks to carry their own frames and as such they require their own // variable scopes. +// There are two mechanisms that work together to achieve that. ForkVisitor +// moves bodies of forked prcesses into new tasks, which results in them getting their +// own scopes. The original statements get replaced with a call to the task which +// passes the required variables by value. +// The second mechanism, DynScopeVisitor, is designed to handle variables which can't be +// captured by value and instead require a reference. Those variables get moved into an +// "anonymous" object, ie. a class with appropriate fields gets generated and an object +// of this class gets instantiated in place of the original variable declarations. +// Any references to those variables are replaced with references to the object's field. +// Since objects are reference-counted this ensures that the variables are accessible +// as long as both the parent and the forked processes require them to be. // //************************************************************************* @@ -34,12 +46,344 @@ #include "V3Ast.h" #include "V3AstNodeExpr.h" #include "V3Global.h" +#include "V3MemberMap.h" #include +#include #include +#include VL_DEFINE_DEBUG_FUNCTIONS; +class ForkDynScopeInstance final { +public: + AstClass* m_classp = nullptr; // Class for holding variables of dynamic scope + AstClassRefDType* m_refDTypep = nullptr; // RefDType for the above + AstVar* m_handlep = nullptr; // Class handle for holding variables of dynamic scope + + // True if the instance exists + bool initialized() const { return m_classp != nullptr; } +}; + +class ForkDynScopeFrame final { +private: + // MEMBERS + AstNodeModule* const m_modp; // Module to insert the scope into + AstNode* const m_procp; // Procedure/block associated with that dynscope + std::set m_captures; // Variables to be moved into the dynscope + ForkDynScopeInstance m_instance; // Nodes to be injected into the AST to create the dynscope + +public: + ForkDynScopeFrame(AstNodeModule* modp, AstNode* procp) + : m_modp{modp} + , m_procp{procp} {} + + ForkDynScopeInstance& createInstancePrototype() { + UASSERT_OBJ(!m_instance.initialized(), m_procp, "Dynamic scope already instantiated."); + + m_instance.m_classp + = new AstClass{m_procp->fileline(), generateDynScopeClassName(m_procp)}; + m_instance.m_refDTypep + = new AstClassRefDType{m_procp->fileline(), m_instance.m_classp, nullptr}; + v3Global.rootp()->typeTablep()->addTypesp(m_instance.m_refDTypep); + m_instance.m_handlep + = new AstVar{m_procp->fileline(), VVarType::BLOCKTEMP, + generateDynScopeHandleName(m_procp), m_instance.m_refDTypep}; + m_instance.m_handlep->funcLocal(true); + m_instance.m_handlep->lifetime(VLifetime::AUTOMATIC); + + return m_instance; + } + + const ForkDynScopeInstance& instance() const { return m_instance; } + void captureVarInsert(AstVar* varp) { m_captures.insert(varp); } + bool captured(AstVar* varp) { return m_captures.count(varp) != 0; } + AstNode* procp() const { return m_procp; } + + void populateClass() { + UASSERT_OBJ(m_instance.initialized(), m_procp, "No DynScope prototype"); + + // Move variables into the class + for (AstVar* varp : m_captures) { + if (varp->direction() == VDirection::INPUT) { + varp = varp->cloneTree(false); + varp->direction(VDirection::NONE); + } else { + varp->unlinkFrBack(); + } + varp->funcLocal(false); + varp->varType(VVarType::MEMBER); + varp->lifetime(VLifetime::AUTOMATIC); + varp->usedLoopIdx(false); // No longer unrollable + m_instance.m_classp->addStmtsp(varp); + } + + // Create class's constructor + AstFunc* const newp + = new AstFunc{m_instance.m_classp->fileline(), "new", nullptr, nullptr}; + newp->isConstructor(true); + newp->classMethod(true); + newp->dtypep(newp->findVoidDType()); + m_instance.m_classp->addStmtsp(newp); + } + + void linkNodes(VMemberMap& memberMap) { + UASSERT_OBJ(m_instance.initialized(), m_procp, "No dynamic scope prototype"); + UASSERT_OBJ(!linked(), m_instance.m_handlep, "Handle already linked"); + + AstNode* stmtp = getProcStmts(); + UASSERT(stmtp, "trying to instantiate dynamic scope while not under proc"); + VNRelinker stmtpHandle; + stmtp->unlinkFrBackWithNext(&stmtpHandle); + + // Find node after last variable declaration + AstNode* initp = stmtp; + while (initp && VN_IS(initp, Var)) initp = initp->nextp(); + UASSERT(stmtp, "Procedure lacks body"); + UASSERT(initp, "Procedure lacks statements besides declarations"); + + AstNew* const newp = new AstNew{m_procp->fileline(), nullptr}; + newp->taskp(VN_AS(memberMap.findMember(m_instance.m_classp, "new"), NodeFTask)); + newp->dtypep(m_instance.m_refDTypep); + newp->classOrPackagep(m_instance.m_classp); + + AstNode* const asgnp = new AstAssign{ + m_procp->fileline(), + new AstVarRef{m_procp->fileline(), m_instance.m_handlep, VAccess::WRITE}, newp}; + + AstNode* initsp = nullptr; // Arguments need to be copied + for (AstVar* varp : m_captures) { + if (varp->direction() != VDirection::INPUT) continue; + + AstMemberSel* const memberselp = new AstMemberSel{ + varp->fileline(), + new AstVarRef{varp->fileline(), m_instance.m_handlep, VAccess::WRITE}, + varp->dtypep()}; + memberselp->name(varp->name()); + memberselp->varp(VN_AS(memberMap.findMember(m_instance.m_classp, varp->name()), Var)); + AstNode* initAsgnp + = new AstAssign{varp->fileline(), memberselp, + new AstVarRef{varp->fileline(), varp, VAccess::READ}}; + initsp = AstNode::addNext(initsp, initAsgnp); + } + if (initsp) AstNode::addNext(asgnp, initsp); + + if (initp != stmtp) { + initp->addHereThisAsNext(asgnp); + } else { + AstNode::addNext(asgnp, static_cast(initp)); + stmtp = asgnp; + } + + AstNode::addNext(static_cast(m_instance.m_handlep), stmtp); + stmtpHandle.relink(m_instance.m_handlep); + m_modp->addStmtsp(m_instance.m_classp); + } + + bool linked() const { return m_instance.initialized() && m_instance.m_handlep->backp(); } + +private: + static string generateDynScopeClassName(const AstNode* fromp) { + string n = "__VDynScope__" + (!fromp->name().empty() ? (fromp->name() + "__") : "ANON__") + + cvtToHex(fromp); + return n; + } + + static string generateDynScopeHandleName(const AstNode* fromp) { + return "__VDynScope_" + (fromp->name().empty() ? cvtToHex(fromp) : fromp->name()); + } + + AstNode* getProcStmts() { + AstNode* stmtsp = nullptr; + if (!m_procp) return nullptr; + if (AstBegin* beginp = VN_CAST(m_procp, Begin)) { + stmtsp = beginp->stmtsp(); + } else if (AstNodeFTask* taskp = VN_CAST(m_procp, NodeFTask)) { + stmtsp = taskp->stmtsp(); + } else { + v3fatal("m_procp is not a begin block or a procedure"); + } + return stmtsp; + } +}; + +//###################################################################### +// Dynamic scope visitor, creates classes and objects for dynamic scoping of variables and +// replaces references to varibles that need a dynamic scope with references to object's +// members + +class DynScopeVisitor final : public VNVisitor { +private: + // NODE STATE + // AstVar::user1() -> int, timing-control fork nesting level of that variable + // AstVarRef::user2() -> bool, 1 = Node is a class handle reference. The handle gets + // modified in the context of this reference. + const VNUser1InUse m_inuser1; + const VNUser2InUse m_inuser2; + + // STATE + AstNodeModule* m_modp = nullptr; // Module we are currently under + AstNode* m_procp = nullptr; // Function/task/block we are currently under + std::map + m_frames; // Mapping from nodes to related DynScopeFrames + VMemberMap m_memberMap; // Class member look-up + int m_forkDepth = 0; // Number of asynchronous forks we are currently under + bool m_afterTimingControl = false; // A timing control might've be executed in the current + // process + + // METHODS + + ForkDynScopeFrame* frameOf(AstNode* nodep) { + auto frameIt = m_frames.find(nodep); + if (frameIt == m_frames.end()) return nullptr; + return frameIt->second; + } + + const ForkDynScopeFrame* frameOf(AstNode* nodep) const { + auto frameIt = m_frames.find(nodep); + if (frameIt == m_frames.end()) return nullptr; + return frameIt->second; + } + + ForkDynScopeFrame* pushDynScopeFrame() { + ForkDynScopeFrame* const frame = new ForkDynScopeFrame{m_modp, m_procp}; + auto r = m_frames.emplace(std::make_pair(m_procp, frame)); + UASSERT_OBJ(r.second, m_modp, "Procedure already contains a frame"); + return frame; + } + + void replaceWithMemberSel(AstVarRef* refp, const ForkDynScopeInstance& dynScope) { + VNRelinker handle; + refp->unlinkFrBack(&handle); + AstMemberSel* const membersel = new AstMemberSel{ + refp->fileline(), new AstVarRef{refp->fileline(), dynScope.m_handlep, refp->access()}, + refp->dtypep()}; + membersel->name(refp->varp()->name()); + if (refp->varp()->direction() == VDirection::INPUT) { + membersel->varp( + VN_AS(m_memberMap.findMember(dynScope.m_classp, refp->varp()->name()), Var)); + } else { + membersel->varp(refp->varp()); + } + handle.relink(membersel); + VL_DO_DANGLING(refp->deleteTree(), refp); + } + + static bool hasAsyncFork(AstNode* nodep) { + bool afork = false; + nodep->foreach([&](AstFork* forkp) { + if (!forkp->joinType().join()) afork = true; + }); + return afork; + } + + void bindNodeToDynScope(AstNode* nodep, ForkDynScopeFrame* frame) { + m_frames.emplace(std::make_pair(nodep, frame)); + } + + bool needsDynScope(const AstVarRef* refp) const { + return + // Can this variable escape the scope + ((m_forkDepth > refp->varp()->user1()) && refp->varp()->isFuncLocal()) + && ( + // Is it mutated + (refp->varp()->isClassHandleValue() ? refp->user2() : refp->access().isWriteOrRW()) + // Or is it after a timing-control event + || m_afterTimingControl); + } + + // VISITORS + void visit(AstNodeModule* nodep) override { + VL_RESTORER(m_modp); + if (!VN_IS(nodep, Class)) m_modp = nodep; + iterateChildren(nodep); + } + void visit(AstNodeFTask* nodep) override { + VL_RESTORER(m_procp); + m_procp = nodep; + if (hasAsyncFork(nodep)) pushDynScopeFrame(); + iterateChildren(nodep); + } + void visit(AstBegin* nodep) override { + VL_RESTORER(m_procp); + m_procp = nodep; + if (hasAsyncFork(nodep)) pushDynScopeFrame(); + iterateChildren(nodep); + } + void visit(AstFork* nodep) override { + VL_RESTORER(m_forkDepth); + if (!nodep->joinType().join()) ++m_forkDepth; + + const bool oldAfterTimingControl = m_afterTimingControl; + for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) { + m_afterTimingControl = false; + iterate(stmtp); + } + m_afterTimingControl = oldAfterTimingControl; + if (nodep->isTimingControl()) m_afterTimingControl = true; + } + void visit(AstNodeFTaskRef* nodep) override { + visit(static_cast(nodep)); + // We are before V3Timing, so unfortnately we need to treat any calls as suspending, + // just to be safe. This might be improved if we could propagate suspendability + // before doing all the other timing-related stuff. + m_afterTimingControl = true; + } + void visit(AstVar* nodep) override { + nodep->user1(m_forkDepth); + ForkDynScopeFrame* const framep = frameOf(m_procp); + if (!framep) return; // Cannot be legally referenced from a fork + bindNodeToDynScope(nodep, framep); + } + void visit(AstVarRef* nodep) override { + ForkDynScopeFrame* const framep = frameOf(nodep->varp()); + if (!framep) return; + + if (needsDynScope(nodep)) { + if (!framep->instance().initialized()) framep->createInstancePrototype(); + framep->captureVarInsert(nodep->varp()); + } + bindNodeToDynScope(nodep, framep); + } + void visit(AstAssign* nodep) override { + if (VN_IS(nodep->lhsp(), VarRef) && nodep->lhsp()->isClassHandleValue()) { + nodep->lhsp()->user2(true); + } + visit(static_cast(nodep)); + } + void visit(AstNode* nodep) override { + if (nodep->isTimingControl()) m_afterTimingControl = true; + iterateChildren(nodep); + } + +public: + // CONSTRUCTORS + DynScopeVisitor(AstNetlist* nodep) { + // Create Dynamic scope class prototypes and objects + visit(nodep); + + // Commit changes to AST + bool typesAdded = false; + for (auto frameIt : m_frames) { + ForkDynScopeFrame* frame = frameIt.second; + if (!frame->instance().initialized()) continue; + + if (!frame->linked()) { + frame->populateClass(); + frame->linkNodes(m_memberMap); + typesAdded = true; + } + + if (AstVarRef* refp = VN_CAST(frameIt.first, VarRef)) { + if (frame->captured(refp->varp())) replaceWithMemberSel(refp, frame->instance()); + } + } + + if (typesAdded) v3Global.rootp()->typeTablep()->repairCache(); + } + ~DynScopeVisitor() override = default; +}; + //###################################################################### // Fork visitor, transforms asynchronous blocks into separate tasks @@ -59,10 +403,10 @@ private: AstVar* m_capturedVarsp = nullptr; // Local copies of captured variables std::set m_forkLocalsp; // Variables local to a given fork AstArg* m_capturedVarRefsp = nullptr; // References to captured variables (as args) - int m_createdTasksCount = 0; // Number of tasks created by this visitor // METHODS - AstVar* captureRef(AstNodeExpr* refp) { + + AstVar* captureRef(AstVarRef* refp) { AstVar* varp = nullptr; for (varp = m_capturedVarsp; varp; varp = VN_AS(varp->nextp(), Var)) if (varp->name() == refp->name()) break; @@ -74,20 +418,20 @@ private: varp->lifetime(VLifetime::AUTOMATIC); m_capturedVarsp = AstNode::addNext(m_capturedVarsp, varp); // Use the original ref as an argument for call - AstArg* arg = new AstArg{refp->fileline(), refp->name(), refp->cloneTree(false)}; - m_capturedVarRefsp = AstNode::addNext(m_capturedVarRefsp, arg); + m_capturedVarRefsp + = AstNode::addNext(m_capturedVarRefsp, new AstArg{refp->fileline(), refp->name(), + refp->cloneTree(false)}); } return varp; } - AstTask* makeTask(FileLine* fl, AstNode* stmtsp, std::string name) { + AstTask* makeTask(FileLine* fl, AstNode* stmtsp, string name) { stmtsp = AstNode::addNext(static_cast(m_capturedVarsp), stmtsp); AstTask* const taskp = new AstTask{fl, name, stmtsp}; - ++m_createdTasksCount; return taskp; } - std::string generateTaskName(AstNode* fromp, std::string kind) { + string generateTaskName(AstNode* fromp, string kind) { // TODO: Ensure no collisions occur return "__V" + kind + (!fromp->name().empty() ? (fromp->name() + "__") : "UNNAMED__") + cvtToHex(fromp); @@ -122,16 +466,16 @@ private: if (AstBegin* beginp = VN_CAST(nodep, Begin)) { UASSERT(beginp->stmtsp(), "No stmtsp\n"); - const std::string taskName = generateTaskName(beginp, "__FORK_BEGIN_"); + const string taskName = generateTaskName(beginp, "__FORK_BEGIN_"); taskp = makeTask(beginp->fileline(), beginp->stmtsp()->unlinkFrBackWithNext(), taskName); beginp->unlinkFrBack(&handle); VL_DO_DANGLING(beginp->deleteTree(), beginp); } else if (AstNodeStmt* stmtp = VN_CAST(nodep, NodeStmt)) { - const std::string taskName = generateTaskName(stmtp, "__FORK_STMT_"); + const string taskName = generateTaskName(stmtp, "__FORK_STMT_"); taskp = makeTask(stmtp->fileline(), stmtp->unlinkFrBack(&handle), taskName); } else if (AstFork* forkp = VN_CAST(nodep, Fork)) { - const std::string taskName = generateTaskName(forkp, "__FORK_NESTED_"); + const string taskName = generateTaskName(forkp, "__FORK_NESTED_"); taskp = makeTask(forkp->fileline(), forkp->unlinkFrBack(&handle), taskName); } @@ -139,7 +483,8 @@ private: AstTaskRef* const taskrefp = new AstTaskRef{nodep->fileline(), taskp->name(), m_capturedVarRefsp}; - AstStmtExpr* const taskcallp = new AstStmtExpr{nodep->fileline(), taskrefp}; + taskrefp->taskp(taskp); + AstStmtExpr* const taskcallp = taskrefp->makeStmt(); // Replaced nodes will be revisited, so we don't need to "lift" the arguments // as captures in case of nested forks. handle.relink(taskcallp); @@ -223,23 +568,19 @@ public: // CONSTRUCTORS ForkVisitor(AstNetlist* nodep) { visit(nodep); } ~ForkVisitor() override = default; - - // UTILITY - int createdTasksCount() { return m_createdTasksCount; } }; //###################################################################### // Fork class functions -int V3Fork::makeTasks(AstNetlist* nodep) { - int createdTasksCount; - +void V3Fork::makeDynamicScopes(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); - { - ForkVisitor fork_visitor(nodep); - createdTasksCount = fork_visitor.createdTasksCount(); - } - V3Global::dumpCheckGlobalTree("fork", 0, dumpTreeLevel() >= 3); - - return createdTasksCount; + { DynScopeVisitor{nodep}; } + V3Global::dumpCheckGlobalTree("fork_dynscope", 0, dumpTreeLevel() >= 3); +} + +void V3Fork::makeTasks(AstNetlist* nodep) { + UINFO(2, __FUNCTION__ << ": " << endl); + { ForkVisitor{nodep}; } + V3Global::dumpCheckGlobalTree("fork", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3Fork.h b/src/V3Fork.h index 8554fa75f..e36b530cb 100644 --- a/src/V3Fork.h +++ b/src/V3Fork.h @@ -27,9 +27,12 @@ class AstNetlist; class V3Fork final { public: - // Create tasks out of begin blocks that can outlive processes in which they were forked. + // Move/copy variables to "anonymous" objects if their lifetime might exceed the scope of a + // procedure that declared them. Update the references apropriately. + static void makeDynamicScopes(AstNetlist* nodep); + // Create tasks out of blocks/statments that can outlive processes in which they were forked. // Return value: number of tasks created - static int makeTasks(AstNetlist* nodep); + static void makeTasks(AstNetlist* nodep); }; #endif // Guard diff --git a/src/Verilator.cpp b/src/Verilator.cpp index c1654b524..243b4c4ae 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -222,9 +222,9 @@ static void process() { V3Inst::dearrayAll(v3Global.rootp()); V3LinkDot::linkDotArrayed(v3Global.rootp()); - // Create dedicated tasks for fork..join_any / fork_join_none processes - if (V3Fork::makeTasks(v3Global.rootp())) - V3LinkDot::linkDotPrimary(v3Global.rootp()); // Link newly created tasks + // Generate classes and tasks required to maintain proper lifetimes for references in forks + V3Fork::makeDynamicScopes(v3Global.rootp()); + V3Fork::makeTasks(v3Global.rootp()); // Task inlining & pushing BEGINs names to variables/cells // Begin processing must be after Param, before module inlining diff --git a/test_regress/t/t_clocking_sched_timing_forkproc.out b/test_regress/t/t_clocking_sched_timing_forkproc.out index 8094d59d9..f0fee8b8e 100755 --- a/test_regress/t/t_clocking_sched_timing_forkproc.out +++ b/test_regress/t/t_clocking_sched_timing_forkproc.out @@ -1,5 +1,58 @@ -%Error: t/t_clocking_sched.v:11:9: Input/output/inout does not appear in port list: 'clk' - : ... In instance t - 11 | input clk; - | ^~~ -%Error: Exiting due to +0 | posedge +0 | cb.y=0 +0 | b=0 +0 | z<=0 +0 | x<=0 +0 | y=0 +0 | c<=0 +0 | c<=1 +0 | cb.a=1 +0 | cb.b=1 +0 | posedge +0 | x<=1 +0 | y=1 +0 | c<=0 +0 | cb.a=0 +0 | cb.b=1 +0 | cb.y=1 +0 | b=1 +0 | x<=0 +0 | y=0 +0 | 0 1 0 0 0 0 +2 | z<=1 +3 | posedge +3 | c<=1 +3 | cb.a=1 +3 | cb.b=1 +3 | cb.y=0 +3 | b=0 +3 | posedge +3 | x<=1 +3 | y=1 +3 | c<=0 +3 | cb.a=0 +3 | cb.b=1 +3 | cb.y=1 +3 | b=1 +3 | x<=0 +3 | y=0 +3 | 0 1 0 0 0 1 +5 | posedge +5 | z<=0 +5 | c<=1 +5 | cb.a=1 +5 | cb.b=1 +5 | cb.y=0 +5 | b=0 +5 | posedge +5 | x<=1 +5 | y=1 +5 | c<=0 +5 | cb.a=0 +5 | cb.b=1 +5 | cb.y=1 +5 | b=1 +5 | x<=0 +5 | y=0 +5 | 0 1 0 0 0 0 +*-* All Finished *-* diff --git a/test_regress/t/t_clocking_sched_timing_forkproc.pl b/test_regress/t/t_clocking_sched_timing_forkproc.pl index d1bb14c97..7c1c36bef 100755 --- a/test_regress/t/t_clocking_sched_timing_forkproc.pl +++ b/test_regress/t/t_clocking_sched_timing_forkproc.pl @@ -7,14 +7,18 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # 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); +scenarios(vlt => 1); top_filename("t/t_clocking_sched.v"); -lint( - verilator_flags2 => ["--timing", "--ftaskify-all-forked"], - expect_filename => $Self->{golden_filename}, - fails => 1, +compile( + timing_loop => 1, + verilator_flags2 => ["--timing"], + ); + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename} ); ok(1); diff --git a/test_regress/t/t_timing_fork_unsup.pl b/test_regress/t/t_fork_dynscope.pl similarity index 65% rename from test_regress/t/t_timing_fork_unsup.pl rename to test_regress/t/t_fork_dynscope.pl index 8ab3c0995..b8493bd06 100755 --- a/test_regress/t/t_timing_fork_unsup.pl +++ b/test_regress/t/t_fork_dynscope.pl @@ -2,18 +2,21 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } # DESCRIPTION: Verilator: Verilog Test driver/expect definition # -# Copyright 2022 by Antmicro Ltd. This program is free software; you +# 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(linter => 1); +scenarios(simulator => 1); -lint( - verilator_flags2 => ["--timing"], - fails => 1, - expect_filename => $Self->{golden_filename}, +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + +execute( + check_finished => 1, ); ok(1); diff --git a/test_regress/t/t_fork_dynscope.v b/test_regress/t/t_fork_dynscope.v new file mode 100644 index 000000000..e1264e238 --- /dev/null +++ b/test_regress/t/t_fork_dynscope.v @@ -0,0 +1,59 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +class Foo; + task do_something(int arg_v); + int dynscope_var; + int x; + dynscope_var = 0; + + fork + #10 begin + x = 0; + // Test capturing a variable that needs to be modified + $display("Incremented dynscope_var: %d", ++dynscope_var); + if (dynscope_var != 1) + $stop; + + // Check nested access + fork + #10 begin + $display("Incremented x: %d", ++x); + $display("Incremented dynscope_var: %d", ++dynscope_var); + if (dynscope_var != 2) + $stop; + end + join_none + end + #10 begin + // Same as the first check, but with an argument + // (so it needs to be copied to the dynamic scope instead of being moved there) + $display("Incremented arg_v: %d", ++arg_v); + if (arg_v != 2) + $stop; + end + join_none + + // Check if regular access to arg_v has been substituted with access to its copy from + // a dynamic scope + $display("Incremented arg_v: %d", ++arg_v); + if (arg_v != 1) + $stop; + endtask +endclass + +module t(); + initial begin + Foo foo; + foo = new; + foo.do_something(0); + + #99 begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule diff --git a/test_regress/t/t_timing_dynscope.pl b/test_regress/t/t_timing_dynscope.pl new file mode 100755 index 000000000..b8493bd06 --- /dev/null +++ b/test_regress/t/t_timing_dynscope.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(simulator => 1); + +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_timing_dynscope.v b/test_regress/t/t_timing_dynscope.v new file mode 100644 index 000000000..73cc70d37 --- /dev/null +++ b/test_regress/t/t_timing_dynscope.v @@ -0,0 +1,41 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +`timescale 1ns / 1ns + +static int counts[10]; + +class Foo; + static task do_something(); + for (int i = 0; i < 10; i++) begin // Should create a dynamic scope for `i` + int ci = i; // Should create another dynamic scope for `ci`, local to the begin block + fork begin + #10; + $display("ci: %d, i: %d", ci, i); + if (i != 10) + $stop; + if (counts[ci-1]++ > 0) + $stop; + end join_none + ci++; + end + endtask +endclass + +module t(); + initial begin + int desired_counts[10]; + counts = '{10{0}}; + desired_counts = '{10{1}}; + + Foo::do_something(); + #20; + if (counts != desired_counts) + $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_timing_fork_unsup.out b/test_regress/t/t_timing_fork_unsup.out deleted file mode 100644 index 399dfd1c3..000000000 --- a/test_regress/t/t_timing_fork_unsup.out +++ /dev/null @@ -1,17 +0,0 @@ -%Error-LIFETIME: t/t_timing_fork_unsup.v:12:12: Invalid reference: Process might outlive variable `x`. - : ... In instance t - : ... Suggest use it as read-only to initialize a local copy at the beginning of the process, or declare it as static. It is also possible to refer by reference to objects and their members. - 12 | #6 x = 4; - | ^ - ... For error description see https://verilator.org/warn/LIFETIME?v=latest -%Error-LIFETIME: t/t_timing_fork_unsup.v:13:12: Invalid reference: Process might outlive variable `x`. - : ... In instance t - : ... Suggest use it as read-only to initialize a local copy at the beginning of the process, or declare it as static. It is also possible to refer by reference to objects and their members. - 13 | #2 x++; - | ^ -%Error-LIFETIME: t/t_timing_fork_unsup.v:14:9: Invalid reference: Process might outlive variable `x`. - : ... In instance t - : ... Suggest use it as read-only to initialize a local copy at the beginning of the process, or declare it as static. It is also possible to refer by reference to objects and their members. - 14 | x = #4 x * 3; - | ^ -%Error: Exiting due to diff --git a/test_regress/t/t_timing_fork_unsup.v b/test_regress/t/t_timing_fork_unsup.v deleted file mode 100644 index 72a698e6d..000000000 --- a/test_regress/t/t_timing_fork_unsup.v +++ /dev/null @@ -1,24 +0,0 @@ -// DESCRIPTION: Verilator: Verilog Test module -// -// This file ONLY is placed under the Creative Commons Public Domain, for -// any use, without warranty, 2022 by Antmicro Ltd. -// SPDX-License-Identifier: CC0-1.0 - -module t; - class C; - task f; - int x = 0; - fork - #6 x = 4; - #2 x++; - x = #4 x * 3; - join_none - x = 1; - endtask - endclass - - initial begin - C o = new; - o.f; - end -endmodule From cf6566b9bc4a08365eb8908876133d2598eadc91 Mon Sep 17 00:00:00 2001 From: Anthony Donlon <4056887+donlon@users.noreply.github.com> Date: Wed, 30 Aug 2023 04:54:32 +0800 Subject: [PATCH 034/111] Internal: Optimize program size by refactoring error reporting routines (#4446) --- src/V3Ast.cpp | 15 +++---- src/V3Ast.h | 4 +- src/V3Dfg.h | 4 +- src/V3Error.cpp | 32 ++++++++++++++ src/V3Error.h | 103 ++++++++++++++++----------------------------- src/V3FileLine.cpp | 4 +- src/V3FileLine.h | 4 +- src/V3Graph.cpp | 6 +-- src/V3Graph.h | 4 +- src/V3Number.cpp | 6 +-- src/V3Number.h | 4 +- src/V3PreProc.cpp | 2 +- src/V3Width.cpp | 11 +++-- 13 files changed, 99 insertions(+), 100 deletions(-) diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index 0224ff574..e57d28ee5 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -1341,12 +1341,6 @@ bool AstNode::isTreePureRecurse() const { return true; } -void AstNode::v3errorEndFatal(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex) { - v3errorEnd(str); - assert(0); // LCOV_EXCL_LINE - VL_UNREACHABLE; -} - string AstNode::instanceStr() const { // Max iterations before giving up on location search, // in case we have some circular reference bug. @@ -1371,9 +1365,9 @@ string AstNode::instanceStr() const { return ""; } -void AstNode::v3errorEnd(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex) { +void AstNode::v3errorEnd(std::ostringstream& str) const VL_RELEASE(V3Error::s().m_mutex) { if (!m_fileline) { - V3Error::s().v3errorEnd(str, instanceStr()); + V3Error::v3errorEnd(str, instanceStr()); } else { std::ostringstream nsstr; nsstr << str.str(); @@ -1390,6 +1384,11 @@ void AstNode::v3errorEnd(std::ostringstream& str) const VL_REQUIRES(V3Error::s() nsstr, m_fileline->warnIsOff(V3Error::s().errorCode()) ? "" : instanceStr()); } } +void AstNode::v3errorEndFatal(std::ostringstream& str) const VL_RELEASE(V3Error::s().m_mutex) { + v3errorEnd(str); + assert(0); // LCOV_EXCL_LINE + VL_UNREACHABLE; +} //====================================================================== // Data type conversion diff --git a/src/V3Ast.h b/src/V3Ast.h index 337d948a7..269197806 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -1916,9 +1916,9 @@ public: static AstBasicDType* findInsertSameDType(AstBasicDType* nodep); // METHODS - dump and error - void v3errorEnd(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex); + void v3errorEnd(std::ostringstream& str) const VL_RELEASE(V3Error::s().m_mutex); void v3errorEndFatal(std::ostringstream& str) const VL_ATTR_NORETURN - VL_REQUIRES(V3Error::s().m_mutex); + VL_RELEASE(V3Error::s().m_mutex); string warnContextPrimary() const VL_REQUIRES(V3Error::s().m_mutex) { return fileline()->warnContextPrimary(); } diff --git a/src/V3Dfg.h b/src/V3Dfg.h index 88c868192..e0d72335b 100644 --- a/src/V3Dfg.h +++ b/src/V3Dfg.h @@ -503,11 +503,11 @@ public: inline bool inlined() const; // Methods that allow DfgVertex to participate in error reporting/messaging - void v3errorEnd(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex) { + void v3errorEnd(std::ostringstream& str) const VL_RELEASE(V3Error::s().m_mutex) { m_filelinep->v3errorEnd(str); } void v3errorEndFatal(std::ostringstream& str) const VL_ATTR_NORETURN - VL_REQUIRES(V3Error::s().m_mutex) { + VL_RELEASE(V3Error::s().m_mutex) { m_filelinep->v3errorEndFatal(str); } string warnContextPrimary() const VL_REQUIRES(V3Error::s().m_mutex) { diff --git a/src/V3Error.cpp b/src/V3Error.cpp index 57ec24e91..48966be77 100644 --- a/src/V3Error.cpp +++ b/src/V3Error.cpp @@ -291,3 +291,35 @@ void V3Error::vlAbort() { VL_GCOV_DUMP(); std::abort(); } +void V3Error::v3errorAcquireLock() VL_ACQUIRE(s().m_mutex) { +#ifndef V3ERROR_NO_GLOBAL_ + V3Error::s().m_mutex.lockCheckStopRequest( + []() -> void { V3ThreadPool::s().waitIfStopRequested(); }); +#else + V3Error::s().m_mutex.lock(); +#endif +} +std::ostringstream& V3Error::v3errorPrep(V3ErrorCode code) VL_ACQUIRE(s().m_mutex) { + v3errorAcquireLock(); + s().v3errorPrep(code); + return v3errorStr(); +} +std::ostringstream& V3Error::v3errorPrepFileLine(V3ErrorCode code, const char* file, int line) + VL_ACQUIRE(s().m_mutex) { + v3errorPrep(code) << file << ":" << std::dec << line << ": "; + return v3errorStr(); +} +std::ostringstream& V3Error::v3errorStr() VL_REQUIRES(s().m_mutex) { return s().v3errorStr(); } +void V3Error::v3errorEnd(std::ostringstream& sstr, const string& extra) VL_RELEASE(s().m_mutex) { + s().v3errorEnd(sstr, extra); + V3Error::s().m_mutex.unlock(); +} + +void v3errorEnd(std::ostringstream& sstr) VL_RELEASE(V3Error::s().m_mutex) { + V3Error::v3errorEnd(sstr); +} +void v3errorEndFatal(std::ostringstream& sstr) VL_RELEASE(V3Error::s().m_mutex) { + V3Error::v3errorEnd(sstr); + assert(0); // LCOV_EXCL_LINE + VL_UNREACHABLE; +} diff --git a/src/V3Error.h b/src/V3Error.h index e5450675c..f3a815775 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -286,9 +286,13 @@ inline std::ostream& operator<<(std::ostream& os, const V3ErrorCode& rhs) { } // ###################################################################### +class V3Error; + class V3ErrorGuarded final { // Should only be used by V3ErrorGuarded::m_mutex is already locked // contains guarded members + friend class V3Error; + public: using MessagesSet = std::set; using ErrorExitCb = void (*)(void); @@ -319,6 +323,16 @@ private: = MAX_ERRORS; // Option: --error-limit Number of errors before exit bool m_warnFatal VL_GUARDED_BY(m_mutex) = true; // Option: --warnFatal Warnings are fatal std::ostringstream m_errorStr VL_GUARDED_BY(m_mutex); // Error string being formed + + void v3errorPrep(V3ErrorCode code) VL_REQUIRES(m_mutex) { + m_errorStr.str(""); + m_errorCode = code; + m_errorContexted = false; + m_errorSuppressed = false; + } + std::ostringstream& v3errorStr() VL_REQUIRES(m_mutex) { return m_errorStr; } + void v3errorEnd(std::ostringstream& sstr, const string& extra = "") VL_REQUIRES(m_mutex); + public: V3RecursiveMutex m_mutex; // Make sure only single thread is in class @@ -361,13 +375,6 @@ public: int errorLimit() VL_REQUIRES(m_mutex) { return m_errorLimit; } void warnFatal(bool flag) VL_REQUIRES(m_mutex) { m_warnFatal = flag; } bool warnFatal() VL_REQUIRES(m_mutex) { return m_warnFatal; } - void v3errorPrep(V3ErrorCode code) VL_REQUIRES(m_mutex) { - m_errorStr.str(""); - m_errorCode = code; - m_errorContexted = false; - m_errorSuppressed = false; - } - std::ostringstream& v3errorStr() VL_REQUIRES(m_mutex) { return m_errorStr; } V3ErrorCode errorCode() VL_REQUIRES(m_mutex) { return m_errorCode; } bool errorContexted() VL_REQUIRES(m_mutex) { return m_errorContexted; } int warnCount() VL_REQUIRES(m_mutex) { return m_warnCount; } @@ -385,7 +392,6 @@ public: void describedWarnings(bool flag) VL_REQUIRES(m_mutex) { m_describedWarnings = flag; } int tellManual() VL_REQUIRES(m_mutex) { return m_tellManual; } void tellManual(int level) VL_REQUIRES(m_mutex) { m_tellManual = level; } - void v3errorEnd(std::ostringstream& sstr, const string& extra = "") VL_REQUIRES(m_mutex); void suppressThisWarning() VL_REQUIRES(m_mutex); string warnContextNone() VL_REQUIRES(m_mutex) { errorContexted(true); @@ -512,66 +518,32 @@ public: // Internals for v3error()/v3fatal() macros only // Error end takes the string stream to output, be careful to seek() as needed - static void v3errorPrep(V3ErrorCode code) VL_MT_SAFE_EXCLUDES(s().m_mutex) { - const V3RecursiveLockGuard guard{s().m_mutex}; - s().v3errorPrep(code); - } - static std::ostringstream& v3errorStr() VL_MT_SAFE_EXCLUDES(s().m_mutex) { - const V3RecursiveLockGuard guard{s().m_mutex}; - return s().v3errorStr(); - } - static void vlAbort(); + static void v3errorAcquireLock() VL_ACQUIRE(s().m_mutex); + static std::ostringstream& v3errorPrep(V3ErrorCode code) VL_ACQUIRE(s().m_mutex); + static std::ostringstream& v3errorPrepFileLine(V3ErrorCode code, const char* file, int line) + VL_ACQUIRE(s().m_mutex); + static std::ostringstream& v3errorStr() VL_REQUIRES(s().m_mutex); // static, but often overridden in classes. static void v3errorEnd(std::ostringstream& sstr, const string& extra = "") - VL_MT_SAFE_EXCLUDES(s().m_mutex) VL_MT_SAFE { - const V3RecursiveLockGuard guard{s().m_mutex}; - s().v3errorEnd(sstr, extra); - } - // We can't call 's().v3errorEnd' directly in 'v3ErrorEnd'/'v3errorEndFatal', - // due to bug in GCC (tested on 11.3.0 version with --enable-m32) - // causing internal error when backtrace is printed. - // Instead use this wrapper. - static void v3errorEndGuardedCall(std::ostringstream& sstr, const string& extra = "") - VL_REQUIRES(s().m_mutex) VL_MT_SAFE { - s().v3errorEnd(sstr, extra); - } + VL_RELEASE(s().m_mutex); + static void vlAbort(); }; -// Global versions, so that if the class doesn't define a operator, we get the functions anyways. -inline void v3errorEnd(std::ostringstream& sstr) VL_REQUIRES(V3Error::s().m_mutex) VL_MT_SAFE { - V3Error::v3errorEndGuardedCall(sstr); -} -inline void v3errorEndFatal(std::ostringstream& sstr) - VL_REQUIRES(V3Error::s().m_mutex) VL_MT_SAFE { - V3Error::v3errorEndGuardedCall(sstr); - assert(0); // LCOV_EXCL_LINE - VL_UNREACHABLE; -} - -#ifndef V3ERROR_NO_GLOBAL_ -#define V3ErrorLockAndCheckStopRequested \ - V3Error::s().m_mutex.lockCheckStopRequest( \ - []() -> void { V3ThreadPool::s().waitIfStopRequested(); }) -#else -#define V3ErrorLockAndCheckStopRequested V3Error::s().m_mutex.lock() -#endif +// Global versions, so that if the class doesn't define an operator, we get the functions anyway. +void v3errorEnd(std::ostringstream& sstr) VL_RELEASE(V3Error::s().m_mutex); +void v3errorEndFatal(std::ostringstream& sstr) VL_RELEASE(V3Error::s().m_mutex); // Theses allow errors using << operators: v3error("foo"<<"bar"); -// Careful, you can't put () around msg, as you would in most macro definitions -// Note the commas are the comma operator, not separating arguments. These are needed to ensure -// evaluation order as otherwise we couldn't ensure v3errorPrep is called first. -// Note: due to limitations of clang thread-safety analysis, we can't use -// lock guard here, instead we are locking the mutex as first operation in temporary, -// but we are unlocking the mutex after function using comma operator. -// This way macros should also work when they are in 'if' stmt without '{}'. -#define v3warnCode(code, msg) \ - v3errorEnd((V3ErrorLockAndCheckStopRequested, V3Error::s().v3errorPrep(code), \ - (V3Error::s().v3errorStr() << msg), V3Error::s().v3errorStr())), \ - V3Error::s().m_mutex.unlock() +// Careful, you can't put () around msg, as you would in most macro definitions. +// 'V3Error::v3errorPrep(code) << msg' could be more efficient but the order of function calls in a +// single statement can be arbitrary until C++17, thus make it possible to execute +// V3Error::v3errorPrep that acquires the lock after functions in the msg may require it. So we use +// the comma operator (,) to guarantee the execution order here. +#define v3errorBuildMessage(prep, msg) \ + (prep, static_cast(V3Error::v3errorStr() << msg)) +#define v3warnCode(code, msg) v3errorEnd(v3errorBuildMessage(V3Error::v3errorPrep(code), msg)) #define v3warnCodeFatal(code, msg) \ - v3errorEndFatal((V3ErrorLockAndCheckStopRequested, V3Error::s().v3errorPrep(code), \ - (V3Error::s().v3errorStr() << msg), V3Error::s().v3errorStr())), \ - V3Error::s().m_mutex.unlock() + v3errorEndFatal(v3errorBuildMessage(V3Error::v3errorPrep(code), msg)) #define v3warn(code, msg) v3warnCode(V3ErrorCode::code, msg) #define v3info(msg) v3warnCode(V3ErrorCode::EC_INFO, msg) #define v3error(msg) v3warnCode(V3ErrorCode::EC_ERROR, msg) @@ -580,14 +552,11 @@ inline void v3errorEndFatal(std::ostringstream& sstr) #define v3fatalExit(msg) v3warnCodeFatal(V3ErrorCode::EC_FATALEXIT, msg) // Use this instead of fatal() to mention the source code line. #define v3fatalSrc(msg) \ - v3warnCodeFatal(V3ErrorCode::EC_FATALSRC, \ - __FILE__ << ":" << std::dec << __LINE__ << ": " << msg) + v3errorEndFatal(v3errorBuildMessage( \ + V3Error::v3errorPrepFileLine(V3ErrorCode::EC_FATALSRC, __FILE__, __LINE__), msg)) // Use this when normal v3fatal is called in static method that overrides fileline. #define v3fatalStatic(msg) \ - (::v3errorEndFatal((V3ErrorLockAndCheckStopRequested, \ - V3Error::s().v3errorPrep(V3ErrorCode::EC_FATAL), \ - (V3Error::s().v3errorStr() << msg), V3Error::s().v3errorStr()))), \ - V3Error::s().m_mutex.unlock() + ::v3errorEndFatal(v3errorBuildMessage(V3Error::v3errorPrep(V3ErrorCode::EC_FATAL), msg)) #define UINFO(level, stmsg) \ do { \ diff --git a/src/V3FileLine.cpp b/src/V3FileLine.cpp index be4a7cd25..f3a0fb6de 100644 --- a/src/V3FileLine.cpp +++ b/src/V3FileLine.cpp @@ -379,7 +379,7 @@ bool FileLine::warnIsOff(V3ErrorCode code) const { // cppverilator-suppress constParameter void FileLine::v3errorEnd(std::ostringstream& sstr, const string& extra) - VL_REQUIRES(V3Error::s().m_mutex) { + VL_RELEASE(V3Error::s().m_mutex) { std::ostringstream nsstr; if (lastLineno()) nsstr << this; nsstr << sstr.str(); @@ -396,7 +396,7 @@ void FileLine::v3errorEnd(std::ostringstream& sstr, const string& extra) nsstr << warnContextPrimary(); } if (!m_waive) V3Waiver::addEntry(V3Error::s().errorCode(), filename(), sstr.str()); - V3Error::s().v3errorEnd(nsstr, lstr.str()); + V3Error::v3errorEnd(nsstr, lstr.str()); } string FileLine::warnMore() const VL_REQUIRES(V3Error::s().m_mutex) { diff --git a/src/V3FileLine.h b/src/V3FileLine.h index cb29f24f9..514299173 100644 --- a/src/V3FileLine.h +++ b/src/V3FileLine.h @@ -318,9 +318,9 @@ public: // OPERATORS void v3errorEnd(std::ostringstream& str, const string& extra = "") - VL_REQUIRES(V3Error::s().m_mutex); + VL_RELEASE(V3Error::s().m_mutex); void v3errorEndFatal(std::ostringstream& str) VL_ATTR_NORETURN - VL_REQUIRES(V3Error::s().m_mutex) { + VL_RELEASE(V3Error::s().m_mutex) { v3errorEnd(str); assert(0); // LCOV_EXCL_LINE VL_UNREACHABLE; diff --git a/src/V3Graph.cpp b/src/V3Graph.cpp index 27b37adf2..b2c3c4756 100644 --- a/src/V3Graph.cpp +++ b/src/V3Graph.cpp @@ -129,7 +129,7 @@ V3GraphEdge* V3GraphVertex::findConnectingEdgep(GraphWay way, const V3GraphVerte } // cppcheck-has-bug-suppress constParameter -void V3GraphVertex::v3errorEnd(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex) { +void V3GraphVertex::v3errorEnd(std::ostringstream& str) const VL_RELEASE(V3Error::s().m_mutex) { std::ostringstream nsstr; nsstr << str.str(); if (debug()) { @@ -139,11 +139,11 @@ void V3GraphVertex::v3errorEnd(std::ostringstream& str) const VL_REQUIRES(V3Erro if (FileLine* const flp = fileline()) { flp->v3errorEnd(nsstr); } else { - V3Error::s().v3errorEnd(nsstr); + V3Error::v3errorEnd(nsstr); } } void V3GraphVertex::v3errorEndFatal(std::ostringstream& str) const - VL_REQUIRES(V3Error::s().m_mutex) { + VL_RELEASE(V3Error::s().m_mutex) { v3errorEnd(str); assert(0); // LCOV_EXCL_LINE VL_UNREACHABLE; diff --git a/src/V3Graph.h b/src/V3Graph.h index 27aa13908..a0482b4e3 100644 --- a/src/V3Graph.h +++ b/src/V3Graph.h @@ -248,8 +248,8 @@ public: V3GraphEdge* beginp(GraphWay way) const { return way.forward() ? outBeginp() : inBeginp(); } // METHODS /// Error reporting - void v3errorEnd(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex); - void v3errorEndFatal(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex); + void v3errorEnd(std::ostringstream& str) const VL_RELEASE(V3Error::s().m_mutex); + void v3errorEndFatal(std::ostringstream& str) const VL_RELEASE(V3Error::s().m_mutex); /// Edges are routed around this vertex to point from "from" directly to "to" void rerouteEdges(V3Graph* graphp); /// Find the edge connecting ap and bp, where bp is wayward from ap. diff --git a/src/V3Number.cpp b/src/V3Number.cpp index cc1d22514..c44c6e17c 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -76,7 +76,7 @@ constexpr int MAX_SPRINTF_DOUBLE_SIZE //====================================================================== // Errors -void V3Number::v3errorEnd(const std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex) { +void V3Number::v3errorEnd(const std::ostringstream& str) const VL_RELEASE(V3Error::s().m_mutex) { std::ostringstream nsstr; nsstr << str.str(); if (m_nodep) { @@ -84,12 +84,12 @@ void V3Number::v3errorEnd(const std::ostringstream& str) const VL_REQUIRES(V3Err } else if (m_fileline) { m_fileline->v3errorEnd(nsstr); } else { - V3Error::s().v3errorEnd(nsstr); + V3Error::v3errorEnd(nsstr); } } void V3Number::v3errorEndFatal(const std::ostringstream& str) const - VL_REQUIRES(V3Error::s().m_mutex) { + VL_RELEASE(V3Error::s().m_mutex) { v3errorEnd(str); assert(0); // LCOV_EXCL_LINE VL_UNREACHABLE; diff --git a/src/V3Number.h b/src/V3Number.h index 46ba16094..e76c854c4 100644 --- a/src/V3Number.h +++ b/src/V3Number.h @@ -566,9 +566,9 @@ private: } public: - void v3errorEnd(const std::ostringstream& sstr) const VL_REQUIRES(V3Error::s().m_mutex); + void v3errorEnd(const std::ostringstream& sstr) const VL_RELEASE(V3Error::s().m_mutex); void v3errorEndFatal(const std::ostringstream& sstr) const VL_ATTR_NORETURN - VL_REQUIRES(V3Error::s().m_mutex); + VL_RELEASE(V3Error::s().m_mutex); void width(int width, bool sized = true) { m_data.m_sized = sized; m_data.resize(width); diff --git a/src/V3PreProc.cpp b/src/V3PreProc.cpp index f59b5d1d3..28058644f 100644 --- a/src/V3PreProc.cpp +++ b/src/V3PreProc.cpp @@ -185,7 +185,7 @@ public: // For getline() string m_lineChars; ///< Characters left for next line - void v3errorEnd(std::ostringstream& str) VL_REQUIRES(V3Error::s().m_mutex) { + void v3errorEnd(std::ostringstream& str) VL_RELEASE(V3Error::s().m_mutex) { fileline()->v3errorEnd(str); } diff --git a/src/V3Width.cpp b/src/V3Width.cpp index ab3f2267a..d5333b6f7 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -121,12 +121,11 @@ std::ostream& operator<<(std::ostream& str, const Castable& rhs) { } #define v3widthWarn(lhs, rhs, msg) \ - v3errorEnd((V3Error::s().m_mutex.lock(), \ - V3Error::s().v3errorPrep((lhs) < (rhs) ? V3ErrorCode::WIDTHTRUNC \ - : (lhs) > (rhs) ? V3ErrorCode::WIDTHEXPAND \ - : V3ErrorCode::WIDTH), \ - (V3Error::s().v3errorStr() << msg), V3Error::s().v3errorStr())), \ - V3Error::s().m_mutex.unlock() + v3errorEnd( \ + v3errorBuildMessage(V3Error::v3errorPrep((lhs) < (rhs) ? V3ErrorCode::WIDTHTRUNC \ + : (lhs) > (rhs) ? V3ErrorCode::WIDTHEXPAND \ + : V3ErrorCode::WIDTH), \ + msg)) //###################################################################### // Width state, as a visitor of each AstNode From 2a30bbe4931791ae2d2a2407d1314fb85ee20ff6 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 29 Aug 2023 18:07:23 -0400 Subject: [PATCH 035/111] Fix internal error on real conversion (#4447). --- Changes | 1 + src/V3Number.cpp | 4 +++- test_regress/t/t_debug_emitv.out | 2 +- test_regress/t/t_math_real.v | 6 ++++++ 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Changes b/Changes index 6bba79b79..e41bc37bd 100644 --- a/Changes +++ b/Changes @@ -28,6 +28,7 @@ Verilator 5.015 devel * Fix coroutine handle movement during queue manipulation (#4431). [Aleksander Kiryk, Antmicro Ltd] * Fix nested assignments on the LHS (#4435). [Ryszard Rozak, Antmicro Ltd] * Fix false MULTITOP on bound interfaces (#4438). [Alex Solomatnikov] +* Fix internal error on real conversion (#4447). [vdhotre-ventana] Verilator 5.014 2023-08-06 diff --git a/src/V3Number.cpp b/src/V3Number.cpp index c44c6e17c..38e7de3a2 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -511,6 +511,7 @@ string V3Number::ascii(bool prefixed, bool cleanVerilog) const VL_MT_STABLE { out << "%E-bad-width-double"; // LCOV_EXCL_LINE } else { out << toDouble(); + if (toDouble() == floor(toDouble())) out << ".0"; } return out.str(); } else if (isString()) { @@ -2217,8 +2218,9 @@ V3Number& V3Number::opAssignNonXZ(const V3Number& lhs, bool ignoreXZ) { } else if (VL_UNLIKELY(lhs.isString())) { // Non-compatible types, see also opAToN() setZero(); + } else if (lhs.isDouble()) { + setDouble(lhs.toDouble()); } else { - // Also handles double as is just bits for (int bit = 0; bit < this->width(); bit++) { setBit(bit, ignoreXZ ? lhs.bitIs1(bit) : lhs.bitIs(bit)); } diff --git a/test_regress/t/t_debug_emitv.out b/test_regress/t/t_debug_emitv.out index abfcc0c61..2fcd6e906 100644 --- a/test_regress/t/t_debug_emitv.out +++ b/test_regress/t/t_debug_emitv.out @@ -285,7 +285,7 @@ module Vt_debug_emitv_t; if ((PKG_PARAM != 'sh1)) begin $stop; end - sub.r = 62; + sub.r = 62.0; $display("%g", $log10(r)); $display("%g", $ln(r)); $display("%g", $exp(r)); diff --git a/test_regress/t/t_math_real.v b/test_regress/t/t_math_real.v index 661837d61..6e0584d5f 100644 --- a/test_regress/t/t_math_real.v +++ b/test_regress/t/t_math_real.v @@ -36,6 +36,9 @@ module t (/*AUTOARG*/ realtime uninit; initial if (uninit != 0.0) $stop; + localparam int TWENTY = 20; + localparam real TWENDIV = $ceil((real'(TWENTY)-14.0)/2.0); + sub_cast_bug374 sub (.cyc5(cyc[4:0]), .*); initial begin @@ -163,6 +166,9 @@ module t (/*AUTOARG*/ r = -$sqrt(-1.0); // NaN s = $sformatf("%g", r); `checks(s, "nan"); + + if (real'(TWENTY) != 20.0) $stop; + if (TWENDIV != 3.0) $stop; end // Test loop From 8d1570db2881f843ff2d15ff19b8243d058e6144 Mon Sep 17 00:00:00 2001 From: Ethan Sifferman Date: Tue, 29 Aug 2023 16:55:37 -0700 Subject: [PATCH 036/111] Add check for conflicting options e.g. binary+lintonly (#4409) --- docs/guide/exe_verilator.rst | 5 ++++- src/V3Options.cpp | 19 +++++++++++++++++++ src/V3Options.h | 2 ++ test_regress/t/t_flag_only_bad.out | 2 ++ test_regress/t/t_flag_only_bad.pl | 23 +++++++++++++++++++++++ test_regress/t/t_flag_only_bad2.out | 2 ++ test_regress/t/t_flag_only_bad2.pl | 23 +++++++++++++++++++++++ test_regress/t/t_flag_only_bad3.out | 2 ++ test_regress/t/t_flag_only_bad3.pl | 23 +++++++++++++++++++++++ test_regress/t/t_lint_eofline.pl | 2 +- 10 files changed, 101 insertions(+), 2 deletions(-) create mode 100755 test_regress/t/t_flag_only_bad.out create mode 100755 test_regress/t/t_flag_only_bad.pl create mode 100755 test_regress/t/t_flag_only_bad2.out create mode 100755 test_regress/t/t_flag_only_bad2.pl create mode 100755 test_regress/t/t_flag_only_bad3.out create mode 100755 test_regress/t/t_flag_only_bad3.pl diff --git a/docs/guide/exe_verilator.rst b/docs/guide/exe_verilator.rst index 87f9db880..99c4bd0ec 100644 --- a/docs/guide/exe_verilator.rst +++ b/docs/guide/exe_verilator.rst @@ -125,9 +125,12 @@ Summary: After generating the SystemC/C++ code, Verilator will invoke the toolchain to build the model library (and executable when :vlopt:`--exe` - is also used). Verilator manages the build itself, and for this --build + is also used). Verilator manages the build itself, and for this --build requires GNU Make to be available on the platform. + :vlopt:`--build` cannot be specified when using :vlopt:`-E`, + :vlopt:`--dpi-hdr-only`, :vlopt:`--lint-only`, or :vlopt:`--xml-only`. + .. option:: --build-dep-bin Rarely needed. When a dependency (.d) file is created, this filename diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 47ac50329..39e74fa95 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -806,6 +806,24 @@ void V3Options::notify() { cmdfl->v3error("--make cannot be used together with --build. Suggest see manual"); } + // m_build, m_preprocOnly, m_dpiHdrOnly, m_lintOnly, and m_xmlOnly are mutually exclusive + std::vector backendFlags; + if (m_build) { + if (m_binary) backendFlags.push_back("--binary"); + else backendFlags.push_back("--build"); + } + if (m_preprocOnly) backendFlags.push_back("-E"); + if (m_dpiHdrOnly) backendFlags.push_back("--dpi-hdr-only"); + if (m_lintOnly) backendFlags.push_back("--lint-only"); + if (m_xmlOnly) backendFlags.push_back("--xml-only"); + if (backendFlags.size() > 1) { + std::string backendFlagsString = backendFlags.front(); + for (size_t i = 1; i < backendFlags.size(); i++) { + backendFlagsString += ", " + backendFlags[i]; + } + v3error("The following cannot be used together: " + backendFlagsString + ". Suggest see manual"); + } + if (m_exe && !v3Global.opt.libCreate().empty()) { cmdfl->v3error("--exe cannot be used together with --lib-create. Suggest see manual"); } @@ -1081,6 +1099,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char FileLine::globalWarnOff(V3ErrorCode::E_UNSUPPORTED, true); }); DECL_OPTION("-binary", CbCall, [this]() { + m_binary = true; m_build = true; m_exe = true; m_main = true; diff --git a/src/V3Options.h b/src/V3Options.h index f68c32d11..dc2d011a8 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -223,6 +223,7 @@ private: bool m_autoflush = false; // main switch: --autoflush bool m_bboxSys = false; // main switch: --bbox-sys bool m_bboxUnsup = false; // main switch: --bbox-unsup + bool m_binary = false; // main switch: --binary bool m_build = false; // main switch: --build bool m_cmake = false; // main switch: --make cmake bool m_context = true; // main switch: --Wcontext @@ -442,6 +443,7 @@ public: bool autoflush() const { return m_autoflush; } bool bboxSys() const { return m_bboxSys; } bool bboxUnsup() const { return m_bboxUnsup; } + bool binary() const { return m_binary; } bool build() const { return m_build; } string buildDepBin() const { return m_buildDepBin; } void buildDepBin(const string& flag) { m_buildDepBin = flag; } diff --git a/test_regress/t/t_flag_only_bad.out b/test_regress/t/t_flag_only_bad.out new file mode 100755 index 000000000..ae416db51 --- /dev/null +++ b/test_regress/t/t_flag_only_bad.out @@ -0,0 +1,2 @@ +%Error: The following cannot be used together: --binary, -E, --dpi-hdr-only, --lint-only, --xml-only. Suggest see manual +%Error: Exiting due to diff --git a/test_regress/t/t_flag_only_bad.pl b/test_regress/t/t_flag_only_bad.pl new file mode 100755 index 000000000..6fb0c0314 --- /dev/null +++ b/test_regress/t/t_flag_only_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 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(vlt => 1); +top_filename("t/t_flag_main.v"); + +compile( + verilator_make_cmake => 0, + verilator_make_gmake => 0, + verilator_flags2 => ["--binary -E --dpi-hdr-only --lint-only --xml-only -Wall"], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_flag_only_bad2.out b/test_regress/t/t_flag_only_bad2.out new file mode 100755 index 000000000..f67b538ce --- /dev/null +++ b/test_regress/t/t_flag_only_bad2.out @@ -0,0 +1,2 @@ +%Error: The following cannot be used together: --build, -E, --dpi-hdr-only, --lint-only, --xml-only. Suggest see manual +%Error: Exiting due to diff --git a/test_regress/t/t_flag_only_bad2.pl b/test_regress/t/t_flag_only_bad2.pl new file mode 100755 index 000000000..34c252411 --- /dev/null +++ b/test_regress/t/t_flag_only_bad2.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(vlt => 1); +top_filename("t/t_flag_main.v"); + +compile( + verilator_make_cmake => 0, + verilator_make_gmake => 0, + verilator_flags2 => ["--build -E -Wno-fatal --dpi-hdr-only --lint-only --xml-only"], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_flag_only_bad3.out b/test_regress/t/t_flag_only_bad3.out new file mode 100755 index 000000000..de3cf93a8 --- /dev/null +++ b/test_regress/t/t_flag_only_bad3.out @@ -0,0 +1,2 @@ +%Error: The following cannot be used together: --dpi-hdr-only, --lint-only, --xml-only. Suggest see manual +%Error: Exiting due to diff --git a/test_regress/t/t_flag_only_bad3.pl b/test_regress/t/t_flag_only_bad3.pl new file mode 100755 index 000000000..f21368eec --- /dev/null +++ b/test_regress/t/t_flag_only_bad3.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(vlt => 1); +top_filename("t/t_flag_main.v"); + +compile( + verilator_make_cmake => 0, + verilator_make_gmake => 0, + verilator_flags2 => ["-Wall --lint-only -Wno-fatal --dpi-hdr-only --xml-only"], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_lint_eofline.pl b/test_regress/t/t_lint_eofline.pl index be8639453..709ff432e 100755 --- a/test_regress/t/t_lint_eofline.pl +++ b/test_regress/t/t_lint_eofline.pl @@ -26,7 +26,7 @@ top_filename("$Self->{obj_dir}/t_lint_eofline_bad.v"); gen($Self->{top_filename}); lint( - verilator_flags2 => ["--lint-only -Wall -Wno-DECLFILENAME -E"], + verilator_flags2 => ["-E -Wall -Wno-DECLFILENAME"], expect_filename => $Self->{golden_filename}, ); From 799a502caca71ac33e25688c36fa510cc230b2bd Mon Sep 17 00:00:00 2001 From: github action Date: Tue, 29 Aug 2023 23:56:25 +0000 Subject: [PATCH 037/111] Apply 'make format' --- src/V3Options.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 39e74fa95..3cf91c24f 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -809,8 +809,10 @@ void V3Options::notify() { // m_build, m_preprocOnly, m_dpiHdrOnly, m_lintOnly, and m_xmlOnly are mutually exclusive std::vector backendFlags; if (m_build) { - if (m_binary) backendFlags.push_back("--binary"); - else backendFlags.push_back("--build"); + if (m_binary) + backendFlags.push_back("--binary"); + else + backendFlags.push_back("--build"); } if (m_preprocOnly) backendFlags.push_back("-E"); if (m_dpiHdrOnly) backendFlags.push_back("--dpi-hdr-only"); @@ -821,7 +823,8 @@ void V3Options::notify() { for (size_t i = 1; i < backendFlags.size(); i++) { backendFlagsString += ", " + backendFlags[i]; } - v3error("The following cannot be used together: " + backendFlagsString + ". Suggest see manual"); + v3error("The following cannot be used together: " + backendFlagsString + + ". Suggest see manual"); } if (m_exe && !v3Global.opt.libCreate().empty()) { From ca6ab584d074a28f4997d1aab25c56a2aeba9530 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 29 Aug 2023 20:29:11 -0400 Subject: [PATCH 038/111] Internals: Remove cloneTreeNull. No functional change intended. --- src/V3Ast.h | 4 ---- src/V3Premit.cpp | 2 +- src/V3Task.cpp | 2 +- src/astgen | 3 --- src/verilog.y | 27 +++++++++++++++++---------- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/V3Ast.h b/src/V3Ast.h index 269197806..dbe2b02a0 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -1956,10 +1956,6 @@ public: AstNode* belowp); // When calling, "this" is second argument // METHODS - Iterate on a tree - // Clone or return nullptr if nullptr - static AstNode* cloneTreeNull(AstNode* nodep, bool cloneNextLink) { - return nodep ? nodep->cloneTree(cloneNextLink) : nullptr; - } AstNode* cloneTree(bool cloneNextLink); // Not const, as sets clonep() on original nodep bool gateTree() { return gateTreeIter(); } // Is tree isGateOptimizable? inline bool sameTree(const AstNode* node2p) const; // Does tree of this == node2p? diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp index 6a134cd89..6887e175d 100644 --- a/src/V3Premit.cpp +++ b/src/V3Premit.cpp @@ -370,7 +370,7 @@ private: UINFO(4, "Autoflush " << nodep << endl); nodep->addNextHere( new AstFFlush{nodep->fileline(), - VN_AS(AstNode::cloneTreeNull(nodep->filep(), true), NodeExpr)}); + nodep->filep() ? nodep->filep()->cloneTree(true) : nullptr}); } } } diff --git a/src/V3Task.cpp b/src/V3Task.cpp index e1435a43b..a2fc9b0a5 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -421,7 +421,7 @@ private: // outvscp is the variable for functions only, if nullptr, it's a task UASSERT_OBJ(refp->taskp(), refp, "Unlinked?"); AstNode* const newbodysp - = AstNode::cloneTreeNull(refp->taskp()->stmtsp(), true); // Maybe nullptr + = refp->taskp()->stmtsp() ? refp->taskp()->stmtsp()->cloneTree(true) : nullptr; AstNode* const beginp = new AstComment{refp->fileline(), string{"Function: "} + refp->name(), true}; if (newbodysp) beginp->addNext(newbodysp); diff --git a/src/astgen b/src/astgen index 3a9b65785..048077e3d 100755 --- a/src/astgen +++ b/src/astgen @@ -961,9 +961,6 @@ def write_ast_macros(filename): Ast{t}* cloneTree(bool cloneNext) {{ return static_cast(AstNode::cloneTree(cloneNext)); }} - static Ast{t}* cloneTreeNull(Ast{t}* nodep, bool cloneNextLink) {{ - return nodep ? nodep->cloneTree(cloneNextLink) : nullptr; - }} Ast{t}* clonep() const {{ return static_cast(AstNode::clonep()); }} Ast{t}* addNext(Ast{t}* nodep) {{ return static_cast(AstNode::addNext(this, nodep)); }} ''', diff --git a/src/verilog.y b/src/verilog.y index 076ea09fa..78f93d150 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -148,13 +148,14 @@ public: AstVar* const nodep = createVariable(fileline, name, rangelistp, nullptr); return nodep; } - AstCell* const nodep = new AstCell{fileline, - GRAMMARP->m_instModuleFl, - name, - GRAMMARP->m_instModule, - pinlistp, - AstPin::cloneTreeNull(GRAMMARP->m_instParamp, true), - GRAMMARP->scrubRange(rangelistp)}; + AstCell* const nodep = new AstCell{ + fileline, + GRAMMARP->m_instModuleFl, + name, + GRAMMARP->m_instModule, + pinlistp, + (GRAMMARP->m_instParamp ? GRAMMARP->m_instParamp->cloneTree(true) : nullptr), + GRAMMARP->scrubRange(rangelistp)}; nodep->trace(GRAMMARP->allTracingOn(fileline)); return nodep; } @@ -284,7 +285,9 @@ public: setScopedSigAttr(new AstAttrOf{PARSEP->lexFileline(), vattrT}); } - AstNode* cloneScopedSigAttr() const { return AstNode::cloneTreeNull(m_scopedSigAttr, true); } + AstNode* cloneScopedSigAttr() const { + return m_scopedSigAttr ? m_scopedSigAttr->cloneTree(true) : nullptr; + } }; const VBasicDTypeKwd LOGIC = VBasicDTypeKwd::LOGIC; // Shorthand "LOGIC" @@ -2194,13 +2197,17 @@ member_decl_assignment: // Derived from IEEE: variable_decl_assi // // So this is different from variable_decl_assignment id variable_dimensionListE { $$ = new AstMemberDType{$1, *$1, VFlagChildDType{}, - GRAMMARP->createArray(AstNodeDType::cloneTreeNull(GRAMMARP->m_memDTypep, true), $2, false), + GRAMMARP->createArray((GRAMMARP->m_memDTypep + ? GRAMMARP->m_memDTypep->cloneTree(true) : nullptr), + $2, false), nullptr}; PARSEP->tagNodep($$); } | id variable_dimensionListE '=' variable_declExpr { $$ = new AstMemberDType{$1, *$1, VFlagChildDType{}, - GRAMMARP->createArray(AstNodeDType::cloneTreeNull(GRAMMARP->m_memDTypep, true), $2, false), + GRAMMARP->createArray((GRAMMARP->m_memDTypep + ? GRAMMARP->m_memDTypep->cloneTree(true) : nullptr), + $2, false), $4}; PARSEP->tagNodep($$); } From b4b74d72f03338d8a82c88dea551a12d84ea2f45 Mon Sep 17 00:00:00 2001 From: Yinan Xu Date: Wed, 30 Aug 2023 19:02:55 +0800 Subject: [PATCH 039/111] Add prepareClone and atClone APIs for Verilated models (#3503) (#4444) This API is used if the user copies the process using `fork` and similar OS-level mechanisms. The `at_clone` member function ensures that all model-allocated resources are re-allocated, such that the copied child process/model can simulate correctly. A typical allocated resource is the thread pool, which every model has its own pool. --- docs/guide/connecting.rst | 37 +++++++++++++ include/verilated.cpp | 8 +++ include/verilated.h | 2 + src/V3EmitCModel.cpp | 15 +++++ src/V3EmitCSyms.cpp | 2 +- test_regress/t/t_flag_csplit.pl | 2 + test_regress/t/t_wrapper_clone.cpp | 89 ++++++++++++++++++++++++++++++ test_regress/t/t_wrapper_clone.out | 15 +++++ test_regress/t/t_wrapper_clone.pl | 25 +++++++++ test_regress/t/t_wrapper_clone.v | 38 +++++++++++++ 10 files changed, 232 insertions(+), 1 deletion(-) create mode 100644 test_regress/t/t_wrapper_clone.cpp create mode 100644 test_regress/t/t_wrapper_clone.out create mode 100755 test_regress/t/t_wrapper_clone.pl create mode 100644 test_regress/t/t_wrapper_clone.v diff --git a/docs/guide/connecting.rst b/docs/guide/connecting.rst index 10b35eec9..2ef1b35bc 100644 --- a/docs/guide/connecting.rst +++ b/docs/guide/connecting.rst @@ -128,6 +128,43 @@ in the distribution. These headers use Doxygen comments, `///` and `//<`, to indicate and document those functions that are part of the Verilated public API. +Process-Level Clone APIs +-------------------------- + +Modern operating systems support process-level clone (a.k.a copying, forking) +with system call interfaces in C/C++, e.g., :code:`fork()` in Linux. + +However, after cloning a parent process, some resources cannot be inherited +in the child process. For example, in POSIX systems, when you fork a process, +the child process inherits all the memory of the parent process. However, +only the thread that called fork is replicated in the child process. Other +threads are not. + +Therefore, to support the process-level clone mechanisms, Verilator supports +:code:`prepareClone()` and :code:`atClone()` APIs to allow the user to manually +re-construct the model in the child process. The two APIs handle all necessary +resources required for releasing and re-initializing before and after cloning. + +The two APIs are supported in the verilated models. Here is an example of usage +with Linux :code:`fork()` and :code:`pthread_atfork` APIs: + +.. code-block:: C++ + + // static function pointers to fit pthread_atfork + static auto prepareClone = [](){ topp->prepareClone(); }; + static auto atClone = [](){ topp->atClone(); }; + + // in main function, register the handlers: + pthread_atfork(prepareClone, atClone, atClone); + +For better flexibility, you can also manually call the handlers before and +after :code:`fork()`. + +With the process-level clone APIs, users can create process-level snapshots +for the verilated models. While the Verilator save/restore option provides +persistent and circuit-independent snapshots, the process-level clone APIs +enable in-memory, circuit-transparent, and highly efficient snapshots. + Direct Programming Interface (DPI) ================================== diff --git a/include/verilated.cpp b/include/verilated.cpp index a77094f65..6ffa7f3d8 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -2608,6 +2608,14 @@ VerilatedVirtualBase* VerilatedContext::threadPoolp() { return m_threadPool.get(); } +void VerilatedContext::prepareClone() { delete m_threadPool.release(); } + +VerilatedVirtualBase* VerilatedContext::threadPoolpOnClone() { + if (VL_UNLIKELY(m_threadPool)) m_threadPool.release(); + m_threadPool = std::make_unique(this, m_threads - 1); + return m_threadPool.get(); +} + VerilatedVirtualBase* VerilatedContext::enableExecutionProfiler(VerilatedVirtualBase* (*construct)(VerilatedContext&)) { if (!m_executionProfiler) m_executionProfiler.reset(construct(*this)); diff --git a/include/verilated.h b/include/verilated.h index 4ee19b681..250f4a83d 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -568,6 +568,8 @@ public: void addModel(VerilatedModel*); VerilatedVirtualBase* threadPoolp(); + void prepareClone(); + VerilatedVirtualBase* threadPoolpOnClone(); VerilatedVirtualBase* enableExecutionProfiler(VerilatedVirtualBase* (*construct)(VerilatedContext&)); diff --git a/src/V3EmitCModel.cpp b/src/V3EmitCModel.cpp index d63708828..3f988ed32 100644 --- a/src/V3EmitCModel.cpp +++ b/src/V3EmitCModel.cpp @@ -234,6 +234,12 @@ class EmitCModel final : public EmitCFunc { puts("const char* hierName() const override final;\n"); puts("const char* modelName() const override final;\n"); puts("unsigned threads() const override final;\n"); + puts("/// Prepare for cloning the model at the process level (e.g. fork in Linux)\n"); + puts("/// Release necessary resources. Called before cloning.\n"); + puts("void prepareClone() const;\n"); + puts("/// Re-init after cloning the model at the process level (e.g. fork in Linux)\n"); + puts("/// Re-allocate necessary resources. Called after cloning.\n"); + puts("void atClone() const;\n"); if (v3Global.opt.trace()) { puts("std::unique_ptr traceConfig() const override final;\n"); } @@ -479,6 +485,15 @@ class EmitCModel final : public EmitCFunc { + "\"; }\n"); puts("unsigned " + topClassName() + "::threads() const { return " + cvtToStr(std::max(1, v3Global.opt.threads())) + "; }\n"); + puts("void " + topClassName() + + "::prepareClone() const { contextp()->prepareClone(); }\n"); + puts("void " + topClassName() + "::atClone() const {\n"); + if (v3Global.opt.threads() > 1) { + puts("vlSymsp->__Vm_threadPoolp = static_cast("); + } + puts("contextp()->threadPoolpOnClone()"); + if (v3Global.opt.threads() > 1) puts(")"); + puts(";\n}\n"); if (v3Global.opt.trace()) { puts("std::unique_ptr " + topClassName() diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index 04ea78814..0ae5d82fd 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -468,7 +468,7 @@ void EmitCSyms::emitSymHdr() { if (v3Global.opt.mtasks()) { puts("\n// MULTI-THREADING\n"); - puts("VlThreadPool* const __Vm_threadPoolp;\n"); + puts("VlThreadPool* __Vm_threadPoolp;\n"); puts("bool __Vm_even_cycle__ico = false;\n"); puts("bool __Vm_even_cycle__act = false;\n"); puts("bool __Vm_even_cycle__nba = false;\n"); diff --git a/test_regress/t/t_flag_csplit.pl b/test_regress/t/t_flag_csplit.pl index 1eb2c8dd4..bcb3f9eef 100755 --- a/test_regress/t/t_flag_csplit.pl +++ b/test_regress/t/t_flag_csplit.pl @@ -97,6 +97,8 @@ sub check_cpp { && $func !~ /::traceInit$/ && $func !~ /::traceFull$/ && $func !~ /::final$/ + && $func !~ /::prepareClone$/ + && $func !~ /::atClone$/ ) { push @funcs, $func; } diff --git a/test_regress/t/t_wrapper_clone.cpp b/test_regress/t/t_wrapper_clone.cpp new file mode 100644 index 000000000..86fbfe1cc --- /dev/null +++ b/test_regress/t/t_wrapper_clone.cpp @@ -0,0 +1,89 @@ +// +// DESCRIPTION: Verilator: Verilog Test module for prepareClone/atClone APIs +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2023 by Yinan Xu. +// SPDX-License-Identifier: CC0-1.0 + +#include + +#include + +#include + +// These require the above. Comment prevents clang-format moving them +#include "TestCheck.h" + +#include VM_PREFIX_INCLUDE + +double sc_time_stamp() { return 0; } + +// Note: Since the pthread_atfork API accepts only function pointers, +// we are using a static variable for the TOP just for a simple example. +// Without using the pthread_atfork API, the user can instead manually call +// prepareClone and atClone before and after calling fork, and topp can be +// allocated dynamically. +static VM_PREFIX* topp = nullptr; +static auto prepareClone = []() { topp->prepareClone(); }; +static auto atClone = []() { topp->atClone(); }; + +void single_cycle(VM_PREFIX* topp) { + topp->clock = 1; + topp->eval(); + + topp->clock = 0; + topp->eval(); +} + +int main(int argc, char** argv) { + // We disable the buffering for stdout in this test. + // Redirecting the stdout to files with buffering causes duplicated stdout + // outputs in both parent and child processes, even if they are actually + // called before the fork. + setvbuf(stdout, nullptr, _IONBF, 0); + + VerilatedContext* contextp = new VerilatedContext; + topp = new VM_PREFIX{contextp}; + + // To avoid resource leaks, prepareClone must be called before fork to + // free all the allocated resources. Though this would bring performance + // overhead to the parent process, we believe that fork should not be + // called frequently, and the overhead is minor compared to simulation. + pthread_atfork(prepareClone, atClone, atClone); + + // If you care about critical performance, prepareClone can be avoided, + // with atClone being called only at the child process, as follows. + // It has the same functionality as the previous one, but has memory leaks. + // According to the sanitizer, 288 bytes are leaked for one fork call. + // pthread_atfork(nullptr, nullptr, atClone); + + topp->reset = 1; + topp->is_parent = 0; + for (int i = 0; i < 5; i++) { single_cycle(topp); } + + topp->reset = 0; + while (!contextp->gotFinish()) { + single_cycle(topp); + + if (topp->do_clone) { + const int pid = fork(); + if (pid < 0) { + printf("fork failed\n"); + } else if (pid == 0) { + printf("child: here we go\n"); + } else { + while (wait(nullptr) > 0) + ; + printf("parent: here we go\n"); + topp->is_parent = 1; + } + } + } + + topp->final(); + + VL_DO_DANGLING(delete topp, topp); + VL_DO_DANGLING(delete contextp, contextp); + + return 0; +} diff --git a/test_regress/t/t_wrapper_clone.out b/test_regress/t/t_wrapper_clone.out new file mode 100644 index 000000000..1a5b106d1 --- /dev/null +++ b/test_regress/t/t_wrapper_clone.out @@ -0,0 +1,15 @@ +counter = 0 +counter = 1 +counter = 2 +counter = 3 +counter = 4 +counter = 5 +child: here we go +counter = 6 +counter = 7 +counter = 8 +parent: here we go +counter = 6 +counter = 7 +counter = 8 +*-* All Finished *-* diff --git a/test_regress/t/t_wrapper_clone.pl b/test_regress/t/t_wrapper_clone.pl new file mode 100755 index 000000000..54682086b --- /dev/null +++ b/test_regress/t/t_wrapper_clone.pl @@ -0,0 +1,25 @@ +#!/usr/bin/env perl +if (!$::Driver) { use strict; use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test module for prepareClone/atClone APIs +# +# This file ONLY is placed into the Public Domain, for any use, +# without warranty, 2023 by Yinan Xu. +# SPDX-License-Identifier: CC0-1.0 + +scenarios(vlt_all => 1); + +compile( + make_top_shell => 0, + make_main => 0, + verilator_flags2 => ["--exe $Self->{t_dir}/$Self->{name}.cpp", + "-cc"], + threads => $Self->{vltmt} ? 2 : 1, + ); + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_wrapper_clone.v b/test_regress/t/t_wrapper_clone.v new file mode 100644 index 000000000..fa6546a8b --- /dev/null +++ b/test_regress/t/t_wrapper_clone.v @@ -0,0 +1,38 @@ +// DESCRIPTION: Verilator: Verilog Test module for prepareClone/atClone APIs +// +// This model counts from 0 to 8. It forks a child process (in C++) at 6 +// and waits for the child to simulate and exit for resumption (of the parent). +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2023 by Yinan Xu. +// SPDX-License-Identifier: CC0-1.0 + +module top( + input clock, + input reset, + input is_parent, + output do_clone +); + +reg [3:0] counter; + +assign do_clone = counter == 4'h6; + +always @(posedge clock) begin + if (reset) begin + counter <= 4'h0; + end + else begin + counter <= counter + 4'h1; + $write("counter = %d\n", counter); + end + + if (counter[3]) begin + if (is_parent) begin + $write("*-* All Finished *-*\n"); + end + $finish(0); + end +end + +endmodule From ccdb52c1d9e528be58f6fe122c563465f4d3da57 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 30 Aug 2023 07:20:25 -0400 Subject: [PATCH 040/111] Fix lifetime unknown error on enum.name (#4448). --- Changes | 1 + src/V3Width.cpp | 1 + test_regress/t/t_fork_join_none_class_cap.v | 7 +++++-- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Changes b/Changes index e41bc37bd..d2707bbec 100644 --- a/Changes +++ b/Changes @@ -29,6 +29,7 @@ Verilator 5.015 devel * Fix nested assignments on the LHS (#4435). [Ryszard Rozak, Antmicro Ltd] * Fix false MULTITOP on bound interfaces (#4438). [Alex Solomatnikov] * Fix internal error on real conversion (#4447). [vdhotre-ventana] +* Fix lifetime unknown error on enum.name (#4448). [jwoutersymatra] Verilator 5.014 2023-08-06 diff --git a/src/V3Width.cpp b/src/V3Width.cpp index d5333b6f7..a279cf416 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -7203,6 +7203,7 @@ private: "__Venumtab_" + VString::downcase(attrType.ascii()) + cvtToStr(m_dtTables++), vardtypep}; + varp->lifetime(VLifetime::STATIC); varp->isConst(true); varp->isStatic(true); varp->valuep(initp); diff --git a/test_regress/t/t_fork_join_none_class_cap.v b/test_regress/t/t_fork_join_none_class_cap.v index 8f5fda807..36ba60f03 100644 --- a/test_regress/t/t_fork_join_none_class_cap.v +++ b/test_regress/t/t_fork_join_none_class_cap.v @@ -6,14 +6,17 @@ event evt1; +typedef enum {ENUM_VALUE} enum_t; + class Foo; int m_member; + enum_t m_en; task do_something(); fork #20 begin m_member++; - $display("this's m_member: ", m_member); + $display("this's m_member: %0d m_en: %s", m_member, m_en.name()); if (m_member != 3) $stop; ->evt1; @@ -29,7 +32,7 @@ class Foo; fork begin foo.m_member++; - $display("foo's m_member: %d", foo.m_member); + $display("foo's m_member: %0d m_en: %s", foo.m_member, foo.m_en.name()); if (foo.m_member != 2) $stop; end From 5e6519c1b08eedbc2ffdc88cc1378cb871622d55 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 30 Aug 2023 07:46:39 -0400 Subject: [PATCH 041/111] Commentary --- docs/guide/connecting.rst | 2 +- docs/spelling.txt | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/guide/connecting.rst b/docs/guide/connecting.rst index 2ef1b35bc..e66fb938d 100644 --- a/docs/guide/connecting.rst +++ b/docs/guide/connecting.rst @@ -162,7 +162,7 @@ after :code:`fork()`. With the process-level clone APIs, users can create process-level snapshots for the verilated models. While the Verilator save/restore option provides -persistent and circuit-independent snapshots, the process-level clone APIs +persistent and circuit-dependent snapshots, the process-level clone APIs enable in-memory, circuit-transparent, and highly efficient snapshots. diff --git a/docs/spelling.txt b/docs/spelling.txt index 49a5ed3b1..e05450bce 100644 --- a/docs/spelling.txt +++ b/docs/spelling.txt @@ -654,6 +654,7 @@ ish isunbounded isunknown jobserver +jwoutersymatra killua lang lcov @@ -931,7 +932,9 @@ vc vcd vcddiff vcoverage +vdhotre vec +ventana ver verFiles verible From 373265752f05568d1c195942a328e214e22bb3cb Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 30 Aug 2023 17:21:33 -0400 Subject: [PATCH 042/111] Fix display %x formatting of real. --- Changes | 1 + src/V3Width.cpp | 10 ++++++++++ .../{t_dict_ref_type.pl => t_assoc_ref_type.pl} | 0 .../t/{t_dict_ref_type.v => t_assoc_ref_type.v} | 0 test_regress/t/t_display.out | 1 + test_regress/t/t_display.v | 17 +++++++++++++++++ 6 files changed, 29 insertions(+) rename test_regress/t/{t_dict_ref_type.pl => t_assoc_ref_type.pl} (100%) rename test_regress/t/{t_dict_ref_type.v => t_assoc_ref_type.v} (100%) diff --git a/Changes b/Changes index d2707bbec..7dc8d7e66 100644 --- a/Changes +++ b/Changes @@ -30,6 +30,7 @@ Verilator 5.015 devel * Fix false MULTITOP on bound interfaces (#4438). [Alex Solomatnikov] * Fix internal error on real conversion (#4447). [vdhotre-ventana] * Fix lifetime unknown error on enum.name (#4448). [jwoutersymatra] +* Fix display %x formatting of real. Verilator 5.014 2023-08-06 diff --git a/src/V3Width.cpp b/src/V3Width.cpp index a279cf416..dbae4389d 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -4815,6 +4815,16 @@ private: } break; } + case 'b': // FALLTHRU + case 'o': // FALLTHRU + case 'x': { + if (argp) { + AstNodeExpr* const nextp = VN_AS(argp->nextp(), NodeExpr); + if (argp->isDouble()) spliceCvtS(argp, true, 64); + argp = nextp; + } + break; + } case 'p': { // Pattern const AstNodeDType* const dtypep = argp ? argp->dtypep()->skipRefp() : nullptr; const AstBasicDType* const basicp = dtypep ? dtypep->basicp() : nullptr; diff --git a/test_regress/t/t_dict_ref_type.pl b/test_regress/t/t_assoc_ref_type.pl similarity index 100% rename from test_regress/t/t_dict_ref_type.pl rename to test_regress/t/t_assoc_ref_type.pl diff --git a/test_regress/t/t_dict_ref_type.v b/test_regress/t/t_assoc_ref_type.v similarity index 100% rename from test_regress/t/t_dict_ref_type.v rename to test_regress/t/t_assoc_ref_type.v diff --git a/test_regress/t/t_display.out b/test_regress/t/t_display.out index 3a8033e7d..4d6c52c96 100644 --- a/test_regress/t/t_display.out +++ b/test_regress/t/t_display.out @@ -3,6 +3,7 @@ [0] In top.t.sub.write_m.subblock (sub) [0] In top.t.sub2.write_m (sub2) [0] In top.t.sub2.write_m.subblock2 (sub2) +a: -0.4=> 0.4 0 0 0 [0] Back \ Quote " [0] %b=000001100 %0b=1100 %b=00000101010111011101110111100110011001100 %0b=101010111011101110111100110011001100 %b=000001010101111000001001000110100010101100111100000010010001101000101011001111000 %0b=1010101111000001001000110100010101100111100000010010001101000101011001111000 [0] %B=000001100 %0B=1100 %B=00000101010111011101110111100110011001100 %0B=101010111011101110111100110011001100 %B=000001010101111000001001000110100010101100111100000010010001101000101011001111000 %0B=1010101111000001001000110100010101100111100000010010001101000101011001111000 diff --git a/test_regress/t/t_display.v b/test_regress/t/t_display.v index 24aa8f428..f04f26cb0 100644 --- a/test_regress/t/t_display.v +++ b/test_regress/t/t_display.v @@ -21,11 +21,13 @@ module t; sub sub (); sub2 sub2 (); + sub3 sub3 (); initial begin $write("[%0t] In %m: Hi\n", $time); sub.write_m; sub2.write_m; + sub3.write_m; // Escapes $display("[%0t] Back \\ Quote \"", $time); // Old bug when \" last on the line. @@ -229,3 +231,18 @@ module sub2; end endtask endmodule + +module sub3; + function real copyr(input real r); + copyr = r; + endfunction + + real a, d; + + task write_m; + a = 0.4; + // verilator lint_off REALCVT + $display("a: -0.4=> %.1f %0d %0x %0b", copyr(a), copyr(a), copyr(a), copyr(a)); + // verilator lint_on REALCVT + endtask +endmodule From 048c9f3fe2b0b5267f9d1445e4abf1db84c5c6f2 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 30 Aug 2023 17:31:11 -0400 Subject: [PATCH 043/111] Support extra commas before $display --- src/verilog.y | 75 +++++++++++++++++++----------------- test_regress/t/t_display.out | 1 + test_regress/t/t_display.v | 2 + 3 files changed, 43 insertions(+), 35 deletions(-) diff --git a/src/verilog.y b/src/verilog.y index 78f93d150..4e31cb1b0 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -4076,30 +4076,30 @@ system_t_call: // IEEE: system_tf_call (as task) | yD_SWRITEH '(' expr ',' exprDispList ')' { $$ = new AstSFormat{$1, $3, $5, 'h'}; } | yD_SWRITEO '(' expr ',' exprDispList ')' { $$ = new AstSFormat{$1, $3, $5, 'o'}; } // - | yD_DISPLAY parenE { $$ = new AstDisplay{$1, VDisplayType::DT_DISPLAY, nullptr, nullptr}; } - | yD_DISPLAY '(' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_DISPLAY, nullptr, $3}; } - | yD_DISPLAYB parenE { $$ = new AstDisplay{$1, VDisplayType::DT_DISPLAY, nullptr, nullptr, 'b'}; } - | yD_DISPLAYB '(' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_DISPLAY, nullptr, $3, 'b'}; } - | yD_DISPLAYH parenE { $$ = new AstDisplay{$1, VDisplayType::DT_DISPLAY, nullptr, nullptr, 'h'}; } - | yD_DISPLAYH '(' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_DISPLAY, nullptr, $3, 'h'}; } - | yD_DISPLAYO parenE { $$ = new AstDisplay{$1, VDisplayType::DT_DISPLAY, nullptr, nullptr, 'o'}; } - | yD_DISPLAYO '(' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_DISPLAY, nullptr, $3, 'o'}; } - | yD_MONITOR '(' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_MONITOR, nullptr, $3}; } - | yD_MONITORB '(' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_MONITOR, nullptr, $3, 'b'}; } - | yD_MONITORH '(' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_MONITOR, nullptr, $3, 'h'}; } - | yD_MONITORO '(' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_MONITOR, nullptr, $3, 'o'}; } - | yD_STROBE '(' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_STROBE, nullptr, $3}; } - | yD_STROBEB '(' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_STROBE, nullptr, $3, 'b'}; } - | yD_STROBEH '(' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_STROBE, nullptr, $3, 'h'}; } - | yD_STROBEO '(' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_STROBE, nullptr, $3, 'o'}; } - | yD_WRITE parenE { $$ = nullptr; } // NOP - | yD_WRITE '(' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_WRITE, nullptr, $3}; } - | yD_WRITEB parenE { $$ = nullptr; } // NOP - | yD_WRITEB '(' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_WRITE, nullptr, $3, 'b'}; } - | yD_WRITEH parenE { $$ = nullptr; } // NOP - | yD_WRITEH '(' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_WRITE, nullptr, $3, 'h'}; } - | yD_WRITEO parenE { $$ = nullptr; } // NOP - | yD_WRITEO '(' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_WRITE, nullptr, $3, 'o'}; } + | yD_DISPLAY parenE { $$ = new AstDisplay{$1, VDisplayType::DT_DISPLAY, nullptr, nullptr}; } + | yD_DISPLAY '(' commasE exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_DISPLAY, nullptr, $4}; } + | yD_DISPLAYB parenE { $$ = new AstDisplay{$1, VDisplayType::DT_DISPLAY, nullptr, nullptr, 'b'}; } + | yD_DISPLAYB '(' commasE exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_DISPLAY, nullptr, $4, 'b'}; } + | yD_DISPLAYH parenE { $$ = new AstDisplay{$1, VDisplayType::DT_DISPLAY, nullptr, nullptr, 'h'}; } + | yD_DISPLAYH '(' commasE exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_DISPLAY, nullptr, $4, 'h'}; } + | yD_DISPLAYO parenE { $$ = new AstDisplay{$1, VDisplayType::DT_DISPLAY, nullptr, nullptr, 'o'}; } + | yD_DISPLAYO '(' commasE exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_DISPLAY, nullptr, $4, 'o'}; } + | yD_MONITOR '(' commasE exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_MONITOR, nullptr, $4}; } + | yD_MONITORB '(' commasE exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_MONITOR, nullptr, $4, 'b'}; } + | yD_MONITORH '(' commasE exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_MONITOR, nullptr, $4, 'h'}; } + | yD_MONITORO '(' commasE exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_MONITOR, nullptr, $4, 'o'}; } + | yD_STROBE '(' commasE exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_STROBE, nullptr, $4}; } + | yD_STROBEB '(' commasE exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_STROBE, nullptr, $4, 'b'}; } + | yD_STROBEH '(' commasE exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_STROBE, nullptr, $4, 'h'}; } + | yD_STROBEO '(' commasE exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_STROBE, nullptr, $4, 'o'}; } + | yD_WRITE parenE { $$ = nullptr; } // NOP + | yD_WRITE '(' commasE exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_WRITE, nullptr, $4}; } + | yD_WRITEB parenE { $$ = nullptr; } // NOP + | yD_WRITEB '(' commasE exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_WRITE, nullptr, $4, 'b'}; } + | yD_WRITEH parenE { $$ = nullptr; } // NOP + | yD_WRITEH '(' commasE exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_WRITE, nullptr, $4, 'h'}; } + | yD_WRITEO parenE { $$ = nullptr; } // NOP + | yD_WRITEO '(' commasE exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_WRITE, nullptr, $4, 'o'}; } | yD_FDISPLAY '(' expr ')' { $$ = new AstDisplay{$1, VDisplayType::DT_DISPLAY, $3, nullptr}; } | yD_FDISPLAY '(' expr ',' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_DISPLAY, $3, $5}; } | yD_FDISPLAYB '(' expr ')' { $$ = new AstDisplay{$1, VDisplayType::DT_DISPLAY, $3, nullptr, 'b'}; } @@ -4108,10 +4108,10 @@ system_t_call: // IEEE: system_tf_call (as task) | yD_FDISPLAYH '(' expr ',' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_DISPLAY, $3, $5, 'h'}; } | yD_FDISPLAYO '(' expr ')' { $$ = new AstDisplay{$1, VDisplayType::DT_DISPLAY, $3, nullptr, 'o'}; } | yD_FDISPLAYO '(' expr ',' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_DISPLAY, $3, $5, 'o'}; } - | yD_FMONITOR '(' expr ',' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_MONITOR, $3, $5}; } - | yD_FMONITORB '(' expr ',' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_MONITOR, $3, $5, 'b'}; } - | yD_FMONITORH '(' expr ',' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_MONITOR, $3, $5, 'h'}; } - | yD_FMONITORO '(' expr ',' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_MONITOR, $3, $5, 'o'}; } + | yD_FMONITOR '(' expr ',' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_MONITOR, $3, $5}; } + | yD_FMONITORB '(' expr ',' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_MONITOR, $3, $5, 'b'}; } + | yD_FMONITORH '(' expr ',' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_MONITOR, $3, $5, 'h'}; } + | yD_FMONITORO '(' expr ',' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_MONITOR, $3, $5, 'o'}; } | yD_FSTROBE '(' expr ')' { $$ = new AstDisplay{$1, VDisplayType::DT_STROBE, $3, nullptr}; } | yD_FSTROBE '(' expr ',' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_STROBE, $3, $5}; } | yD_FSTROBEB '(' expr ',' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_STROBE, $3, $5, 'b'}; } @@ -4122,13 +4122,13 @@ system_t_call: // IEEE: system_tf_call (as task) | yD_FWRITEB '(' expr ',' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_WRITE, $3, $5, 'b'}; } | yD_FWRITEH '(' expr ',' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_WRITE, $3, $5, 'h'}; } | yD_FWRITEO '(' expr ',' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_WRITE, $3, $5, 'o'}; } - | yD_INFO parenE { $$ = new AstDisplay{$1, VDisplayType::DT_INFO, nullptr, nullptr}; } - | yD_INFO '(' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_INFO, nullptr, $3}; } - | yD_WARNING parenE { $$ = new AstDisplay{$1, VDisplayType::DT_WARNING, nullptr, nullptr}; } - | yD_WARNING '(' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_WARNING, nullptr, $3}; } - | yD_ERROR parenE { $$ = GRAMMARP->createDisplayError($1); } - | yD_ERROR '(' exprDispList ')' - { $$ = new AstDisplay{$1, VDisplayType::DT_ERROR, nullptr, $3}; + | yD_INFO parenE { $$ = new AstDisplay{$1, VDisplayType::DT_INFO, nullptr, nullptr}; } + | yD_INFO '(' commasE exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_INFO, nullptr, $4}; } + | yD_WARNING parenE { $$ = new AstDisplay{$1, VDisplayType::DT_WARNING, nullptr, nullptr}; } + | yD_WARNING '(' commasE exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_WARNING, nullptr, $4}; } + | yD_ERROR parenE { $$ = GRAMMARP->createDisplayError($1); } + | yD_ERROR '(' commasE exprDispList ')' + { $$ = new AstDisplay{$1, VDisplayType::DT_ERROR, nullptr, $4}; $$->addNext(new AstStop{$1, true}); } | yD_FATAL parenE { $$ = new AstDisplay{$1, VDisplayType::DT_FATAL, nullptr, nullptr}; @@ -5066,6 +5066,11 @@ vrdList: | vrdList ',' idClassSel { $$ = $1->addNext($3); } ; +commasE: + /* empty */ { } /* ignored */ + | ',' commasE { } /* ignored */ + ; + commaVRDListE: /* empty */ { $$ = nullptr; } | ',' vrdList { $$ = $2; } diff --git a/test_regress/t/t_display.out b/test_regress/t/t_display.out index 4d6c52c96..00db3a06d 100644 --- a/test_regress/t/t_display.out +++ b/test_regress/t/t_display.out @@ -93,4 +93,5 @@ XXX 1x5X X Z ZzX + 10 *-* All Finished *-* diff --git a/test_regress/t/t_display.v b/test_regress/t/t_display.v index f04f26cb0..ca2b59b21 100644 --- a/test_regress/t/t_display.v +++ b/test_regress/t/t_display.v @@ -204,6 +204,8 @@ multiline", $time); $display("%d", 32'b11111z111); $display("%h", 12'b1zz1_zzzz_1x1z); + $display(,, 10); // Strange but legal + $write("*-* All Finished *-*\n"); $finish; end From 6d5dde86456635d7b10a9fab35eed57a04b6c7e6 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 30 Aug 2023 17:59:25 -0400 Subject: [PATCH 044/111] Fix duplicate Vfork functions (#4418) --- src/V3Broken.cpp | 6 +-- src/V3SchedTiming.cpp | 5 +- test_regress/t/t_timing_debug1.out | 74 +++++++++++++++--------------- test_regress/t/t_timing_debug2.out | 16 +++---- 4 files changed, 50 insertions(+), 51 deletions(-) diff --git a/src/V3Broken.cpp b/src/V3Broken.cpp index 961d243ec..54e761246 100644 --- a/src/V3Broken.cpp +++ b/src/V3Broken.cpp @@ -284,10 +284,8 @@ private: // Check for duplicate names, otherwise linker might just ignore them string nameArgs = nodep->name(); if (!nodep->argTypes().empty()) nameArgs += "(" + nodep->argTypes() + ")"; - if (false) { // bug4418 - UASSERT_OBJ(m_cFuncNames.emplace(nameArgs).second, nodep, - "Duplicate cfunc name: '" << nameArgs << "'"); - } + UASSERT_OBJ(m_cFuncNames.emplace(nameArgs).second, nodep, + "Duplicate cfunc name: '" << nameArgs << "'"); processAndIterate(nodep); diff --git a/src/V3SchedTiming.cpp b/src/V3SchedTiming.cpp index f52870299..ca7e45626 100644 --- a/src/V3SchedTiming.cpp +++ b/src/V3SchedTiming.cpp @@ -362,8 +362,9 @@ void transformForks(AstNetlist* const netlistp) { UASSERT_OBJ(!nodep->name().empty(), nodep, "Begin needs a name"); // Create a function to put this begin's statements in FileLine* const flp = nodep->fileline(); - AstCFunc* const newfuncp - = new AstCFunc{flp, nodep->name(), m_funcp->scopep(), "VlCoroutine"}; + AstCFunc* const newfuncp = new AstCFunc{ + flp, m_funcp->name() + "__" + nodep->name(), m_funcp->scopep(), "VlCoroutine"}; + m_funcp->addNextHere(newfuncp); newfuncp->isLoose(m_funcp->isLoose()); newfuncp->slow(m_funcp->slow()); diff --git a/test_regress/t/t_timing_debug1.out b/test_regress/t/t_timing_debug1.out index 2740c8bd0..337319d92 100644 --- a/test_regress/t/t_timing_debug1.out +++ b/test_regress/t/t_timing_debug1.out @@ -26,9 +26,9 @@ -V{t#,#}+ Vt_timing_debug1___024root___stl_sequent__TOP__2 -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__2 -V{t#,#}+ Vt_timing_debug1___024root___stl_comb__TOP__1 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___stl_comb__TOP__2 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_2__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__1____Vfork_2__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__stl -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__stl -V{t#,#} No triggers active @@ -49,9 +49,9 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__1 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_2__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__1____Vfork_2__0 -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__2 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act @@ -91,7 +91,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) @@ -150,7 +150,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} No triggers active @@ -222,7 +222,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) @@ -276,7 +276,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__1 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_2__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__1____Vfork_2__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 5 is active: @(posedge t.clk2) @@ -344,7 +344,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} No triggers active @@ -414,7 +414,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) @@ -472,7 +472,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} No triggers active @@ -542,7 +542,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) @@ -594,7 +594,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__1 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_2__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__1____Vfork_2__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} No triggers active @@ -632,7 +632,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} No triggers active @@ -702,7 +702,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) @@ -754,7 +754,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} No triggers active @@ -826,9 +826,9 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__1 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_2__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__1____Vfork_2__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) @@ -932,7 +932,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} No triggers active @@ -1002,7 +1002,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) @@ -1060,7 +1060,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} No triggers active @@ -1130,7 +1130,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__1 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_2__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__1____Vfork_2__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} No triggers active @@ -1167,7 +1167,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) @@ -1219,7 +1219,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} No triggers active @@ -1289,7 +1289,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) @@ -1341,7 +1341,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} No triggers active @@ -1383,7 +1383,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__1 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_2__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__1____Vfork_2__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 5 is active: @(posedge t.clk2) @@ -1478,7 +1478,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) @@ -1536,7 +1536,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} No triggers active @@ -1606,7 +1606,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) @@ -1660,9 +1660,9 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__1 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_2__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__1____Vfork_2__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} No triggers active @@ -1732,7 +1732,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) @@ -1784,7 +1784,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} No triggers active @@ -1854,7 +1854,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) @@ -1906,7 +1906,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__1 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_2__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__1____Vfork_2__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 5 is active: @(posedge t.clk2) @@ -1976,7 +1976,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} No triggers active diff --git a/test_regress/t/t_timing_debug2.out b/test_regress/t/t_timing_debug2.out index 4bf0ad4c3..6698864f4 100644 --- a/test_regress/t/t_timing_debug2.out +++ b/test_regress/t/t_timing_debug2.out @@ -68,10 +68,10 @@ -V{t#,#}+ Vt_timing_debug2_t__03a__03aForkClass::new -V{t#,#}+ Vt_timing_debug2_t__03a__03aForkClass::_ctor_var_reset -V{t#,#}+ Vt_timing_debug2_t__03a__03aForkClass::__VnoInFunc_do_fork --V{t#,#}+ Vt_timing_debug2_t__03a__03aForkClass::__Vfork_1__0 --V{t#,#}+ Vt_timing_debug2_t__03a__03aForkClass::__Vfork_1__1 --V{t#,#}+ Vt_timing_debug2_t__03a__03aForkClass::__Vfork_2__0 --V{t#,#}+ Vt_timing_debug2_t__03a__03aForkClass::__Vfork_2__1 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aForkClass::__VnoInFunc_do_fork____Vfork_1__0 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aForkClass::__VnoInFunc_do_fork____Vfork_1__1 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aForkClass::__VnoInFunc_do_fork____Vfork_1__1____Vfork_2__0 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aForkClass::__VnoInFunc_do_fork____Vfork_1__1____Vfork_2__1 -V{t#,#} Awaiting join of fork at: t/t_timing_class.v:250 -V{t#,#} Awaiting join of fork at: t/t_timing_class.v:245 -V{t#,#}+ Vt_timing_debug2_t___eval_initial__TOP__t__8 @@ -892,9 +892,9 @@ -V{t#,#} - Process waiting at t/t_timing_class.v:58 -V{t#,#} Resuming: Process waiting at t/t_timing_class.v:58 -V{t#,#}+ Vt_timing_debug2_t__03a__03aLocalWaitClass::__VnoInFunc_await --V{t#,#}+ Vt_timing_debug2_t__03a__03aLocalWaitClass::__Vfork_1__0 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aLocalWaitClass::__VnoInFunc_await____Vfork_1__0 -V{t#,#} Suspending process waiting for @([true] ((32'sh2a == t::LocalWaitClass.a) | (32'sh64 != t::LocalWaitClass.b))) at t/t_timing_class.v:75 --V{t#,#}+ Vt_timing_debug2_t__03a__03aLocalWaitClass::__Vfork_1__1 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aLocalWaitClass::__VnoInFunc_await____Vfork_1__1 -V{t#,#} Awaiting join of fork at: t/t_timing_class.v:74 -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act @@ -993,7 +993,7 @@ -V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay40::__VnoInFunc_do_sth_else -V{t#,#}+ Vt_timing_debug2_t__03a__03aNoDelay::__VnoInFunc_do_delay -V{t#,#}+ Vt_timing_debug2_t__03a__03aNoDelay::__VnoInFunc_do_sth_else --V{t#,#}+ Vt_timing_debug2_t____Vfork_1__0 +-V{t#,#}+ Vt_timing_debug2_t___eval_initial__TOP__t__6____Vfork_1__0 -V{t#,#}+ Vt_timing_debug2_t__03a__03aAssignDelayClass::__VnoInFunc_do_assign -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act @@ -1078,7 +1078,7 @@ -V{t#,#} Resuming delayed processes -V{t#,#} Resuming: Process waiting at t/t_timing_class.v:136 -V{t#,#} Resuming: Process waiting at t/t_timing_class.v:190 --V{t#,#}+ Vt_timing_debug2_t____Vfork_2__0 +-V{t#,#}+ Vt_timing_debug2_t___eval_initial__TOP__t__6____Vfork_2__0 -V{t#,#}+ Vt_timing_debug2_t__03a__03aAssignDelayClass::__VnoInFunc_do_assign -V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 -V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip From 3d2399ea0fd7af1232a985448e8b72648571bc11 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 30 Aug 2023 18:10:30 -0400 Subject: [PATCH 045/111] Tests: Enable fixed-earlier (#2314) --- test_regress/t/t_dynarray_unpacked.v | 2 -- 1 file changed, 2 deletions(-) diff --git a/test_regress/t/t_dynarray_unpacked.v b/test_regress/t/t_dynarray_unpacked.v index 530a6cbc3..b5fe7d411 100644 --- a/test_regress/t/t_dynarray_unpacked.v +++ b/test_regress/t/t_dynarray_unpacked.v @@ -17,14 +17,12 @@ module t (/*AUTOARG*/); dyn[0] = '{101, 100}; dyn[1] = '{111, 110}; dyn[2] = '{121, 120}; -`ifndef verilator // bug2314 `checkh(dyn[0][0], 100); `checkh(dyn[0][1], 101); `checkh(dyn[1][0], 110); `checkh(dyn[1][1], 111); `checkh(dyn[2][0], 120); `checkh(dyn[2][1], 121); -`endif end $write("*-* All Finished *-*\n"); From 96ee81fa3f6d527fd4d158fb835515e7b8ceb019 Mon Sep 17 00:00:00 2001 From: Anthony Donlon <4056887+donlon@users.noreply.github.com> Date: Fri, 1 Sep 2023 01:42:37 +0800 Subject: [PATCH 046/111] Fix unstable output of VHashSha256 (#4453) --- src/V3String.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/V3String.cpp b/src/V3String.cpp index 9c1365c60..5ed5279e1 100644 --- a/src/V3String.cpp +++ b/src/V3String.cpp @@ -237,9 +237,8 @@ static void sha256Block(uint32_t* h, const uint32_t* chunk) VL_PURE { // Initialize working variables to current hash value for (unsigned i = 0; i < 8; i++) ah[i] = h[i]; // Compression function main loop + uint32_t w[16] = {}; for (unsigned i = 0; i < 4; ++i) { - uint32_t w[16]; - for (unsigned j = 0; j < 16; ++j) { if (i == 0) { w[j] = *p++; From ffbbd438aef65b34e6cb0dc004158d5c3f9ef94f Mon Sep 17 00:00:00 2001 From: Krzysztof Bieganski Date: Fri, 1 Sep 2023 00:00:53 +0200 Subject: [PATCH 047/111] Internals: Use runtime type info instead of `dynamic_cast` for faster graph type checks (#4397) --- src/V3Active.cpp | 1 + src/V3Gate.cpp | 20 +++--- src/V3Graph.h | 70 +++++++++++++++++++++ src/V3GraphAcyc.cpp | 2 + src/V3GraphTest.cpp | 1 + src/V3LifePost.cpp | 2 +- src/V3LinkCells.cpp | 6 +- src/V3Order.cpp | 26 ++++---- src/V3OrderGraph.h | 8 +++ src/V3OrderMoveGraph.h | 2 + src/V3Partition.cpp | 47 +++++++------- src/V3PartitionGraph.h | 3 + src/V3Rtti.h | 131 +++++++++++++++++++++++++++++++++++++++ src/V3SchedAcyclic.cpp | 68 +++++++++++--------- src/V3SchedPartition.cpp | 11 ++-- src/V3SchedReplicate.cpp | 43 +++++++------ src/V3Split.cpp | 42 ++++++++----- src/V3TSP.cpp | 1 + src/V3Task.cpp | 1 + src/V3Timing.cpp | 3 + src/V3Trace.cpp | 38 ++++++------ src/V3Tristate.cpp | 7 ++- 22 files changed, 390 insertions(+), 143 deletions(-) create mode 100644 src/V3Rtti.h diff --git a/src/V3Active.cpp b/src/V3Active.cpp index fc40166c0..54b110d00 100644 --- a/src/V3Active.cpp +++ b/src/V3Active.cpp @@ -47,6 +47,7 @@ VL_DEFINE_DEBUG_FUNCTIONS; // Extend V3GraphVertex class for use in latch detection graph class LatchDetectGraphVertex final : public V3GraphVertex { + VL_RTTI_IMPL(LatchDetectGraphVertex, V3GraphVertex) public: enum VertexType : uint8_t { VT_BLOCK, VT_BRANCH, VT_OUTPUT }; diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index e1a9375a4..e99c1561f 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -65,6 +65,7 @@ public: // Support classes class GateEitherVertex VL_NOT_FINAL : public V3GraphVertex { + VL_RTTI_IMPL(GateEitherVertex, V3GraphVertex) AstScope* const m_scopep; // Scope vertex refers to bool m_reducible = true; // True if this node should be able to be eliminated bool m_dedupable = true; // True if this node should be able to be deduped @@ -122,6 +123,7 @@ public: }; class GateVarVertex final : public GateEitherVertex { + VL_RTTI_IMPL(GateVarVertex, GateEitherVertex) AstVarScope* const m_varScp; bool m_isTop = false; bool m_isClock = false; @@ -164,6 +166,7 @@ public: }; class GateLogicVertex final : public GateEitherVertex { + VL_RTTI_IMPL(GateLogicVertex, GateEitherVertex) AstNode* const m_nodep; AstActive* const m_activep; // Under what active; nullptr is ok (under cfunc or such) const bool m_slow; // In slow block @@ -568,7 +571,7 @@ public: void GateVisitor::optimizeSignals(bool allowMultiIn) { for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { - GateVarVertex* const vvertexp = dynamic_cast(itp); + GateVarVertex* const vvertexp = itp->cast(); // Consider "inlining" variables if (!vvertexp) continue; @@ -710,7 +713,7 @@ void GateVisitor::consumedMove() { // We need the "usually" block logic to do a better job at this for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) { - if (const GateVarVertex* const vvertexp = dynamic_cast(vertexp)) { + if (const GateVarVertex* const vvertexp = vertexp->cast()) { if (!vvertexp->consumed() && !vvertexp->user()) { UINFO(8, "Unconsumed " << vvertexp->varScp() << endl); } @@ -734,7 +737,7 @@ void GateVisitor::consumedMove() { void GateVisitor::warnSignals() { AstNode::user2ClearTree(); for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { - if (const GateVarVertex* const vvertexp = dynamic_cast(itp)) { + if (const GateVarVertex* const vvertexp = itp->cast()) { const AstVarScope* const vscp = vvertexp->varScp(); const AstNode* const sp = vvertexp->rstSyncNodep(); const AstNode* const ap = vvertexp->rstAsyncNodep(); @@ -1136,14 +1139,14 @@ void GateVisitor::dedupe() { // Traverse starting from each of the clocks UINFO(9, "Gate dedupe() clocks:\n"); for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { - if (GateVarVertex* const vvertexp = dynamic_cast(itp)) { + if (GateVarVertex* const vvertexp = itp->cast()) { if (vvertexp->isClock()) deduper.dedupeTree(vvertexp); } } // Traverse starting from each of the outputs UINFO(9, "Gate dedupe() outputs:\n"); for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { - if (GateVarVertex* const vvertexp = dynamic_cast(itp)) { + if (GateVarVertex* const vvertexp = itp->cast()) { if (vvertexp->isTop() && vvertexp->varScp()->varp()->isWritable()) { deduper.dedupeTree(vvertexp); } @@ -1187,8 +1190,7 @@ private: for (V3GraphEdge* edgep = vvertexp->inBeginp(); edgep;) { V3GraphEdge* oldedgep = edgep; edgep = edgep->inNextp(); // for recursive since the edge could be deleted - if (GateLogicVertex* const lvertexp - = dynamic_cast(oldedgep->fromp())) { + if (GateLogicVertex* const lvertexp = oldedgep->fromp()->cast()) { if (AstNodeAssign* const assignp = VN_CAST(lvertexp->nodep(), NodeAssign)) { // if (lvertexp->outSize1() && VN_IS(assignp->lhsp(), Sel)) { if (VN_IS(assignp->lhsp(), Sel) && lvertexp->outSize1()) { @@ -1274,7 +1276,7 @@ void GateVisitor::mergeAssigns() { UINFO(6, "mergeAssigns\n"); GateMergeAssignsGraphVisitor merger{&m_graph}; for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { - if (GateVarVertex* const vvertexp = dynamic_cast(itp)) { + if (GateVarVertex* const vvertexp = itp->cast()) { merger.mergeAssignsTree(vvertexp); } } @@ -1460,7 +1462,7 @@ void GateVisitor::decomposeClkVectors() { AstNode::user2ClearTree(); GateClkDecompGraphVisitor decomposer{&m_graph}; for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { - if (GateVarVertex* const vertp = dynamic_cast(itp)) { + if (GateVarVertex* const vertp = itp->cast()) { const AstVarScope* const vsp = vertp->varScp(); if (vsp->varp()->attrClocker() == VVarAttrClocker::CLOCKER_YES) { if (vsp->varp()->width() > 1) { diff --git a/src/V3Graph.h b/src/V3Graph.h index a0482b4e3..2d277826c 100644 --- a/src/V3Graph.h +++ b/src/V3Graph.h @@ -22,6 +22,7 @@ #include "V3Error.h" #include "V3List.h" +#include "V3Rtti.h" #include @@ -173,6 +174,7 @@ public: //============================================================================ class V3GraphVertex VL_NOT_FINAL { + VL_RTTI_IMPL_BASE(V3GraphVertex) // Vertices may be a 'gate'/wire statement OR a variable protected: friend class V3Graph; @@ -209,6 +211,40 @@ public: void unlinkEdges(V3Graph* graphp); void unlinkDelete(V3Graph* graphp); + // METHODS + // Return true iff of type T + template + bool is() const { + static_assert(std::is_base_of::value, + "'T' must be a subtype of V3GraphVertex"); + static_assert(std::is_same::type, + VTypeListFront>::value, + "Missing VL_RTTI_IMPL(...) call in 'T'"); + return this->isInstanceOfClassWithId(T::rttiClassId()); + } + + // Return cast to subtype T and assert of that type + template + T* as() { + UASSERT_OBJ(is(), this, "V3GraphVertex is not of expected type"); + return static_cast(this); + } + template + const T* as() const { + UASSERT_OBJ(is(), this, "V3GraphVertex is not of expected type"); + return static_cast(this); + } + + // Return cast to subtype T, else nullptr if different type + template + T* cast() { + return is() ? static_cast(this) : nullptr; + } + template + const T* cast() const { + return is() ? static_cast(this) : nullptr; + } + // ACCESSORS virtual string name() const { return ""; } virtual string dotColor() const { return "black"; } @@ -262,6 +298,7 @@ std::ostream& operator<<(std::ostream& os, V3GraphVertex* vertexp); //============================================================================ class V3GraphEdge VL_NOT_FINAL { + VL_RTTI_IMPL_BASE(V3GraphEdge) // Wires/variables aren't edges. Edges have only a single to/from vertex public: // ENUMS @@ -308,6 +345,39 @@ public: } virtual ~V3GraphEdge() = default; // METHODS + // Return true iff of type T + template + bool is() const { + static_assert(std::is_base_of::value, + "'T' must be a subtype of V3GraphEdge"); + static_assert(std::is_same::type, + VTypeListFront>::value, + "Missing VL_RTTI_IMPL(...) call in 'T'"); + return this->isInstanceOfClassWithId(T::rttiClassId()); + } + + // Return cast to subtype T and assert of that type + template + T* as() { + UASSERT(is(), "V3GraphEdge is not of expected type"); + return static_cast(this); + } + template + const T* as() const { + UASSERT(is(), "V3GraphEdge is not of expected type"); + return static_cast(this); + } + + // Return cast to subtype T, else nullptr if different type + template + T* cast() { + return is() ? static_cast(this) : nullptr; + } + template + const T* cast() const { + return is() ? static_cast(this) : nullptr; + } + virtual string name() const { return m_fromp->name() + "->" + m_top->name(); } virtual string dotLabel() const { return ""; } virtual string dotColor() const { return cutable() ? "yellowGreen" : "red"; } diff --git a/src/V3GraphAcyc.cpp b/src/V3GraphAcyc.cpp index ddae8c48b..4b15ca3dd 100644 --- a/src/V3GraphAcyc.cpp +++ b/src/V3GraphAcyc.cpp @@ -32,6 +32,7 @@ VL_DEFINE_DEBUG_FUNCTIONS; // Break the minimal number of backward edges to make the graph acyclic class GraphAcycVertex final : public V3GraphVertex { + VL_RTTI_IMPL(GraphAcycVertex, V3GraphVertex) // user() is used for various sub-algorithm pieces V3GraphVertex* const m_origVertexp; // Pointer to first vertex this represents protected: @@ -56,6 +57,7 @@ public: //-------------------------------------------------------------------- class GraphAcycEdge final : public V3GraphEdge { + VL_RTTI_IMPL(GraphAcycEdge, V3GraphEdge) // userp() is always used to point to the head original graph edge private: using OrigEdgeList = std::list; // List of orig edges, see also GraphAcyc's decl diff --git a/src/V3GraphTest.cpp b/src/V3GraphTest.cpp index 93ed93b89..0550e73c1 100644 --- a/src/V3GraphTest.cpp +++ b/src/V3GraphTest.cpp @@ -52,6 +52,7 @@ public: // Vertices and nodes class V3GraphTestVertex VL_NOT_FINAL : public V3GraphVertex { + VL_RTTI_IMPL(V3GraphTestVertex, V3GraphVertex) const string m_name; public: diff --git a/src/V3LifePost.cpp b/src/V3LifePost.cpp index 56121b68e..f62882369 100644 --- a/src/V3LifePost.cpp +++ b/src/V3LifePost.cpp @@ -333,7 +333,7 @@ private: } for (V3GraphVertex* mtaskVxp = nodep->depGraphp()->verticesBeginp(); mtaskVxp; mtaskVxp = mtaskVxp->verticesNextp()) { - const ExecMTask* const mtaskp = dynamic_cast(mtaskVxp); + const ExecMTask* const mtaskp = mtaskVxp->as(); m_execMTaskp = mtaskp; m_sequence = 0; iterate(mtaskp->bodyp()); diff --git a/src/V3LinkCells.cpp b/src/V3LinkCells.cpp index d44ae8361..6087999b3 100644 --- a/src/V3LinkCells.cpp +++ b/src/V3LinkCells.cpp @@ -52,6 +52,7 @@ public: }; class LinkCellsVertex final : public V3GraphVertex { + VL_RTTI_IMPL(LinkCellsVertex, V3GraphVertex) AstNodeModule* const m_modp; public: @@ -69,6 +70,7 @@ public: }; class LibraryVertex final : public V3GraphVertex { + VL_RTTI_IMPL(LibraryVertex, V3GraphVertex) public: explicit LibraryVertex(V3Graph* graphp) : V3GraphVertex{graphp} {} @@ -77,7 +79,7 @@ public: }; void LinkCellsGraph::loopsMessageCb(V3GraphVertex* vertexp) { - if (const LinkCellsVertex* const vvertexp = dynamic_cast(vertexp)) { + if (const LinkCellsVertex* const vvertexp = vertexp->cast()) { vvertexp->modp()->v3warn(E_UNSUPPORTED, "Unsupported: Recursive multiple modules (module instantiates " "something leading back to itself): " @@ -171,7 +173,7 @@ private: if (dumpGraphLevel()) m_graph.dumpDotFilePrefixed("linkcells"); m_graph.rank(); for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { - if (const LinkCellsVertex* const vvertexp = dynamic_cast(itp)) { + if (const LinkCellsVertex* const vvertexp = itp->cast()) { // +1 so we leave level 1 for the new wrapper we'll make in a moment AstNodeModule* const modp = vvertexp->modp(); modp->level(vvertexp->rank() + 1); diff --git a/src/V3Order.cpp b/src/V3Order.cpp index ae0365019..066d5d5b4 100644 --- a/src/V3Order.cpp +++ b/src/V3Order.cpp @@ -597,7 +597,7 @@ public: // For each logic vertex, make a T_MoveVertex, for each variable vertex, allocate storage for (V3GraphVertex* itp = m_graphp->verticesBeginp(); itp; itp = itp->verticesNextp()) { - if (OrderLogicVertex* const lvtxp = dynamic_cast(itp)) { + if (OrderLogicVertex* const lvtxp = itp->cast()) { lvtxp->userp(m_vxMakerp->makeVertexp(lvtxp, nullptr, lvtxp->domainp())); } else { // This is an OrderVarVertex @@ -607,7 +607,7 @@ public: } // Build edges between logic vertices for (V3GraphVertex* itp = m_graphp->verticesBeginp(); itp; itp = itp->verticesNextp()) { - if (OrderLogicVertex* const lvtxp = dynamic_cast(itp)) { + if (OrderLogicVertex* const lvtxp = itp->cast()) { iterateLogicVertex(lvtxp); } } @@ -941,8 +941,8 @@ void OrderMoveDomScope::movedVertex(OrderProcess* opp, OrderMoveVertex* vertexp) void OrderProcess::processDomains() { for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { - OrderEitherVertex* const vertexp = dynamic_cast(itp); - UASSERT(vertexp, "Null or vertex not derived from EitherVertex"); + UASSERT(itp, "Vertex should not be null"); + OrderEitherVertex* const vertexp = itp->as(); processDomainsIterate(vertexp); } } @@ -958,7 +958,7 @@ void OrderProcess::processDomainsIterate(OrderEitherVertex* vertexp) { UINFO(5, " pdi: " << vertexp << endl); AstSenTree* domainp = nullptr; - if (OrderLogicVertex* const lvtxp = dynamic_cast(vertexp)) { + if (OrderLogicVertex* const lvtxp = vertexp->cast()) { domainp = lvtxp->hybridp(); } @@ -970,7 +970,7 @@ void OrderProcess::processDomainsIterate(OrderEitherVertex* vertexp) { AstSenTree* fromDomainp = fromVertexp->domainp(); UASSERT(!fromDomainp->hasCombo(), "There should be no need for combinational domains"); - if (OrderVarVertex* const varVtxp = dynamic_cast(fromVertexp)) { + if (OrderVarVertex* const varVtxp = fromVertexp->cast()) { AstVarScope* const vscp = varVtxp->vscp(); // Add in any external domains externalDomainps.clear(); @@ -1023,13 +1023,13 @@ void OrderProcess::processEdgeReport() { for (const auto& pair : m_trigToSen) trigToSen.emplace(*pair.first, pair.second); for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { - if (OrderVarVertex* const vvertexp = dynamic_cast(itp)) { + if (OrderVarVertex* const vvertexp = itp->cast()) { string name(vvertexp->vscp()->prettyName()); - if (dynamic_cast(itp)) { + if (itp->is()) { name += " {PRE}"; - } else if (dynamic_cast(itp)) { + } else if (itp->is()) { name += " {POST}"; - } else if (dynamic_cast(itp)) { + } else if (itp->is()) { name += " {PORD}"; } std::ostringstream os; @@ -1335,8 +1335,7 @@ void OrderProcess::processMTasks() { // information in V3EmitC when we lay out var's in memory. const OrderLogicVertex* const logicp = movep->logicp(); for (const V3GraphEdge* edgep = logicp->inBeginp(); edgep; edgep = edgep->inNextp()) { - const OrderVarVertex* const pre_varp - = dynamic_cast(edgep->fromp()); + const OrderVarVertex* const pre_varp = edgep->fromp()->cast(); if (!pre_varp) continue; AstVar* const varp = pre_varp->vscp()->varp(); // varp depends on logicp, so logicp produces varp, @@ -1344,8 +1343,7 @@ void OrderProcess::processMTasks() { varp->addProducingMTaskId(mtaskId); } for (const V3GraphEdge* edgep = logicp->outBeginp(); edgep; edgep = edgep->outNextp()) { - const OrderVarVertex* const post_varp - = dynamic_cast(edgep->top()); + const OrderVarVertex* const post_varp = edgep->top()->cast(); if (!post_varp) continue; AstVar* const varp = post_varp->vscp()->varp(); varp->addConsumingMTaskId(mtaskId); diff --git a/src/V3OrderGraph.h b/src/V3OrderGraph.h index d51a540a0..af6788d6e 100644 --- a/src/V3OrderGraph.h +++ b/src/V3OrderGraph.h @@ -102,6 +102,7 @@ public: // Vertex types class OrderEitherVertex VL_NOT_FINAL : public V3GraphVertex { + VL_RTTI_IMPL(OrderEitherVertex, V3GraphVertex) // Event domain of vertex. For OrderLogicVertex this represents the conditions when the logic // block must be executed. For OrderVarVertex, this is the union of the domains of all the // OrderLogicVertex vertices that drive the variable. If initially set to nullptr (e.g.: all @@ -133,6 +134,7 @@ public: }; class OrderLogicVertex final : public OrderEitherVertex { + VL_RTTI_IMPL(OrderLogicVertex, OrderEitherVertex) AstNode* const m_nodep; // The logic this vertex represents AstScope* const m_scopep; // Scope the logic is under AstSenTree* const m_hybridp; // Additional sensitivities for hybrid combinational logic @@ -167,6 +169,7 @@ public: }; class OrderVarVertex VL_NOT_FINAL : public OrderEitherVertex { + VL_RTTI_IMPL(OrderVarVertex, OrderEitherVertex) AstVarScope* const m_vscp; public: @@ -189,6 +192,7 @@ public: }; class OrderVarStdVertex final : public OrderVarVertex { + VL_RTTI_IMPL(OrderVarStdVertex, OrderVarVertex) public: // CONSTRUCTOR OrderVarStdVertex(OrderGraph* graphp, AstVarScope* vscp) @@ -205,6 +209,7 @@ public: }; class OrderVarPreVertex final : public OrderVarVertex { + VL_RTTI_IMPL(OrderVarPreVertex, OrderVarVertex) public: // CONSTRUCTOR OrderVarPreVertex(OrderGraph* graphp, AstVarScope* vscp) @@ -221,6 +226,7 @@ public: }; class OrderVarPostVertex final : public OrderVarVertex { + VL_RTTI_IMPL(OrderVarPostVertex, OrderVarVertex) public: // CONSTRUCTOR OrderVarPostVertex(OrderGraph* graphp, AstVarScope* vscp) @@ -237,6 +243,7 @@ public: }; class OrderVarPordVertex final : public OrderVarVertex { + VL_RTTI_IMPL(OrderVarPordVertex, OrderVarVertex) public: // CONSTRUCTOR OrderVarPordVertex(OrderGraph* graphp, AstVarScope* vscp) @@ -256,6 +263,7 @@ public: // Edge type class OrderEdge final : public V3GraphEdge { + VL_RTTI_IMPL(OrderEdge, V3GraphEdge) friend class OrderGraph; // Only the OrderGraph can create these // CONSTRUCTOR OrderEdge(OrderGraph* graphp, OrderEitherVertex* fromp, OrderEitherVertex* top, int weight, diff --git a/src/V3OrderMoveGraph.h b/src/V3OrderMoveGraph.h index fb54ac7a0..af5da4df0 100644 --- a/src/V3OrderMoveGraph.h +++ b/src/V3OrderMoveGraph.h @@ -33,6 +33,7 @@ class OrderMoveDomScope; class OrderMoveVertex final : public V3GraphVertex { + VL_RTTI_IMPL(OrderMoveVertex, V3GraphVertex) enum OrderMState : uint8_t { POM_WAIT, POM_READY, POM_MOVED }; OrderLogicVertex* const m_logicp; @@ -92,6 +93,7 @@ public: // Similar to OrderMoveVertex, but modified for threaded code generation. class MTaskMoveVertex final : public V3GraphVertex { + VL_RTTI_IMPL(MTaskMoveVertex, V3GraphVertex) // This could be more compact, since we know m_varp and m_logicp // cannot both be set. Each MTaskMoveVertex represents a logic node // or a var node, it can't be both. diff --git a/src/V3Partition.cpp b/src/V3Partition.cpp index 4eeb0d6a2..ebc271a71 100644 --- a/src/V3Partition.cpp +++ b/src/V3Partition.cpp @@ -448,10 +448,10 @@ private: public: // METHODS - SiblingMC* toSiblingMC(); // Instead of dynamic_cast - const SiblingMC* toSiblingMC() const; // Instead of dynamic_cast - MTaskEdge* toMTaskEdge(); // Instead of dynamic_cast - const MTaskEdge* toMTaskEdge() const; // Instead of dynamic_cast + SiblingMC* toSiblingMC(); // Instead of cast<>/as<> + const SiblingMC* toSiblingMC() const; // Instead of cast<>/as<> + MTaskEdge* toMTaskEdge(); // Instead of cast<>/as<> + const MTaskEdge* toMTaskEdge() const; // Instead of cast<>/as<> bool mergeWouldCreateCycle() const; // Instead of virtual method inline void rescore(); @@ -511,6 +511,7 @@ static_assert(!std::is_polymorphic::value, "Should not have a vtable" // GraphEdge for the MTask graph class MTaskEdge final : public V3GraphEdge, public MergeCandidate { + VL_RTTI_IMPL(MTaskEdge, V3GraphEdge) friend class LogicMTask; template friend class PartPropagateCp; @@ -806,7 +807,7 @@ public: UINFO(0, " Parallelism factor = " << parallelismFactor() << endl); } static uint32_t vertexCost(const V3GraphVertex* vertexp) { - return dynamic_cast(vertexp)->cost(); + return vertexp->as()->cost(); } private: @@ -857,7 +858,7 @@ static void partInitCriticalPaths(V3Graph* mtasksp) { // They would have been all zeroes on initial creation of the MTaskEdges. for (V3GraphVertex* vxp = mtasksp->verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { for (V3GraphEdge* edgep = vxp->outBeginp(); edgep; edgep = edgep->outNextp()) { - MTaskEdge* const mtedgep = dynamic_cast(edgep); + MTaskEdge* const mtedgep = edgep->as(); mtedgep->resetCriticalPaths(); } } @@ -1966,7 +1967,7 @@ private: void findAdjacentTasks(const OrderVarStdVertex* varVtxp, TasksByRank& tasksByRank) { // Find all writer tasks for this variable, group by rank. for (V3GraphEdge* edgep = varVtxp->inBeginp(); edgep; edgep = edgep->inNextp()) { - if (const auto* const logicVtxp = dynamic_cast(edgep->fromp())) { + if (const auto* const logicVtxp = edgep->fromp()->cast()) { LogicMTask* const writerMtaskp = static_cast(logicVtxp->userp()); tasksByRank[writerMtaskp->rank()].insert(writerMtaskp); } @@ -2058,7 +2059,7 @@ public: nextp = vtxp->verticesNextp(); // Only consider OrderVarStdVertex which reflects // an actual lvalue assignment; the others do not. - if (const OrderVarStdVertex* const vvtxp = dynamic_cast(vtxp)) { + if (const OrderVarStdVertex* const vvtxp = vtxp->cast()) { if (vvtxp->vscp()->varp()->isSc()) { systemCVars.push_back(vvtxp); } else { @@ -2203,7 +2204,7 @@ public: const uint32_t thisThreadId = threadId(mtaskp); uint32_t result = 0; for (V3GraphEdge* edgep = mtaskp->inBeginp(); edgep; edgep = edgep->inNextp()) { - const ExecMTask* const prevp = dynamic_cast(edgep->fromp()); + const ExecMTask* const prevp = edgep->fromp()->as(); if (threadId(prevp) != thisThreadId) ++result; } return result; @@ -2248,7 +2249,7 @@ void ThreadSchedule::dumpDotFile(const V3Graph& graph, const string& filename) c // Find minimum cost MTask for scaling MTask node widths uint32_t minCost = UINT32_MAX; for (const V3GraphVertex* vxp = graph.verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { - if (const ExecMTask* const mtaskp = dynamic_cast(vxp)) { + if (const ExecMTask* const mtaskp = vxp->cast()) { minCost = minCost > mtaskp->cost() ? mtaskp->cost() : minCost; } } @@ -2271,13 +2272,13 @@ void ThreadSchedule::dumpDotFile(const V3Graph& graph, const string& filename) c // Emit MTasks for (const V3GraphVertex* vxp = graph.verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { - if (const ExecMTask* const mtaskp = dynamic_cast(vxp)) emitMTask(mtaskp); + if (const ExecMTask* const mtaskp = vxp->cast()) emitMTask(mtaskp); } // Emit MTask dependency edges *logp << "\n // MTask dependencies\n"; for (const V3GraphVertex* vxp = graph.verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { - if (const ExecMTask* const mtaskp = dynamic_cast(vxp)) { + if (const ExecMTask* const mtaskp = vxp->cast()) { for (V3GraphEdge* edgep = mtaskp->outBeginp(); edgep; edgep = edgep->outNextp()) { const V3GraphVertex* const top = edgep->top(); *logp << " " << vxp->name() << " -> " << top->name() << "\n"; @@ -2365,7 +2366,7 @@ private: bool isReady(ThreadSchedule& schedule, const ExecMTask* mtaskp) { for (V3GraphEdge* edgeInp = mtaskp->inBeginp(); edgeInp; edgeInp = edgeInp->inNextp()) { - const ExecMTask* const prevp = dynamic_cast(edgeInp->fromp()); + const ExecMTask* const prevp = edgeInp->fromp()->as(); if (schedule.threadId(prevp) == ThreadSchedule::UNASSIGNED) { // This predecessor is not assigned yet return false; @@ -2388,7 +2389,7 @@ public: // Build initial ready list for (V3GraphVertex* vxp = mtaskGraph.verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { - ExecMTask* const mtaskp = dynamic_cast(vxp); + ExecMTask* const mtaskp = vxp->as(); if (isReady(schedule, mtaskp)) readyMTasks.insert(mtaskp); } @@ -2409,7 +2410,7 @@ public: } for (V3GraphEdge* edgep = mtaskp->inBeginp(); edgep; edgep = edgep->inNextp()) { - const ExecMTask* const priorp = dynamic_cast(edgep->fromp()); + const ExecMTask* const priorp = edgep->fromp()->as(); const uint32_t priorEndTime = completionTime(schedule, priorp, threadId); if (priorEndTime > timeBegin) timeBegin = priorEndTime; } @@ -2449,7 +2450,7 @@ public: UASSERT_OBJ(erased > 0, bestMtaskp, "Should have erased something?"); for (V3GraphEdge* edgeOutp = bestMtaskp->outBeginp(); edgeOutp; edgeOutp = edgeOutp->outNextp()) { - ExecMTask* const nextp = dynamic_cast(edgeOutp->top()); + ExecMTask* const nextp = edgeOutp->top()->as(); // Dependent MTask should not yet be assigned to a thread UASSERT(schedule.threadId(nextp) == ThreadSchedule::UNASSIGNED, "Tasks after one being assigned should not be assigned yet"); @@ -2540,7 +2541,7 @@ void V3Partition::debugMTaskGraphStats(const V3Graph* graphp, const string& stag for (const V3GraphVertex* mtaskp = graphp->verticesBeginp(); mtaskp; mtaskp = mtaskp->verticesNextp()) { ++mtaskCount; - uint32_t mtaskCost = dynamic_cast(mtaskp)->cost(); + uint32_t mtaskCost = mtaskp->as()->cost(); totalCost += mtaskCost; unsigned log2Cost = 0; @@ -2928,7 +2929,7 @@ static void fillinCosts(V3Graph* execMTaskGraphp) { for (const V3GraphVertex* vxp = execMTaskGraphp->verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { - ExecMTask* const mtp = dynamic_cast(const_cast(vxp)); + ExecMTask* const mtp = const_cast(vxp)->as(); // Compute name of mtask, for hash lookup mtp->hashName(m_uniqueNames.get(mtp->bodyp())); @@ -2949,7 +2950,7 @@ static void fillinCosts(V3Graph* execMTaskGraphp) { int missingProfiles = 0; for (const V3GraphVertex* vxp = execMTaskGraphp->verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { - ExecMTask* const mtp = dynamic_cast(const_cast(vxp)); + ExecMTask* const mtp = const_cast(vxp)->as(); const uint32_t costEstimate = costs[mtp->id()].first; const uint64_t costProfiled = costs[mtp->id()].second; UINFO(9, "ce = " << costEstimate << " cp=" << costProfiled << endl); @@ -2978,14 +2979,14 @@ static void fillinCosts(V3Graph* execMTaskGraphp) { static void finalizeCosts(V3Graph* execMTaskGraphp) { GraphStreamUnordered ser(execMTaskGraphp, GraphWay::REVERSE); while (const V3GraphVertex* const vxp = ser.nextp()) { - ExecMTask* const mtp = dynamic_cast(const_cast(vxp)); + ExecMTask* const mtp = const_cast(vxp)->as(); // "Priority" is the critical path from the start of the mtask, to // the end of the graph reachable from this mtask. Given the // choice among several ready mtasks, we'll want to start the // highest priority one first, so we're always working on the "long // pole" for (V3GraphEdge* edgep = mtp->outBeginp(); edgep; edgep = edgep->outNextp()) { - const ExecMTask* const followp = dynamic_cast(edgep->top()); + const ExecMTask* const followp = edgep->top()->as(); if ((followp->priority() + mtp->cost()) > mtp->priority()) { mtp->priority(followp->priority() + mtp->cost()); } @@ -2996,7 +2997,7 @@ static void finalizeCosts(V3Graph* execMTaskGraphp) { // (It's common for tasks to shrink to nothing when V3LifePost // removes dly assignments.) for (V3GraphVertex* vxp = execMTaskGraphp->verticesBeginp(); vxp;) { - ExecMTask* const mtp = dynamic_cast(vxp); + ExecMTask* const mtp = vxp->as(); vxp = vxp->verticesNextp(); // Advance before delete // Don't rely on checking mtp->cost() == 0 to detect an empty task. @@ -3100,7 +3101,7 @@ static void addMTaskToFunction(const ThreadSchedule& schedule, const uint32_t th // For any dependent mtask that's on another thread, signal one dependency completion. for (V3GraphEdge* edgep = mtaskp->outBeginp(); edgep; edgep = edgep->outNextp()) { - const ExecMTask* const nextp = dynamic_cast(edgep->top()); + const ExecMTask* const nextp = edgep->top()->as(); if (schedule.threadId(nextp) != threadId) { addStrStmt("vlSelf->__Vm_mtaskstate_" + cvtToStr(nextp->id()) + ".signalUpstreamDone(even_cycle);\n"); diff --git a/src/V3PartitionGraph.h b/src/V3PartitionGraph.h index 0827ca381..eb1455e2a 100644 --- a/src/V3PartitionGraph.h +++ b/src/V3PartitionGraph.h @@ -29,6 +29,7 @@ // MTasks and graph structures class AbstractMTask VL_NOT_FINAL : public V3GraphVertex { + VL_RTTI_IMPL(AbstractMTask, V3GraphVertex) public: explicit AbstractMTask(V3Graph* graphp) : V3GraphVertex{graphp} {} @@ -38,6 +39,7 @@ public: }; class AbstractLogicMTask VL_NOT_FINAL : public AbstractMTask { + VL_RTTI_IMPL(AbstractLogicMTask, AbstractMTask) public: // TYPES using VxList = std::list; @@ -53,6 +55,7 @@ public: }; class ExecMTask final : public AbstractMTask { + VL_RTTI_IMPL(ExecMTask, AbstractMTask) private: AstMTaskBody* const m_bodyp; // Task body const uint32_t m_id; // Unique id of this mtask. diff --git a/src/V3Rtti.h b/src/V3Rtti.h new file mode 100644 index 000000000..f787ef8c7 --- /dev/null +++ b/src/V3Rtti.h @@ -0,0 +1,131 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Simple and efficient Run-Time Type Information +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-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 +// +//************************************************************************* + +#ifndef VERILATOR_V3RTTI_H_ +#define VERILATOR_V3RTTI_H_ + +#include "verilatedos.h" + +#include +#include + +// Holds list of types as template parameter pack. +// Useful in compile-time code generation. +template +struct VTypeList { + template + constexpr VTypeList operator+(VTypeList) const { + return {}; + } +}; + +// Holds one type. +// Can be safely used as a return or argument type, and even instantiated, without triggering any +// potential limitations or effects of the held type. +template +struct VTypeWrapper { + using type_t = T; +}; + +// Implementation details of other constructs defined in this header. +namespace V3RttiInternal { + +// Helper function for extracting first type from VTypeList. +template +static inline constexpr VTypeWrapper vlTypeListFront(VTypeList) { + return {}; +} + +// Overload for empty type list. Returns false. +inline static constexpr bool isClassIdOfOneOf(uintptr_t id, VTypeList<>) VL_PURE { return false; } + +// Returns true iff `id` has the same value as `T::rttiClassId()`, where `T` is any type held by +// `VTypeList` object passed as the second argument. +template +inline static constexpr bool isClassIdOfOneOf(uintptr_t id, VTypeList) VL_PURE { + return id == Base0::rttiClassId() || isClassIdOfOneOf(id, VTypeList{}); +} + +} // namespace V3RttiInternal + +// Alias for the first (frontmost) type held by type list `TL`. +template +using VTypeListFront = typename decltype(::V3RttiInternal::vlTypeListFront(TL{}))::type_t; + +// `VTypeList` holding types from type lists `TL1` followed by types from type list `TL2`. +template +using VJoinedTypeLists = decltype(TL1{} + TL2{}); + +// Common code used by VL_RTTI_COMMON_IMPL and VL_RTTI_COMMON_IMPL_BASE. +#define V3RTTIINTERNAL_VL_RTTI_COMMON_IMPL(ThisClass) \ +private: \ + /* A type used only for implementation of the static_assert below. */ \ + struct RttiUniqueTypeForThisClass {}; \ + static_assert( \ + std::is_same::value, \ + "'ThisClass' argument (" #ThisClass ") does not match the class name"); \ +\ +public: \ + /* Returns unique ID of the class. Useful with `isInstanceOfClassWithId()` method. */ \ + static uintptr_t rttiClassId() VL_PURE { \ + /* The only purpose of the following variable is to occupy an unique memory address. */ \ + /* This address is used as an unique class ID. */ \ + static char aStaticVariable; \ + return reinterpret_cast(&aStaticVariable); \ + } + +// Call this macro at the beginning of class definition if the class derives from a +// class with VL_RTTI_IMPL or VL_RTTI_IMPL_BASE calls. +#define VL_RTTI_IMPL(ThisClass, DirectBaseClass) \ + V3RTTIINTERNAL_VL_RTTI_COMMON_IMPL(ThisClass) \ + static_assert( \ + std::is_same>::value, \ + "Missing VL_RTTI_IMPL(...) in the direct base class (" #DirectBaseClass ")"); \ +\ +public: \ + /* Type list containing this class and all classes from the inheritance chain. */ \ + using RttiThisAndBaseClassesList \ + = VJoinedTypeLists, \ + typename DirectBaseClass::RttiThisAndBaseClassesList>; \ +\ +protected: \ + /* Returns true iff `id` has the same value as `T::rttiClassId()`, where `T` is either this \ + * class or any class from this class' inheritance chain. */ \ + bool isInstanceOfClassWithId(uintptr_t id) const override VL_PURE { \ + return ::V3RttiInternal::isClassIdOfOneOf(id, RttiThisAndBaseClassesList{}); \ + } \ +\ +private: /* Revert to private visibility after this macro */ + +// Call this macro at the beginning of a base class to implement class type queries using +// `p->isInstanceOfClassWithId(ClassName::rttiClassId())`. +#define VL_RTTI_IMPL_BASE(ThisClass) \ + V3RTTIINTERNAL_VL_RTTI_COMMON_IMPL(ThisClass) \ +public: \ + /* Type list containing this class and all classes from the inheritance chain. */ \ + using RttiThisAndBaseClassesList = VTypeList; \ +\ +protected: \ + /* Returns true iff `id` has the same value as value returned by this class' \ + `rttiClassId()` method. */ \ + virtual bool isInstanceOfClassWithId(uintptr_t id) const VL_PURE { \ + return id == rttiClassId(); \ + } \ +\ +private: /* Revert to private visibility after this macro */ + +#endif // Guard diff --git a/src/V3SchedAcyclic.cpp b/src/V3SchedAcyclic.cpp index 20cfc4c7b..769383678 100644 --- a/src/V3SchedAcyclic.cpp +++ b/src/V3SchedAcyclic.cpp @@ -59,17 +59,18 @@ namespace { // ############################################################################## // Data structures (graph types) -class LogicVertex final : public V3GraphVertex { +class SchedAcyclicLogicVertex final : public V3GraphVertex { + VL_RTTI_IMPL(SchedAcyclicLogicVertex, V3GraphVertex) AstNode* const m_logicp; // The logic node this vertex represents AstScope* const m_scopep; // The enclosing AstScope of the logic node public: - LogicVertex(V3Graph* graphp, AstNode* logicp, AstScope* scopep) + SchedAcyclicLogicVertex(V3Graph* graphp, AstNode* logicp, AstScope* scopep) : V3GraphVertex{graphp} , m_logicp{logicp} , m_scopep{scopep} {} V3GraphVertex* clone(V3Graph* graphp) const override { - return new LogicVertex{graphp, logicp(), scopep()}; + return new SchedAcyclicLogicVertex{graphp, logicp(), scopep()}; } AstNode* logicp() const { return m_logicp; } @@ -81,16 +82,19 @@ public: // LCOV_EXCL_STOP }; -class VarVertex final : public V3GraphVertex { +class SchedAcyclicVarVertex final : public V3GraphVertex { + VL_RTTI_IMPL(SchedAcyclicVarVertex, V3GraphVertex) AstVarScope* const m_vscp; // The AstVarScope this vertex represents public: - VarVertex(V3Graph* graphp, AstVarScope* vscp) + SchedAcyclicVarVertex(V3Graph* graphp, AstVarScope* vscp) : V3GraphVertex{graphp} , m_vscp{vscp} {} AstVarScope* vscp() const { return m_vscp; } AstVar* varp() const { return m_vscp->varp(); } - V3GraphVertex* clone(V3Graph* graphp) const override { return new VarVertex{graphp, vscp()}; } + V3GraphVertex* clone(V3Graph* graphp) const override { + return new SchedAcyclicVarVertex{graphp, vscp()}; + } // LCOV_EXCL_START // Debug code string name() const override VL_MT_STABLE { return m_vscp->name(); } @@ -102,13 +106,12 @@ public: class Graph final : public V3Graph { void loopsVertexCb(V3GraphVertex* vtxp) override { // TODO: 'typeName' is an internal thing. This should be more human readable. - if (LogicVertex* const lvtxp = dynamic_cast(vtxp)) { + if (SchedAcyclicLogicVertex* const lvtxp = vtxp->cast()) { AstNode* const logicp = lvtxp->logicp(); std::cerr << logicp->fileline()->warnOtherStandalone() << " Example path: " << logicp->typeName() << endl; } else { - VarVertex* const vvtxp = dynamic_cast(vtxp); - UASSERT(vvtxp, "Cannot be anything else"); + SchedAcyclicVarVertex* const vvtxp = vtxp->as(); AstVarScope* const vscp = vvtxp->vscp(); std::cerr << vscp->fileline()->warnOtherStandalone() << " Example path: " << vscp->prettyName() << endl; @@ -125,8 +128,8 @@ std::unique_ptr buildGraph(const LogicByScope& lbs) { // AstVarScope::user1() -> VarVertx const VNUser1InUse user1InUse; const auto getVarVertex = [&](AstVarScope* vscp) { - if (!vscp->user1p()) vscp->user1p(new VarVertex{graphp.get(), vscp}); - return vscp->user1u().to(); + if (!vscp->user1p()) vscp->user1p(new SchedAcyclicVarVertex{graphp.get(), vscp}); + return vscp->user1u().to(); }; const auto addEdge = [&](V3GraphVertex* fromp, V3GraphVertex* top, int weight, bool cuttable) { @@ -141,13 +144,14 @@ std::unique_ptr buildGraph(const LogicByScope& lbs) { // Can safely ignore Postponed as we generate them all if (VN_IS(nodep, AlwaysPostponed)) continue; - LogicVertex* const lvtxp = new LogicVertex{graphp.get(), nodep, scopep}; + SchedAcyclicLogicVertex* const lvtxp + = new SchedAcyclicLogicVertex{graphp.get(), nodep, scopep}; const VNUser2InUse user2InUse; const VNUser3InUse user3InUse; nodep->foreach([&](AstVarRef* refp) { AstVarScope* const vscp = refp->varScopep(); - VarVertex* const vvtxp = getVarVertex(vscp); + SchedAcyclicVarVertex* const vvtxp = getVarVertex(vscp); // We want to cut the narrowest signals const int weight = vscp->width() / 8 + 1; // If written, add logic -> var edge @@ -208,7 +212,7 @@ void removeNonCyclic(Graph* graphp) { } // Has this VarVertex been cut? (any edges in or out has been cut) -bool isCut(const VarVertex* vtxp) { +bool isCut(const SchedAcyclicVarVertex* vtxp) { for (V3GraphEdge* edgep = vtxp->inBeginp(); edgep; edgep = edgep->inNextp()) { if (edgep->weight() == 0) return true; } @@ -218,33 +222,33 @@ bool isCut(const VarVertex* vtxp) { return false; } -std::vector findCutVertices(Graph* graphp) { - std::vector result; +std::vector findCutVertices(Graph* graphp) { + std::vector result; const VNUser1InUse user1InUse; // bool: already added to result for (V3GraphVertex* vtxp = graphp->verticesBeginp(); vtxp; vtxp = vtxp->verticesNextp()) { - if (VarVertex* const vvtxp = dynamic_cast(vtxp)) { + if (SchedAcyclicVarVertex* const vvtxp = vtxp->cast()) { if (!vvtxp->vscp()->user1SetOnce() && isCut(vvtxp)) result.push_back(vvtxp); } } return result; } -void resetEdgeWeights(const std::vector& cutVertices) { - for (VarVertex* const vvtxp : cutVertices) { +void resetEdgeWeights(const std::vector& cutVertices) { + for (SchedAcyclicVarVertex* const vvtxp : cutVertices) { for (V3GraphEdge* ep = vvtxp->inBeginp(); ep; ep = ep->inNextp()) ep->weight(1); for (V3GraphEdge* ep = vvtxp->outBeginp(); ep; ep = ep->outNextp()) ep->weight(1); } } // A VarVertex together with its fanout -using Candidate = std::pair; +using Candidate = std::pair; // Gather all splitting candidates that are in the same SCC as the given vertex void gatherSCCCandidates(V3GraphVertex* vtxp, std::vector& candidates) { if (vtxp->user()) return; // Already done vtxp->user(true); - if (VarVertex* const vvtxp = dynamic_cast(vtxp)) { + if (SchedAcyclicVarVertex* const vvtxp = vtxp->cast()) { AstVar* const varp = vvtxp->varp(); const string name = varp->prettyName(); if (!varp->user3SetOnce() // Only consider each AstVar once @@ -270,7 +274,7 @@ void gatherSCCCandidates(V3GraphVertex* vtxp, std::vector& candidates } // Find all variables in a loop (SCC) that are candidates for splitting to break loops. -void reportLoopVars(Graph* graphp, VarVertex* vvtxp) { +void reportLoopVars(Graph* graphp, SchedAcyclicVarVertex* vvtxp) { // Vector of variables in UNOPTFLAT loop that are candidates for splitting. std::vector candidates; { @@ -325,8 +329,8 @@ void reportLoopVars(Graph* graphp, VarVertex* vvtxp) { V3Stats::addStat("Scheduling, split_var, candidates", splittable); } -void reportCycles(Graph* graphp, const std::vector& cutVertices) { - for (VarVertex* vvtxp : cutVertices) { +void reportCycles(Graph* graphp, const std::vector& cutVertices) { + for (SchedAcyclicVarVertex* vvtxp : cutVertices) { AstVarScope* const vscp = vvtxp->vscp(); FileLine* const flp = vscp->fileline(); @@ -350,16 +354,18 @@ void reportCycles(Graph* graphp, const std::vector& cutVertices) { } } -LogicByScope fixCuts(AstNetlist* netlistp, const std::vector& cutVertices) { +LogicByScope fixCuts(AstNetlist* netlistp, + const std::vector& cutVertices) { // For all logic that reads a cut vertex, build a map from logic -> list of cut AstVarScope // they read. Also build a vector of the involved logic for deterministic results. - std::unordered_map> lvtx2Cuts; - std::vector lvtxps; + std::unordered_map> lvtx2Cuts; + std::vector lvtxps; { const VNUser1InUse user1InUse; // bool: already added to 'lvtxps' - for (VarVertex* const vvtxp : cutVertices) { + for (SchedAcyclicVarVertex* const vvtxp : cutVertices) { for (V3GraphEdge* edgep = vvtxp->outBeginp(); edgep; edgep = edgep->outNextp()) { - LogicVertex* const lvtxp = static_cast(edgep->top()); + SchedAcyclicLogicVertex* const lvtxp + = static_cast(edgep->top()); if (!lvtxp->logicp()->user1SetOnce()) lvtxps.push_back(lvtxp); lvtx2Cuts[lvtxp].push_back(vvtxp->vscp()); } @@ -370,7 +376,7 @@ LogicByScope fixCuts(AstNetlist* netlistp, const std::vector& cutVer // explicit additional triggers on the cut variables) LogicByScope result; SenTreeFinder finder{netlistp}; - for (LogicVertex* const lvtxp : lvtxps) { + for (SchedAcyclicLogicVertex* const lvtxp : lvtxps) { AstNode* const logicp = lvtxp->logicp(); logicp->unlinkFrBack(); FileLine* const flp = logicp->fileline(); @@ -412,7 +418,7 @@ LogicByScope breakCycles(AstNetlist* netlistp, LogicByScope& combinationalLogic) graphp->acyclic(&V3GraphEdge::followAlwaysTrue); // Find all cut vertices - const std::vector cutVertices = findCutVertices(graphp.get()); + const std::vector cutVertices = findCutVertices(graphp.get()); // Reset edge weights for reporting resetEdgeWeights(cutVertices); diff --git a/src/V3SchedPartition.cpp b/src/V3SchedPartition.cpp index 1f3a0075b..6299813b2 100644 --- a/src/V3SchedPartition.cpp +++ b/src/V3SchedPartition.cpp @@ -55,6 +55,7 @@ namespace V3Sched { namespace { class SchedSenVertex final : public V3GraphVertex { + VL_RTTI_IMPL(SchedSenVertex, V3GraphVertex) const AstSenItem* const m_senItemp; public: @@ -74,6 +75,7 @@ public: }; class SchedLogicVertex final : public V3GraphVertex { + VL_RTTI_IMPL(SchedLogicVertex, V3GraphVertex) AstScope* const m_scopep; AstSenTree* const m_senTreep; AstNode* const m_logicp; @@ -97,6 +99,7 @@ public: }; class SchedVarVertex final : public V3GraphVertex { + VL_RTTI_IMPL(SchedVarVertex, V3GraphVertex) const AstVarScope* const m_vscp; public: @@ -299,7 +302,7 @@ void colorActiveRegion(const V3Graph& graph) { // Trace from all SchedSenVertex for (V3GraphVertex* vtxp = graph.verticesBeginp(); vtxp; vtxp = vtxp->verticesNextp()) { - if (const auto activeEventVtxp = dynamic_cast(vtxp)) { + if (const auto activeEventVtxp = vtxp->cast()) { queue.push_back(activeEventVtxp); } } @@ -323,9 +326,9 @@ void colorActiveRegion(const V3Graph& graph) { // If this is a logic vertex, also enqueue all variable vertices that are driven from this // logic. This will ensure that if a variable is set in the active region, then all // settings of that variable will be in the active region. - if (dynamic_cast(&vtx)) { + if (vtx.is()) { for (V3GraphEdge* edgep = vtx.outBeginp(); edgep; edgep = edgep->outNextp()) { - UASSERT(dynamic_cast(edgep->top()), "Should be var vertex"); + UASSERT(edgep->top()->is(), "Should be var vertex"); queue.push_back(edgep->top()); } } @@ -350,7 +353,7 @@ LogicRegions partition(LogicByScope& clockedLogic, LogicByScope& combinationalLo LogicRegions result; for (V3GraphVertex* vtxp = graphp->verticesBeginp(); vtxp; vtxp = vtxp->verticesNextp()) { - if (const auto lvtxp = dynamic_cast(vtxp)) { + if (const auto lvtxp = vtxp->cast()) { LogicByScope& lbs = lvtxp->color() ? result.m_act : result.m_nba; AstNode* const logicp = lvtxp->logicp(); logicp->unlinkFrBack(); diff --git a/src/V3SchedReplicate.cpp b/src/V3SchedReplicate.cpp index 961f0e29f..e47e2fad8 100644 --- a/src/V3SchedReplicate.cpp +++ b/src/V3SchedReplicate.cpp @@ -59,11 +59,12 @@ enum RegionFlags : uint8_t { //############################################################################## // Data structures (graph types) -class Vertex VL_NOT_FINAL : public V3GraphVertex { - RegionFlags m_drivingRegions{NONE}; // The regions driving this vertex +class SchedReplicateVertex VL_NOT_FINAL : public V3GraphVertex { + VL_RTTI_IMPL(SchedReplicateVertex, V3GraphVertex) + RegionFlags m_drivingRegions{RegionFlags::NONE}; // The regions driving this vertex public: - explicit Vertex(V3Graph* graphp) + explicit SchedReplicateVertex(V3Graph* graphp) : V3GraphVertex{graphp} {} uint8_t drivingRegions() const { return m_drivingRegions; } void addDrivingRegions(uint8_t regions) { @@ -87,16 +88,17 @@ public: // LCOV_EXCL_STOP }; -class LogicVertex final : public Vertex { +class SchedReplicateLogicVertex final : public SchedReplicateVertex { + VL_RTTI_IMPL(SchedReplicateLogicVertex, SchedReplicateVertex) AstScope* const m_scopep; // The enclosing AstScope of the logic node AstSenTree* const m_senTreep; // The sensitivity of the logic node AstNode* const m_logicp; // The logic node this vertex represents RegionFlags const m_assignedRegion; // The region this logic is originally assigned to public: - LogicVertex(V3Graph* graphp, AstScope* scopep, AstSenTree* senTreep, AstNode* logicp, - RegionFlags assignedRegion) - : Vertex{graphp} + SchedReplicateLogicVertex(V3Graph* graphp, AstScope* scopep, AstSenTree* senTreep, + AstNode* logicp, RegionFlags assignedRegion) + : SchedReplicateVertex{graphp} , m_scopep{scopep} , m_senTreep{senTreep} , m_logicp{logicp} @@ -113,12 +115,13 @@ public: string dotShape() const override { return "rectangle"; } }; -class VarVertex final : public Vertex { +class SchedReplicateVarVertex final : public SchedReplicateVertex { + VL_RTTI_IMPL(SchedReplicateVarVertex, SchedReplicateVertex) AstVarScope* const m_vscp; // The AstVarScope this vertex represents public: - VarVertex(V3Graph* graphp, AstVarScope* vscp) - : Vertex{graphp} + SchedReplicateVarVertex(V3Graph* graphp, AstVarScope* vscp) + : SchedReplicateVertex{graphp} , m_vscp{vscp} { // Top level inputs are if (varp()->isPrimaryInish() || varp()->isSigUserRWPublic() || varp()->isWrittenByDpi()) { @@ -149,11 +152,11 @@ std::unique_ptr buildGraph(const LogicRegions& logicRegions) { // AstVarScope::user1() -> VarVertx const VNUser1InUse user1InUse; const auto getVarVertex = [&](AstVarScope* vscp) { - if (!vscp->user1p()) vscp->user1p(new VarVertex{graphp.get(), vscp}); - return vscp->user1u().to(); + if (!vscp->user1p()) vscp->user1p(new SchedReplicateVarVertex{graphp.get(), vscp}); + return vscp->user1u().to(); }; - const auto addEdge = [&](Vertex* fromp, Vertex* top) { + const auto addEdge = [&](SchedReplicateVertex* fromp, SchedReplicateVertex* top) { new V3GraphEdge{graphp.get(), fromp, top, 1}; }; @@ -182,14 +185,14 @@ std::unique_ptr buildGraph(const LogicRegions& logicRegions) { } for (AstNode* nodep = activep->stmtsp(); nodep; nodep = nodep->nextp()) { - LogicVertex* const lvtxp - = new LogicVertex{graphp.get(), scopep, senTreep, nodep, region}; + SchedReplicateLogicVertex* const lvtxp + = new SchedReplicateLogicVertex{graphp.get(), scopep, senTreep, nodep, region}; const VNUser2InUse user2InUse; const VNUser3InUse user3InUse; nodep->foreach([&](AstVarRef* refp) { AstVarScope* const vscp = refp->varScopep(); - VarVertex* const vvtxp = getVarVertex(vscp); + SchedReplicateVarVertex* const vvtxp = getVarVertex(vscp); // If read, add var -> logic edge // Note: Use same heuristic as ordering does to ignore written variables @@ -216,7 +219,7 @@ std::unique_ptr buildGraph(const LogicRegions& logicRegions) { return graphp; } -void propagateDrivingRegions(Vertex* vtxp) { +void propagateDrivingRegions(SchedReplicateVertex* vtxp) { // Note: The graph is always acyclic, so the recursion will terminate // Nothing to do if already visited @@ -225,7 +228,7 @@ void propagateDrivingRegions(Vertex* vtxp) { // Compute union of driving regions of all inputs uint8_t drivingRegions = 0; for (V3GraphEdge* edgep = vtxp->inBeginp(); edgep; edgep = edgep->inNextp()) { - Vertex* const srcp = static_cast(edgep->fromp()); + SchedReplicateVertex* const srcp = edgep->fromp()->as(); propagateDrivingRegions(srcp); drivingRegions |= srcp->drivingRegions(); } @@ -240,7 +243,7 @@ void propagateDrivingRegions(Vertex* vtxp) { LogicReplicas replicate(Graph* graphp) { LogicReplicas result; for (V3GraphVertex* vtxp = graphp->verticesBeginp(); vtxp; vtxp = vtxp->verticesNextp()) { - if (LogicVertex* const lvtxp = dynamic_cast(vtxp)) { + if (SchedReplicateLogicVertex* const lvtxp = vtxp->cast()) { const auto replicateTo = [&](LogicByScope& lbs) { lbs.add(lvtxp->scopep(), lvtxp->senTreep(), lvtxp->logicp()->cloneTree(false)); }; @@ -264,7 +267,7 @@ LogicReplicas replicateLogic(LogicRegions& logicRegionsRegions) { if (dumpGraphLevel() >= 6) graphp->dumpDotFilePrefixed("sched-replicate"); // Propagate driving region flags for (V3GraphVertex* vtxp = graphp->verticesBeginp(); vtxp; vtxp = vtxp->verticesNextp()) { - propagateDrivingRegions(static_cast(vtxp)); + propagateDrivingRegions(vtxp->as()); } // Dump for debug if (dumpGraphLevel() >= 6) graphp->dumpDotFilePrefixed("sched-replicate-propagated"); diff --git a/src/V3Split.cpp b/src/V3Split.cpp index cbabdbffc..80eb67778 100644 --- a/src/V3Split.cpp +++ b/src/V3Split.cpp @@ -99,6 +99,7 @@ VL_DEFINE_DEBUG_FUNCTIONS; // Support classes class SplitNodeVertex VL_NOT_FINAL : public V3GraphVertex { + VL_RTTI_IMPL(SplitNodeVertex, V3GraphVertex) AstNode* const m_nodep; protected: @@ -117,6 +118,7 @@ public: }; class SplitPliVertex final : public SplitNodeVertex { + VL_RTTI_IMPL(SplitPliVertex, SplitNodeVertex) public: explicit SplitPliVertex(V3Graph* graphp, AstNode* nodep) : SplitNodeVertex{graphp, nodep} {} @@ -126,6 +128,7 @@ public: }; class SplitLogicVertex final : public SplitNodeVertex { + VL_RTTI_IMPL(SplitLogicVertex, SplitNodeVertex) public: SplitLogicVertex(V3Graph* graphp, AstNode* nodep) : SplitNodeVertex{graphp, nodep} {} @@ -134,6 +137,7 @@ public: }; class SplitVarStdVertex final : public SplitNodeVertex { + VL_RTTI_IMPL(SplitVarStdVertex, SplitNodeVertex) public: SplitVarStdVertex(V3Graph* graphp, AstNode* nodep) : SplitNodeVertex{graphp, nodep} {} @@ -142,6 +146,7 @@ public: }; class SplitVarPostVertex final : public SplitNodeVertex { + VL_RTTI_IMPL(SplitVarPostVertex, SplitNodeVertex) public: SplitVarPostVertex(V3Graph* graphp, AstNode* nodep) : SplitNodeVertex{graphp, nodep} {} @@ -154,6 +159,7 @@ public: // Edge types class SplitEdge VL_NOT_FINAL : public V3GraphEdge { + VL_RTTI_IMPL(SplitEdge, V3GraphEdge) uint32_t m_ignoreInStep = 0; // Step number that if set to, causes this edge to be ignored static uint32_t s_stepNum; // Global step number protected: @@ -170,14 +176,12 @@ public: void setIgnoreThisStep() { m_ignoreInStep = s_stepNum; } virtual bool followScoreboard() const = 0; static bool followScoreboard(const V3GraphEdge* edgep) { - const SplitEdge* const oedgep = dynamic_cast(edgep); - if (!oedgep) v3fatalSrc("Following edge of non-SplitEdge type"); + const SplitEdge* const oedgep = edgep->as(); if (oedgep->ignoreThisStep()) return false; return oedgep->followScoreboard(); } static bool followCyclic(const V3GraphEdge* edgep) { - const SplitEdge* const oedgep = dynamic_cast(edgep); - if (!oedgep) v3fatalSrc("Following edge of non-SplitEdge type"); + const SplitEdge* const oedgep = edgep->as(); return (!oedgep->ignoreThisStep()); } string dotStyle() const override { @@ -187,6 +191,7 @@ public: uint32_t SplitEdge::s_stepNum = 0; class SplitPostEdge final : public SplitEdge { + VL_RTTI_IMPL(SplitPostEdge, SplitEdge) public: SplitPostEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) : SplitEdge{graphp, fromp, top, WEIGHT_NORMAL} {} @@ -196,6 +201,7 @@ public: }; class SplitLVEdge final : public SplitEdge { + VL_RTTI_IMPL(SplitLVEdge, SplitEdge) public: SplitLVEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) : SplitEdge{graphp, fromp, top, WEIGHT_NORMAL} {} @@ -205,6 +211,7 @@ public: }; class SplitRVEdge final : public SplitEdge { + VL_RTTI_IMPL(SplitRVEdge, SplitEdge) public: SplitRVEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) : SplitEdge{graphp, fromp, top, WEIGHT_NORMAL} {} @@ -213,7 +220,8 @@ public: string dotColor() const override { return "green"; } }; -struct SplitScorebdEdge : public SplitEdge { +class SplitScorebdEdge final : public SplitEdge { + VL_RTTI_IMPL(SplitScorebdEdge, SplitEdge) public: SplitScorebdEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) : SplitEdge{graphp, fromp, top, WEIGHT_NORMAL} {} @@ -222,7 +230,8 @@ public: string dotColor() const override { return "blue"; } }; -struct SplitStrictEdge : public SplitEdge { +class SplitStrictEdge final : public SplitEdge { + VL_RTTI_IMPL(SplitStrictEdge, SplitEdge) // A strict order, based on the original statement order in the graph // The only non-cutable edge type public: @@ -316,14 +325,14 @@ protected: void pruneDepsOnInputs() { for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) { - if (!vertexp->outBeginp() && dynamic_cast(vertexp)) { + if (!vertexp->outBeginp() && vertexp->is()) { if (debug() >= 9) { const SplitVarStdVertex* const stdp = static_cast(vertexp); UINFO(0, "Will prune deps on var " << stdp->nodep() << endl); stdp->nodep()->dumpTree("- "); } for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) { - SplitEdge* const oedgep = dynamic_cast(edgep); + SplitEdge* const oedgep = edgep->as(); oedgep->setIgnoreThisStep(); } } @@ -474,17 +483,16 @@ protected: // vertexes not involved with this step as unimportant for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) { - if (const SplitLogicVertex* const vvertexp - = dynamic_cast(vertexp)) { - if (!vvertexp->user()) { + if (!vertexp->user()) { + if (const SplitLogicVertex* const vvertexp = vertexp->cast()) { for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) { - SplitEdge* const oedgep = dynamic_cast(edgep); + SplitEdge* const oedgep = edgep->as(); oedgep->setIgnoreThisStep(); } for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { - SplitEdge* const oedgep = dynamic_cast(edgep); + SplitEdge* const oedgep = edgep->as(); oedgep->setIgnoreThisStep(); } } @@ -903,7 +911,7 @@ protected: // inputs) prune all edges that depend on the 'if'. for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) { - const SplitLogicVertex* const logicp = dynamic_cast(vertexp); + const SplitLogicVertex* const logicp = vertexp->cast(); if (!logicp) continue; const AstNodeIf* const ifNodep = VN_CAST(logicp->nodep(), NodeIf); @@ -911,7 +919,7 @@ protected: bool pruneMe = true; for (V3GraphEdge* edgep = logicp->outBeginp(); edgep; edgep = edgep->outNextp()) { - const SplitEdge* const oedgep = dynamic_cast(edgep); + const SplitEdge* const oedgep = edgep->as(); if (!oedgep->ignoreThisStep()) { // This if conditional depends on something we can't // prune -- a variable generated in the current block. @@ -921,7 +929,7 @@ protected: // give a hint about why... if (debug() >= 9) { V3GraphVertex* vxp = oedgep->top(); - const SplitNodeVertex* const nvxp = dynamic_cast(vxp); + const SplitNodeVertex* const nvxp = vxp->as(); UINFO(0, "Cannot prune if-node due to edge " << oedgep << " pointing to node " << nvxp->nodep() << endl); nvxp->nodep()->dumpTree("- "); @@ -935,7 +943,7 @@ protected: // This if can be split; prune dependencies on it. for (V3GraphEdge* edgep = logicp->inBeginp(); edgep; edgep = edgep->inNextp()) { - SplitEdge* const oedgep = dynamic_cast(edgep); + SplitEdge* const oedgep = edgep->as(); oedgep->setIgnoreThisStep(); } } diff --git a/src/V3TSP.cpp b/src/V3TSP.cpp index f8961e5eb..09774b8fc 100644 --- a/src/V3TSP.cpp +++ b/src/V3TSP.cpp @@ -54,6 +54,7 @@ static void selfTestString(); // Vertex that tracks a per-vertex key template class TspVertexTmpl final : public V3GraphVertex { + VL_RTTI_IMPL(TspVertexTmpl, V3GraphVertex) private: const T_Key m_key; diff --git a/src/V3Task.cpp b/src/V3Task.cpp index a2fc9b0a5..f7010fa7c 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -85,6 +85,7 @@ public: }; class TaskEdge final : public V3GraphEdge { + VL_RTTI_IMPL(TaskEdge, V3GraphEdge) public: TaskEdge(V3Graph* graphp, TaskBaseVertex* fromp, TaskBaseVertex* top) : V3GraphEdge{graphp, fromp, top, 1, false} {} diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp index 5b8651d20..15b5a2e0d 100644 --- a/src/V3Timing.cpp +++ b/src/V3Timing.cpp @@ -93,6 +93,7 @@ private: // Vertex of a dependency graph of suspendable nodes, e.g. if a node (process or task) is // suspendable, all its dependents should also be suspendable class DepVtx VL_NOT_FINAL : public V3GraphVertex { + VL_RTTI_IMPL(DepVtx, V3GraphVertex) AstClass* const m_classp; // Class associated with a method AstNode* const m_nodep; // AST node represented by this graph vertex @@ -121,6 +122,7 @@ private: }; class SuspendDepVtx final : public DepVtx { + VL_RTTI_IMPL(SuspendDepVtx, DepVtx) string dotColor() const override { if (nodep()->user2() & T_SUSPENDER) return "red"; if (nodep()->user2() & T_SUSPENDEE) return "blue"; @@ -134,6 +136,7 @@ private: }; class NeedsProcDepVtx final : public DepVtx { + VL_RTTI_IMPL(NeedsProcDepVtx, DepVtx) string dotColor() const override { if (nodep()->user2() & T_CALLS_PROC_SELF) return "red"; if (nodep()->user2() & T_HAS_PROC) return "blue"; diff --git a/src/V3Trace.cpp b/src/V3Trace.cpp index ced3fc9fd..abd9b5ffd 100644 --- a/src/V3Trace.cpp +++ b/src/V3Trace.cpp @@ -56,6 +56,7 @@ VL_DEFINE_DEBUG_FUNCTIONS; // Graph vertexes class TraceActivityVertex final : public V3GraphVertex { + VL_RTTI_IMPL(TraceActivityVertex, V3GraphVertex) AstNode* const m_insertp; int32_t m_activityCode; bool m_slow; // If always slow, we can use the same code @@ -100,6 +101,7 @@ public: }; class TraceCFuncVertex final : public V3GraphVertex { + VL_RTTI_IMPL(TraceCFuncVertex, V3GraphVertex) AstCFunc* const m_nodep; public: @@ -115,6 +117,7 @@ public: }; class TraceTraceVertex final : public V3GraphVertex { + VL_RTTI_IMPL(TraceTraceVertex, V3GraphVertex) AstTraceDecl* const m_nodep; // TRACEINC this represents // nullptr, or other vertex with the real code() that duplicates this one TraceTraceVertex* m_duplicatep = nullptr; @@ -137,6 +140,7 @@ public: }; class TraceVarVertex final : public V3GraphVertex { + VL_RTTI_IMPL(TraceVarVertex, V3GraphVertex) AstVarScope* const m_nodep; public: @@ -204,8 +208,7 @@ private: // Hash all of the values the traceIncs need for (const V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { - if (const TraceTraceVertex* const vvertexp - = dynamic_cast(itp)) { + if (const TraceTraceVertex* const vvertexp = itp->cast()) { const AstTraceDecl* const nodep = vvertexp->nodep(); if (nodep->valuep()) { UASSERT_OBJ(nodep->valuep()->backp() == nodep, nodep, @@ -220,7 +223,7 @@ private: } // Find if there are any duplicates for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { - if (TraceTraceVertex* const vvertexp = dynamic_cast(itp)) { + if (TraceTraceVertex* const vvertexp = itp->cast()) { const AstTraceDecl* const nodep = vvertexp->nodep(); if (nodep->valuep() && !vvertexp->duplicatep()) { const auto dupit = dupFinder.findDuplicate(nodep->valuep()); @@ -229,7 +232,7 @@ private: = VN_AS(dupit->second->backp(), TraceDecl); UASSERT_OBJ(dupDeclp, nodep, "Trace duplicate of wrong type"); TraceTraceVertex* const dupvertexp - = dynamic_cast(dupDeclp->user1u().toGraphVertex()); + = dupDeclp->user1u().toGraphVertex()->cast(); UINFO(8, " Orig " << nodep << endl); UINFO(8, " dup " << dupDeclp << endl); // Mark the hashed node as the original and our @@ -246,7 +249,7 @@ private: // Remove all variable nodes for (V3GraphVertex *nextp, *itp = m_graph.verticesBeginp(); itp; itp = nextp) { nextp = itp->verticesNextp(); - if (TraceVarVertex* const vvertexp = dynamic_cast(itp)) { + if (TraceVarVertex* const vvertexp = itp->cast()) { vvertexp->rerouteEdges(&m_graph); vvertexp->unlinkDelete(&m_graph); } @@ -258,7 +261,7 @@ private: // Remove all Cfunc nodes for (V3GraphVertex *nextp, *itp = m_graph.verticesBeginp(); itp; itp = nextp) { nextp = itp->verticesNextp(); - if (TraceCFuncVertex* const vvertexp = dynamic_cast(itp)) { + if (TraceCFuncVertex* const vvertexp = itp->cast()) { vvertexp->rerouteEdges(&m_graph); vvertexp->unlinkDelete(&m_graph); } @@ -271,16 +274,13 @@ private: // If there are any edges from a always, keep only the always for (const V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { - if (const TraceTraceVertex* const vvertexp - = dynamic_cast(itp)) { + if (const TraceTraceVertex* const vvertexp = itp->cast()) { // Search for the incoming always edge const V3GraphEdge* alwaysEdgep = nullptr; for (const V3GraphEdge* edgep = vvertexp->inBeginp(); edgep; edgep = edgep->inNextp()) { const TraceActivityVertex* const actVtxp - = dynamic_cast(edgep->fromp()); - UASSERT_OBJ(actVtxp, vvertexp->nodep(), - "Tracing a node with FROM non activity"); + = edgep->fromp()->as(); if (actVtxp->activityAlways()) { alwaysEdgep = edgep; break; @@ -299,7 +299,7 @@ private: // Activity points with no outputs can be removed for (V3GraphVertex *nextp, *itp = m_graph.verticesBeginp(); itp; itp = nextp) { nextp = itp->verticesNextp(); - if (TraceActivityVertex* const vtxp = dynamic_cast(itp)) { + if (TraceActivityVertex* const vtxp = itp->cast()) { // Leave in the always vertex for later use. if (vtxp != m_alwaysVtxp && !vtxp->outBeginp()) vtxp->unlinkDelete(&m_graph); } @@ -309,7 +309,7 @@ private: uint32_t assignactivityNumbers() { uint32_t activityNumber = 1; // Note 0 indicates "slow" only for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { - if (TraceActivityVertex* const vvertexp = dynamic_cast(itp)) { + if (TraceActivityVertex* const vvertexp = itp->cast()) { if (vvertexp != m_alwaysVtxp) { if (vvertexp->slow()) { vvertexp->activityCode(TraceActivityVertex::ACTIVITY_SLOW); @@ -328,14 +328,14 @@ private: nFullCodes = 0; nChgCodes = 0; for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { - if (TraceTraceVertex* const vtxp = dynamic_cast(itp)) { + if (TraceTraceVertex* const vtxp = itp->cast()) { ActCodeSet actSet; UINFO(9, " Add to sort: " << vtxp << endl); if (debug() >= 9) vtxp->nodep()->dumpTree("- trnode: "); for (const V3GraphEdge* edgep = vtxp->inBeginp(); edgep; edgep = edgep->inNextp()) { const TraceActivityVertex* const cfvertexp - = dynamic_cast(edgep->fromp()); + = edgep->fromp()->cast(); UASSERT_OBJ(cfvertexp, vtxp->nodep(), "Should have been function pointing to this trace"); UINFO(9, " Activity: " << cfvertexp << endl); @@ -471,8 +471,7 @@ private: // Insert activity setters for (const V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { - if (const TraceActivityVertex* const vtxp - = dynamic_cast(itp)) { + if (const TraceActivityVertex* const vtxp = itp->cast()) { if (vtxp->activitySlow()) { // Just set all flags in slow code as it should be rare. // This will be rolled up into a loop by V3Reloop. @@ -787,7 +786,7 @@ private: TraceCFuncVertex* getCFuncVertexp(AstCFunc* nodep) { TraceCFuncVertex* vertexp - = dynamic_cast(nodep->user1u().toGraphVertex()); + = nodep->user1() ? nodep->user1u().toGraphVertex()->cast() : nullptr; if (!vertexp) { vertexp = new TraceCFuncVertex{&m_graph, nodep}; nodep->user1p(vertexp); @@ -796,7 +795,8 @@ private: } TraceActivityVertex* getActivityVertexp(AstNode* nodep, bool slow) { TraceActivityVertex* vertexp - = dynamic_cast(nodep->user3u().toGraphVertex()); + = nodep->user3() ? nodep->user3u().toGraphVertex()->cast() + : nullptr; if (!vertexp) { vertexp = new TraceActivityVertex{&m_graph, nodep, slow}; nodep->user3p(vertexp); diff --git a/src/V3Tristate.cpp b/src/V3Tristate.cpp index 6ad090603..fdf303b28 100644 --- a/src/V3Tristate.cpp +++ b/src/V3Tristate.cpp @@ -142,6 +142,7 @@ public: // Graph support classes class TristateVertex final : public V3GraphVertex { + VL_RTTI_IMPL(TristateVertex, V3GraphVertex) AstNode* const m_nodep; bool m_isTristate = false; // Logic indicates a tristate bool m_feedsTri = false; // Propagates to a tristate node (on RHS) @@ -222,7 +223,7 @@ private: UINFO(9, " Mark tri " << level << " " << vtxp << endl); if (!vtxp->varp()) { // not a var where we stop the recursion for (V3GraphEdge* edgep = vtxp->outBeginp(); edgep; edgep = edgep->outNextp()) { - TristateVertex* const vvertexp = dynamic_cast(edgep->top()); + TristateVertex* const vvertexp = edgep->top()->as(); // Doesn't hurt to not check if already set, but by doing so when we // print out the debug messages, we'll see this node at level 0 instead. if (!vvertexp->isTristate()) { @@ -234,7 +235,7 @@ private: // A variable is tristated. Find all of the LHS VARREFs that // drive this signal now need tristate drivers for (V3GraphEdge* edgep = vtxp->inBeginp(); edgep; edgep = edgep->inNextp()) { - TristateVertex* const vvertexp = dynamic_cast(edgep->fromp()); + TristateVertex* const vvertexp = edgep->fromp()->as(); if (const AstVarRef* const refp = VN_CAST(vvertexp->nodep(), VarRef)) { if (refp->access().isWriteOrRW() // Doesn't hurt to not check if already set, but by doing so when we @@ -259,7 +260,7 @@ private: UINFO(9, " Mark feedstri " << level << " " << vtxp << endl); if (!vtxp->varp()) { // not a var where we stop the recursion for (V3GraphEdge* edgep = vtxp->inBeginp(); edgep; edgep = edgep->inNextp()) { - TristateVertex* const vvertexp = dynamic_cast(edgep->fromp()); + TristateVertex* const vvertexp = edgep->fromp()->as(); // Doesn't hurt to not check if already set, but by doing so when we // print out the debug messages, we'll see this node at level 0 instead. if (!vvertexp->feedsTri()) { From 8c480fd39e0e3d67d7cd915a7461427c0bdfdec0 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 31 Aug 2023 18:29:58 -0400 Subject: [PATCH 048/111] Internals: Fix cppcheck warnings --- include/verilated_timing.h | 4 ++++ src/V3Fork.cpp | 6 +++--- src/V3Options.h | 2 +- src/V3Premit.cpp | 2 +- src/V3Sched.h | 2 +- src/V3SchedAcyclic.cpp | 2 +- src/V3ThreadPool.h | 4 +++- src/V3Width.cpp | 16 +++++++++------- src/V3WidthSel.cpp | 1 + 9 files changed, 24 insertions(+), 15 deletions(-) diff --git a/include/verilated_timing.h b/include/verilated_timing.h index c7684fe5a..54b505e2a 100644 --- a/include/verilated_timing.h +++ b/include/verilated_timing.h @@ -102,6 +102,8 @@ class VlCoroutineHandle final { public: // CONSTRUCTORS // Construct + // non-explicit: + // cppcheck-suppress noExplicitConstructor VlCoroutineHandle(VlProcessRef process) : m_coro{nullptr} , m_process{process} { @@ -114,6 +116,8 @@ public: if (m_process) m_process->state(VlProcess::WAITING); } // Move the handle, leaving a nullptr + // non-explicit: + // cppcheck-suppress noExplicitConstructor VlCoroutineHandle(VlCoroutineHandle&& moved) : m_coro{std::exchange(moved.m_coro, nullptr)} , m_process{std::exchange(moved.m_process, nullptr)} diff --git a/src/V3Fork.cpp b/src/V3Fork.cpp index d0829181a..7229b08d2 100644 --- a/src/V3Fork.cpp +++ b/src/V3Fork.cpp @@ -358,7 +358,7 @@ private: public: // CONSTRUCTORS - DynScopeVisitor(AstNetlist* nodep) { + explicit DynScopeVisitor(AstNetlist* nodep) { // Create Dynamic scope class prototypes and objects visit(nodep); @@ -431,7 +431,7 @@ private: return taskp; } - string generateTaskName(AstNode* fromp, string kind) { + string generateTaskName(AstNode* fromp, const string& kind) { // TODO: Ensure no collisions occur return "__V" + kind + (!fromp->name().empty() ? (fromp->name() + "__") : "UNNAMED__") + cvtToHex(fromp); @@ -566,7 +566,7 @@ private: public: // CONSTRUCTORS - ForkVisitor(AstNetlist* nodep) { visit(nodep); } + explicit ForkVisitor(AstNetlist* nodep) { visit(nodep); } ~ForkVisitor() override = default; }; diff --git a/src/V3Options.h b/src/V3Options.h index dc2d011a8..702ff680b 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -281,7 +281,7 @@ private: bool m_traceCoverage = false; // main switch: --trace-coverage bool m_traceParams = true; // main switch: --trace-params bool m_traceStructs = false; // main switch: --trace-structs - bool m_noTraceTop; // main switch: --no-trace-top + bool m_noTraceTop = false; // main switch: --no-trace-top bool m_traceUnderscore = false; // main switch: --trace-underscore bool m_underlineZero = false; // main switch: --underline-zero; undocumented old Verilator 2 bool m_verilate = true; // main switch: --verilate diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp index 6887e175d..2d1d3cfdb 100644 --- a/src/V3Premit.cpp +++ b/src/V3Premit.cpp @@ -214,7 +214,7 @@ private: } iterateAndNextNull(nodep->rhsp()); { - VL_RESTORER(m_assignLhs); + // VL_RESTORER(m_assignLhs); // Not needed; part of RESTORER_START_STATEMENT() m_assignLhs = true; iterateAndNextNull(nodep->lhsp()); } diff --git a/src/V3Sched.h b/src/V3Sched.h index ffd12dcad..526525a37 100644 --- a/src/V3Sched.h +++ b/src/V3Sched.h @@ -158,7 +158,7 @@ void transformForks(AstNetlist* const netlistp); void schedule(AstNetlist*); // Sub-steps -LogicByScope breakCycles(AstNetlist* netlistp, LogicByScope& combinationalLogic); +LogicByScope breakCycles(AstNetlist* netlistp, const LogicByScope& combinationalLogic); LogicRegions partition(LogicByScope& clockedLogic, LogicByScope& combinationalLogic, LogicByScope& hybridLogic); LogicReplicas replicateLogic(LogicRegions&); diff --git a/src/V3SchedAcyclic.cpp b/src/V3SchedAcyclic.cpp index 769383678..1416bc2e4 100644 --- a/src/V3SchedAcyclic.cpp +++ b/src/V3SchedAcyclic.cpp @@ -398,7 +398,7 @@ LogicByScope fixCuts(AstNetlist* netlistp, } // namespace -LogicByScope breakCycles(AstNetlist* netlistp, LogicByScope& combinationalLogic) { +LogicByScope breakCycles(AstNetlist* netlistp, const LogicByScope& combinationalLogic) { // Build the dataflow (dependency) graph const std::unique_ptr graphp = buildGraph(combinationalLogic); diff --git a/src/V3ThreadPool.h b/src/V3ThreadPool.h index b7c0658f4..7d21d157a 100644 --- a/src/V3ThreadPool.h +++ b/src/V3ThreadPool.h @@ -41,7 +41,7 @@ class VAnyPackagedTask final { struct PTWrapper final : PTWrapperBase { std::packaged_task m_pt; - PTWrapper(std::packaged_task&& pt) + explicit PTWrapper(std::packaged_task&& pt) : m_pt(std::move(pt)) {} void operator()() final override { m_pt(); } @@ -53,6 +53,8 @@ class VAnyPackagedTask final { public: // CONSTRUCTORS template + // non-explicit: + // cppcheck-suppress noExplicitConstructor VAnyPackagedTask(std::packaged_task&& pt) : m_ptWrapperp{std::make_unique>(std::move(pt))} {} diff --git a/src/V3Width.cpp b/src/V3Width.cpp index dbae4389d..0d5e5696d 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -2781,7 +2781,7 @@ private: VL_DO_DANGLING(pushDeletep(nodep), nodep); return true; } - if (AstNodeFTask* const methodp = VN_CAST(foundp, NodeFTask)) { + if (VN_IS(foundp, NodeFTask)) { nodep->replaceWith(new AstMethodCall{nodep->fileline(), nodep->fromp()->unlinkFrBack(), nodep->name(), nullptr}); @@ -7554,12 +7554,14 @@ AstNodeDType* V3Width::getCommonClassTypep(AstNode* nodep1, AstNode* nodep2) { // First handle cases with null values and when one class is a super class of the other. if (VN_IS(nodep1, Const)) std::swap(nodep1, nodep2); - const Castable castable - = WidthVisitor::computeCastable(nodep1->dtypep(), nodep2->dtypep(), nodep2); - if (castable == SAMEISH || castable == COMPATIBLE) { - return nodep1->dtypep(); - } else if (castable == DYNAMIC_CLASS) { - return nodep2->dtypep(); + { + const Castable castable + = WidthVisitor::computeCastable(nodep1->dtypep(), nodep2->dtypep(), nodep2); + if (castable == SAMEISH || castable == COMPATIBLE) { + return nodep1->dtypep(); + } else if (castable == DYNAMIC_CLASS) { + return nodep2->dtypep(); + } } AstClassRefDType* classDtypep1 = VN_CAST(nodep1->dtypep(), ClassRefDType); diff --git a/src/V3WidthSel.cpp b/src/V3WidthSel.cpp index f12893f40..96c88a2d5 100644 --- a/src/V3WidthSel.cpp +++ b/src/V3WidthSel.cpp @@ -248,6 +248,7 @@ private: adtypep, "Array extraction with width miscomputed " << adtypep->width() << "/" << fromRange.elements()); + // cppcheck-suppress zerodivcond const int elwidth = adtypep->width() / fromRange.elements(); AstSel* const newp = new AstSel{ nodep->fileline(), fromp, From 2f90fb2bec9ad398e50e45180c3b247e3db6b37b Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 31 Aug 2023 18:34:37 -0400 Subject: [PATCH 049/111] Set lifetime for repeat variable (#4451 partial) --- src/V3LinkJump.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/V3LinkJump.cpp b/src/V3LinkJump.cpp index de4c1230e..b7785e975 100644 --- a/src/V3LinkJump.cpp +++ b/src/V3LinkJump.cpp @@ -196,6 +196,7 @@ private: // Spec says value is integral, if negative is ignored AstVar* const varp = new AstVar{nodep->fileline(), VVarType::BLOCKTEMP, name, nodep->findSigned32DType()}; + varp->lifetime(VLifetime::AUTOMATIC); varp->usedLoopIdx(true); m_modp->addStmtsp(varp); AstNode* initsp = new AstAssign{ From 5b7e32581bd5e61da96d1e0122ebfab903452548 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Fri, 1 Sep 2023 14:03:16 +0200 Subject: [PATCH 050/111] Internals: Cleanup V3Task. No function change intended. (#4454) --- src/V3Task.cpp | 42 ++++++------------------------------------ 1 file changed, 6 insertions(+), 36 deletions(-) diff --git a/src/V3Task.cpp b/src/V3Task.cpp index f7010fa7c..44449ae67 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -349,10 +349,6 @@ private: const VNUser2InUse m_inuser2; // TYPES - enum InsertMode : uint8_t { - IM_BEFORE, // Pointing at statement ref is in, insert before this - IM_WHILE_PRECOND // Pointing to for loop, add to body end - }; using DpiCFuncs = std::map>; // STATE @@ -360,7 +356,6 @@ private: AstNodeModule* m_modp = nullptr; // Current module AstTopScope* const m_topScopep = v3Global.rootp()->topScopep(); // The AstTopScope AstScope* m_scopep = nullptr; // Current scope - InsertMode m_insMode = IM_BEFORE; // How to insert AstNode* m_insStmtp = nullptr; // Where to insert statement bool m_inSensesp = false; // Are we under a senitem? int m_modNCalls = 0; // Incrementing func # for making symbols @@ -1335,33 +1330,17 @@ private: // Iterate into the FTask we are calling. Note it may be under a different // scope then the caller, so we need to restore state. VL_RESTORER(m_scopep); - VL_RESTORER(m_insMode); VL_RESTORER(m_insStmtp); { m_scopep = m_statep->getScope(nodep); iterate(nodep); } } - AstNode* insertBeforeStmt(AstNode* nodep, AstNode* newp) { - // Return node that must be visited, if any + void insertBeforeStmt(AstNode* nodep, AstNode* newp) { if (debug() >= 9) nodep->dumpTree("- newstmt: "); UASSERT_OBJ(m_insStmtp, nodep, "Function call not underneath a statement"); - AstNode* visitp = nullptr; - if (m_insMode == IM_BEFORE) { - // Add the whole thing before insertAt - UINFO(5, " IM_Before " << m_insStmtp << endl); - if (debug() >= 9) newp->dumpTree("- newfunc: "); - m_insStmtp->addHereThisAsNext(newp); - } else if (m_insMode == IM_WHILE_PRECOND) { - UINFO(5, " IM_While_Precond " << m_insStmtp << endl); - AstWhile* const whilep = VN_AS(m_insStmtp, While); - UASSERT_OBJ(whilep, nodep, "Insert should be under WHILE"); - whilep->addPrecondsp(newp); - visitp = newp; - } else { - nodep->v3fatalSrc("Unknown InsertMode"); - } - return visitp; + if (debug() >= 9) newp->dumpTree("- newfunc: "); + m_insStmtp->addHereThisAsNext(newp); } // VISITORS @@ -1420,17 +1399,15 @@ private: } else { beginp = createInlinedFTask(nodep, namePrefix, outvscp); } - // Replace the ref - AstNode* visitp = nullptr; if (VN_IS(nodep, New)) { - visitp = insertBeforeStmt(nodep, beginp); + insertBeforeStmt(nodep, beginp); UASSERT_OBJ(cnewp, nodep, "didn't create cnew for new"); 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"); - visitp = insertBeforeStmt(nodep, beginp); + insertBeforeStmt(nodep, beginp); AstVarRef* const outrefp = new AstVarRef{nodep->fileline(), outvscp, VAccess::READ}; nodep->replaceWith(outrefp); VL_DO_DANGLING(nodep->deleteTree(), nodep); @@ -1441,7 +1418,7 @@ private: nodep->replaceWith(beginp); VL_DO_DANGLING(nodep->deleteTree(), nodep); } else { - visitp = insertBeforeStmt(nodep, beginp); + insertBeforeStmt(nodep, beginp); if (nodep->taskp()->isFunction()) { nodep->v3warn( IGNOREDRETURN, @@ -1451,14 +1428,10 @@ private: VL_DO_DANGLING(nodep->deleteTree(), nodep); } UINFO(4, " FTask REF Done.\n"); - // Visit nodes that normal iteration won't find - if (visitp) iterateAndNextNull(visitp); } void visit(AstNodeFTask* nodep) override { UINFO(4, " visitFTask " << nodep << endl); - VL_RESTORER(m_insMode); VL_RESTORER(m_insStmtp); - m_insMode = IM_BEFORE; m_insStmtp = nodep->stmtsp(); // Might be null if no statements, but we won't use it if (!nodep->user1SetOnce()) { // Just one creation needed per function // Expand functions in it @@ -1529,7 +1502,6 @@ private: m_insStmtp = nullptr; // First thing should be new statement iterateAndNextNull(nodep->precondsp()); // Conditions insert first at end of precondsp. - m_insMode = IM_WHILE_PRECOND; m_insStmtp = nodep; iterateAndNextNull(nodep->condp()); // Body insert just before themselves @@ -1544,7 +1516,6 @@ private: "For statements should have been converted to while statements in V3Begin.cpp"); } void visit(AstNodeStmt* nodep) override { - m_insMode = IM_BEFORE; m_insStmtp = nodep; iterateChildren(nodep); m_insStmtp = nullptr; // Next thing should be new statement @@ -1557,7 +1528,6 @@ private: } } void visit(AstStmtExpr* nodep) override { - m_insMode = IM_BEFORE; m_insStmtp = nodep; iterateChildren(nodep); if (!nodep->exprp()) VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); From 147aa41ba5cbb1003fc09481be2f861dee0956bb Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 1 Sep 2023 17:58:17 -0400 Subject: [PATCH 051/111] Internals: Fix virt call in constructor warning. No functional change. --- include/verilated_vpi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/verilated_vpi.cpp b/include/verilated_vpi.cpp index 1262a9df0..2e021f2c5 100644 --- a/include/verilated_vpi.cpp +++ b/include/verilated_vpi.cpp @@ -175,7 +175,7 @@ public: VerilatedVpioVarBase(const VerilatedVar* varp, const VerilatedScope* scopep) : m_varp{varp} , m_scopep{scopep} - , m_fullname{std::string{m_scopep->name()} + '.' + name()} {} + , m_fullname{std::string{m_scopep->name()} + '.' + m_varp->name()} {} explicit VerilatedVpioVarBase(const VerilatedVpioVarBase* varp) { if (varp) { m_varp = varp->m_varp; From ed25aaaad9a3531a0969e019ea4108eb3d69e832 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 1 Sep 2023 17:59:30 -0400 Subject: [PATCH 052/111] Internals: Fix g++ std11 warning. No functional change. --- include/verilated.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/verilated.cpp b/include/verilated.cpp index 6ffa7f3d8..a1718a408 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -320,7 +320,7 @@ std::string VlRNG::get_randstate() const VL_MT_UNSAFE { const char* const stateCharsp = reinterpret_cast(&m_state); static_assert(sizeof(m_state) == 16, ""); std::string result{"R00112233445566770011223344556677"}; - for (int i = 0; i < sizeof(m_state); ++i) { + for (size_t i = 0; i < sizeof(m_state); ++i) { result[1 + i * 2] = 'a' + ((stateCharsp[i] >> 4) & 15); result[1 + i * 2 + 1] = 'a' + (stateCharsp[i] & 15); } @@ -332,7 +332,7 @@ void VlRNG::set_randstate(const std::string& state) VL_MT_UNSAFE { return; } char* const stateCharsp = reinterpret_cast(&m_state); - for (int i = 0; i < sizeof(m_state); ++i) { + for (size_t i = 0; i < sizeof(m_state); ++i) { stateCharsp[i] = (((state[1 + i * 2] - 'a') & 15) << 4) | ((state[1 + i * 2 + 1] - 'a') & 15); } From 36932d31c4ec19e9b0aac93275af8b166a083389 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 1 Sep 2023 18:07:15 -0400 Subject: [PATCH 053/111] Fix C++11 missing C++14's std::make_unique. --- include/verilated.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/verilated.cpp b/include/verilated.cpp index a1718a408..41a1df170 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -2612,7 +2612,7 @@ void VerilatedContext::prepareClone() { delete m_threadPool.release(); } VerilatedVirtualBase* VerilatedContext::threadPoolpOnClone() { if (VL_UNLIKELY(m_threadPool)) m_threadPool.release(); - m_threadPool = std::make_unique(this, m_threads - 1); + m_threadPool = std::unique_ptr(new VlThreadPool{this, m_threads - 1}); return m_threadPool.get(); } From 679a4314dc0d13392aa3668ca82f2f13aedc6d2e Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 1 Sep 2023 19:26:50 -0400 Subject: [PATCH 054/111] Tests: Avoid side effect on array index --- test_regress/t/t_extract_static_const.v | 18 +++++----- .../t/t_extract_static_const_multimodule.v | 20 ++++++----- test_regress/t/t_flag_prefix.v | 10 +++--- test_regress/t/t_param_array7.v | 35 ++++++++++--------- 4 files changed, 47 insertions(+), 36 deletions(-) diff --git a/test_regress/t/t_extract_static_const.v b/test_regress/t/t_extract_static_const.v index 5e258dbe9..94a1c528b 100644 --- a/test_regress/t/t_extract_static_const.v +++ b/test_regress/t/t_extract_static_const.v @@ -25,16 +25,18 @@ module t (/*AUTOARG*/); 32'h7777_7777, 32'h8888_8888}; + int i; + initial begin // Note: Base index via $c to prevent optimizatoin by Verilator - $display("0x%8x", C[$c(0*32)+:32]); - $display("0x%8x", D[$c(1*32)+:32]); - $display("0x%8x", C[$c(2*32)+:32]); - $display("0x%8x", D[$c(3*32)+:32]); - $display("0x%8x", C[$c(4*32)+:32]); - $display("0x%8x", D[$c(5*32)+:32]); - $display("0x%8x", C[$c(6*32)+:32]); - $display("0x%8x", D[$c(7*32)+:32]); + i = $c(0*32); $display("0x%8x", C[i+:32]); + i = $c(1*32); $display("0x%8x", D[i+:32]); + i = $c(2*32); $display("0x%8x", C[i+:32]); + i = $c(3*32); $display("0x%8x", D[i+:32]); + i = $c(4*32); $display("0x%8x", C[i+:32]); + i = $c(5*32); $display("0x%8x", D[i+:32]); + i = $c(6*32); $display("0x%8x", C[i+:32]); + i = $c(7*32); $display("0x%8x", D[i+:32]); $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_extract_static_const_multimodule.v b/test_regress/t/t_extract_static_const_multimodule.v index 7885ecb5b..227fdcf1c 100644 --- a/test_regress/t/t_extract_static_const_multimodule.v +++ b/test_regress/t/t_extract_static_const_multimodule.v @@ -25,14 +25,16 @@ module a( 32'h7777_7777, 32'h8888_8888}; + int i; + always @(posedge clk) begin trig_o <= 1'd0; if (trig_i) begin // Note: Base index via $c to prevent optimizatoin by Verilator - $display("0x%8x", C[$c(0*32)+:32]); - $display("0x%8x", C[$c(2*32)+:32]); - $display("0x%8x", C[$c(4*32)+:32]); - $display("0x%8x", C[$c(6*32)+:32]); + i = $c(0*32); $display("0x%8x", C[i+:32]); + i = $c(2*32); $display("0x%8x", C[i+:32]); + i = $c(4*32); $display("0x%8x", C[i+:32]); + i = $c(6*32); $display("0x%8x", C[i+:32]); $display("0x%32x", C); trig_o <= 1'd1; end @@ -57,14 +59,16 @@ module b( 32'h7777_7777, 32'h8888_8888}; + int i; + always @(posedge clk) begin trig_o <= 1'd0; if (trig_i) begin // Note: Base index via $c to prevent optimizatoin by Verilator - $display("0x%8x", C[$c(1*32)+:32]); - $display("0x%8x", C[$c(3*32)+:32]); - $display("0x%8x", C[$c(5*32)+:32]); - $display("0x%8x", C[$c(7*32)+:32]); + i = $c(1*32); $display("0x%8x", C[i+:32]); + i = $c(3*32); $display("0x%8x", C[i+:32]); + i = $c(5*32); $display("0x%8x", C[i+:32]); + i = $c(7*32); $display("0x%8x", C[i+:32]); $display("0x%32x", C); trig_o <= 1'd1; end diff --git a/test_regress/t/t_flag_prefix.v b/test_regress/t/t_flag_prefix.v index 00634520b..1ee503c93 100644 --- a/test_regress/t/t_flag_prefix.v +++ b/test_regress/t/t_flag_prefix.v @@ -22,12 +22,14 @@ module sub; 32'h7777_7777, 32'h8888_8888}; + int i; + initial begin // Note: Base index via $c to prevent optimization - $display("0x%32x", C[$c(0*32)+:32]); - $display("0x%32x", C[$c(2*32)+:32]); - $display("0x%32x", C[$c(4*32)+:32]); - $display("0x%32x", C[$c(6*32)+:32]); + i = $c(0*32); $display("0x%32x", C[i+:32]); + i = $c(1*32); $display("0x%32x", C[i+:32]); + i = $c(2*32); $display("0x%32x", C[i+:32]); + i = $c(3*32); $display("0x%32x", C[i+:32]); $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_param_array7.v b/test_regress/t/t_param_array7.v index 72380d0a9..d7b167941 100644 --- a/test_regress/t/t_param_array7.v +++ b/test_regress/t/t_param_array7.v @@ -33,24 +33,27 @@ module a parameter s_t p3 [2] = '{'{a: 1, b: 2, c: 3}, '{a: 1, b: 2, c: 3}} ); + + int i; + initial begin // Go via $c to ensure parameters are emitted - if (p0[$c("0")] != 5) $stop; - if (p0[$c("1")] != 6) $stop; - if (p0[$c("2")] != 7) $stop; - if (p0[$c("3")] != 8) $stop; - if (p1[$c("0")] != 9) $stop; - if (p1[$c("1")] != 10) $stop; - if (p1[$c("2")] != 11) $stop; - if (p1[$c("3")] != 12) $stop; - if (p2[$c("0")] != "baz") $stop; - if (p2[$c("1")] != "quux") $stop; - if (p3[$c("0")].a != 100) $stop; - if (p3[$c("0")].b != 200) $stop; - if (p3[$c("0")].c != 300) $stop; - if (p3[$c("1")].a != 1000) $stop; - if (p3[$c("1")].b != 2000) $stop; - if (p3[$c("1")].c != 3000) $stop; + i = $c("0"); if (p0[i] != 5) $stop; + i = $c("1"); if (p0[i] != 6) $stop; + i = $c("2"); if (p0[i] != 7) $stop; + i = $c("3"); if (p0[i] != 8) $stop; + i = $c("0"); if (p1[i] != 9) $stop; + i = $c("1"); if (p1[i] != 10) $stop; + i = $c("2"); if (p1[i] != 11) $stop; + i = $c("3"); if (p1[i] != 12) $stop; + i = $c("0"); if (p2[i] != "baz") $stop; + i = $c("1"); if (p2[i] != "quux") $stop; + i = $c("0"); if (p3[i].a != 100) $stop; + i = $c("0"); if (p3[i].b != 200) $stop; + i = $c("0"); if (p3[i].c != 300) $stop; + i = $c("1"); if (p3[i].a != 1000) $stop; + i = $c("1"); if (p3[i].b != 2000) $stop; + i = $c("1"); if (p3[i].c != 3000) $stop; $write("*-* All Finished *-*\n"); $finish; end From c324895cbcb102d7b47c270333312c066a1fb019 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 1 Sep 2023 19:49:57 -0400 Subject: [PATCH 055/111] Internals: Remove unnecessary cloneTree. --- src/V3Const.cpp | 1 + src/V3LinkInc.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 856a13b57..0771629b4 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -1809,6 +1809,7 @@ private: VL_DO_DANGLING(nodep->deleteTree(), nodep); } void replaceConcatMerge(AstConcat* nodep) { + // {llp OP lrp, rlp OP rrp} => {llp, rlp} OP {lrp, rrp}, where OP = AND/OR/XOR AstNodeBiop* const lp = VN_AS(nodep->lhsp(), NodeBiop); AstNodeBiop* const rp = VN_AS(nodep->rhsp(), NodeBiop); AstNodeExpr* const llp = lp->lhsp()->cloneTree(false); diff --git a/src/V3LinkInc.cpp b/src/V3LinkInc.cpp index eeb339af1..3a6eb7eaf 100644 --- a/src/V3LinkInc.cpp +++ b/src/V3LinkInc.cpp @@ -263,7 +263,7 @@ private: return; } AstNodeExpr* const readp = nodep->rhsp(); - AstNodeExpr* const writep = nodep->thsp(); + AstNodeExpr* const writep = nodep->thsp()->unlinkFrBack(); AstConst* const constp = VN_AS(nodep->lhsp(), Const); UASSERT_OBJ(nodep, constp, "Expecting CONST"); @@ -295,8 +295,8 @@ private: = new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE}, operp}; insertNextToStmt(nodep, assignp); // Immediately after incrementing - assign it to the original variable - assignp->addNextHere(new AstAssign{fl, writep->cloneTree(true), - new AstVarRef{fl, varp, VAccess::READ}}); + assignp->addNextHere( + new AstAssign{fl, writep, new AstVarRef{fl, varp, VAccess::READ}}); } else { // PostAdd/PostSub operations // Assign the original variable to the temporary one @@ -304,7 +304,7 @@ private: readp->cloneTree(true)}; insertNextToStmt(nodep, assignp); // Increment the original variable by one - assignp->addNextHere(new AstAssign{fl, writep->cloneTree(true), operp}); + assignp->addNextHere(new AstAssign{fl, writep, operp}); } // Replace the node with the temporary From ad329612fd834eaa193acfa81f540af175c8ed5d Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 1 Sep 2023 20:13:20 -0400 Subject: [PATCH 056/111] Internals: Remove unnecessary cloneTree. --- src/V3Const.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 0771629b4..ad8795e55 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -1799,7 +1799,7 @@ private: UASSERT_OBJ((rstart + rwidth) == lstart, nodep, "tried to merge two selects which are not adjacent"); AstSel* const newselp = new AstSel{ - lselp->fromp()->fileline(), rselp->fromp()->cloneTree(false), rstart, lwidth + rwidth}; + lselp->fromp()->fileline(), rselp->fromp()->unlinkFrBack(), rstart, lwidth + rwidth}; UINFO(5, "merged two adjacent sel " << lselp << " and " << rselp << " to one " << newselp << endl); From c8c980c49dbfba7639bd5b4300b5b13e8a007cba Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 2 Sep 2023 08:33:56 -0400 Subject: [PATCH 057/111] Fix mis-warning on #() in classes' own functions. --- Changes | 1 + src/V3LinkDot.cpp | 8 ++++-- test_regress/t/t_class_new_noparen.pl | 21 +++++++++++++++ test_regress/t/t_class_new_noparen.v | 39 +++++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 2 deletions(-) create mode 100755 test_regress/t/t_class_new_noparen.pl create mode 100644 test_regress/t/t_class_new_noparen.v diff --git a/Changes b/Changes index 7dc8d7e66..f70355566 100644 --- a/Changes +++ b/Changes @@ -31,6 +31,7 @@ Verilator 5.015 devel * Fix internal error on real conversion (#4447). [vdhotre-ventana] * Fix lifetime unknown error on enum.name (#4448). [jwoutersymatra] * Fix display %x formatting of real. +* Fix mis-warning on #() in classes' own functions. Verilator 5.014 2023-08-06 diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 3a1819911..afec76e4d 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2905,10 +2905,14 @@ private: UINFO(4, "(Backto) Link ClassOrPackageRef: " << nodep << endl); iterateChildren(nodep); } - if (m_statep->forPrimary() && VN_IS(nodep->classOrPackagep(), Class) && !nodep->paramsp() + AstClass* const refClassp = VN_CAST(nodep->classOrPackagep(), Class); + AstClass* const modClassp = VN_CAST(m_modp, Class); + if (m_statep->forPrimary() && refClassp && !nodep->paramsp() && nodep->classOrPackagep()->hasGParam() // Don't warn on typedefs, which are hard to know if there's a param somewhere buried - && VN_IS(nodep->classOrPackageNodep(), Class)) { + && VN_IS(nodep->classOrPackageNodep(), Class) + // References to class:: within class itself are OK per IEEE (UVM does this) + && modClassp != refClassp) { nodep->v3error("Reference to parameterized class without #() (IEEE 1800-2017 8.25.1)\n" << nodep->warnMore() << "... Suggest use '" << nodep->classOrPackageNodep()->prettyName() << "#()'"); diff --git a/test_regress/t/t_class_new_noparen.pl b/test_regress/t/t_class_new_noparen.pl new file mode 100755 index 000000000..859050d63 --- /dev/null +++ b/test_regress/t/t_class_new_noparen.pl @@ -0,0 +1,21 @@ +#!/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(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_new_noparen.v b/test_regress/t/t_class_new_noparen.v new file mode 100644 index 000000000..17073677b --- /dev/null +++ b/test_regress/t/t_class_new_noparen.v @@ -0,0 +1,39 @@ +// 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 + +class u_object; + string m_name; + function new(string name); + m_name = name; + endfunction +endclass + +class u_cache#(type KEY_T=int, type DATA_T=int) extends u_object; + typedef int unsigned size_t; + int m_max_size; + + extern function new(string name="u_cache", size_t max_size = 256); +endclass + +// #() not required below, see IEEE 1800-2017 8.25.1 +function u_cache::new(string name="u_cache", u_cache::size_t max_size = 256); + super.new(name); + this.m_max_size = max_size; +endfunction + +module t(/*AUTOARG*/); + + u_cache #(real, real) obj; + + initial begin + obj = new("fred", 62); + if (obj.m_name != "fred") $stop; + if (obj.m_max_size != 62) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule From de77f1ee5cee08d3ab8809dccaf12c5676af0af5 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 3 Sep 2023 09:08:43 -0400 Subject: [PATCH 058/111] Improve error that assert-under-assert is unsupported --- src/V3LinkResolve.cpp | 4 ++- test_regress/t/t_cover_assert.out | 5 +++ test_regress/t/t_cover_assert.pl | 20 +++++++++++ test_regress/t/t_cover_assert.v | 46 ++++++++++++++++++++++++++ test_regress/t/t_dist_warn_coverage.pl | 1 - 5 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 test_regress/t/t_cover_assert.out create mode 100755 test_regress/t/t_cover_assert.pl create mode 100644 test_regress/t/t_cover_assert.v diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index 3a917eb02..5ea9726c3 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -89,7 +89,9 @@ private: } } void visit(AstNodeCoverOrAssert* nodep) override { - if (m_assertp) nodep->v3error("Assert not allowed under another assert"); + if (m_assertp) { + nodep->v3warn(E_UNSUPPORTED, "Unsupported: Assert not allowed under another assert"); + } m_assertp = nodep; iterateChildren(nodep); m_assertp = nullptr; diff --git a/test_regress/t/t_cover_assert.out b/test_regress/t/t_cover_assert.out new file mode 100644 index 000000000..d108ec402 --- /dev/null +++ b/test_regress/t/t_cover_assert.out @@ -0,0 +1,5 @@ +%Error-UNSUPPORTED: t/t_cover_assert.v:42:16: Unsupported: Assert not allowed under another assert + 42 | A2: assert (b); + | ^~~~~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error: Exiting due to diff --git a/test_regress/t/t_cover_assert.pl b/test_regress/t/t_cover_assert.pl new file mode 100755 index 000000000..d76b12847 --- /dev/null +++ b/test_regress/t/t_cover_assert.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 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. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +lint( + verilator_flags2 => ["-Wall -Wno-DECLFILENAME --coverage"], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_cover_assert.v b/test_regress/t/t_cover_assert.v new file mode 100644 index 000000000..94ec4456b --- /dev/null +++ b/test_regress/t/t_cover_assert.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, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + integer cyc = 0; + bit a; + bit b; + + // Test loop + always @ (posedge clk) begin + cyc <= cyc + 1; + if (cyc == 0) begin + a <= '0; + b <= '0; + end + else if (cyc == 10) begin + a <= '1; + b <= '1; + end + else if (cyc == 11) begin + a <= '0; + b <= '1; + end + else if (cyc == 99) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + + always_ff @(posedge clk) begin + C1: cover property(a) + begin + // Assert under cover legal in some other simulators + A2: assert (b); + end + end + +endmodule diff --git a/test_regress/t/t_dist_warn_coverage.pl b/test_regress/t/t_dist_warn_coverage.pl index 2889553a5..2a69f2402 100755 --- a/test_regress/t/t_dist_warn_coverage.pl +++ b/test_regress/t/t_dist_warn_coverage.pl @@ -37,7 +37,6 @@ foreach my $s ( '/*verilator sformat*/ can only be applied to last argument of ', 'Argument needed for string.', 'Array initialization has too few elements, need element ', - 'Assert not allowed under another assert', 'Assigned pin is neither input nor output', 'Assignment pattern with no members', 'Attempted parameter setting of non-parameter: Param ', From c65265477f94ee687c41d198c655a36133d07812 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 3 Sep 2023 21:02:42 -0400 Subject: [PATCH 059/111] Tests: Enable cover named property --- src/V3AstNodeExpr.h | 4 +++- test_regress/t/t_assert_cover.v | 7 ++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 648779532..ed2e771bd 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -1317,7 +1317,9 @@ public: bool cleanOut() const override { return true; } }; class AstImplication final : public AstNodeExpr { - // Verilog |-> |=> + // Verilog Implication Operator + // Nonoverlapping "|=>" + // Overlapping "|->" (doesn't currently use this - might make new Ast type) // @astgen op1 := lhsp : AstNodeExpr // @astgen op2 := rhsp : AstNodeExpr // @astgen op3 := sentreep : Optional[AstSenTree] diff --git a/test_regress/t/t_assert_cover.v b/test_regress/t/t_assert_cover.v index 26a51005a..fe4b6d93d 100644 --- a/test_regress/t/t_assert_cover.v +++ b/test_regress/t/t_assert_cover.v @@ -94,7 +94,6 @@ module Test end endgenerate -`ifndef verilator // Unsupported //============================================================ // Using a more complicated property property C1; @@ -104,6 +103,8 @@ module Test endproperty cover property (C1) $display("*COVER: Cyc==5"); +`ifndef verilator // Unsupported + //============================================================ // Using covergroup // Note a covergroup is really inheritance of a special system "covergroup" class. covergroup counter1 @ (posedge cyc); @@ -131,9 +132,9 @@ module Test // option.at_least = {number}; // Default 1 - Hits to be considered covered // option.auto_bin_max = {number}; // Default 64 - // option.comment = {string} + // option.comment = {string}; // Default "" // option.goal = {number}; // Default 90% - // option.name = {string} + // option.name = {string}; // Default "" // option.per_instance = 1; // Default 0 - each instance separately counted (cadence default is 1) // option.weight = {number}; // Default 1 From 6cdf8da3f7274a664b7956cd0b18c41c13109982 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 5 Sep 2023 07:25:33 -0400 Subject: [PATCH 060/111] Fix documentation line wrap (#4456) --- docs/guide/exe_verilator.rst | 54 +++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/docs/guide/exe_verilator.rst b/docs/guide/exe_verilator.rst index 99c4bd0ec..644d11557 100644 --- a/docs/guide/exe_verilator.rst +++ b/docs/guide/exe_verilator.rst @@ -1538,13 +1538,15 @@ Summary: .. option:: -Wno-lint - Disable all lint-related warning messages, and all style warnings. This is - equivalent to ``-Wno-ALWCOMBORDER -Wno-ASCRANGE -Wno-BSSPACE -Wno-CASEINCOMPLETE - -Wno-CASEOVERLAP -Wno-CASEX -Wno-CASTCONST -Wno-CASEWITHX -Wno-CMPCONST -Wno-COLONPLUS - -Wno-IMPLICIT -Wno-IMPLICITSTATIC -Wno-PINCONNECTEMPTY - -Wno-PINMISSING -Wno-STATICVAR -Wno-SYNCASYNCNET -Wno-UNDRIVEN -Wno-UNSIGNED - -Wno-UNUSEDGENVAR -Wno-UNUSEDPARAM -Wno-UNUSEDSIGNAL - -Wno-WIDTH`` plus the list shown for Wno-style. + Disable all lint-related warning messages, and all style warnings. This + is equivalent to ``-Wno-ALWCOMBORDER`` ``-Wno-ASCRANGE`` + ``-Wno-BSSPACE`` ``-Wno-CASEINCOMPLETE`` ``-Wno-CASEOVERLAP`` + ``-Wno-CASEX`` ``-Wno-CASTCONST`` ``-Wno-CASEWITHX`` ``-Wno-CMPCONST`` + ``-Wno-COLONPLUS`` ``-Wno-IMPLICIT`` ``-Wno-IMPLICITSTATIC`` + ``-Wno-PINCONNECTEMPTY`` ``-Wno-PINMISSING`` ``-Wno-STATICVAR`` + ``-Wno-SYNCASYNCNET`` ``-Wno-UNDRIVEN`` ``-Wno-UNSIGNED`` + ``-Wno-UNUSEDGENVAR`` ``-Wno-UNUSEDPARAM`` ``-Wno-UNUSEDSIGNAL`` + ``-Wno-WIDTH``, plus the list shown for :vlopt:`-Wno-style`. It is strongly recommended that you clean up your code rather than using this option; it is only intended to be used when running test-cases of code @@ -1552,12 +1554,13 @@ Summary: .. option:: -Wno-style - Disable all code style related warning messages (note that by default, they are - already disabled). This is equivalent to ``-Wno-DECLFILENAME -Wno-DEFPARAM - -Wno-EOFNEWLINE -Wno-GENUNNAMED -Wno-IMPORTSTAR -Wno-INCABSPATH -Wno-PINCONNECTEMPTY - -Wno-PINNOCONNECT -Wno-SYNCASYNCNET -Wno-UNDRIVEN - -Wno-UNUSEDGENVAR -Wno-UNUSEDPARAM -Wno-UNUSEDSIGNAL - -Wno-VARHIDDEN``. + Disable all code style related warning messages (note that by default, + they are already disabled). This is equivalent to ``-Wno-DECLFILENAME`` + ``-Wno-DEFPARAM`` ``-Wno-EOFNEWLINE`` ``-Wno-GENUNNAMED`` + ``-Wno-IMPORTSTAR`` ``-Wno-INCABSPATH`` ``-Wno-PINCONNECTEMPTY`` + ``-Wno-PINNOCONNECT`` ``-Wno-SYNCASYNCNET`` ``-Wno-UNDRIVEN`` + ``-Wno-UNUSEDGENVAR`` ``-Wno-UNUSEDPARAM`` ``-Wno-UNUSEDSIGNAL`` + ``-Wno-VARHIDDEN``. .. option:: -Wpedantic @@ -1575,20 +1578,25 @@ Summary: .. option:: -Wwarn-lint - Enable all lint-related warning messages (note that by default, they are already - enabled), but do not affect style messages. This is equivalent to - ``-Wwarn-ALWCOMBORDER -Wwarn-ASCRANGE -Wwarn-BSSPACE -Wwarn-CASEINCOMPLETE - -Wwarn-CASEOVERLAP -Wwarn-CASEWITHX -Wwarn-CASEX -Wwarn-CASTCONST -Wwarn-CMPCONST - -Wwarn-COLONPLUS -Wwarn-IMPLICIT -Wwarn-IMPLICITSTATIC -Wwarn-LATCH -Wwarn-MISINDENT - -Wwarn-NEWERSTD -Wwarn-PINMISSING -Wwarn-REALCVT -Wwarn-STATICVAR -Wwarn-UNSIGNED - -Wwarn-WIDTHTRUNC -Wwarn-WIDTHEXPAND -Wwarn-WIDTHXZEXPAND``. + Enable all lint-related warning messages (note that by default, they are + already enabled), but do not affect style messages. This is equivalent + to ``-Wwarn-ALWCOMBORDER`` ``-Wwarn-ASCRANGE`` ``-Wwarn-BSSPACE`` + ``-Wwarn-CASEINCOMPLETE`` ``-Wwarn-CASEOVERLAP`` ``-Wwarn-CASEWITHX`` + ``-Wwarn-CASEX`` ``-Wwarn-CASTCONST`` ``-Wwarn-CMPCONST`` + ``-Wwarn-COLONPLUS`` ``-Wwarn-IMPLICIT`` ``-Wwarn-IMPLICITSTATIC`` + ``-Wwarn-LATCH`` ``-Wwarn-MISINDENT`` ``-Wwarn-NEWERSTD`` + ``-Wwarn-PINMISSING`` ``-Wwarn-REALCVT`` ``-Wwarn-STATICVAR`` + ``-Wwarn-UNSIGNED`` ``-Wwarn-WIDTHTRUNC`` ``-Wwarn-WIDTHEXPAND`` + ``-Wwarn-WIDTHXZEXPAND``. .. option:: -Wwarn-style Enable all code style-related warning messages. This is equivalent to - ``-Wwarn ASSIGNDLY -Wwarn-DECLFILENAME -Wwarn-DEFPARAM -Wwarn-EOFNEWLINE - -Wwarn-GENUNNAMED -Wwarn-INCABSPATH -Wwarn-PINNOCONNECT -Wwarn-SYNCASYNCNET -Wwarn-UNDRIVEN - -Wwarn-UNUSEDGENVAR -Wwarn-UNUSEDPARAM -Wwarn-UNUSEDSIGNAL -Wwarn-VARHIDDEN``. + ``-Wwarn-ASSIGNDLY`` ``-Wwarn-DECLFILENAME`` ``-Wwarn-DEFPARAM`` + ``-Wwarn-EOFNEWLINE`` ``-Wwarn-GENUNNAMED`` ``-Wwarn-INCABSPATH`` + ``-Wwarn-PINNOCONNECT`` ``-Wwarn-SYNCASYNCNET`` ``-Wwarn-UNDRIVEN`` + ``-Wwarn-UNUSEDGENVAR`` ``-Wwarn-UNUSEDPARAM`` ``-Wwarn-UNUSEDSIGNAL`` + ``-Wwarn-VARHIDDEN``. .. option:: --x-assign 0 From c40e34b1340c27f8ba8c45246bc317c06733635e Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Wed, 6 Sep 2023 15:25:48 +0200 Subject: [PATCH 061/111] Support assignments of stream expressions on queues to packed values (#4458) --- include/verilated_funcs.h | 14 ++++++++ src/V3AstNodeExpr.h | 14 ++++++++ src/V3Const.cpp | 36 +++++++++++++------ src/V3EmitCFunc.h | 13 +++++++ test_regress/t/t_stream_dynamic.v | 20 +++++++++++ .../t/t_stream_dynamic_wide_unsup.out | 10 ++++++ test_regress/t/t_stream_dynamic_wide_unsup.pl | 19 ++++++++++ test_regress/t/t_stream_dynamic_wide_unsup.v | 23 ++++++++++++ 8 files changed, 139 insertions(+), 10 deletions(-) create mode 100644 test_regress/t/t_stream_dynamic_wide_unsup.out create mode 100755 test_regress/t/t_stream_dynamic_wide_unsup.pl create mode 100644 test_regress/t/t_stream_dynamic_wide_unsup.v diff --git a/include/verilated_funcs.h b/include/verilated_funcs.h index 98e14738a..a33b9023b 100644 --- a/include/verilated_funcs.h +++ b/include/verilated_funcs.h @@ -1534,6 +1534,20 @@ static inline void VL_ASSIGN_DYN_Q(VlQueue& q, int elem_size, int lbits, QDat for (int i = 0; i < size; ++i) q.at(i) = (T)((from >> (i * elem_size)) & mask); } +template +static inline IData VL_DYN_TO_I(const VlQueue& q, int elem_size) { + IData ret = 0; + for (int i = 0; i < q.size(); ++i) ret |= q.at(i) << (i * elem_size); + return ret; +} + +template +static inline QData VL_DYN_TO_Q(const VlQueue& q, int elem_size) { + QData ret = 0; + for (int i = 0; i < q.size(); ++i) ret |= q.at(i) << (i * elem_size); + return ret; +} + // Because concats are common and wide, it's valuable to always have a clean output. // Thus we specify inputs must be clean, so we don't need to clean the output. // Note the bit shifts are always constants, so the adds in these constify out. diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index ed2e771bd..75694f61d 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -1013,6 +1013,20 @@ public: // May return nullptr on parse failure. static AstConst* parseParamLiteral(FileLine* fl, const string& literal); }; +class AstCvtDynArrayToPacked final : public AstNodeExpr { + // Cast from dynamic queue data type to packed array + // @astgen op1 := fromp : AstNodeExpr +public: + AstCvtDynArrayToPacked(FileLine* fl, AstNodeExpr* fromp, AstNodeDType* dtp) + : ASTGEN_SUPER_CvtDynArrayToPacked(fl) { + this->fromp(fromp); + dtypeFrom(dtp); + } + ASTGEN_MEMBERS_AstCvtDynArrayToPacked; + string emitVerilog() override { V3ERROR_NA_RETURN(""); } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return true; } +}; class AstCvtPackedToDynArray final : public AstNodeExpr { // Cast from packed array to dynamic queue data type // @astgen op1 := fromp : AstNodeExpr diff --git a/src/V3Const.cpp b/src/V3Const.cpp index ad8795e55..f43f31afe 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -2146,14 +2146,19 @@ private: return true; } else if (m_doV && VN_IS(nodep->rhsp(), StreamR)) { // The right-streaming operator on rhs of assignment does not - // change the order of bits. Eliminate stream but keep its lhsp - // Unlink the stuff - AstNodeExpr* const srcp = VN_AS(nodep->rhsp(), StreamR)->lhsp()->unlinkFrBack(); - AstNode* const sizep = VN_AS(nodep->rhsp(), StreamR)->rhsp()->unlinkFrBack(); - AstNodeExpr* const streamp = VN_AS(nodep->rhsp(), StreamR)->unlinkFrBack(); + // change the order of bits. Eliminate stream but keep its lhsp. + // Add a cast if needed. + AstStreamR* const streamp = VN_AS(nodep->rhsp(), StreamR)->unlinkFrBack(); + AstNodeExpr* srcp = streamp->lhsp()->unlinkFrBack(); + AstNodeDType* const srcDTypep = srcp->dtypep(); + if (VN_IS(srcDTypep, QueueDType) || VN_IS(srcDTypep, DynArrayDType)) { + if (nodep->lhsp()->widthMin() > 64) { + nodep->v3warn(E_UNSUPPORTED, "Unsupported: Assignment of stream of dynamic " + "array to a variable of size greater than 64"); + } + srcp = new AstCvtDynArrayToPacked{srcp->fileline(), srcp, srcDTypep}; + } nodep->rhsp(srcp); - // Cleanup - VL_DO_DANGLING(sizep->deleteTree(), sizep); VL_DO_DANGLING(streamp->deleteTree(), streamp); // Further reduce, any of the nodes may have more reductions. return true; @@ -2186,7 +2191,6 @@ private: // then we select bits from the left-most, not the right-most. AstNodeExpr* const streamp = nodep->lhsp()->unlinkFrBack(); AstNodeExpr* const dstp = VN_AS(streamp, StreamR)->lhsp()->unlinkFrBack(); - AstNode* const sizep = VN_AS(streamp, StreamR)->rhsp()->unlinkFrBack(); AstNodeExpr* srcp = nodep->rhsp()->unlinkFrBack(); const int sWidth = srcp->width(); const int dWidth = dstp->width(); @@ -2197,11 +2201,23 @@ private: } nodep->lhsp(dstp); nodep->rhsp(srcp); - // Cleanup - VL_DO_DANGLING(sizep->deleteTree(), sizep); VL_DO_DANGLING(streamp->deleteTree(), streamp); // Further reduce, any of the nodes may have more reductions. return true; + } else if (m_doV && VN_IS(nodep->rhsp(), StreamL)) { + AstNodeDType* const lhsDtypep = nodep->lhsp()->dtypep(); + AstStreamL* streamp = VN_AS(nodep->rhsp(), StreamL); + AstNodeExpr* const srcp = streamp->lhsp(); + const AstNodeDType* const srcDTypep = srcp->dtypep(); + if (VN_IS(srcDTypep, QueueDType) || VN_IS(srcDTypep, DynArrayDType)) { + if (lhsDtypep->widthMin() > 64) { + nodep->v3warn(E_UNSUPPORTED, "Unsupported: Assignment of stream of dynamic " + "array to a variable of size greater than 64"); + } + srcp->unlinkFrBack(); + streamp->lhsp(new AstCvtDynArrayToPacked{srcp->fileline(), srcp, lhsDtypep}); + streamp->dtypeFrom(lhsDtypep); + } } else if (m_doV && replaceAssignMultiSel(nodep)) { return true; } diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index 459618ff7..a1c1cd515 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -345,6 +345,19 @@ public: emitVarDecl(nodep); } + void visit(AstCvtDynArrayToPacked* nodep) override { + puts("VL_DYN_TO_"); + emitIQW(nodep); + puts("<"); + const AstNodeDType* const elemDTypep = nodep->fromp()->dtypep()->subDTypep(); + putbs(elemDTypep->cType("", false, false)); + puts(">("); + iterateAndNextConstNull(nodep->fromp()); + puts(", "); + puts(cvtToStr(elemDTypep->widthMin())); + puts(")"); + } + void visit(AstNodeAssign* nodep) override { bool paren = true; bool decind = false; diff --git a/test_regress/t/t_stream_dynamic.v b/test_regress/t/t_stream_dynamic.v index 60c127bef..0c02f1db8 100644 --- a/test_regress/t/t_stream_dynamic.v +++ b/test_regress/t/t_stream_dynamic.v @@ -5,6 +5,7 @@ // SPDX-License-Identifier: CC0-1.0 `define stop $stop +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); `define checks(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); module t (/*AUTOARG*/); @@ -15,25 +16,44 @@ module t (/*AUTOARG*/); bit [5:0] arr6[$]; string v; bit [5:0] bit6 = 6'b111000; + bit [5:0] ans; { >> bit {arr}} = bit6; v = $sformatf("%p", arr); `checks(v, "'{'h0, 'h0, 'h0, 'h1, 'h1, 'h1} "); + ans = { >> bit {arr} }; + `checkh(ans, bit6); + { << bit {arr}} = bit6; v = $sformatf("%p", arr); `checks(v, "'{'h1, 'h1, 'h1, 'h0, 'h0, 'h0} "); + ans = { << bit {arr} }; + `checkh(ans, bit6); + { >> bit[1:0] {arr2}} = bit6; v = $sformatf("%p", arr2); `checks(v, "'{'h0, 'h2, 'h3} "); + ans = { >> bit[1:0] {arr2} }; + `checkh(ans, bit6); + { << bit[1:0] {arr2}} = bit6; v = $sformatf("%p", arr2); `checks(v, "'{'h3, 'h2, 'h0} "); + ans = { << bit[1:0] {arr2} }; + `checkh(ans, bit6); + { >> bit [5:0] {arr6} } = bit6; v = $sformatf("%p", arr6); `checks(v, "'{'h38} "); + ans = { >> bit[5:0] {arr6} }; + `checkh(ans, bit6); + { << bit [5:0] {arr6} } = bit6; v = $sformatf("%p", arr6); `checks(v, "'{'h38} "); + ans = { << bit[5:0] {arr6} }; + `checkh(ans, bit6); + $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_stream_dynamic_wide_unsup.out b/test_regress/t/t_stream_dynamic_wide_unsup.out new file mode 100644 index 000000000..6ddca3aaf --- /dev/null +++ b/test_regress/t/t_stream_dynamic_wide_unsup.out @@ -0,0 +1,10 @@ +%Error-UNSUPPORTED: t/t_stream_dynamic_wide_unsup.v:15:14: Unsupported: Assignment of stream of dynamic array to a variable of size greater than 64 + : ... In instance t + 15 | bit100 = { >> bit {arr} }; + | ^ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error-UNSUPPORTED: t/t_stream_dynamic_wide_unsup.v:17:14: Unsupported: Assignment of stream of dynamic array to a variable of size greater than 64 + : ... In instance t + 17 | bit100 = { << bit {arr} }; + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_stream_dynamic_wide_unsup.pl b/test_regress/t/t_stream_dynamic_wide_unsup.pl new file mode 100755 index 000000000..7be596e0f --- /dev/null +++ b/test_regress/t/t_stream_dynamic_wide_unsup.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 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( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_stream_dynamic_wide_unsup.v b/test_regress/t/t_stream_dynamic_wide_unsup.v new file mode 100644 index 000000000..a9860f430 --- /dev/null +++ b/test_regress/t/t_stream_dynamic_wide_unsup.v @@ -0,0 +1,23 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +`define stop $stop +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); + +module t (/*AUTOARG*/); + initial begin + bit[3:0] arr[] = '{25{4'b1000}}; + bit [99:0] bit100; + + bit100 = { >> bit {arr} }; + `checkh(bit100[3:0], 4'b1000); + bit100 = { << bit {arr} }; + `checkh(bit100[3:0], 4'b0001); + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule From 0c7d48541713ab0a1a6e4f886a71eea070e0c295 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 6 Sep 2023 21:07:06 -0400 Subject: [PATCH 062/111] Fix error printing internal name() --- src/V3Width.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 0d5e5696d..f947d720e 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -6605,8 +6605,8 @@ private: if (VN_IS(underp, NodeDType)) { // Note the node itself, not node's data type // Must be near top of these checks as underp->dtypep() will look normal underp->v3error(ucfirst(nodep->prettyOperatorName()) - << " expected non-datatype " << side << " but '" << underp->name() - << "' is a datatype."); + << " expected non-datatype " << side << " but " + << underp->prettyNameQ() << " is a datatype."); } else if (expDTypep == underp->dtypep()) { // Perfect underp = userIterateSubtreeReturnEdits(underp, WidthVP{expDTypep, FINAL}.p()); } else if (expDTypep->isDouble() && underp->isDouble()) { // Also good @@ -6674,8 +6674,8 @@ private: } else if (!VN_IS(expDTypep->skipRefp(), IfaceRefDType) && VN_IS(underp->dtypep()->skipRefp(), IfaceRefDType)) { underp->v3error(ucfirst(nodep->prettyOperatorName()) - << " expected non-interface on " << side << " but '" - << underp->name() << "' is an interface."); + << " expected non-interface on " << side << " but " + << underp->prettyNameQ() << " is an interface."); } else if (const AstIfaceRefDType* expIfaceRefp = VN_CAST(expDTypep->skipRefp(), IfaceRefDType)) { const AstIfaceRefDType* underIfaceRefp @@ -6688,8 +6688,8 @@ private: } else if (expIfaceRefp->ifaceViaCellp() != underIfaceRefp->ifaceViaCellp()) { underp->v3error(ucfirst(nodep->prettyOperatorName()) << " expected " << expIfaceRefp->ifaceViaCellp()->prettyNameQ() - << " interface on " << side << " but '" << underp->name() - << "' is a different interface (" + << " interface on " << side << " but " << underp->prettyNameQ() + << " is a different interface (" << underIfaceRefp->ifaceViaCellp()->prettyNameQ() << ")."); } else if (underIfaceRefp->modportp() && expIfaceRefp->modportp() != underIfaceRefp->modportp()) { From 11b5dae88d735cacc23cbec5f7305267973f3c62 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 7 Sep 2023 21:45:51 -0400 Subject: [PATCH 063/111] Support let --- Changes | 1 + src/V3AstNodeOther.h | 14 +++++ src/V3LinkDot.cpp | 2 +- src/V3LinkResolve.cpp | 52 ++++++++++++++++++- src/verilog.y | 49 +++++++++++------ test_regress/t/t_let.out | 41 --------------- test_regress/t/t_let.pl | 8 ++- test_regress/t/t_let.v | 11 ++-- test_regress/t/t_let_arg_bad.out | 19 +++++++ .../t/{t_let_bad.pl => t_let_arg_bad.pl} | 0 test_regress/t/t_let_arg_bad.v | 22 ++++++++ test_regress/t/t_let_bad.out | 11 ---- test_regress/t/t_let_recurse_bad.out | 4 ++ test_regress/t/t_let_recurse_bad.pl | 19 +++++++ .../t/{t_let_bad.v => t_let_recurse_bad.v} | 7 +-- test_regress/t/t_let_side.pl | 21 ++++++++ test_regress/t/t_let_side.v | 29 +++++++++++ test_regress/t/t_let_unsup.out | 8 +++ test_regress/t/t_let_unsup.pl | 19 +++++++ test_regress/t/t_let_unsup.v | 21 ++++++++ 20 files changed, 275 insertions(+), 83 deletions(-) delete mode 100644 test_regress/t/t_let.out create mode 100644 test_regress/t/t_let_arg_bad.out rename test_regress/t/{t_let_bad.pl => t_let_arg_bad.pl} (100%) create mode 100644 test_regress/t/t_let_arg_bad.v delete mode 100644 test_regress/t/t_let_bad.out create mode 100644 test_regress/t/t_let_recurse_bad.out create mode 100755 test_regress/t/t_let_recurse_bad.pl rename test_regress/t/{t_let_bad.v => t_let_recurse_bad.v} (65%) create mode 100755 test_regress/t/t_let_side.pl create mode 100644 test_regress/t/t_let_side.v create mode 100644 test_regress/t/t_let_unsup.out create mode 100755 test_regress/t/t_let_unsup.pl create mode 100644 test_regress/t/t_let_unsup.v diff --git a/Changes b/Changes index f70355566..7106cfbb9 100644 --- a/Changes +++ b/Changes @@ -16,6 +16,7 @@ Verilator 5.015 devel * Add --no-trace-top to not trace top signals (#4412) (#4422). [Frans Skarman] * Support assignments of packed values to stream expressions on queues (#4401). [Ryszard Rozak, Antmicro Ltd] * Support no-parentheses calls to static methods (#4432). [Krzysztof Boroński] +* Support 'let'. * Fix Windows filename format, etc (#3873) (#4421). [Anthony Donlon]. * Fix data type of condition operation on class objects (#4345) (#4352). [Ryszard Rozak, Antmicro Ltd] * Fix ++/-- under statements (#4399). [Aleksander Kiryk, Antmicro Ltd] diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index 7e7199427..e3535c806 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -2093,6 +2093,20 @@ public: ASTGEN_MEMBERS_AstFunc; bool hasDType() const override { return true; } }; +class AstLet final : public AstNodeFTask { + // Verilog "let" statement + // Parents: MODULE + // stmtp is always a StmtExpr as Let always returns AstNodeExpr +public: + AstLet(FileLine* fl, const string& name) + : ASTGEN_SUPER_Let(fl, name, nullptr) {} + ASTGEN_MEMBERS_AstLet; + bool hasDType() const override { return true; } + const char* broken() const override { + BROKEN_RTN(!VN_IS(stmtsp(), StmtExpr)); + return nullptr; + } +}; class AstProperty final : public AstNodeFTask { // A property inside a module public: diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index afec76e4d..f376457f0 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -1121,9 +1121,9 @@ class LinkDotFindVisitor final : public VNVisitor { m_statep->insertSym(m_curSymp, newvarp->name(), newvarp, nullptr /*classOrPackagep*/); } + VL_RESTORER(m_ftaskp); m_ftaskp = nodep; iterateChildren(nodep); - m_ftaskp = nullptr; } } void visit(AstClocking* nodep) override { diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index 5ea9726c3..187d84028 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -32,6 +32,7 @@ #include "V3Ast.h" #include "V3Global.h" #include "V3String.h" +#include "V3Task.h" #include #include @@ -45,7 +46,8 @@ class LinkResolveVisitor final : public VNVisitor { private: // NODE STATE // Entire netlist: - // AstCaseItem::user2() // bool Moved default caseitems + // AstCaseItem::user2() // bool Moved default caseitems + // AstNodeFTaskRef::user2() // bool Processing - to check for recursion const VNUser2InUse m_inuser2; // STATE @@ -113,6 +115,7 @@ private: } void visit(AstNodeFTask* nodep) override { + // Note AstLet is handled specifically elsewhere // NodeTask: Remember its name for later resolution if (m_underGenerate) nodep->underGenerate(true); // Remember the existing symbol table scope @@ -140,6 +143,47 @@ private: } void visit(AstNodeFTaskRef* nodep) override { iterateChildren(nodep); + if (AstLet* letp = VN_CAST(nodep->taskp(), Let)) { + UINFO(7, "letSubstitute() " << nodep << " <- " << letp << endl); + if (letp->user2()) { + nodep->v3error("Recursive let substitution " << letp->prettyNameQ()); + nodep->replaceWith(new AstConst{nodep->fileline(), AstConst::BitFalse{}}); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + return; + } + letp->user2(true); + // letp->dumpTree("-let-let "); + // nodep->dumpTree("-let-ref "); + AstStmtExpr* const letStmtp = VN_AS(letp->stmtsp(), StmtExpr); + AstNodeExpr* const newp = letStmtp->exprp()->cloneTree(false); + const V3TaskConnects tconnects = V3Task::taskConnects(nodep, letp->stmtsp()); + std::map portToExprs; + for (const auto& tconnect : tconnects) { + const AstVar* const portp = tconnect.first; + const AstArg* const argp = tconnect.second; + AstNodeExpr* const pinp = argp->exprp(); + if (!pinp) continue; // Argument error we'll find later + portToExprs.emplace(portp, pinp); + } + // Replace VarRefs of arguments with the argument values + newp->foreach([&](AstVarRef* refp) { // + const auto it = portToExprs.find(refp->varp()); + if (it != portToExprs.end()) { + AstNodeExpr* const pinp = it->second; + UINFO(9, "let pin subst " << refp << " <- " << pinp << endl); + // Side effects are copied into pins, to match other simulators + refp->replaceWith(pinp->cloneTree(false)); + VL_DO_DANGLING(pushDeletep(refp), refp); + } + }); + // newp->dumpTree("-let-new "); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + // Iterate to expand further now, so we can look for recursions + visit(newp); + letp->user2(false); + return; + } if (nodep->taskp() && (nodep->taskp()->dpiContext() || nodep->taskp()->dpiExport())) { nodep->scopeNamep(new AstScopeName{nodep->fileline(), false}); } @@ -170,6 +214,12 @@ private: } } + void visit(AstLet* nodep) override { + // Lets have been (or about to be) substituted, we can remove + nodep->unlinkFrBack(); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } + void visit(AstPragma* nodep) override { if (nodep->pragType() == VPragmaType::HIER_BLOCK) { UASSERT_OBJ(m_modp, nodep, "HIER_BLOCK not under a module"); diff --git a/src/verilog.y b/src/verilog.y index 4e31cb1b0..507c3020d 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -5176,29 +5176,31 @@ stream_expressionOrDataType: // IEEE: from streaming_concatenation //************************************************ // Let -letId: // IEEE: pert of let_declaration +letId: // IEEE: pert of let_declaration idAny/*let_identifieer*/ { $$ = $1; $$ = nullptr; - // No unsupported message as caller has one, for now just use a func - $$ = new AstFunc{$$, *$1, nullptr, nullptr}; + $$ = new AstLet{$$, *$1}; SYMP->pushNewUnderNodeOrCurrent($$, $$); } ; -let_declaration: // IEEE: let_declaration +let_declaration: // IEEE: let_declaration yLET letId '=' expr ';' - { $$ = nullptr; - SYMP->popScope($2); - BBUNSUP($1, "Unsupported: let"); } + { $$ = $2; + $$->addStmtsp(new AstStmtExpr{$1, $4}); + SYMP->popScope($2); } | yLET letId '(' let_port_listE ')' '=' expr ';' - { $$ = nullptr; - SYMP->popScope($2); - BBUNSUP($1, "Unsupported: let"); } + { $$ = $2; + $$->addStmtsp(new AstStmtExpr{$1, $7}); + $$->addStmtsp($4); + SYMP->popScope($2); } ; let_port_listE: // IEEE: [ let_port_list ] /*empty*/ { $$ = nullptr; } - | let_port_list { $$ = $1; } + | /*emptyStart*/ + /*mid*/ { VARRESET_LIST(UNKNOWN); VARIO(INOUT); } + /*cont*/ let_port_list { $$ = $2; VARRESET_NONLIST(UNKNOWN); } ; let_port_list: // IEEE: let_port_list @@ -5206,14 +5208,31 @@ let_port_list: // IEEE: let_port_list | let_port_list ',' let_port_item { $$ = addNextNull($1, $3); } ; -let_port_item: // IEEE: let_port_Item +let_port_item: // IEEE: let_port_Item // // IEEE: Expanded let_formal_type yUNTYPED idAny/*formal_port_identifier*/ variable_dimensionListE exprEqE - { $$ = nullptr; BBUNSUP($1, "Unsupported: let untyped ports"); } + { $$ = new AstVar{$2, VVarType::PORT, *$2, VFlagChildDType{}, + new AstBasicDType{$2, LOGIC_IMPLICIT}}; + $$->direction(VDirection::INOUT); + $$->lifetime(VLifetime::AUTOMATIC); + if ($4) $$->valuep($4); + PINNUMINC(); } | data_type id/*formal_port_identifier*/ variable_dimensionListE exprEqE - { $$ = nullptr; BBUNSUP($1, "Unsupported: let ports"); } + { BBUNSUP($1, "Unsupported: let typed ports"); + $$ = new AstVar{$2, VVarType::PORT, *$2, VFlagChildDType{}, + new AstBasicDType{$2, LOGIC_IMPLICIT}}; + $$->direction(VDirection::INOUT); + $$->lifetime(VLifetime::AUTOMATIC); + if ($4) $$->valuep($4); + PINNUMINC(); } | implicit_typeE id/*formal_port_identifier*/ variable_dimensionListE exprEqE - { $$ = nullptr; BBUNSUP($1, "Unsupported: let ports"); } + { if ($1) BBUNSUP($1, "Unsupported: let typed ports"); + $$ = new AstVar{$2, VVarType::PORT, *$2, VFlagChildDType{}, + new AstBasicDType{$2, LOGIC_IMPLICIT}}; + $$->direction(VDirection::INOUT); + $$->lifetime(VLifetime::AUTOMATIC); + if ($4) $$->valuep($4); + PINNUMINC(); } ; //************************************************ diff --git a/test_regress/t/t_let.out b/test_regress/t/t_let.out deleted file mode 100644 index aca0f5993..000000000 --- a/test_regress/t/t_let.out +++ /dev/null @@ -1,41 +0,0 @@ -%Error-UNSUPPORTED: t/t_let.v:8:4: Unsupported: let - 8 | let P = 11; - | ^~~ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error-UNSUPPORTED: t/t_let.v:13:4: Unsupported: let - 13 | let A = 10; - | ^~~ -%Error-UNSUPPORTED: t/t_let.v:14:4: Unsupported: let - 14 | let B() = 20; - | ^~~ -%Error-UNSUPPORTED: t/t_let.v:13:14: Unsupported: let ports - 13 | let A = 10; - | ^ -%Error-UNSUPPORTED: t/t_let.v:15:4: Unsupported: let - 15 | let C(a) = 30 + a; - | ^~~ -%Error-UNSUPPORTED: t/t_let.v:15:13: Unsupported: let ports - 15 | let C(a) = 30 + a; - | ^ -%Error-UNSUPPORTED: t/t_let.v:16:4: Unsupported: let - 16 | let D(a, b) = 30 + a + b; - | ^~~ -%Error-UNSUPPORTED: t/t_let.v:16:16: Unsupported: let ports - 16 | let D(a, b) = 30 + a + b; - | ^ -%Error-UNSUPPORTED: t/t_let.v:17:4: Unsupported: let - 17 | let E(a, b=7) = 30 + a + b; - | ^~~ -%Error-UNSUPPORTED: t/t_let.v:18:10: Unsupported: let untyped ports - 18 | let F(untyped a) = 30 + a; - | ^~~~~~~ -%Error-UNSUPPORTED: t/t_let.v:18:4: Unsupported: let - 18 | let F(untyped a) = 30 + a; - | ^~~ -%Error-UNSUPPORTED: t/t_let.v:19:10: Unsupported: let ports - 19 | let G(int a) = 30 + a; - | ^~~ -%Error-UNSUPPORTED: t/t_let.v:19:4: Unsupported: let - 19 | let G(int a) = 30 + a; - | ^~~ -%Error: Exiting due to diff --git a/test_regress/t/t_let.pl b/test_regress/t/t_let.pl index c18ffc8f0..97d8dcc12 100755 --- a/test_regress/t/t_let.pl +++ b/test_regress/t/t_let.pl @@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); compile( - expect_filename => $Self->{golden_filename}, - fails => 1, ); -#execute( -# check_finished => 1, -# ); +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_let.v b/test_regress/t/t_let.v index b8d010fb3..3eb6a403c 100644 --- a/test_regress/t/t_let.v +++ b/test_regress/t/t_let.v @@ -6,6 +6,7 @@ package Pkg; let P = 11; + let PP(a) = 30 + a; endpackage module t(/*AUTOARG*/); @@ -14,9 +15,8 @@ module t(/*AUTOARG*/); let B() = 20; let C(a) = 30 + a; let D(a, b) = 30 + a + b; - let E(a, b=7) = 30 + a + b; + let E(a=1, b=7) = 30 + a + b; let F(untyped a) = 30 + a; - let G(int a) = 30 + a; initial begin if (A != 10) $stop; @@ -24,11 +24,14 @@ module t(/*AUTOARG*/); if (B != 20) $stop; if (B() != 20) $stop; if (C(1) != (30 + 1)) $stop; + if (C(.a(1)) != (30 + 1)) $stop; if (D(1, 2) != (30 + 1 + 2)) $stop; - if (E(1) != (30 + 1 + 7)) $stop; + if (D(.a(1), .b(2)) != (30 + 1 + 2)) $stop; + if (E(2) != (30 + 2 + 7)) $stop; + if (E(.b(1)) != (30 + 1 + 1)) $stop; if (F(1) != (30 + 1)) $stop; - if (G(1) != (30 + 1)) $stop; if (Pkg::P != 11) $stop; + if (Pkg::PP(6) != (30 + 6)) $stop; $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_let_arg_bad.out b/test_regress/t/t_let_arg_bad.out new file mode 100644 index 000000000..f1d6d297e --- /dev/null +++ b/test_regress/t/t_let_arg_bad.out @@ -0,0 +1,19 @@ +%Error: t/t_let_arg_bad.v:13:18: Too many arguments in function call to LET 'NO_ARG' + 13 | if (NO_ARG(10) != 10) $stop; + | ^~ +%Error: t/t_let_arg_bad.v:14:11: Missing argument on non-defaulted argument 'a' in function call to LET 'ONE_ARG' + 14 | if (ONE_ARG != 10) $stop; + | ^~~~~~~ +%Error: t/t_let_arg_bad.v:15:11: Missing argument on non-defaulted argument 'a' in function call to LET 'ONE_ARG' + 15 | if (ONE_ARG() != 10) $stop; + | ^~~~~~~ +%Error: t/t_let_arg_bad.v:16:23: Too many arguments in function call to LET 'ONE_ARG' + 16 | if (ONE_ARG(10, 20) != 10) $stop; + | ^~ +%Error: t/t_let_arg_bad.v:17:20: No such argument 'b' in function call to LET 'ONE_ARG' + 17 | if (ONE_ARG(.b(1)) != 10) $stop; + | ^ +%Error: t/t_let_arg_bad.v:17:11: Missing argument on non-defaulted argument 'a' in function call to LET 'ONE_ARG' + 17 | if (ONE_ARG(.b(1)) != 10) $stop; + | ^~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_let_bad.pl b/test_regress/t/t_let_arg_bad.pl similarity index 100% rename from test_regress/t/t_let_bad.pl rename to test_regress/t/t_let_arg_bad.pl diff --git a/test_regress/t/t_let_arg_bad.v b/test_regress/t/t_let_arg_bad.v new file mode 100644 index 000000000..6b8781e5d --- /dev/null +++ b/test_regress/t/t_let_arg_bad.v @@ -0,0 +1,22 @@ +// 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 + +module t(/*AUTOARG*/); + + let NO_ARG = 10; + let ONE_ARG(a) = 10; + + initial begin + if (NO_ARG(10) != 10) $stop; // BAD extra arg + if (ONE_ARG != 10) $stop; // BAD need arg + if (ONE_ARG() != 10) $stop; // BAD need arg + if (ONE_ARG(10, 20) != 10) $stop; // BAD extra arg + if (ONE_ARG(.b(1)) != 10) $stop; // BAD wrong arg name + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_let_bad.out b/test_regress/t/t_let_bad.out deleted file mode 100644 index ce76ac770..000000000 --- a/test_regress/t/t_let_bad.out +++ /dev/null @@ -1,11 +0,0 @@ -%Error-UNSUPPORTED: t/t_let_bad.v:9:4: Unsupported: let - 9 | let NO_ARG = 10; - | ^~~ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error-UNSUPPORTED: t/t_let_bad.v:9:19: Unsupported: let ports - 9 | let NO_ARG = 10; - | ^ -%Error-UNSUPPORTED: t/t_let_bad.v:10:4: Unsupported: let - 10 | let ONE_ARG(a) = 10; - | ^~~ -%Error: Exiting due to diff --git a/test_regress/t/t_let_recurse_bad.out b/test_regress/t/t_let_recurse_bad.out new file mode 100644 index 000000000..dfa9fc32b --- /dev/null +++ b/test_regress/t/t_let_recurse_bad.out @@ -0,0 +1,4 @@ +%Error: t/t_let_recurse_bad.v:9:36: Recursive let substitution 'RECURSE' + 9 | let RECURSE(a) = (a == 1) ? 1 : RECURSE(a - 1); + | ^~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_let_recurse_bad.pl b/test_regress/t/t_let_recurse_bad.pl new file mode 100755 index 000000000..882bc2418 --- /dev/null +++ b/test_regress/t/t_let_recurse_bad.pl @@ -0,0 +1,19 @@ +#!/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(linter => 1); + +compile( + expect_filename => $Self->{golden_filename}, + fails => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_let_bad.v b/test_regress/t/t_let_recurse_bad.v similarity index 65% rename from test_regress/t/t_let_bad.v rename to test_regress/t/t_let_recurse_bad.v index 816b46651..47603c7db 100644 --- a/test_regress/t/t_let_bad.v +++ b/test_regress/t/t_let_recurse_bad.v @@ -6,13 +6,10 @@ module t(/*AUTOARG*/); - let NO_ARG = 10; - let ONE_ARG(a) = 10; + let RECURSE(a) = (a == 1) ? 1 : RECURSE(a - 1); // BAD no recursion per IEEE 1800-2017 11.12 initial begin - if (NO_ARG(10) != 10) $stop; // BAD - if (ONE_ARG() != 10) $stop; // BAD - if (ONE_ARG(10, 20) != 10) $stop; // BAD + if (RECURSE(1) != 1) $stop; $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_let_side.pl b/test_regress/t/t_let_side.pl new file mode 100755 index 000000000..97d8dcc12 --- /dev/null +++ b/test_regress/t/t_let_side.pl @@ -0,0 +1,21 @@ +#!/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( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_let_side.v b/test_regress/t/t_let_side.v new file mode 100644 index 000000000..0200da525 --- /dev/null +++ b/test_regress/t/t_let_side.v @@ -0,0 +1,29 @@ +// 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 + +module t(/*AUTOARG*/); + + let F(a) = {a, a, a}; + + function byte g(); + static byte r = 0; + return ++r; + endfunction + + bit [23:0] res; + + initial begin + res = F(g()); + $display("%h", res); + // Commercial1 010101 -- seems wrong by my reading of IEEE but anyhow + // Commercial2/Vlt 010203 + // Commercial3/4 030201 + if (res != 24'h010101 && res != 24'h010203 && res != 24'h030201) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_let_unsup.out b/test_regress/t/t_let_unsup.out new file mode 100644 index 000000000..66e9536c0 --- /dev/null +++ b/test_regress/t/t_let_unsup.out @@ -0,0 +1,8 @@ +%Error-UNSUPPORTED: t/t_let_unsup.v:10:10: Unsupported: let typed ports + 10 | let G(int a) = 30 + a; + | ^~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error-UNSUPPORTED: t/t_let_unsup.v:11:10: Unsupported: let typed ports + 11 | let H(signed a) = 30 + a; + | ^~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_let_unsup.pl b/test_regress/t/t_let_unsup.pl new file mode 100755 index 000000000..882bc2418 --- /dev/null +++ b/test_regress/t/t_let_unsup.pl @@ -0,0 +1,19 @@ +#!/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(linter => 1); + +compile( + expect_filename => $Self->{golden_filename}, + fails => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_let_unsup.v b/test_regress/t/t_let_unsup.v new file mode 100644 index 000000000..2a5859cdc --- /dev/null +++ b/test_regress/t/t_let_unsup.v @@ -0,0 +1,21 @@ +// 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 + +module t(/*AUTOARG*/); + + let F(untyped a) = 30 + a; + let G(int a) = 30 + a; + let H(signed a) = 30 + a; + + initial begin + if (F(1) != (30 + 1)) $stop; + if (G(1) != (30 + 1)) $stop; + if (H(1) != (30 + 1)) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule From 91227d26bb967426b315738996a4c8e89dfc4e97 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Fri, 8 Sep 2023 08:51:19 +0200 Subject: [PATCH 064/111] Internals: Rename pure to dpiPure. No functional change. (#4461) --- src/V3AstNodeOther.h | 20 +++++++++++--------- src/V3AstNodes.cpp | 6 +++--- src/V3Life.cpp | 2 +- src/V3Partition.cpp | 4 ++-- src/V3Task.cpp | 6 +++--- src/verilog.y | 4 ++-- 6 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index e3535c806..db6fd3b14 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -81,7 +81,7 @@ private: bool m_isConstructor : 1; // Class constructor bool m_isHideLocal : 1; // Verilog local bool m_isHideProtected : 1; // Verilog protected - bool m_pure : 1; // DPI import pure (vs. virtual pure) + bool m_dpiPure : 1; // DPI import pure (vs. virtual pure) bool m_pureVirtual : 1; // Pure virtual bool m_recursive : 1; // Recursive or part of recursion bool m_underGenerate : 1; // Under generate (for warning) @@ -107,7 +107,7 @@ protected: , m_isConstructor{false} , m_isHideLocal{false} , m_isHideProtected{false} - , m_pure{false} + , m_dpiPure{false} , m_pureVirtual{false} , m_recursive{false} , m_underGenerate{false} @@ -122,7 +122,9 @@ public: 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; } - bool isGateOptimizable() const override { return !((m_dpiExport || m_dpiImport) && !m_pure); } + bool isGateOptimizable() const override { + return !((m_dpiExport || m_dpiImport) && !m_dpiPure); + } // {AstFunc only} op1 = Range output variable void name(const string& name) override { m_name = name; } string cname() const { return m_cname; } @@ -162,8 +164,8 @@ public: void isHideLocal(bool flag) { m_isHideLocal = flag; } bool isHideProtected() const { return m_isHideProtected; } void isHideProtected(bool flag) { m_isHideProtected = flag; } - void pure(bool flag) { m_pure = flag; } - bool pure() const { return m_pure; } + void dpiPure(bool flag) { m_dpiPure = flag; } + bool dpiPure() const { return m_dpiPure; } void pureVirtual(bool flag) { m_pureVirtual = flag; } bool pureVirtual() const { return m_pureVirtual; } void recursive(bool flag) { m_recursive = flag; } @@ -578,7 +580,7 @@ private: bool m_isInline : 1; // Inline function bool m_isVirtual : 1; // Virtual function bool m_entryPoint : 1; // User may call into this top level function - bool m_pure : 1; // Pure function + bool m_dpiPure : 1; // Pure DPI function bool m_dpiContext : 1; // Declared as 'context' DPI import/export function bool m_dpiExportDispatcher : 1; // This is the DPI export entry point (i.e.: called by user) bool m_dpiExportImpl : 1; // DPI export implementation (called from DPI dispatcher via lookup) @@ -607,7 +609,7 @@ public: m_isVirtual = false; m_needProcess = false; m_entryPoint = false; - m_pure = false; + m_dpiPure = false; m_dpiContext = false; m_dpiExportDispatcher = false; m_dpiExportImpl = false; @@ -678,8 +680,8 @@ public: void setNeedProcess() { m_needProcess = true; } bool entryPoint() const { return m_entryPoint; } void entryPoint(bool flag) { m_entryPoint = flag; } - bool pure() const { return m_pure; } - void pure(bool flag) { m_pure = flag; } + bool dpiPure() const { return m_dpiPure; } + void dpiPure(bool flag) { m_dpiPure = flag; } bool dpiContext() const { return m_dpiContext; } void dpiContext(bool flag) { m_dpiContext = flag; } bool dpiExportDispatcher() const VL_MT_SAFE { return m_dpiExportDispatcher; } diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 704932733..65eed3af0 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -64,7 +64,7 @@ void AstNodeFTaskRef::cloneRelink() { bool AstNodeFTaskRef::isPure() const { // TODO: For non-DPI functions we could traverse the AST of function's body to determine // pureness. - return this->taskp() && this->taskp()->dpiImport() && this->taskp()->pure(); + return this->taskp() && this->taskp()->dpiImport() && this->taskp()->dpiPure(); } bool AstNodeFTaskRef::isGateOptimizable() const { return m_taskp && m_taskp->isGateOptimizable(); } @@ -127,7 +127,7 @@ const char* AstNodeCCall::broken() const { BROKEN_RTN(m_funcp && !m_funcp->brokeExists()); return nullptr; } -bool AstNodeCCall::isPure() const { return funcp()->pure(); } +bool AstNodeCCall::isPure() const { return funcp()->dpiPure(); } string AstCCall::selfPointerProtect(bool useSelfForThis) const { const string& sp @@ -2299,7 +2299,7 @@ void AstCFile::dump(std::ostream& str) const { void AstCFunc::dump(std::ostream& str) const { this->AstNode::dump(str); if (slow()) str << " [SLOW]"; - if (pure()) str << " [PURE]"; + if (dpiPure()) str << " [DPIPURE]"; if (isStatic()) str << " [STATIC]"; if (dpiExportDispatcher()) str << " [DPIED]"; if (dpiExportImpl()) str << " [DPIEI]"; diff --git a/src/V3Life.cpp b/src/V3Life.cpp index c3ff35eba..0b5f83122 100644 --- a/src/V3Life.cpp +++ b/src/V3Life.cpp @@ -432,7 +432,7 @@ private: // UINFO(4, " CFUNC " << nodep << endl); if (!m_tracingCall && !nodep->entryPoint()) return; m_tracingCall = false; - if (nodep->dpiImportPrototype() && !nodep->pure()) { + if (nodep->dpiImportPrototype() && !nodep->dpiPure()) { m_sideEffect = true; // If appears on assign RHS, don't ever delete the assignment } iterateChildren(nodep); diff --git a/src/V3Partition.cpp b/src/V3Partition.cpp index ebc271a71..37a8b923d 100644 --- a/src/V3Partition.cpp +++ b/src/V3Partition.cpp @@ -1840,8 +1840,8 @@ private: if (!m_tracingCall) return; m_tracingCall = false; if (nodep->dpiImportWrapper()) { - if (nodep->pure() ? !v3Global.opt.threadsDpiPure() - : !v3Global.opt.threadsDpiUnpure()) { + if (nodep->dpiPure() ? !v3Global.opt.threadsDpiPure() + : !v3Global.opt.threadsDpiUnpure()) { m_hasDpiHazard = true; } } diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 44449ae67..b5af41942 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -639,7 +639,7 @@ private: // Return fancy signature for DPI function. Variable names are not included so differences // in only argument names will not matter (as required by the standard). string dpiproto; - if (nodep->pure()) dpiproto += "pure "; + if (nodep->dpiPure()) dpiproto += "pure "; if (nodep->dpiContext()) dpiproto += "context "; dpiproto += rtnvarp ? rtnvarp->dpiArgType(true, true) : "void"; dpiproto += " " + nodep->cname() + " ("; @@ -908,7 +908,7 @@ private: funcp->entryPoint(false); funcp->isMethod(false); funcp->protect(false); - funcp->pure(nodep->pure()); + funcp->dpiPure(nodep->dpiPure()); // Add DPI Import to top, since it's a global function m_topScopep->scopep()->addBlocksp(funcp); makePortList(nodep, funcp); @@ -1183,7 +1183,7 @@ private: cfuncp->isStatic(false); } cfuncp->isVirtual(nodep->isVirtual()); - cfuncp->pure(nodep->pure()); + cfuncp->dpiPure(nodep->dpiPure()); if (nodep->name() == "new") { cfuncp->isConstructor(true); AstClass* const classp = m_statep->getClassp(nodep); diff --git a/src/verilog.y b/src/verilog.y index 507c3020d..731fa419d 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -4624,7 +4624,7 @@ dpi_import_export: // ==IEEE: dpi_import_export { $$ = $5; if (*$4 != "") $5->cname(*$4); $5->dpiContext($3 == iprop_CONTEXT); - $5->pure($3 == iprop_PURE); + $5->dpiPure($3 == iprop_PURE); $5->dpiImport(true); $5->dpiTraceInit($6); GRAMMARP->checkDpiVer($1, *$2); v3Global.dpi(true); @@ -4634,7 +4634,7 @@ dpi_import_export: // ==IEEE: dpi_import_export { $$ = $5; if (*$4 != "") $5->cname(*$4); $5->dpiContext($3 == iprop_CONTEXT); - $5->pure($3 == iprop_PURE); + $5->dpiPure($3 == iprop_PURE); $5->dpiImport(true); $5->dpiTask(true); GRAMMARP->checkDpiVer($1, *$2); v3Global.dpi(true); From 1a1f9198823e43688a552b82e4792aa478622a78 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Fri, 8 Sep 2023 08:51:54 +0200 Subject: [PATCH 065/111] Check the output in t_class_method_str_literal.v (#4459) --- test_regress/t/t_class_method_str_literal.v | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test_regress/t/t_class_method_str_literal.v b/test_regress/t/t_class_method_str_literal.v index 3e5e9225d..5f6309c02 100644 --- a/test_regress/t/t_class_method_str_literal.v +++ b/test_regress/t/t_class_method_str_literal.v @@ -7,21 +7,21 @@ module t; class T; - function automatic void print_str(input string a_string); - $display(a_string); + function automatic string return_str(input string a_string); + return a_string; endfunction - static function automatic void static_print_str(input string a_string); - $display(a_string); + static function automatic string static_return_str(input string a_string); + return a_string; endfunction endclass initial begin T t_c = new; - t_c.print_str("function though member"); - t_c.static_print_str("static function through member"); - T::static_print_str("static function through class"); + if (t_c.return_str("A") != "A") $stop; + if (t_c.static_return_str("B") != "B") $stop; + if (T::static_return_str("C") != "C") $stop; $write("*-* All Finished *-*\n"); $finish; end From 9882ab6c67811f5650e83b12b5cbebb22fe2cc93 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 8 Sep 2023 07:22:40 -0400 Subject: [PATCH 066/111] Tests: Remove unstable new test --- test_regress/t/t_let_side.pl | 21 --------------------- test_regress/t/t_let_side.v | 29 ----------------------------- 2 files changed, 50 deletions(-) delete mode 100755 test_regress/t/t_let_side.pl delete mode 100644 test_regress/t/t_let_side.v diff --git a/test_regress/t/t_let_side.pl b/test_regress/t/t_let_side.pl deleted file mode 100755 index 97d8dcc12..000000000 --- a/test_regress/t/t_let_side.pl +++ /dev/null @@ -1,21 +0,0 @@ -#!/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( - ); - -execute( - check_finished => 1, - ); - -ok(1); -1; diff --git a/test_regress/t/t_let_side.v b/test_regress/t/t_let_side.v deleted file mode 100644 index 0200da525..000000000 --- a/test_regress/t/t_let_side.v +++ /dev/null @@ -1,29 +0,0 @@ -// 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 - -module t(/*AUTOARG*/); - - let F(a) = {a, a, a}; - - function byte g(); - static byte r = 0; - return ++r; - endfunction - - bit [23:0] res; - - initial begin - res = F(g()); - $display("%h", res); - // Commercial1 010101 -- seems wrong by my reading of IEEE but anyhow - // Commercial2/Vlt 010203 - // Commercial3/4 030201 - if (res != 24'h010101 && res != 24'h010203 && res != 24'h030201) $stop; - $write("*-* All Finished *-*\n"); - $finish; - end - -endmodule From fb1fc46b06625a94dab914daa8c11cb1d3eb3047 Mon Sep 17 00:00:00 2001 From: Krzysztof Bieganski Date: Fri, 8 Sep 2023 13:34:35 +0200 Subject: [PATCH 067/111] Internals: Rework self pointers (#4396) --- src/V3Ast.cpp | 12 ++++++++++ src/V3Ast.h | 38 +++++++++++++++++++++++++++++++ src/V3AstInlines.h | 2 +- src/V3AstNodeExpr.h | 26 +++++++++++++--------- src/V3AstNodeOther.h | 1 - src/V3AstNodes.cpp | 12 ---------- src/V3CCtors.cpp | 4 ++-- src/V3Descope.cpp | 53 +++++++++++++++++++++++++++++++------------- src/V3EmitCFunc.cpp | 6 ++--- src/V3EmitCFunc.h | 4 ++-- src/V3EmitCImp.cpp | 10 ++++----- src/V3EmitV.cpp | 5 +++-- src/V3Hasher.cpp | 2 +- 13 files changed, 120 insertions(+), 55 deletions(-) diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index e57d28ee5..67dba756d 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -63,6 +63,18 @@ const VNTypeInfo VNType::typeInfoTable[] = { std::ostream& operator<<(std::ostream& os, VNType rhs); +//###################################################################### +// VSelfPointerText + +const std::shared_ptr VSelfPointerText::s_emptyp = std::make_shared(""); +const std::shared_ptr VSelfPointerText::s_thisp = std::make_shared("this"); + +string VSelfPointerText::protect(bool useSelfForThis, bool protect) const { + const string& sp + = useSelfForThis ? VString::replaceWord(asString(), "this", "vlSelf") : asString(); + return VIdProtect::protectWordsIf(sp, protect); +} + //###################################################################### // AstNode diff --git a/src/V3Ast.h b/src/V3Ast.h index dbe2b02a0..dc2a6b523 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -1247,6 +1247,44 @@ public: ~VBasicTypeKey() = default; }; +// ###################################################################### +// VSelfPointerText - Represents text to be emitted before a given var reference, call, etc. to +// serve as a pointer to a 'self' object. For example, it could be empty (no self pointer), or the +// string 'this', or 'vlSymsp->...' + +class VSelfPointerText final { +private: + // STATIC MEMBERS + // Keep these in shared pointers to avoid branching for special cases + static const std::shared_ptr s_emptyp; // Holds "" + static const std::shared_ptr s_thisp; // Holds "this" + + // MEMBERS + std::shared_ptr m_strp; + +public: + // CONSTRUCTORS + class Empty {}; // for creator type-overload selection + VSelfPointerText(Empty) + : m_strp{s_emptyp} {} + class This {}; // for creator type-overload selection + VSelfPointerText(This) + : m_strp{s_thisp} {} + VSelfPointerText(This, const string& field) + : m_strp{std::make_shared("this->" + field)} {} + class VlSyms {}; // for creator type-overload selection + VSelfPointerText(VlSyms, const string& field) + : m_strp{std::make_shared("(&vlSymsp->" + field + ')')} {} + + // METHODS + bool isEmpty() const { return m_strp == s_emptyp; } + bool isVlSym() const { return m_strp->find("vlSymsp") != string::npos; } + bool hasThis() const { return m_strp == s_thisp || VString::startsWith(*m_strp, "this"); } + string protect(bool useSelfForThis, bool protect) const; + const std::string& asString() const { return *m_strp; } + bool operator==(const VSelfPointerText& other) const { return *m_strp == *other.m_strp; } +}; + //###################################################################### // AstNUser - Generic base class for AST User nodes. // - Also used to allow parameter passing up/down iterate calls diff --git a/src/V3AstInlines.h b/src/V3AstInlines.h index cff4fd9e5..3c40963b2 100644 --- a/src/V3AstInlines.h +++ b/src/V3AstInlines.h @@ -176,7 +176,7 @@ bool AstVarRef::sameNoLvalue(AstVarRef* samep) const { return (varScopep() == samep->varScopep()); } else { return (selfPointer() == samep->selfPointer() - && (!selfPointer().empty() || !samep->selfPointer().empty()) + && (!selfPointer().isEmpty() || !samep->selfPointer().isEmpty()) && varp()->name() == samep->varp()->name()); } } diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 75694f61d..1a421e928 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -444,8 +444,9 @@ class AstNodeVarRef VL_NOT_FINAL : public AstNodeExpr { AstVar* m_varp; // [AfterLink] Pointer to variable itself AstVarScope* m_varScopep = nullptr; // Varscope for hierarchy AstNodeModule* m_classOrPackagep = nullptr; // Class/package of the variable - string m_selfPointer; // Output code object pointer (e.g.: 'this') - + VSelfPointerText m_selfPointer + = VSelfPointerText{VSelfPointerText::Empty()}; // Output code object + // pointer (e.g.: 'this') protected: AstNodeVarRef(VNType t, FileLine* fl, const VAccess& access) : AstNodeExpr{t, fl} @@ -474,9 +475,11 @@ public: } AstVarScope* varScopep() const { return m_varScopep; } void varScopep(AstVarScope* varscp) { m_varScopep = varscp; } - string selfPointer() const { return m_selfPointer; } - void selfPointer(const string& value) { m_selfPointer = value; } - string selfPointerProtect(bool useSelfForThis) const; + const VSelfPointerText& selfPointer() const { return m_selfPointer; } + void selfPointer(const VSelfPointerText& selfPointer) { m_selfPointer = selfPointer; } + string selfPointerProtect(bool useSelfForThis) const { + return selfPointer().protect(useSelfForThis, protect()); + } AstNodeModule* classOrPackagep() const { return m_classOrPackagep; } void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; } // Know no children, and hot function, so skip iterator for speed @@ -4048,16 +4051,19 @@ public: // === AstNodeCCall === class AstCCall final : public AstNodeCCall { // C++ function call - string m_selfPointer; // Output code object pointer (e.g.: 'this') - + VSelfPointerText m_selfPointer + = VSelfPointerText{VSelfPointerText::Empty()}; // Output code object + // pointer (e.g.: 'this') public: AstCCall(FileLine* fl, AstCFunc* funcp, AstNodeExpr* argsp = nullptr) : ASTGEN_SUPER_CCall(fl, funcp, argsp) {} ASTGEN_MEMBERS_AstCCall; - string selfPointer() const { return m_selfPointer; } - void selfPointer(const string& value) { m_selfPointer = value; } - string selfPointerProtect(bool useSelfForThis) const; + const VSelfPointerText& selfPointer() const { return m_selfPointer; } + void selfPointer(const VSelfPointerText& selfPointer) { m_selfPointer = selfPointer; } + string selfPointerProtect(bool useSelfForThis) const { + return selfPointer().protect(useSelfForThis, protect()); + } }; class AstCMethodCall final : public AstNodeCCall { // C++ method call diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index db6fd3b14..e677af491 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -1390,7 +1390,6 @@ public: void dump(std::ostream& str) const override; bool same(const AstNode* samep) const override; string nameDotless() const; - string nameVlSym() const { return string{"vlSymsp->"} + nameDotless(); } AstNodeModule* modp() const { return m_modp; } // AstScope* aboveScopep() const VL_MT_SAFE { return m_aboveScopep; } diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 65eed3af0..5a411d606 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -84,12 +84,6 @@ void AstNodeVarRef::cloneRelink() { } } -string AstNodeVarRef::selfPointerProtect(bool useSelfForThis) const { - const string& sp - = useSelfForThis ? VString::replaceWord(selfPointer(), "this", "vlSelf") : selfPointer(); - return VIdProtect::protectWordsIf(sp, protect()); -} - void AstAddrOfCFunc::cloneRelink() { if (m_funcp && m_funcp->clonep()) m_funcp = m_funcp->clonep(); } @@ -129,12 +123,6 @@ const char* AstNodeCCall::broken() const { } bool AstNodeCCall::isPure() const { return funcp()->dpiPure(); } -string AstCCall::selfPointerProtect(bool useSelfForThis) const { - const string& sp - = useSelfForThis ? VString::replaceWord(selfPointer(), "this", "vlSelf") : selfPointer(); - return VIdProtect::protectWordsIf(sp, protect()); -} - AstNodeCond::AstNodeCond(VNType t, FileLine* fl, AstNodeExpr* condp, AstNodeExpr* thenp, AstNodeExpr* elsep) : AstNodeTriop{t, fl, condp, thenp, elsep} { diff --git a/src/V3CCtors.cpp b/src/V3CCtors.cpp index 3c1265c67..0cec01ab1 100644 --- a/src/V3CCtors.cpp +++ b/src/V3CCtors.cpp @@ -117,7 +117,7 @@ public: callp->argTypes("vlSymsp"); } else { if (m_type.isCoverage()) callp->argTypes("first"); - callp->selfPointer("this"); + callp->selfPointer(VSelfPointerText{VSelfPointerText::This()}); } rootFuncp->addStmtsp(callp->makeStmt()); } @@ -229,7 +229,7 @@ void V3CCtors::evalAsserts() { // if (signal & CONST(upper_non_clean_mask)) { fail; } AstVarRef* const vrefp = new AstVarRef{varp->fileline(), varp, VAccess::READ}; - vrefp->selfPointer("this"); + vrefp->selfPointer(VSelfPointerText{VSelfPointerText::This()}); AstNodeExpr* newp = vrefp; if (varp->isWide()) { newp = new AstWordSel{ diff --git a/src/V3Descope.cpp b/src/V3Descope.cpp index 1d4866faf..fe5fe15f9 100644 --- a/src/V3Descope.cpp +++ b/src/V3Descope.cpp @@ -46,6 +46,10 @@ private: // TYPES using FuncMmap = std::multimap; + struct ScopeSelfPtr final { + VSelfPointerText thisPtr = VSelfPointerText{VSelfPointerText::Empty()}; + VSelfPointerText vlSymsPtr = VSelfPointerText{VSelfPointerText::Empty()}; + }; // STATE AstNodeModule* m_modp = nullptr; // Current module @@ -53,6 +57,7 @@ private: const AstCFunc* m_funcp = nullptr; // Current function bool m_modSingleton = false; // m_modp is only instantiated once FuncMmap m_modFuncs; // Name of public functions added + std::map m_scopeToSelf; // Scope to self pointers // METHODS @@ -68,12 +73,32 @@ private: return (instances == 1); } + // Construct a 'this' self pointer for the given scope + VSelfPointerText scopeThis(const AstScope* scopep) { + auto& ret = m_scopeToSelf[scopep]; + if (ret.thisPtr.isEmpty()) { + string name = scopep->name(); + string::size_type pos; + if ((pos = name.rfind('.')) != string::npos) name.erase(0, pos + 1); + ret.thisPtr = VSelfPointerText{VSelfPointerText::This(), name}; + } + return ret.thisPtr; + } + // Construct a 'vlSyms' self pointer for the given scope + VSelfPointerText scopeVlSyms(const AstScope* scopep) { + auto& ret = m_scopeToSelf[scopep]; + if (ret.vlSymsPtr.isEmpty()) { + ret.vlSymsPtr = VSelfPointerText{VSelfPointerText::VlSyms(), scopep->nameDotless()}; + } + return ret.vlSymsPtr; + } + // Construct the best self pointer to reference an object in 'scopep' from a CFunc in // 'm_scopep'. Result may be relative ("this->[...]") or absolute ("vlSyms->[...]"). // // Using relative references allows V3Combine'ing code across multiple instances of the same // module. - string descopedSelfPointer(const AstScope* scopep) { + VSelfPointerText descopedSelfPointer(const AstScope* scopep) { UASSERT(scopep, "Var/Func not scoped"); // Static functions can't use relative references via 'this->' const bool relativeRefOk = !m_funcp->isStatic(); @@ -85,23 +110,20 @@ private: if (VN_IS(scopep->modp(), Class)) { // Direct reference to class members are from within the class itself, references from // outside the class must go via AstMemberSel - return "this"; + return VSelfPointerText{VSelfPointerText::This()}; } else if (relativeRefOk && scopep == m_scopep) { - return "this"; + return VSelfPointerText{VSelfPointerText::This()}; } else if (relativeRefOk && !m_modSingleton && scopep->aboveScopep() == m_scopep && VN_IS(scopep->modp(), Module)) { // Reference to scope of instance directly under this module, can just "this->cell", // which can potentially be V3Combined, but note this requires one extra pointer // dereference which is slower, so we only use it if the source scope is not a // singleton. - string name = scopep->name(); - string::size_type pos; - if ((pos = name.rfind('.')) != string::npos) name.erase(0, pos + 1); - return "this->" + name; + return scopeThis(scopep); } else { // Reference to something elsewhere, or relative references are disabled. Use global // variable - return "(&" + scopep->nameVlSym() + ")"; + return scopeVlSyms(scopep); } } @@ -163,11 +185,10 @@ private: if (moreOfSame) { AstIf* const ifp = new AstIf{ funcp->fileline(), - new AstEq{ - funcp->fileline(), new AstCExpr{funcp->fileline(), "this", 64}, - new AstCExpr{funcp->fileline(), - string{"&("} + funcp->scopep()->nameVlSym() + ")", - 64}}, + new AstEq{funcp->fileline(), + new AstCExpr{funcp->fileline(), "this", 64}, + new AstCExpr{funcp->fileline(), + scopeVlSyms(funcp->scopep()).asString(), 64}}, returnp}; newfuncp->addStmtsp(ifp); } else { @@ -225,15 +246,15 @@ private: const AstScope* const scopep = nodep->varScopep()->scopep(); if (varp->isFuncLocal()) { // Reference to function locals need no self pointer - nodep->selfPointer(""); + nodep->selfPointer(VSelfPointerText{VSelfPointerText::Empty()}); } else if (scopep->modp() == v3Global.rootp()->constPoolp()->modp()) { // Reference to constant pool value need no self pointer - nodep->selfPointer(""); + nodep->selfPointer(VSelfPointerText{VSelfPointerText::Empty()}); } else { nodep->selfPointer(descopedSelfPointer(scopep)); } nodep->varScopep(nullptr); - UINFO(9, " refout " << nodep << " selfPtr=" << nodep->selfPointer() << endl); + UINFO(9, " refout " << nodep << " selfPtr=" << nodep->selfPointer().asString() << endl); } void visit(AstCCall* nodep) override { // UINFO(9, " " << nodep << endl); diff --git a/src/V3EmitCFunc.cpp b/src/V3EmitCFunc.cpp index cbb894671..8fd63dcf8 100644 --- a/src/V3EmitCFunc.cpp +++ b/src/V3EmitCFunc.cpp @@ -108,7 +108,7 @@ void EmitCFunc::emitOpName(AstNode* nodep, const string& format, AstNode* lhsp, UASSERT_OBJ(m_wideTempRefp, nodep, "Wide Op w/ no temp, perhaps missing op in V3EmitC?"); COMMA; - if (!m_wideTempRefp->selfPointer().empty()) { + if (!m_wideTempRefp->selfPointer().isEmpty()) { emitDereference(m_wideTempRefp->selfPointerProtect(m_useSelfForThis)); } puts(m_wideTempRefp->varp()->nameProtect()); @@ -516,7 +516,7 @@ void EmitCFunc::emitConstant(AstConst* nodep, AstVarRef* assigntop, const string if (!assigntop) { puts(assignString); } else { - if (!assigntop->selfPointer().empty()) { + if (!assigntop->selfPointer().isEmpty()) { emitDereference(assigntop->selfPointerProtect(m_useSelfForThis)); } puts(assigntop->varp()->nameProtect()); @@ -538,7 +538,7 @@ void EmitCFunc::emitConstant(AstConst* nodep, AstVarRef* assigntop, const string if (!assigntop) { puts(assignString); } else { - if (!assigntop->selfPointer().empty()) { + if (!assigntop->selfPointer().isEmpty()) { emitDereference(assigntop->selfPointerProtect(m_useSelfForThis)); } puts(assigntop->varp()->nameProtect()); diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index a1c1cd515..6481ea2c4 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -494,7 +494,7 @@ public: puts(funcNameProtect(funcp)); } else { // Calling regular method/function - if (!nodep->selfPointer().empty()) { + if (!nodep->selfPointer().isEmpty()) { emitDereference(nodep->selfPointerProtect(m_useSelfForThis)); } puts(funcp->nameProtect()); @@ -1265,7 +1265,7 @@ public: } else if (varp->isIfaceRef()) { puts(nodep->selfPointerProtect(m_useSelfForThis)); return; - } else if (!nodep->selfPointer().empty()) { + } else if (!nodep->selfPointer().isEmpty()) { emitDereference(nodep->selfPointerProtect(m_useSelfForThis)); } puts(nodep->varp()->nameProtect()); diff --git a/src/V3EmitCImp.cpp b/src/V3EmitCImp.cpp index 18f75acc4..f84e9442c 100644 --- a/src/V3EmitCImp.cpp +++ b/src/V3EmitCImp.cpp @@ -59,18 +59,18 @@ class EmitCGatherDependencies final : VNVisitorConst { } } } - void addSelfDependency(const string& selfPointer, AstNode* nodep) { - if (selfPointer.empty()) { + void addSelfDependency(VSelfPointerText selfPointer, AstNode* nodep) { + if (selfPointer.isEmpty()) { // No self pointer (e.g.: function locals, const pool values, loose static methods), // so no dependency - } else if (VString::startsWith(selfPointer, "this")) { + } else if (selfPointer.hasThis()) { // Dereferencing 'this', we need the definition of this module, which is also the // module that contains the variable. addModDependency(EmitCParentModule::get(nodep)); } else { // Must be an absolute reference - UASSERT_OBJ(selfPointer.find("vlSymsp") != string::npos, nodep, - "Unknown self pointer: '" << selfPointer << "'"); + UASSERT_OBJ(selfPointer.isVlSym(), nodep, + "Unknown self pointer: '" << selfPointer.asString() << "'"); // Dereferencing vlSymsp, so we need it's definition... addSymsDependency(); } diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index 953a3d937..2f0e40351 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -682,10 +682,11 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst { putfs(nodep, nodep->varScopep()->prettyName()); } else { if (nodep->varp()) { - if (nodep->selfPointer().empty()) { + if (nodep->selfPointer().isEmpty()) { putfs(nodep, nodep->varp()->prettyName()); } else { - putfs(nodep, nodep->selfPointer() + "->"); + putfs(nodep, nodep->selfPointer().asString()); + putfs(nodep, "->"); puts(nodep->varp()->prettyName()); } } else { diff --git a/src/V3Hasher.cpp b/src/V3Hasher.cpp index 432f62b17..2ecfaaa69 100644 --- a/src/V3Hasher.cpp +++ b/src/V3Hasher.cpp @@ -207,7 +207,7 @@ private: iterateConstNull(nodep->varScopep()); } else { iterateConstNull(nodep->varp()); - m_hash += nodep->selfPointer(); + m_hash += nodep->selfPointer().asString(); } }); } From 139e93d37174f823c33309cc83778562eeaab754 Mon Sep 17 00:00:00 2001 From: Krzysztof Bieganski Date: Fri, 8 Sep 2023 13:35:52 +0200 Subject: [PATCH 068/111] Internals: Reduce the number of typechecks in graphs (#4398). No functional change intended. --- src/V3Split.cpp | 17 +++++++++-------- src/V3Tristate.cpp | 6 +++--- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/V3Split.cpp b/src/V3Split.cpp index 80eb67778..5ff887b59 100644 --- a/src/V3Split.cpp +++ b/src/V3Split.cpp @@ -176,12 +176,12 @@ public: void setIgnoreThisStep() { m_ignoreInStep = s_stepNum; } virtual bool followScoreboard() const = 0; static bool followScoreboard(const V3GraphEdge* edgep) { - const SplitEdge* const oedgep = edgep->as(); + const SplitEdge* const oedgep = static_cast(edgep); if (oedgep->ignoreThisStep()) return false; return oedgep->followScoreboard(); } static bool followCyclic(const V3GraphEdge* edgep) { - const SplitEdge* const oedgep = edgep->as(); + const SplitEdge* const oedgep = static_cast(edgep); return (!oedgep->ignoreThisStep()); } string dotStyle() const override { @@ -332,7 +332,7 @@ protected: stdp->nodep()->dumpTree("- "); } for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) { - SplitEdge* const oedgep = edgep->as(); + SplitEdge* const oedgep = static_cast(edgep); oedgep->setIgnoreThisStep(); } } @@ -487,12 +487,12 @@ protected: if (const SplitLogicVertex* const vvertexp = vertexp->cast()) { for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) { - SplitEdge* const oedgep = edgep->as(); + SplitEdge* const oedgep = static_cast(edgep); oedgep->setIgnoreThisStep(); } for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { - SplitEdge* const oedgep = edgep->as(); + SplitEdge* const oedgep = static_cast(edgep); oedgep->setIgnoreThisStep(); } } @@ -919,7 +919,7 @@ protected: bool pruneMe = true; for (V3GraphEdge* edgep = logicp->outBeginp(); edgep; edgep = edgep->outNextp()) { - const SplitEdge* const oedgep = edgep->as(); + const SplitEdge* const oedgep = static_cast(edgep); if (!oedgep->ignoreThisStep()) { // This if conditional depends on something we can't // prune -- a variable generated in the current block. @@ -929,7 +929,8 @@ protected: // give a hint about why... if (debug() >= 9) { V3GraphVertex* vxp = oedgep->top(); - const SplitNodeVertex* const nvxp = vxp->as(); + const SplitNodeVertex* const nvxp + = static_cast(vxp); UINFO(0, "Cannot prune if-node due to edge " << oedgep << " pointing to node " << nvxp->nodep() << endl); nvxp->nodep()->dumpTree("- "); @@ -943,7 +944,7 @@ protected: // This if can be split; prune dependencies on it. for (V3GraphEdge* edgep = logicp->inBeginp(); edgep; edgep = edgep->inNextp()) { - SplitEdge* const oedgep = edgep->as(); + SplitEdge* const oedgep = static_cast(edgep); oedgep->setIgnoreThisStep(); } } diff --git a/src/V3Tristate.cpp b/src/V3Tristate.cpp index fdf303b28..99ff0f328 100644 --- a/src/V3Tristate.cpp +++ b/src/V3Tristate.cpp @@ -223,7 +223,7 @@ private: UINFO(9, " Mark tri " << level << " " << vtxp << endl); if (!vtxp->varp()) { // not a var where we stop the recursion for (V3GraphEdge* edgep = vtxp->outBeginp(); edgep; edgep = edgep->outNextp()) { - TristateVertex* const vvertexp = edgep->top()->as(); + TristateVertex* const vvertexp = static_cast(edgep->top()); // Doesn't hurt to not check if already set, but by doing so when we // print out the debug messages, we'll see this node at level 0 instead. if (!vvertexp->isTristate()) { @@ -235,7 +235,7 @@ private: // A variable is tristated. Find all of the LHS VARREFs that // drive this signal now need tristate drivers for (V3GraphEdge* edgep = vtxp->inBeginp(); edgep; edgep = edgep->inNextp()) { - TristateVertex* const vvertexp = edgep->fromp()->as(); + TristateVertex* const vvertexp = static_cast(edgep->fromp()); if (const AstVarRef* const refp = VN_CAST(vvertexp->nodep(), VarRef)) { if (refp->access().isWriteOrRW() // Doesn't hurt to not check if already set, but by doing so when we @@ -260,7 +260,7 @@ private: UINFO(9, " Mark feedstri " << level << " " << vtxp << endl); if (!vtxp->varp()) { // not a var where we stop the recursion for (V3GraphEdge* edgep = vtxp->inBeginp(); edgep; edgep = edgep->inNextp()) { - TristateVertex* const vvertexp = edgep->fromp()->as(); + TristateVertex* const vvertexp = static_cast(edgep->fromp()); // Doesn't hurt to not check if already set, but by doing so when we // print out the debug messages, we'll see this node at level 0 instead. if (!vvertexp->feedsTri()) { From 014301587f4817f89d7ccb27a7c8962949196dd4 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 8 Sep 2023 08:37:17 -0400 Subject: [PATCH 069/111] Unsupported instead of syntax error on parameter var initial values --- src/verilog.y | 23 ++++++----- .../t/t_assert_property_var_unsup.out | 10 +++++ test_regress/t/t_assert_property_var_unsup.pl | 20 ++++++++++ test_regress/t/t_assert_property_var_unsup.v | 38 +++++++++++++++++++ 4 files changed, 81 insertions(+), 10 deletions(-) create mode 100644 test_regress/t/t_assert_property_var_unsup.out create mode 100755 test_regress/t/t_assert_property_var_unsup.pl create mode 100644 test_regress/t/t_assert_property_var_unsup.v diff --git a/src/verilog.y b/src/verilog.y index 731fa419d..21c804874 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -4334,13 +4334,15 @@ elaboration_system_task_guts: // IEEE: part of elaboration_system_task | yD_FATAL '(' expr ',' exprListE ')' { $$ = new AstElabDisplay{$1, VDisplayType::DT_FATAL, $5}; DEL($3); } ; -//UNSUPproperty_actual_arg: // ==IEEE: property_actual_arg -//UNSUP // // IEEE: property_expr -//UNSUP // // IEEE: sequence_actual_arg -//UNSUP pev_expr { $$ = $1; } -//UNSUP // // IEEE: sequence_expr -//UNSUP // // property_expr already includes sequence_expr -//UNSUP ; +property_actual_arg: // ==IEEE: property_actual_arg + // // IEEE: property_expr + // // IEEE: sequence_actual_arg + //UNSUP pev_expr { $$ = $1; } + //UNSUP remove below: + pexpr { $$ = $1; } + // // IEEE: sequence_expr + // // property_expr already includes sequence_expr + ; exprOrDataType: // expr | data_type: combined to prevent conflicts expr { $$ = $1; } @@ -4902,7 +4904,7 @@ fexpr: // For use as first part of statement (disam BISONPRE_COPY(expr,{s/~l~/f/g; s/~r~/f/g; s/~f__IGNORE~/__IGNORE/g;}) // {copied} ; -//UNSUPev_expr: // IEEE: event_expression +//UNSUPpev_expr: // IEEE: event_expression //UNSUP // // for yOR/, see event_expression //UNSUP // //UNSUP // // IEEE: [ edge_identifier ] expression [ yIFF expression ] @@ -5938,8 +5940,9 @@ property_port_itemFront: // IEEE: part of property_port_item/sequence_port_item property_port_itemAssignment: // IEEE: part of property_port_item/sequence_port_item/checker_port_direction id variable_dimensionListE { $$ = VARDONEA($1, *$1, $2, nullptr); } - //UNSUP|id variable_dimensionListE '=' property_actual_arg - //UNSUP { VARDONE($1, $1, $2, $4); PINNUMINC(); } + | id variable_dimensionListE '=' property_actual_arg + { $$ = VARDONEA($1, *$1, $2, $4); + BBUNSUP($3, "Unsupported: property variable default value"); } ; property_port_itemDirE: diff --git a/test_regress/t/t_assert_property_var_unsup.out b/test_regress/t/t_assert_property_var_unsup.out new file mode 100644 index 000000000..ad85bd9df --- /dev/null +++ b/test_regress/t/t_assert_property_var_unsup.out @@ -0,0 +1,10 @@ +%Error: t/t_assert_property_var_unsup.v:17:11: syntax error, unexpected IDENTIFIER, expecting "'{" + 17 | int prevcyc; + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_assert_property_var_unsup.v:24:31: Unsupported: property variable default value + 24 | property with_def(int nine = 9); + | ^ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error: Internal Error: t/t_assert_property_var_unsup.v:7:8: ../V3ParseSym.h:#: Symbols suggest ending PROPERTY 'prop' but parser thinks ending MODULE 't' + 7 | module t ( + | ^ diff --git a/test_regress/t/t_assert_property_var_unsup.pl b/test_regress/t/t_assert_property_var_unsup.pl new file mode 100755 index 000000000..c9ca914d8 --- /dev/null +++ b/test_regress/t/t_assert_property_var_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 2022 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( + expect_filename => $Self->{golden_filename}, + verilator_flags2 => ['--assert --error-limit 1000'], + fails => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_assert_property_var_unsup.v b/test_regress/t/t_assert_property_var_unsup.v new file mode 100644 index 000000000..6b9170d09 --- /dev/null +++ b/test_regress/t/t_assert_property_var_unsup.v @@ -0,0 +1,38 @@ +// 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 + +module t (/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + int cyc; + bit valid; + + property prop; + int prevcyc; + (valid, prevcyc = cyc) |=> (cyc == prevcyc + 1); + endproperty + + default clocking @(posedge clk); endclocking + assert property(prop); + + property with_def(int nine = 9); + cyc == 9 |-> cyc == nine; + endproperty + + assert property(with_def); + + always @(posedge clk) begin + cyc <= cyc + 1; + valid <= cyc == 5; + if (cyc == 10) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule From 70b11f91b49c11ce5636a0d39fa51951c4c99fd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Boro=C5=84ski?= <94375110+kboronski-ant@users.noreply.github.com> Date: Fri, 8 Sep 2023 16:40:14 +0200 Subject: [PATCH 070/111] Support block_item_declaration in forks (#4455) --- src/V3AstNodeOther.h | 5 +- src/V3Fork.cpp | 77 +++++++++++++++++-- src/verilog.y | 35 ++++++--- .../t/t_fork_block_item_declaration.pl | 23 ++++++ .../t/t_fork_block_item_declaration.v | 36 +++++++++ 5 files changed, 155 insertions(+), 21 deletions(-) create mode 100755 test_regress/t/t_fork_block_item_declaration.pl create mode 100644 test_regress/t/t_fork_block_item_declaration.v diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index e677af491..bcf4bbe14 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -32,7 +32,7 @@ class AstNodeBlock VL_NOT_FINAL : public AstNode { // A Begin/fork block - // @astgen op1 := stmtsp : List[AstNode] + // @astgen op2 := stmtsp : List[AstNode] // Parents: statement private: string m_name; // Name of block @@ -2049,7 +2049,7 @@ public: class AstBegin final : public AstNodeBlock { // A Begin/end named block, only exists shortly after parsing until linking // Parents: statement - // @astgen op2 := genforp : Optional[AstNode] + // @astgen op1 := genforp : Optional[AstNode] bool m_generate; // Underneath a generate const bool m_implied; // Not inserted by user @@ -2068,6 +2068,7 @@ public: }; class AstFork final : public AstNodeBlock { // A fork named block + // @astgen op1 := initsp : List[AstNode] // Parents: statement // Children: statements private: diff --git a/src/V3Fork.cpp b/src/V3Fork.cpp index 7229b08d2..bd7763776 100644 --- a/src/V3Fork.cpp +++ b/src/V3Fork.cpp @@ -45,6 +45,7 @@ #include "V3Ast.h" #include "V3AstNodeExpr.h" +#include "V3Error.h" #include "V3Global.h" #include "V3MemberMap.h" @@ -131,6 +132,11 @@ public: UASSERT_OBJ(m_instance.initialized(), m_procp, "No dynamic scope prototype"); UASSERT_OBJ(!linked(), m_instance.m_handlep, "Handle already linked"); + if (VN_IS(m_procp, Fork)) { + linkNodesOfFork(memberMap); + return; + } + AstNode* stmtp = getProcStmts(); UASSERT(stmtp, "trying to instantiate dynamic scope while not under proc"); VNRelinker stmtpHandle; @@ -183,6 +189,44 @@ public: bool linked() const { return m_instance.initialized() && m_instance.m_handlep->backp(); } private: + AstAssign* instantiateDynScope(VMemberMap& memberMap) { + AstNew* const newp = new AstNew{m_procp->fileline(), nullptr}; + newp->taskp(VN_AS(memberMap.findMember(m_instance.m_classp, "new"), NodeFTask)); + newp->dtypep(m_instance.m_refDTypep); + newp->classOrPackagep(m_instance.m_classp); + + return new AstAssign{ + m_procp->fileline(), + new AstVarRef{m_procp->fileline(), m_instance.m_handlep, VAccess::WRITE}, newp}; + } + + void linkNodesOfFork(VMemberMap& memberMap) { + // Special case + + AstFork* const forkp = VN_AS(m_procp, Fork); + VNRelinker forkHandle; + forkp->unlinkFrBack(&forkHandle); + + AstBegin* const beginp = new AstBegin{ + forkp->fileline(), + "_Vwrapped_" + (forkp->name().empty() ? cvtToHex(forkp) : forkp->name()), + m_instance.m_handlep, false, true}; + forkHandle.relink(beginp); + + AstNode* const instAsgnp = instantiateDynScope(memberMap); + + beginp->stmtsp()->addNext(instAsgnp); + beginp->stmtsp()->addNext(forkp); + + forkp->initsp()->foreach([forkp](AstAssign* asgnp) { + asgnp->unlinkFrBack(); + forkp->addHereThisAsNext(asgnp); + }); + UASSERT_OBJ(!forkp->initsp(), forkp, "Leftover nodes in block_item_declaration"); + + m_modp->addStmtsp(m_instance.m_classp); + } + static string generateDynScopeClassName(const AstNode* fromp) { string n = "__VDynScope__" + (!fromp->name().empty() ? (fromp->name() + "__") : "ANON__") + cvtToHex(fromp); @@ -245,11 +289,11 @@ private: return frameIt->second; } - ForkDynScopeFrame* pushDynScopeFrame() { - ForkDynScopeFrame* const frame = new ForkDynScopeFrame{m_modp, m_procp}; - auto r = m_frames.emplace(std::make_pair(m_procp, frame)); + ForkDynScopeFrame* pushDynScopeFrame(AstNode* procp) { + ForkDynScopeFrame* const framep = new ForkDynScopeFrame{m_modp, procp}; + auto r = m_frames.emplace(std::make_pair(procp, framep)); UASSERT_OBJ(r.second, m_modp, "Procedure already contains a frame"); - return frame; + return framep; } void replaceWithMemberSel(AstVarRef* refp, const ForkDynScopeInstance& dynScope) { @@ -301,13 +345,13 @@ private: void visit(AstNodeFTask* nodep) override { VL_RESTORER(m_procp); m_procp = nodep; - if (hasAsyncFork(nodep)) pushDynScopeFrame(); + if (hasAsyncFork(nodep)) pushDynScopeFrame(m_procp); iterateChildren(nodep); } void visit(AstBegin* nodep) override { VL_RESTORER(m_procp); m_procp = nodep; - if (hasAsyncFork(nodep)) pushDynScopeFrame(); + if (hasAsyncFork(nodep)) pushDynScopeFrame(m_procp); iterateChildren(nodep); } void visit(AstFork* nodep) override { @@ -315,6 +359,26 @@ private: if (!nodep->joinType().join()) ++m_forkDepth; const bool oldAfterTimingControl = m_afterTimingControl; + + ForkDynScopeFrame* framep = nullptr; + if (nodep->initsp()) framep = pushDynScopeFrame(nodep); + + for (AstNode* stmtp = nodep->initsp(); stmtp; stmtp = stmtp->nextp()) { + if (AstVar* varp = VN_CAST(stmtp, Var)) { + // This can be probably optimized to detect cases in which dynscopes + // could be avoided + if (!framep->instance().initialized()) framep->createInstancePrototype(); + framep->captureVarInsert(varp); + bindNodeToDynScope(varp, framep); + } else { + AstAssign* const asgnp = VN_CAST(stmtp, Assign); + UASSERT_OBJ(asgnp, stmtp, + "Invalid node under block item initialization part of fork"); + bindNodeToDynScope(asgnp->lhsp(), framep); + iterate(asgnp->rhsp()); + } + } + for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) { m_afterTimingControl = false; iterate(stmtp); @@ -432,7 +496,6 @@ private: } string generateTaskName(AstNode* fromp, const string& kind) { - // TODO: Ensure no collisions occur return "__V" + kind + (!fromp->name().empty() ? (fromp->name() + "__") : "UNNAMED__") + cvtToHex(fromp); } diff --git a/src/verilog.y b/src/verilog.y index 21c804874..16dc3c644 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -288,6 +288,17 @@ public: AstNode* cloneScopedSigAttr() const { return m_scopedSigAttr ? m_scopedSigAttr->cloneTree(true) : nullptr; } + + static void addForkStmtsp(AstFork* forkp, AstNode* stmtsp) { + forkp->addStmtsp(stmtsp); + for (AstNode* stmtp = stmtsp; stmtp; stmtp = stmtp->nextp()) { + AstVar* const varp = VN_CAST(stmtp, Var); + if (!varp) break; + varp->unlinkFrBack(); + varp->funcLocal(true); + forkp->addInitsp(varp); + } + } }; const VBasicDTypeKwd LOGIC = VBasicDTypeKwd::LOGIC; // Shorthand "LOGIC" @@ -3387,31 +3398,31 @@ seq_blockPreId: // IEEE: seq_block, but called with leading ID par_block: // ==IEEE: par_block par_blockFront blockDeclStmtListE yJOIN endLabelE - { $$ = $1; $1->addStmtsp($2); - $1->joinType(VJoinType::JOIN); + { $$ = $1; $1->joinType(VJoinType::JOIN); + V3ParseGrammar::addForkStmtsp($1, $2); SYMP->popScope($1); GRAMMARP->endLabel($4, $1, $4); } | par_blockFront blockDeclStmtListE yJOIN_ANY endLabelE - { $$ = $1; $1->addStmtsp($2); - $1->joinType(VJoinType::JOIN_ANY); + { $$ = $1; $1->joinType(VJoinType::JOIN_ANY); + V3ParseGrammar::addForkStmtsp($1, $2); SYMP->popScope($1); GRAMMARP->endLabel($4, $1, $4); } | par_blockFront blockDeclStmtListE yJOIN_NONE endLabelE - { $$ = $1; $1->addStmtsp($2); - $1->joinType(VJoinType::JOIN_NONE); + { $$ = $1; $1->joinType(VJoinType::JOIN_NONE); + V3ParseGrammar::addForkStmtsp($1, $2); SYMP->popScope($1); GRAMMARP->endLabel($4, $1, $4); } ; par_blockPreId: // ==IEEE: par_block but called with leading ID par_blockFrontPreId blockDeclStmtListE yJOIN endLabelE - { $$ = $1; $1->addStmtsp($2); - $1->joinType(VJoinType::JOIN); + { $$ = $1; $1->joinType(VJoinType::JOIN); + V3ParseGrammar::addForkStmtsp($1, $2); SYMP->popScope($1); GRAMMARP->endLabel($4, $1, $4); } | par_blockFrontPreId blockDeclStmtListE yJOIN_ANY endLabelE - { $$ = $1; $1->addStmtsp($2); - $1->joinType(VJoinType::JOIN_ANY); + { $$ = $1; $1->joinType(VJoinType::JOIN_ANY); + V3ParseGrammar::addForkStmtsp($1, $2); SYMP->popScope($1); GRAMMARP->endLabel($4, $1, $4); } | par_blockFrontPreId blockDeclStmtListE yJOIN_NONE endLabelE - { $$ = $1; $1->addStmtsp($2); - $1->joinType(VJoinType::JOIN_NONE); + { $$ = $1; $1->joinType(VJoinType::JOIN_NONE); + V3ParseGrammar::addForkStmtsp($1, $2); SYMP->popScope($1); GRAMMARP->endLabel($4, $1, $4); } ; diff --git a/test_regress/t/t_fork_block_item_declaration.pl b/test_regress/t/t_fork_block_item_declaration.pl new file mode 100755 index 000000000..b8493bd06 --- /dev/null +++ b/test_regress/t/t_fork_block_item_declaration.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(simulator => 1); + +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_fork_block_item_declaration.v b/test_regress/t/t_fork_block_item_declaration.v new file mode 100644 index 000000000..93cd19215 --- /dev/null +++ b/test_regress/t/t_fork_block_item_declaration.v @@ -0,0 +1,36 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +static int counts[10]; + +class Foo; + static task do_something(); + for (int i = 0; i < 10; i++) + frk : fork + int ii = i; + #(10 + i) begin + $display("i: %d, ii: %d", i, ii); + if (counts[ii]++ != 0) + $stop; + end + join_none : frk + endtask +endclass + +module t(); + initial begin + int desired_counts[10] = '{10{1}}; + counts = '{10{0}}; + + Foo::do_something(); + #20; + + if (counts != desired_counts) + $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule From 6e977e1024ae70caed75f994d8291e1a237359ae Mon Sep 17 00:00:00 2001 From: Kamil Rakoczy Date: Fri, 8 Sep 2023 23:26:11 +0200 Subject: [PATCH 071/111] Generate compile_commands.json using bear (#4463) --- ci/ci-install.bash | 4 +-- docs/guide/install.rst | 2 +- nodist/clang_check_attributes | 61 ++++++++++++++++++++++++++--------- src/Makefile.in | 27 +++++++++++++--- 4 files changed, 71 insertions(+), 23 deletions(-) diff --git a/ci/ci-install.bash b/ci/ci-install.bash index 96a223c81..668400b07 100755 --- a/ci/ci-install.bash +++ b/ci/ci-install.bash @@ -71,8 +71,8 @@ if [ "$CI_BUILD_STAGE_NAME" = "build" ]; then sudo apt-get install libsystemc libsystemc-dev fi if [ "$CI_RUNS_ON" = "ubuntu-22.04" ]; then - sudo apt-get install mold || - sudo apt-get install mold + sudo apt-get install bear mold || + sudo apt-get install bear mold fi if [ "$COVERAGE" = 1 ]; then yes yes | sudo cpan -fi Parallel::Forker diff --git a/docs/guide/install.rst b/docs/guide/install.rst index 81da117c9..33a90f92c 100644 --- a/docs/guide/install.rst +++ b/docs/guide/install.rst @@ -126,7 +126,7 @@ Those developing Verilator itself may also want these (see internals.rst): :: sudo apt-get install clang clang-format-14 cmake gdb gprof graphviz lcov - sudo apt-get install libclang-dev yapf3 + sudo apt-get install libclang-dev yapf3 bear sudo pip3 install clang sphinx sphinx_rtd_theme sphinxcontrib-spelling breathe ruff cpan install Pod::Perldoc cpan install Parallel::Forker diff --git a/nodist/clang_check_attributes b/nodist/clang_check_attributes index 50409714a..9aacc015f 100755 --- a/nodist/clang_check_attributes +++ b/nodist/clang_check_attributes @@ -19,7 +19,13 @@ import multiprocessing import tempfile import clang.cindex -from clang.cindex import CursorKind, Index, TranslationUnitSaveError, TranslationUnitLoadError +from clang.cindex import ( + CursorKind, + Index, + TranslationUnitSaveError, + TranslationUnitLoadError, + CompilationDatabase, +) def fully_qualified_name(node): @@ -761,7 +767,7 @@ def run_analysis(ccl: Iterable[CompileCommand], pccl: Iterable[CompileCommand], is_ignored_def, is_ignored_call) for compile_command in ccl: cav.compile_and_analyze_file(compile_command.filename, - compile_command.args + extra_args, + extra_args + compile_command.args, compile_command.directory) @@ -947,10 +953,15 @@ def main(): type=int, default=0, help="Number of parallel jobs to use.") + parser.add_argument( + "--compile-commands-dir", + type=str, + default=None, + help="Path to directory containing compile_commands.json.") parser.add_argument("--cxxflags", type=str, default=None, - help="Flags passed to clang++.") + help="Extra flags passed to clang++.") parser.add_argument( "--compilation-root", type=str, @@ -975,34 +986,52 @@ def main(): cmdline.compilation_root = cmdline.verilator_root verilator_root = os.path.abspath(cmdline.verilator_root) - compilation_root = os.path.abspath(cmdline.compilation_root) + default_compilation_root = os.path.abspath(cmdline.compilation_root) + + compdb: Optional[CompilationDatabase] = None + if cmdline.compile_commands_dir: + compdb = CompilationDatabase.fromDirectory( + cmdline.compile_commands_dir) - default_cxx_flags = [ - f"-I{verilator_root}/src", - f"-I{verilator_root}/include", - f"-I{verilator_root}/src/obj_opt", - "-fcoroutines-ts", - ] if cmdline.cxxflags is not None: - cxxflags = shlex.split(cmdline.cxxflags) + common_cxxflags = shlex.split(cmdline.cxxflags) else: - cxxflags = default_cxx_flags + common_cxxflags = [] precompile_commands_list = [] if cmdline.precompile: - hdr_cxxflags = ['-xc++-header'] + cxxflags + hdr_cxxflags = ['-xc++-header'] + common_cxxflags for refid, file in enumerate(cmdline.precompile): filename = os.path.abspath(file) compile_command = CompileCommand(refid, filename, hdr_cxxflags, - compilation_root) + default_compilation_root) precompile_commands_list.append(compile_command) compile_commands_list = [] for refid, file in enumerate(cmdline.file): filename = os.path.abspath(file) - compile_command = CompileCommand(refid, filename, cxxflags, - compilation_root) + root = default_compilation_root + cxxflags = [] + if compdb: + entry = compdb.getCompileCommands(filename) + entry_list = list(entry) + # Compilation database can contain multiple entries for single file, + # e.g. when it has been updated by appending new entries. + # Use last entry for the file, if it exists, as it is the newest one. + if len(entry_list) > 0: + last_entry = entry_list[-1] + root = last_entry.directory + entry_args = list(last_entry.arguments) + # First argument in compile_commands.json arguments list is + # compiler executable name/path. CIndex (libclang) always + # implicitly prepends executable name, so it shouldn't be passed + # here. + cxxflags = common_cxxflags + entry_args[1:] + else: + cxxflags = common_cxxflags[:] + + compile_command = CompileCommand(refid, filename, cxxflags, root) compile_commands_list.append(compile_command) summary_printer = TopDownSummaryPrinter() diff --git a/src/Makefile.in b/src/Makefile.in index a1af5cf21..9a77cfbf1 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -18,14 +18,13 @@ #### Start of system configuration section. #### srcdir = @srcdir@ -PYTHON3 = @PYTHON3@ EXEEXT = @EXEEXT@ +PYTHON3 = @PYTHON3@ # VPATH only does sources; fix install_test's not creating ../bin vpath %.h @srcdir@ #### End of system configuration section. #### - default: dbg opt debug: dbg optimize: opt @@ -36,6 +35,26 @@ endif UNDER_GIT = $(wildcard ${srcdir}/../.git/logs/HEAD) +ifeq (,$(wildcard obj_dbg/bear.o)) + ifneq (, $(shell which bear 2>/dev/null)) + BEAR := $(shell which bear) + ifeq (, $(shell $(BEAR) --output obj_dbg/comptest.json -- true)) + $(shell which bear 2>/dev/null >obj_dbg/bear.o) + else + # unsupported version + BEAR := + endif + endif +else + BEAR := $(shell cat obj_dbg/bear.o) +endif + +ifneq ($(BEAR),) +BEAR_OBJ_OPT := $(BEAR) --append --output obj_dbg/compile_commands.json -- +else +BEAR_OBJ_OPT := +endif + #********************************************************************* obj_opt: @@ -62,8 +81,8 @@ endif dbg: ../bin/verilator_bin_dbg$(EXEEXT) ../bin/verilator_coverage_bin_dbg$(EXEEXT) ../bin/verilator_bin_dbg$(EXEEXT): obj_dbg ../bin prefiles - $(MAKE) -C obj_dbg -j 1 TGT=../$@ VL_DEBUG=1 -f ../Makefile_obj serial - $(MAKE) -C obj_dbg TGT=../$@ VL_DEBUG=1 -f ../Makefile_obj + $(BEAR_OBJ_OPT) $(MAKE) -C obj_dbg -j 1 TGT=../$@ VL_DEBUG=1 -f ../Makefile_obj serial + $(BEAR_OBJ_OPT) $(MAKE) -C obj_dbg TGT=../$@ VL_DEBUG=1 -f ../Makefile_obj ../bin/verilator_coverage_bin_dbg$(EXEEXT): obj_dbg ../bin prefiles $(MAKE) -C obj_dbg TGT=../$@ VL_DEBUG=1 VL_VLCOV=1 -f ../Makefile_obj serial_vlcov From 2f2f0164ff3a392572bc055234094c502eff79e3 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 8 Sep 2023 21:51:59 -0400 Subject: [PATCH 072/111] Internals: Use specific types on some cloneTrees. No functional change. --- src/V3Assert.cpp | 2 +- src/V3Subst.cpp | 4 ++-- src/V3Width.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/V3Assert.cpp b/src/V3Assert.cpp index a731dfee3..59fd8ede5 100644 --- a/src/V3Assert.cpp +++ b/src/V3Assert.cpp @@ -256,7 +256,7 @@ private: ifp = nextifp; } while (ifp); - AstNode* const newifp = nodep->cloneTree(false); + AstIf* const newifp = nodep->cloneTree(false); const bool allow_none = nodep->unique0Pragma(); // Empty case means no property diff --git a/src/V3Subst.cpp b/src/V3Subst.cpp index a83a4cf93..eecb39579 100644 --- a/src/V3Subst.cpp +++ b/src/V3Subst.cpp @@ -123,7 +123,7 @@ public: if (!m_varp->isWide() && !m_whole.m_complex && m_whole.m_assignp && !m_wordAssign) { const AstNodeAssign* const assp = m_whole.m_assignp; UASSERT_OBJ(assp, errp, "Reading whole that was never assigned"); - return (assp->rhsp()); + return assp->rhsp(); } else { return nullptr; } @@ -133,7 +133,7 @@ public: if (!m_whole.m_complex && !m_whole.m_assignp && !m_words[word].m_complex) { const AstNodeAssign* const assp = getWordAssignp(word); UASSERT_OBJ(assp, errp, "Reading a word that was never assigned, or bad word #"); - return (assp->rhsp()); + return assp->rhsp(); } else { return nullptr; } diff --git a/src/V3Width.cpp b/src/V3Width.cpp index f947d720e..ebc770fc3 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -3884,7 +3884,7 @@ private: patp = VN_AS(patp->nextp(), PatMember)) { const int times = visitPatMemberRep(patp); for (int i = 1; i < times; i++) { - AstNode* const newp = patp->cloneTree(false); + AstPatMember* const newp = patp->cloneTree(false); patp->addNextHere(newp); // This loop will see the new elements as part of nextp() } From cdd89530851c7befa416e6c161c1f529945e22c4 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 8 Sep 2023 21:52:33 -0400 Subject: [PATCH 073/111] Disable Subst when not pure --- src/V3Const.cpp | 2 +- src/V3Subst.cpp | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/V3Const.cpp b/src/V3Const.cpp index f43f31afe..b76c8244b 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -2053,7 +2053,7 @@ private: VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); return true; } - } else if (m_doV && VN_IS(nodep->lhsp(), Concat)) { + } else if (m_doV && VN_IS(nodep->lhsp(), Concat) && nodep->isTreePureRecurse()) { bool need_temp = false; if (m_warn && !VN_IS(nodep, AssignDly)) { // Is same var on LHS and RHS? // Note only do this (need user4) when m_warn, which is diff --git a/src/V3Subst.cpp b/src/V3Subst.cpp index eecb39579..38ebafb6a 100644 --- a/src/V3Subst.cpp +++ b/src/V3Subst.cpp @@ -198,7 +198,10 @@ private: } } void visit(AstConst*) override {} // Accelerate - void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { + if (!nodep->isPure()) m_ok = false; + iterateChildren(nodep); + } public: // CONSTRUCTORS From 4de25369dac03fcc2b21a30b22308963867ce40e Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 8 Sep 2023 22:29:23 -0400 Subject: [PATCH 074/111] Tests: Add t_uvm_all --- test_regress/t/t_dist_copyright.pl | 1 + test_regress/t/t_uvm_all.pl | 23 + test_regress/t/t_uvm_all.v | 16 + test_regress/t/t_uvm_pkg_all.vh | 34201 +++++++++++++++++++++++++++ 4 files changed, 34241 insertions(+) create mode 100755 test_regress/t/t_uvm_all.pl create mode 100644 test_regress/t/t_uvm_all.v create mode 100644 test_regress/t/t_uvm_pkg_all.vh diff --git a/test_regress/t/t_dist_copyright.pl b/test_regress/t/t_dist_copyright.pl index 065f54ff5..a44cb1e21 100755 --- a/test_regress/t/t_dist_copyright.pl +++ b/test_regress/t/t_dist_copyright.pl @@ -41,6 +41,7 @@ our @Exempt_Files_List = qw( test_regress/t/t_fuzz_eof_bad.v test_regress/t/t_incr_void.v test_regress/t/t_timing_trace_fst.pl + test_regress/t/t_uvm_pkg_all.vh test_regress/t/t_wrapper_context.pl test_regress/t/t_wrapper_context_fst.pl test_regress/t/t_wrapper_context_seq.pl diff --git a/test_regress/t/t_uvm_all.pl b/test_regress/t/t_uvm_all.pl new file mode 100755 index 000000000..d4b291ae6 --- /dev/null +++ b/test_regress/t/t_uvm_all.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); + +lint( + v_flags2 => ["-Wno-PKGNODECL -Wno-UNPACKED -Wno-RANDC -Wno-IMPLICITSTATIC -Wno-CONSTRAINTIGN -Wno-MISINDENT", + "--error-limit 200 --debug-exit-uvm"], + ); + +#execute( +# check_finished => 1, +# ); + +ok(1); +1; diff --git a/test_regress/t/t_uvm_all.v b/test_regress/t/t_uvm_all.v new file mode 100644 index 000000000..32f1ff78c --- /dev/null +++ b/test_regress/t/t_uvm_all.v @@ -0,0 +1,16 @@ +// 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 + +`include "t_uvm_pkg_all.vh" + +module t(/*AUTOARG*/); + + initial begin + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_uvm_pkg_all.vh b/test_regress/t/t_uvm_pkg_all.vh new file mode 100644 index 000000000..9e4b85028 --- /dev/null +++ b/test_regress/t/t_uvm_pkg_all.vh @@ -0,0 +1,34201 @@ +// DESCRIPTION: Verilator: Concatenated UVM header for internal testing +// SPDX-License-Identifier: Apache-2.0 +//------------------------------------------------------------------------------ +// To recreate: +// Using verilator_ext_tests +// t/t_uvm_parse.pl --debug --no-dump-tree +// Copy to here t/obj_vlt/Vt_uvm_parse/Vt_uvm_parse__inputs.vpp +// M-x untabify +// (global-replace-regexp "[ ]+$" "") +// (global-replace-regexp ", +" ", ") +// Add this header +//------------------------------------------------------------------------------ +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2010 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2010 AMD +// Copyright 2017 NVIDIA Corporation +// All Rights Reserved Worldwide +// +// Licensed under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of +// the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in +// writing, software distributed under the License is +// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See +// the License for the specific language governing +// permissions and limitations under the License. +//------------------------------------------------------------------------------ + +package uvm_pkg; +parameter int UVM_HDL_MAX_WIDTH = 1024; +typedef logic [UVM_HDL_MAX_WIDTH-1:0] uvm_hdl_data_t; + import "DPI-C" context function int uvm_hdl_check_path(string path); + import "DPI-C" context function int uvm_hdl_deposit(string path, uvm_hdl_data_t value); + import "DPI-C" context function int uvm_hdl_force(string path, uvm_hdl_data_t value); + task uvm_hdl_force_time(string path, uvm_hdl_data_t value, time force_time = 0); + if (force_time == 0) begin + void'(uvm_hdl_deposit(path, value)); + return; + end + if (!uvm_hdl_force(path, value)) + return; + #force_time; + void'(uvm_hdl_release_and_read(path, value)); + endtask + import "DPI-C" context function int uvm_hdl_release_and_read(string path, inout uvm_hdl_data_t value); + import "DPI-C" context function int uvm_hdl_release(string path); + import "DPI-C" context function int uvm_hdl_read(string path, output uvm_hdl_data_t value); +import "DPI-C" function string uvm_dpi_get_next_arg_c (int init); +import "DPI-C" function string uvm_dpi_get_tool_name_c (); +import "DPI-C" function string uvm_dpi_get_tool_version_c (); +function string uvm_dpi_get_next_arg(int init=0); + return uvm_dpi_get_next_arg_c(init); +endfunction +function string uvm_dpi_get_tool_name(); + return uvm_dpi_get_tool_name_c(); +endfunction +function string uvm_dpi_get_tool_version(); + return uvm_dpi_get_tool_version_c(); +endfunction +import "DPI-C" function chandle uvm_dpi_regcomp(string regex); +import "DPI-C" function int uvm_dpi_regexec(chandle preg, string str); +import "DPI-C" function void uvm_dpi_regfree(chandle preg); +import "DPI-C" context function int uvm_re_match(string re, string str); +import "DPI-C" context function string uvm_glob_to_re(string glob); + typedef class uvm_cmdline_processor; +parameter string UVM_VERSION_STRING = "Accellera:1800.2-2017:UVM:1.0"; +function string uvm_revision_string(); + return UVM_VERSION_STRING; +endfunction +parameter UVM_STREAMBITS = 4096; +typedef logic signed [UVM_STREAMBITS-1:0] uvm_bitstream_t; +typedef logic signed [63:0] uvm_integral_t; +parameter UVM_FIELD_FLAG_RESERVED_BITS = 28; +typedef bit [UVM_FIELD_FLAG_RESERVED_BITS-1 : 0] uvm_field_flag_t; +typedef enum uvm_field_flag_t { + UVM_BIN = 'h1000000, + UVM_DEC = 'h2000000, + UVM_UNSIGNED = 'h3000000, + UVM_UNFORMAT2 = 'h4000000, + UVM_UNFORMAT4 = 'h5000000, + UVM_OCT = 'h6000000, + UVM_HEX = 'h7000000, + UVM_STRING = 'h8000000, + UVM_TIME = 'h9000000, + UVM_ENUM = 'ha000000, + UVM_REAL = 'hb000000, + UVM_REAL_DEC = 'hc000000, + UVM_REAL_EXP = 'hd000000, + UVM_NORADIX = 0 +} uvm_radix_enum; +parameter UVM_RADIX = 'hf000000; +function string uvm_radix_to_string(uvm_radix_enum radix); + case(radix) + UVM_BIN: return "b"; + UVM_OCT: return "o"; + UVM_DEC: return "d"; + UVM_HEX: return "h"; + UVM_UNSIGNED: return "u"; + UVM_UNFORMAT2: return "u"; + UVM_UNFORMAT4: return "z"; + UVM_STRING: return "s"; + UVM_TIME: return "t"; + UVM_ENUM: return "s"; + UVM_REAL: return "g"; + UVM_REAL_DEC: return "f"; + UVM_REAL_EXP: return "e"; + default: return "x"; + endcase +endfunction +typedef enum uvm_field_flag_t { + UVM_DEFAULT_POLICY = 0, + UVM_DEEP = (1<<16), + UVM_SHALLOW = (1<<17), + UVM_REFERENCE = (1<<18) + } uvm_recursion_policy_enum; +parameter UVM_RECURSION = (UVM_DEEP|UVM_SHALLOW|UVM_REFERENCE); +typedef enum bit { UVM_PASSIVE=0, UVM_ACTIVE=1 } uvm_active_passive_enum; +parameter uvm_field_flag_t UVM_MACRO_NUMFLAGS = 19; +parameter uvm_field_flag_t UVM_DEFAULT = 'b000010101010101; +parameter uvm_field_flag_t UVM_ALL_ON = 'b000000101010101; +parameter uvm_field_flag_t UVM_FLAGS_ON = 'b000000101010101; +parameter uvm_field_flag_t UVM_FLAGS_OFF = 0; +parameter uvm_field_flag_t UVM_COPY = (1<<0); +parameter uvm_field_flag_t UVM_NOCOPY = (1<<1); +parameter uvm_field_flag_t UVM_COMPARE = (1<<2); +parameter uvm_field_flag_t UVM_NOCOMPARE = (1<<3); +parameter uvm_field_flag_t UVM_PRINT = (1<<4); +parameter uvm_field_flag_t UVM_NOPRINT = (1<<5); +parameter uvm_field_flag_t UVM_RECORD = (1<<6); +parameter uvm_field_flag_t UVM_NORECORD = (1<<7); +parameter uvm_field_flag_t UVM_PACK = (1<<8); +parameter uvm_field_flag_t UVM_NOPACK = (1<<9); +parameter uvm_field_flag_t UVM_UNPACK = (1<<10); +parameter uvm_field_flag_t UVM_NOUNPACK = UVM_NOPACK; +parameter uvm_field_flag_t UVM_SET = (1<<11); +parameter uvm_field_flag_t UVM_NOSET = (1<<12); +parameter uvm_field_flag_t UVM_NODEFPRINT = (1<<15); +parameter uvm_field_flag_t UVM_MACRO_EXTRAS = (1<"; + uvm_object_value_str.itoa(v.get_inst_id()); + uvm_object_value_str = {"@",uvm_object_value_str}; +endfunction +function string uvm_leaf_scope (string full_name, byte scope_separator = "."); + byte bracket_match; + int pos; + int bmatches; + bmatches = 0; + case(scope_separator) + "[": bracket_match = "]"; + "(": bracket_match = ")"; + "<": bracket_match = ">"; + "{": bracket_match = "}"; + default: bracket_match = ""; + endcase + if(bracket_match != "" && bracket_match != full_name[full_name.len()-1]) + bracket_match = ""; + for(pos=full_name.len()-1; pos>0; --pos) begin + if(full_name[pos] == bracket_match) bmatches++; + else if(full_name[pos] == scope_separator) begin + bmatches--; + if(!bmatches || (bracket_match == "")) break; + end + end + if(pos) begin + if(scope_separator != ".") pos--; + uvm_leaf_scope = full_name.substr(pos+1,full_name.len()-1); + end + else begin + uvm_leaf_scope = full_name; + end +endfunction +function string uvm_bitstream_to_string (uvm_bitstream_t value, int size, + uvm_radix_enum radix=UVM_NORADIX, + string radix_str=""); + if (radix == UVM_DEC && value[size-1] === 1) + return $sformatf("%0d", value); + if($isunknown(value)) begin + uvm_bitstream_t _t; + _t=0; + for(int idx=0;idx 0 && (arg[i] != "[")) begin + --i; + if((arg[i] == "*") || (arg[i] == "?")) i=0; + else if((arg[i] < "0") || (arg[i] > "9") && (arg[i] != "[")) begin + uvm_get_array_index_int = -1; + i=0; + end + end + else begin + is_wildcard = 0; + return 0; + end + if(i>0) begin + arg = arg.substr(i+1, arg.len()-2); + uvm_get_array_index_int = arg.atoi(); + is_wildcard = 0; + end +endfunction +function string uvm_get_array_index_string(string arg, output bit is_wildcard); + int i; + uvm_get_array_index_string = ""; + is_wildcard = 1; + i = arg.len() - 1; + if(arg[i] == "]") + while(i > 0 && (arg[i] != "[")) begin + if((arg[i] == "*") || (arg[i] == "?")) i=0; + --i; + end + if(i>0) begin + uvm_get_array_index_string = arg.substr(i+1, arg.len()-2); + is_wildcard = 0; + end +endfunction +function bit uvm_is_array(string arg); + return arg[arg.len()-1] == "]"; +endfunction +function automatic bit uvm_has_wildcard (string arg); + uvm_has_wildcard = 0; + if( (arg.len() > 1) && (arg[0] == "/") && (arg[arg.len()-1] == "/") ) + return 1; + foreach(arg[i]) + if( (arg[i] == "*") || (arg[i] == "+") || (arg[i] == "?") ) + uvm_has_wildcard = 1; +endfunction +typedef class uvm_component; +typedef class uvm_root; +typedef class uvm_report_object; +function automatic string m_uvm_string_queue_join(ref string i[$]); + m_uvm_string_queue_join = {>>{i}}; +endfunction +typedef class uvm_factory; +typedef class uvm_default_factory; +typedef class uvm_report_server; +typedef class uvm_default_report_server; +typedef class uvm_root; +typedef class uvm_visitor; +typedef class uvm_component_name_check_visitor; +typedef class uvm_component; +typedef class uvm_comparer; +typedef class uvm_copier; +typedef class uvm_packer; +typedef class uvm_printer; +typedef class uvm_table_printer; +typedef class uvm_tr_database; +typedef class uvm_text_tr_database; +typedef class uvm_resource_pool; +typedef class uvm_default_coreservice_t; +virtual class uvm_coreservice_t; + pure virtual function uvm_factory get_factory(); + pure virtual function void set_factory(uvm_factory f); + pure virtual function uvm_report_server get_report_server(); + pure virtual function void set_report_server(uvm_report_server server); + pure virtual function uvm_tr_database get_default_tr_database(); + pure virtual function void set_default_tr_database(uvm_tr_database db); + pure virtual function void set_component_visitor(uvm_visitor#(uvm_component) v); + pure virtual function uvm_visitor#(uvm_component) get_component_visitor(); + pure virtual function uvm_root get_root(); + pure virtual function void set_phase_max_ready_to_end(int max); + pure virtual function int get_phase_max_ready_to_end(); + pure virtual function void set_default_printer(uvm_printer printer); + pure virtual function uvm_printer get_default_printer(); + pure virtual function void set_default_packer(uvm_packer packer); + pure virtual function uvm_packer get_default_packer(); + pure virtual function void set_default_comparer(uvm_comparer comparer); + pure virtual function uvm_comparer get_default_comparer(); + pure virtual function int unsigned get_global_seed(); + pure virtual function void set_default_copier(uvm_copier copier); + pure virtual function uvm_copier get_default_copier(); + pure virtual function bit get_uvm_seeding(); + pure virtual function void set_uvm_seeding(bit enable); + pure virtual function void set_resource_pool (uvm_resource_pool pool); + pure virtual function uvm_resource_pool get_resource_pool(); + pure virtual function void set_resource_pool_default_precedence(int unsigned precedence); + pure virtual function int unsigned get_resource_pool_default_precedence(); + static uvm_coreservice_t inst; + static function uvm_coreservice_t get(); + if(inst==null) + uvm_init(null); + return inst; + endfunction + static function void set(uvm_coreservice_t cs); + inst=cs; + endfunction +endclass +class uvm_default_coreservice_t extends uvm_coreservice_t; + local uvm_factory factory; + virtual function uvm_factory get_factory(); + if(factory==null) begin + uvm_default_factory f; + f=new; + factory=f; + end + return factory; + endfunction + virtual function void set_factory(uvm_factory f); + factory = f; + endfunction + local uvm_tr_database tr_database; + virtual function uvm_tr_database get_default_tr_database(); + if (tr_database == null) begin + process p = process::self(); + uvm_text_tr_database tx_db; + string s; + if(p != null) + s = p.get_randstate(); + tx_db = new("default_tr_database"); + tr_database = tx_db; + if(p != null) + p.set_randstate(s); + end + return tr_database; + endfunction : get_default_tr_database + virtual function void set_default_tr_database(uvm_tr_database db); + tr_database = db; + endfunction : set_default_tr_database + local uvm_report_server report_server; + virtual function uvm_report_server get_report_server(); + if(report_server==null) begin + uvm_default_report_server f; + f=new; + report_server=f; + end + return report_server; + endfunction + virtual function void set_report_server(uvm_report_server server); + report_server=server; + endfunction + virtual function uvm_root get_root(); + return uvm_root::m_uvm_get_root(); + endfunction + local uvm_visitor#(uvm_component) _visitor; + virtual function void set_component_visitor(uvm_visitor#(uvm_component) v); + _visitor=v; + endfunction + virtual function uvm_visitor#(uvm_component) get_component_visitor(); + if(_visitor==null) begin + uvm_component_name_check_visitor v = new("name-check-visitor"); + _visitor=v; + end + return _visitor; + endfunction + local uvm_printer m_printer ; + virtual function void set_default_printer(uvm_printer printer); + m_printer = printer ; + endfunction + virtual function uvm_printer get_default_printer(); + if (m_printer == null) begin + m_printer = uvm_table_printer::get_default() ; + end + return m_printer ; + endfunction + local uvm_packer m_packer ; + virtual function void set_default_packer(uvm_packer packer); + m_packer = packer ; + endfunction + virtual function uvm_packer get_default_packer(); + if (m_packer == null) begin + m_packer = new("uvm_default_packer") ; + end + return m_packer ; + endfunction + local uvm_comparer m_comparer ; + virtual function void set_default_comparer(uvm_comparer comparer); + m_comparer = comparer ; + endfunction + virtual function uvm_comparer get_default_comparer(); + if (m_comparer == null) begin + m_comparer = new("uvm_default_comparer") ; + end + return m_comparer ; + endfunction + local int m_default_max_ready_to_end_iters = 20; + virtual function void set_phase_max_ready_to_end(int max); + m_default_max_ready_to_end_iters = max; + endfunction + virtual function int get_phase_max_ready_to_end(); + return m_default_max_ready_to_end_iters; + endfunction + local uvm_resource_pool m_rp ; + virtual function void set_resource_pool (uvm_resource_pool pool); + m_rp = pool; + endfunction + virtual function uvm_resource_pool get_resource_pool(); + if(m_rp == null) + m_rp = new(); + return m_rp; + endfunction + local int unsigned m_default_precedence = 1000; + virtual function void set_resource_pool_default_precedence(int unsigned precedence); + m_default_precedence = precedence; + endfunction + virtual function int unsigned get_resource_pool_default_precedence(); + return m_default_precedence; + endfunction + local int unsigned m_uvm_global_seed = $urandom; + virtual function int unsigned get_global_seed(); + return m_uvm_global_seed; + endfunction + local bit m_use_uvm_seeding = 1; + virtual function bit get_uvm_seeding(); + return m_use_uvm_seeding; + endfunction : get_uvm_seeding + virtual function void set_uvm_seeding(bit enable); + m_use_uvm_seeding = enable; + endfunction : set_uvm_seeding + local uvm_copier m_copier ; + virtual function void set_default_copier(uvm_copier copier); + m_copier = copier ; + endfunction + virtual function uvm_copier get_default_copier(); + if (m_copier == null) begin + m_copier = new("uvm_default_copier") ; + end + return m_copier ; + endfunction +endclass +typedef class uvm_root; +typedef class uvm_report_object; +typedef class uvm_report_message; +task run_test (string test_name=""); + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + top.run_test(test_name); +endtask +function uvm_report_object uvm_get_report_object(); + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + return top; +endfunction +function int uvm_report_enabled (int verbosity, + uvm_severity severity=UVM_INFO, string id=""); + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + return top.uvm_report_enabled(verbosity,severity,id); +endfunction +function void uvm_report( uvm_severity severity, + string id, + string message, + 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 = "", + bit report_enabled_checked = 0); + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + top.uvm_report(severity, id, message, verbosity, filename, line, context_name, report_enabled_checked); +endfunction +export "DPI-C" function m__uvm_report_dpi; +function void m__uvm_report_dpi(int severity, + string id, + string message, + int verbosity, + string filename, + int line); + uvm_report(uvm_severity'(severity), id, message, verbosity, filename, line); +endfunction : m__uvm_report_dpi +function void uvm_report_info(string id, + string message, + int verbosity = UVM_MEDIUM, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + top.uvm_report_info(id, message, verbosity, filename, line, context_name, + report_enabled_checked); +endfunction +function void uvm_report_warning(string id, + string message, + int verbosity = UVM_MEDIUM, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + top.uvm_report_warning(id, message, verbosity, filename, line, context_name, + report_enabled_checked); +endfunction +function void uvm_report_error(string id, + string message, + int verbosity = UVM_NONE, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + top.uvm_report_error(id, message, verbosity, filename, line, context_name, + report_enabled_checked); +endfunction +function void uvm_report_fatal(string id, + string message, + int verbosity = UVM_NONE, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + top.uvm_report_fatal(id, message, verbosity, filename, line, context_name, + report_enabled_checked); +endfunction +function void uvm_process_report_message(uvm_report_message report_message); + uvm_root top; + uvm_coreservice_t cs; + process p; + p = process::self(); + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + top.uvm_process_report_message(report_message); +endfunction +function bit uvm_string_to_severity (string sev_str, output uvm_severity sev); + case (sev_str) + "UVM_INFO": sev = UVM_INFO; + "UVM_WARNING": sev = UVM_WARNING; + "UVM_ERROR": sev = UVM_ERROR; + "UVM_FATAL": sev = UVM_FATAL; + default: return 0; + endcase + return 1; +endfunction +function automatic bit uvm_string_to_action (string action_str, output uvm_action action); + string actions[$]; + uvm_split_string(action_str,"|",actions); + uvm_string_to_action = 1; + action = 0; + foreach(actions[i]) begin + case (actions[i]) + "UVM_NO_ACTION": action |= UVM_NO_ACTION; + "UVM_DISPLAY": action |= UVM_DISPLAY; + "UVM_LOG": action |= UVM_LOG; + "UVM_COUNT": action |= UVM_COUNT; + "UVM_EXIT": action |= UVM_EXIT; + "UVM_CALL_HOOK": action |= UVM_CALL_HOOK; + "UVM_STOP": action |= UVM_STOP; + "UVM_RM_RECORD": action |= UVM_RM_RECORD; + default: uvm_string_to_action = 0; + endcase + end +endfunction +function bit uvm_is_match (string expr, string str); + string s; + s = uvm_glob_to_re(expr); + return (uvm_re_match(s, str) == 0); +endfunction +parameter UVM_LINE_WIDTH = 120; +parameter UVM_NUM_LINES = 120; +parameter UVM_SMALL_STRING = UVM_LINE_WIDTH*8-1; +parameter UVM_LARGE_STRING = UVM_LINE_WIDTH*UVM_NUM_LINES*8-1; +function logic[UVM_LARGE_STRING:0] uvm_string_to_bits(string str); + $swrite(uvm_string_to_bits, "%0s", str); +endfunction +function uvm_core_state get_core_state(); + return m_uvm_core_state; +endfunction +function void uvm_init(uvm_coreservice_t cs=null); + uvm_default_coreservice_t dcs; + if(get_core_state()!=UVM_CORE_UNINITIALIZED) begin + if (get_core_state() == UVM_CORE_PRE_INIT) begin + dcs = new(); + uvm_coreservice_t::set(dcs); + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"UVM/INIT/MULTI")) + uvm_report_fatal ("UVM/INIT/MULTI", "Non-recoverable race during uvm_init", UVM_NONE, "t/uvm/src/base/uvm_globals.svh", 335, "", 1); + end + end + else begin + uvm_coreservice_t actual; + actual = uvm_coreservice_t::inst; + if ((cs != actual) && (cs != null)) + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/INIT/MULTI")) + uvm_report_warning ("UVM/INIT/MULTI", "uvm_init() called after library has already completed initialization, subsequent calls are ignored!", UVM_NONE, "t/uvm/src/base/uvm_globals.svh", 349, "", 1); + end + end + return; + end + m_uvm_core_state=UVM_CORE_PRE_INIT; + if(cs == null) begin + dcs = new(); + cs = dcs; + end + uvm_coreservice_t::set(cs); + m_uvm_core_state=UVM_CORE_INITIALIZING; + foreach(uvm_deferred_init[idx]) begin + uvm_deferred_init[idx].initialize(); + end + uvm_deferred_init.delete(); + begin + uvm_root top; + top = uvm_root::get(); + top.report_header(); + top.m_check_uvm_field_flag_size(); + top.m_check_verbosity(); + end + m_uvm_core_state=UVM_CORE_INITIALIZED; +endfunction +function string uvm_bits_to_string(logic [UVM_LARGE_STRING:0] str); + $swrite(uvm_bits_to_string, "%0s", str); +endfunction +task uvm_wait_for_nba_region; + int nba; + int next_nba; + next_nba++; + nba <= next_nba; + @(nba); +endtask +function automatic void uvm_split_string (string str, byte sep, ref string values[$]); + int s = 0, e = 0; + values.delete(); + while(e < str.len()) begin + for(s=e; e"; endfunction + virtual function uvm_object create (string name=""); return null; endfunction + extern virtual function uvm_object clone (); + extern function void print (uvm_printer printer=null); + extern function string sprint (uvm_printer printer=null); + extern virtual function void do_print (uvm_printer printer); + extern virtual function string convert2string(); + extern function void record (uvm_recorder recorder=null); + extern virtual function void do_record (uvm_recorder recorder); + extern function void copy (uvm_object rhs, uvm_copier copier=null); + extern virtual function void do_copy (uvm_object rhs); + extern function bit compare (uvm_object rhs, uvm_comparer comparer=null); + extern virtual function bit do_compare (uvm_object rhs, + uvm_comparer comparer); + extern function int pack (ref bit bitstream[], + input uvm_packer packer=null); + extern function int pack_bytes (ref byte unsigned bytestream[], + input uvm_packer packer=null); + extern function int pack_ints (ref int unsigned intstream[], + input uvm_packer packer=null); + extern function int pack_longints (ref longint unsigned longintstream[], + input uvm_packer packer=null); + extern virtual function void do_pack (uvm_packer packer); + extern function int unpack (ref bit bitstream[], + input uvm_packer packer=null); + extern function int unpack_bytes (ref byte unsigned bytestream[], + input uvm_packer packer=null); + extern function int unpack_ints (ref int unsigned intstream[], + input uvm_packer packer=null); + extern function int unpack_longints (ref longint unsigned longintstream[], + input uvm_packer packer=null); + extern virtual function void do_unpack (uvm_packer packer); + extern virtual function void do_execute_op ( uvm_field_op op); + extern virtual function void set_local(uvm_resource_base rsrc) ; + extern local function void m_pack (inout uvm_packer packer); + extern local function void m_unpack_pre (inout uvm_packer packer); + extern local function int m_unpack_post (uvm_packer packer); + extern virtual function void m_unsupported_set_local(uvm_resource_base rsrc); + local string m_leaf_name; + local int m_inst_id; + static protected int m_inst_count; + extern virtual function void __m_uvm_field_automation (uvm_object tmp_data__, + uvm_field_flag_t what__, + string str__); + extern protected virtual function uvm_report_object m_get_report_object(); +endclass +function uvm_object::new (string name=""); + m_inst_id = m_inst_count++; + m_leaf_name = name; +endfunction +function bit uvm_object::get_uvm_seeding(); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + return cs.get_uvm_seeding(); +endfunction +function void uvm_object::set_uvm_seeding(bit enable); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + cs.set_uvm_seeding(enable); +endfunction +function void uvm_object::reseed (); + if(get_uvm_seeding()) + this.srandom(uvm_create_random_seed(get_type_name(), get_full_name())); +endfunction +function uvm_object_wrapper uvm_object::get_type(); + uvm_report_error("NOTYPID", "get_type not implemented in derived class.", UVM_NONE); + return null; +endfunction +function int uvm_object::get_inst_id(); + return m_inst_id; +endfunction +function uvm_object_wrapper uvm_object::get_object_type(); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory=cs.get_factory(); + if(get_type_name() == "") return null; + return factory.find_wrapper_by_name(get_type_name()); +endfunction +function int uvm_object::get_inst_count(); + return m_inst_count; +endfunction +function string uvm_object::get_name (); + return m_leaf_name; +endfunction +function string uvm_object::get_full_name (); + return get_name(); +endfunction +function void uvm_object::set_name (string name); + m_leaf_name = name; +endfunction +function void uvm_object::print(uvm_printer printer=null); + if (printer==null) printer = uvm_printer::get_default(); + $fwrite(printer.get_file(),sprint(printer)); +endfunction +function string uvm_object::sprint(uvm_printer printer=null); + string name; + if(printer==null) printer = uvm_printer::get_default(); + if (printer.get_active_object_depth() == 0) begin + printer.flush() ; + name = printer.get_root_enabled() ? get_full_name() : get_name(); + end + else begin + name = get_name(); + end + printer.print_object(name,this); + return printer.emit(); +endfunction +function string uvm_object::convert2string(); + return ""; +endfunction +function void uvm_object::set_local(uvm_resource_base rsrc) ; + if(rsrc==null) begin + return ; + end + else begin + begin + uvm_field_op op; + op = uvm_field_op::m_get_available_op(); + op.set(UVM_SET,null,rsrc); + this.do_execute_op(op); + op.m_recycle(); + end + end +endfunction +function void uvm_object::m_unsupported_set_local(uvm_resource_base rsrc); + return; +endfunction +function uvm_object uvm_object::clone(); + uvm_object tmp; + tmp = this.create(get_name()); + if(tmp == null) + uvm_report_warning("CRFLD", $sformatf("The create method failed for %s, object cannot be cloned", get_name()), UVM_NONE); + else + tmp.copy(this); + return(tmp); +endfunction +function void uvm_object::copy (uvm_object rhs, uvm_copier copier=null); +uvm_coreservice_t coreservice ; +uvm_copier m_copier; + if(rhs == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"OBJ/COPY")) + uvm_report_error ("OBJ/COPY", "Passing a null object to be copied", UVM_NONE, "t/uvm/src/base/uvm_object.svh", 1138, "", 1); + end + return; + end + if(copier == null) begin + coreservice = uvm_coreservice_t::get() ; + m_copier = coreservice.get_default_copier() ; + end + else + m_copier = copier; + if(m_copier.get_active_object_depth() == 0) + m_copier.flush(); + m_copier.copy_object(this,rhs); +endfunction +function void uvm_object::do_copy (uvm_object rhs); + return; +endfunction +function bit uvm_object::compare (uvm_object rhs, + uvm_comparer comparer=null); + if (comparer == null) comparer = uvm_comparer::get_default(); + if (comparer.get_active_object_depth() == 0) + comparer.flush() ; + compare = comparer.compare_object(get_name(),this,rhs); +endfunction +function bit uvm_object::do_compare (uvm_object rhs, + uvm_comparer comparer); + return 1; +endfunction +function void uvm_object::__m_uvm_field_automation (uvm_object tmp_data__, + uvm_field_flag_t what__, + string str__ ); + return; +endfunction +function void uvm_object::do_print(uvm_printer printer); + return; +endfunction +function void uvm_object::m_pack (inout uvm_packer packer); + if (packer == null) + packer = uvm_packer::get_default(); + if(packer.get_active_object_depth() == 0) + packer.flush(); + packer.pack_object(this); +endfunction +function int uvm_object::pack (ref bit bitstream [], + input uvm_packer packer =null ); + m_pack(packer); + packer.get_packed_bits(bitstream); + return packer.get_packed_size(); +endfunction +function int uvm_object::pack_bytes (ref byte unsigned bytestream [], + input uvm_packer packer=null ); + m_pack(packer); + packer.get_packed_bytes(bytestream); + return packer.get_packed_size(); +endfunction +function int uvm_object::pack_ints (ref int unsigned intstream [], + input uvm_packer packer=null ); + m_pack(packer); + packer.get_packed_ints(intstream); + return packer.get_packed_size(); +endfunction +function int uvm_object::pack_longints (ref longint unsigned longintstream [], + input uvm_packer packer=null ); + m_pack(packer); + packer.get_packed_longints(longintstream); + return packer.get_packed_size(); +endfunction +function void uvm_object::do_pack (uvm_packer packer ); + if (packer == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/OBJ/PACK/NULL")) + uvm_report_error ("UVM/OBJ/PACK/NULL", "uvm_object::do_pack called with null packer!", UVM_NONE, "t/uvm/src/base/uvm_object.svh", 1265, "", 1); + end + return; +endfunction +function void uvm_object::m_unpack_pre (inout uvm_packer packer); + if (packer == null) + packer = uvm_packer::get_default(); + if(packer.get_active_object_depth() == 0) + packer.flush(); +endfunction +function int uvm_object::m_unpack_post (uvm_packer packer); + int size_before_unpack = packer.get_packed_size(); + packer.unpack_object(this); + return size_before_unpack - packer.get_packed_size(); +endfunction +function int uvm_object::unpack (ref bit bitstream [], + input uvm_packer packer=null); + m_unpack_pre(packer); + packer.set_packed_bits(bitstream); + return m_unpack_post(packer); +endfunction +function int uvm_object::unpack_bytes (ref byte unsigned bytestream [], + input uvm_packer packer=null); + m_unpack_pre(packer); + packer.set_packed_bytes(bytestream); + return m_unpack_post(packer); +endfunction +function int uvm_object::unpack_ints (ref int unsigned intstream [], + input uvm_packer packer=null); + m_unpack_pre(packer); + packer.set_packed_ints(intstream); + return m_unpack_post(packer); +endfunction +function int uvm_object::unpack_longints (ref longint unsigned longintstream [], + input uvm_packer packer=null); + m_unpack_pre(packer); + packer.set_packed_longints(longintstream); + return m_unpack_post(packer); +endfunction +function void uvm_object::do_execute_op ( uvm_field_op op); +endfunction +function void uvm_object::do_unpack (uvm_packer packer); + if (packer == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/OBJ/UNPACK/NULL")) + uvm_report_error ("UVM/OBJ/UNPACK/NULL", "uvm_object::do_unpack called with null packer!", UVM_NONE, "t/uvm/src/base/uvm_object.svh", 1345, "", 1); + end + return; +endfunction +function void uvm_object::record (uvm_recorder recorder=null); + if(recorder == null) + return; + recorder.record_object(get_name(), this); +endfunction +function void uvm_object::do_record (uvm_recorder recorder); + return; +endfunction +function uvm_report_object uvm_object::m_get_report_object(); + return null; +endfunction +typedef class uvm_object; +typedef class uvm_component; +typedef class uvm_object_wrapper; +typedef class uvm_factory_override; +typedef struct {uvm_object_wrapper m_type; + string m_type_name;} m_uvm_factory_type_pair_t; +class uvm_factory_queue_class; + uvm_factory_override queue[$]; +endclass +virtual class uvm_factory; + static function uvm_factory get(); + uvm_coreservice_t s; + s = uvm_coreservice_t::get(); + return s.get_factory(); + endfunction + static function void set(uvm_factory f); + uvm_coreservice_t s; + s = uvm_coreservice_t::get(); + s.set_factory(f); + endfunction + pure virtual function void register (uvm_object_wrapper obj); + pure virtual function + void set_inst_override_by_type (uvm_object_wrapper original_type, + uvm_object_wrapper override_type, + string full_inst_path); + pure virtual function + void set_inst_override_by_name (string original_type_name, + string override_type_name, + string full_inst_path); + pure virtual function + void set_type_override_by_type (uvm_object_wrapper original_type, + uvm_object_wrapper override_type, + bit replace=1); + pure virtual function + void set_type_override_by_name (string original_type_name, + string override_type_name, + bit replace=1); + pure virtual function + uvm_object create_object_by_type (uvm_object_wrapper requested_type, + string parent_inst_path="", + string name=""); + pure virtual function + uvm_component create_component_by_type (uvm_object_wrapper requested_type, + string parent_inst_path="", + string name, + uvm_component parent); + pure virtual function + uvm_object create_object_by_name (string requested_type_name, + string parent_inst_path="", + string name=""); + pure virtual + function bit is_type_name_registered (string type_name); + pure virtual + function bit is_type_registered (uvm_object_wrapper obj); + pure virtual function + uvm_component create_component_by_name (string requested_type_name, + string parent_inst_path="", + string name, + uvm_component parent); + pure virtual function + void set_type_alias(string alias_type_name, + uvm_object_wrapper original_type); + pure virtual function + void set_inst_alias(string alias_type_name, + uvm_object_wrapper original_type, string full_inst_path); + pure virtual function + void debug_create_by_type (uvm_object_wrapper requested_type, + string parent_inst_path="", + string name=""); + pure virtual function + void debug_create_by_name (string requested_type_name, + string parent_inst_path="", + string name=""); + pure virtual function + uvm_object_wrapper find_override_by_type (uvm_object_wrapper requested_type, + string full_inst_path); + pure virtual function + uvm_object_wrapper find_override_by_name (string requested_type_name, + string full_inst_path); + pure virtual + function uvm_object_wrapper find_wrapper_by_name (string type_name); + pure virtual function void print (int all_types=1); +endclass +class uvm_default_factory extends uvm_factory; + extern virtual function void register (uvm_object_wrapper obj); + extern virtual function + void set_inst_override_by_type (uvm_object_wrapper original_type, + uvm_object_wrapper override_type, + string full_inst_path); + extern virtual function + void set_inst_override_by_name (string original_type_name, + string override_type_name, + string full_inst_path); + extern virtual function + void set_type_override_by_type (uvm_object_wrapper original_type, + uvm_object_wrapper override_type, + bit replace=1); + extern virtual function + void set_type_override_by_name (string original_type_name, + string override_type_name, + bit replace=1); + extern virtual function + void set_type_alias(string alias_type_name, + uvm_object_wrapper original_type); + extern virtual function + void set_inst_alias(string alias_type_name, + uvm_object_wrapper original_type, string full_inst_path); + extern virtual function + uvm_object create_object_by_type (uvm_object_wrapper requested_type, + string parent_inst_path="", + string name=""); + extern virtual function + uvm_component create_component_by_type (uvm_object_wrapper requested_type, + string parent_inst_path="", + string name, + uvm_component parent); + extern virtual function + uvm_object create_object_by_name (string requested_type_name, + string parent_inst_path="", + string name=""); + extern virtual function + uvm_component create_component_by_name (string requested_type_name, + string parent_inst_path="", + string name, + uvm_component parent); + extern virtual + function bit is_type_name_registered (string type_name); + extern virtual + function bit is_type_registered (uvm_object_wrapper obj); + extern virtual function + void debug_create_by_type (uvm_object_wrapper requested_type, + string parent_inst_path="", + string name=""); + extern virtual function + void debug_create_by_name (string requested_type_name, + string parent_inst_path="", + string name=""); + extern virtual function + uvm_object_wrapper find_override_by_type (uvm_object_wrapper requested_type, + string full_inst_path); + extern virtual function + uvm_object_wrapper find_override_by_name (string requested_type_name, + string full_inst_path); + extern virtual + function uvm_object_wrapper find_wrapper_by_name (string type_name); + extern virtual function void print (int all_types=1); + extern protected + function void m_debug_create (string requested_type_name, + uvm_object_wrapper requested_type, + string parent_inst_path, + string name); + extern protected + function void m_debug_display(string requested_type_name, + uvm_object_wrapper result, + string full_inst_path); + extern + function uvm_object_wrapper m_resolve_type_name(string requested_type_name); + extern + function uvm_object_wrapper m_resolve_type_name_by_inst(string requested_type_name, + string full_inst_path); + extern + function bit m_matches_type_pair(m_uvm_factory_type_pair_t match_type_pair, + uvm_object_wrapper requested_type, + string requested_type_name); + extern + function bit m_matches_type_override(uvm_factory_override override, + uvm_object_wrapper requested_type, + string requested_type_name, + string full_inst_path="", + bit match_original_type = 1, + bit resolve_null_type_by_inst=0); + extern + function bit m_matches_inst_override(uvm_factory_override override, + uvm_object_wrapper requested_type, + string requested_type_name, + string full_inst_path=""); + typedef struct { + m_uvm_factory_type_pair_t orig; + string alias_type_name; + string full_inst_path; + } m_inst_typename_alias_t; + protected bit m_types[uvm_object_wrapper]; + protected bit m_lookup_strs[string]; + protected uvm_object_wrapper m_type_names[string]; + protected m_inst_typename_alias_t m_inst_aliases[$]; + protected uvm_factory_override m_type_overrides[$]; + protected uvm_factory_override m_inst_overrides[$]; + local uvm_factory_override m_override_info[$]; + local static bit m_debug_pass; + extern function bit check_inst_override_exists + (uvm_object_wrapper original_type, + string original_type_name, + uvm_object_wrapper override_type, + string override_type_name, + string full_inst_path); +endclass +virtual class uvm_object_wrapper; + virtual function uvm_object create_object (string name=""); + return null; + endfunction + virtual function uvm_component create_component (string name, + uvm_component parent); + return null; + endfunction + pure virtual function string get_type_name(); + virtual function void initialize(); endfunction +endclass +class uvm_factory_override; + string full_inst_path; + m_uvm_factory_type_pair_t orig; + m_uvm_factory_type_pair_t ovrd; + bit replace; + bit selected; + int unsigned used; + bit has_wildcard; + function new (string full_inst_path="", + string orig_type_name="", + uvm_object_wrapper orig_type=null, + uvm_object_wrapper ovrd_type, + string ovrd_type_name="", + bit replace=0); + this.full_inst_path= full_inst_path; + this.orig.m_type_name = orig_type_name; + this.orig.m_type = orig_type; + this.ovrd.m_type_name = ovrd_type_name; + this.ovrd.m_type = ovrd_type; + this.replace = replace; + this.has_wildcard = m_has_wildcard(full_inst_path); + endfunction + function bit m_has_wildcard(string nm); + foreach (nm[i]) + if(nm[i] == "*" || nm[i] == "?") return 1; + return 0; + endfunction +endclass +function void uvm_default_factory::register (uvm_object_wrapper obj); + if (obj == null) begin + uvm_report_fatal ("NULLWR", "Attempting to register a null object with the factory", UVM_NONE); + end + if (obj.get_type_name() != "" && obj.get_type_name() != "") begin + if (m_type_names.exists(obj.get_type_name())) + uvm_report_warning("TPRGED", {"Type name '",obj.get_type_name(), + "' already registered with factory. No string-based lookup ", + "support for multiple types with the same type name."}, UVM_NONE); + else + m_type_names[obj.get_type_name()] = obj; + end + if (m_types.exists(obj)) begin + if (obj.get_type_name() != "" && obj.get_type_name() != "") + uvm_report_warning("TPRGED", {"Object type '",obj.get_type_name(), + "' already registered with factory. "}, UVM_NONE); + end + else begin + uvm_factory_override overrides[$]; + m_types[obj] = 1; + overrides = {m_type_overrides, m_inst_overrides}; + foreach (overrides[index]) begin + if(m_matches_type_pair(.match_type_pair(overrides[index].orig), + .requested_type(null), + .requested_type_name(obj.get_type_name()))) begin + overrides[index].orig.m_type = obj; + end + if(m_matches_type_pair(.match_type_pair(overrides[index].ovrd), + .requested_type(null), + .requested_type_name(obj.get_type_name()))) begin + overrides[index].ovrd.m_type = obj; + end + end + end +endfunction +function void uvm_default_factory::set_type_override_by_type (uvm_object_wrapper original_type, + uvm_object_wrapper override_type, + bit replace=1); + bit replaced; + if (original_type == override_type) begin + if (original_type.get_type_name() == "" || original_type.get_type_name() == "") + uvm_report_warning("TYPDUP", {"Original and override type ", + "arguments are identical"}, UVM_NONE); + else + uvm_report_warning("TYPDUP", {"Original and override type ", + "arguments are identical: ", + original_type.get_type_name()}, UVM_NONE); + end + if (!m_types.exists(original_type)) + register(original_type); + if (!m_types.exists(override_type)) + register(override_type); + foreach (m_type_overrides[index]) begin + if(m_matches_type_override(.override(m_type_overrides[index]), + .requested_type(original_type), + .requested_type_name(original_type.get_type_name()))) begin + string msg; + msg = {"Original object type '",original_type.get_type_name(), + "' already registered to produce '", + m_type_overrides[index].ovrd.m_type_name,"'"}; + if (!replace) begin + msg = {msg, ". Set 'replace' argument to replace the existing entry."}; + uvm_report_info("TPREGD", msg, UVM_MEDIUM); + return; + end + msg = {msg, ". Replacing with override to produce type '", + override_type.get_type_name(),"'."}; + uvm_report_info("TPREGR", msg, UVM_MEDIUM); + replaced = 1; + m_type_overrides[index].orig.m_type = original_type; + m_type_overrides[index].orig.m_type_name = original_type.get_type_name(); + m_type_overrides[index].ovrd.m_type = override_type; + m_type_overrides[index].ovrd.m_type_name = override_type.get_type_name(); + m_type_overrides[index].replace = replace; + end + else if (m_type_overrides[index].orig.m_type == null) begin + break; + end + end + if (!replaced) begin + uvm_factory_override override; + override = new(.orig_type(original_type), + .orig_type_name(original_type.get_type_name()), + .ovrd_type(override_type), + .ovrd_type_name(override_type.get_type_name()), + .replace(replace)); + m_type_overrides.push_front(override); + end +endfunction +function void uvm_default_factory::set_type_override_by_name (string original_type_name, + string override_type_name, + bit replace=1); + bit replaced; + uvm_object_wrapper original_type; + uvm_object_wrapper override_type; + if(m_type_names.exists(original_type_name)) + original_type = m_type_names[original_type_name]; + if(m_type_names.exists(override_type_name)) + override_type = m_type_names[override_type_name]; + if (original_type_name == override_type_name) begin + uvm_report_warning("TYPDUP", {"Requested and actual type name ", + " arguments are identical: ",original_type_name,". Ignoring this override."}, UVM_NONE); + return; + end + foreach (m_type_overrides[index]) begin + if(m_matches_type_override(.override(m_type_overrides[index]), + .requested_type(original_type), + .requested_type_name(original_type_name))) begin + if (!replace) begin + uvm_report_info("TPREGD", {"Original type '",original_type_name, "'/'",m_type_overrides[index].orig.m_type_name, + "' already registered to produce '",m_type_overrides[index].ovrd.m_type_name, + "'. Set 'replace' argument to replace the existing entry."}, UVM_MEDIUM); + return; + end + uvm_report_info("TPREGR", {"Original object type '",original_type_name, "'/'",m_type_overrides[index].orig.m_type_name, + "' already registered to produce '",m_type_overrides[index].ovrd.m_type_name, + "'. Replacing with override to produce type '",override_type_name,"'."}, UVM_MEDIUM); + replaced = 1; + m_type_overrides[index].ovrd.m_type = override_type; + m_type_overrides[index].ovrd.m_type_name = override_type_name; + m_type_overrides[index].replace = replace; + end + else if ((m_type_overrides[index].orig.m_type == null) || (original_type == null)) begin + break; + end + end + if (original_type == null) + m_lookup_strs[original_type_name] = 1; + if (!replaced) begin + uvm_factory_override override; + override = new(.orig_type(original_type), + .orig_type_name(original_type_name), + .ovrd_type(override_type), + .ovrd_type_name(override_type_name), + .replace(replace) + ); + m_type_overrides.push_front(override); + end +endfunction +function bit uvm_default_factory::check_inst_override_exists (uvm_object_wrapper original_type, + string original_type_name, + uvm_object_wrapper override_type, + string override_type_name, + string full_inst_path); + uvm_factory_override override; + foreach (m_inst_overrides[i]) begin + override = m_inst_overrides[i]; + if (override.full_inst_path == full_inst_path && + override.orig.m_type == original_type && + override.orig.m_type_name == original_type_name && + override.ovrd.m_type == override_type && + override.ovrd.m_type_name == override_type_name) begin + uvm_report_info("DUPOVRD",{"Instance override for '", + original_type_name,"' already exists: override type '", + override_type_name,"' with full_inst_path '", + full_inst_path,"'"},UVM_HIGH); + return 1; + end + end + return 0; +endfunction +function void uvm_default_factory::set_inst_override_by_type (uvm_object_wrapper original_type, + uvm_object_wrapper override_type, + string full_inst_path); + uvm_factory_override override; + if (!m_types.exists(original_type)) + register(original_type); + if (!m_types.exists(override_type)) + register(override_type); + if (check_inst_override_exists(original_type, + original_type.get_type_name(), + override_type, + override_type.get_type_name(), + full_inst_path)) + return; + override = new(.full_inst_path(full_inst_path), + .orig_type(original_type), + .orig_type_name(original_type.get_type_name()), + .ovrd_type(override_type), + .ovrd_type_name(override_type.get_type_name())); + m_inst_overrides.push_back(override); +endfunction +function void uvm_default_factory::set_inst_override_by_name (string original_type_name, + string override_type_name, + string full_inst_path); + uvm_factory_override override; + uvm_object_wrapper original_type; + uvm_object_wrapper override_type; + if(m_type_names.exists(original_type_name)) + original_type = m_type_names[original_type_name]; + if(m_type_names.exists(override_type_name)) + override_type = m_type_names[override_type_name]; + if (original_type == null) + m_lookup_strs[original_type_name] = 1; + override = new(.full_inst_path(full_inst_path), + .orig_type(original_type), + .orig_type_name(original_type_name), + .ovrd_type(override_type), + .ovrd_type_name(override_type_name)); + if (check_inst_override_exists(original_type, + original_type_name, + override_type, + override_type_name, + full_inst_path)) + return; + m_inst_overrides.push_back(override); +endfunction +function void uvm_default_factory::set_type_alias(string alias_type_name, + uvm_object_wrapper original_type); + if (!is_type_registered(original_type)) + uvm_report_warning("BDTYP",{"Cannot define alias of type '", + original_type.get_type_name(),"' because it is not registered with the factory."}, UVM_NONE); + else begin + if (!m_type_names.exists(alias_type_name)) begin + uvm_factory_override overrides[$]; + m_type_names[alias_type_name] = original_type; + overrides = {m_type_overrides, m_inst_overrides}; + foreach (overrides[index]) begin + if(m_matches_type_pair(.match_type_pair(overrides[index].orig), + .requested_type(null), + .requested_type_name(alias_type_name))) begin + overrides[index].orig.m_type = original_type; + end + if(m_matches_type_pair(.match_type_pair(overrides[index].ovrd), + .requested_type(null), + .requested_type_name(alias_type_name))) begin + overrides[index].ovrd.m_type = original_type; + end + end + end + end +endfunction +function void uvm_default_factory::set_inst_alias(string alias_type_name, + uvm_object_wrapper original_type, string full_inst_path); + string original_type_name; + m_inst_typename_alias_t orig_type_alias_per_inst; + original_type_name = original_type.get_type_name(); + if (!is_type_registered(original_type)) + uvm_report_warning("BDTYP",{"Cannot define alias of type '", + original_type_name,"' because it is not registered with the factory."}, UVM_NONE); + else begin + orig_type_alias_per_inst.alias_type_name = alias_type_name; + orig_type_alias_per_inst.full_inst_path = full_inst_path; + orig_type_alias_per_inst.orig.m_type_name = original_type_name; + orig_type_alias_per_inst.orig.m_type = original_type; + m_inst_aliases.push_back(orig_type_alias_per_inst); + end +endfunction +function uvm_object uvm_default_factory::create_object_by_name (string requested_type_name, + string parent_inst_path="", + string name=""); + uvm_object_wrapper wrapper; + string inst_path; + if (parent_inst_path == "") + inst_path = name; + else if (name != "") + inst_path = {parent_inst_path,".",name}; + else + inst_path = parent_inst_path; + m_override_info.delete(); + wrapper = find_override_by_name(requested_type_name, inst_path); + if (wrapper==null) begin + wrapper = m_resolve_type_name_by_inst(requested_type_name,inst_path); + if(wrapper == null) begin + uvm_report_warning("BDTYP",{"Cannot create an object of type '", + requested_type_name,"' because it is not registered with the factory."}, UVM_NONE); + return null; + end + end + return wrapper.create_object(name); +endfunction +function uvm_object uvm_default_factory::create_object_by_type (uvm_object_wrapper requested_type, + string parent_inst_path="", + string name=""); + string full_inst_path; + if (parent_inst_path == "") + full_inst_path = name; + else if (name != "") + full_inst_path = {parent_inst_path,".",name}; + else + full_inst_path = parent_inst_path; + m_override_info.delete(); + requested_type = find_override_by_type(requested_type, full_inst_path); + return requested_type.create_object(name); +endfunction +function bit uvm_default_factory::is_type_name_registered (string type_name); + return (m_type_names.exists(type_name)); +endfunction +function bit uvm_default_factory::is_type_registered (uvm_object_wrapper obj); + return (m_types.exists(obj)); +endfunction +function uvm_component uvm_default_factory::create_component_by_name (string requested_type_name, + string parent_inst_path="", + string name, + uvm_component parent); + uvm_object_wrapper wrapper; + string inst_path; + if (parent_inst_path == "") + inst_path = name; + else if (name != "") + inst_path = {parent_inst_path,".",name}; + else + inst_path = parent_inst_path; + m_override_info.delete(); + wrapper = find_override_by_name(requested_type_name, inst_path); + if (wrapper == null) begin + if(!m_type_names.exists(requested_type_name)) begin + uvm_report_warning("BDTYP",{"Cannot create a component of type '", + requested_type_name,"' because it is not registered with the factory."}, UVM_NONE); + return null; + end + wrapper = m_type_names[requested_type_name]; + end + return wrapper.create_component(name, parent); +endfunction +function uvm_component uvm_default_factory::create_component_by_type (uvm_object_wrapper requested_type, + string parent_inst_path="", + string name, + uvm_component parent); + string full_inst_path; + if (parent_inst_path == "") + full_inst_path = name; + else if (name != "") + full_inst_path = {parent_inst_path,".",name}; + else + full_inst_path = parent_inst_path; + m_override_info.delete(); + requested_type = find_override_by_type(requested_type, full_inst_path); + return requested_type.create_component(name, parent); +endfunction +function uvm_object_wrapper uvm_default_factory::find_wrapper_by_name(string type_name); + uvm_object_wrapper wrapper = m_resolve_type_name(type_name); + if (wrapper != null) + return wrapper; + uvm_report_warning("UnknownTypeName", {"find_wrapper_by_name: Type name '",type_name, + "' not registered with the factory."}, UVM_NONE); +endfunction +function uvm_object_wrapper uvm_default_factory::find_override_by_name (string requested_type_name, + string full_inst_path); + uvm_object_wrapper rtype; + uvm_factory_override lindex; + rtype = m_resolve_type_name_by_inst(requested_type_name,full_inst_path); + if(full_inst_path != "") + begin + foreach(m_inst_overrides[i]) begin + if(m_matches_inst_override(.override(m_inst_overrides[i]), + .requested_type(rtype), + .requested_type_name(requested_type_name), + .full_inst_path(full_inst_path))) begin + m_override_info.push_back(m_inst_overrides[i]); + if (lindex == null) begin + lindex = m_inst_overrides[i]; + if (!m_debug_pass) begin + break; + end + end + end + end + end + if ((lindex == null) || m_debug_pass) begin + uvm_factory_override matched_overrides[$]; + foreach (m_type_overrides[index]) begin + if(m_matches_type_override(.override(m_type_overrides[index]), + .requested_type(rtype), + .requested_type_name(requested_type_name), + .full_inst_path(full_inst_path), + .resolve_null_type_by_inst(1))) begin + matched_overrides.push_back(m_type_overrides[index]); + if ((lindex == null) || (lindex.replace == 0)) begin + lindex = m_type_overrides[index]; + if (!m_debug_pass && lindex.replace) begin + break; + end + end + end + end + if(matched_overrides.size() != 0) begin + if (m_debug_pass) begin + m_override_info = {m_override_info,matched_overrides}; + end + else begin + m_override_info.push_back(matched_overrides[$]); + end + end + end + if (lindex != null) begin + uvm_object_wrapper override = lindex.ovrd.m_type; + lindex.used++; + if (m_debug_pass) begin + lindex.selected = 1; + end + if(!m_matches_type_override(.override(lindex), + .requested_type(rtype), + .requested_type_name(requested_type_name), + .full_inst_path(full_inst_path), + .match_original_type(0), + .resolve_null_type_by_inst(1))) begin + if(override == null) begin + override = find_override_by_name(lindex.ovrd.m_type_name,full_inst_path); + end + else begin + override = find_override_by_type(override,full_inst_path); + end + end + else if(override == null) begin + override = m_resolve_type_name_by_inst(lindex.ovrd.m_type_name,full_inst_path); + end + if(override == null) begin + uvm_report_error("TYPNTF", {"Cannot resolve override for original type '", + lindex.orig.m_type_name,"' because the override type '", + lindex.ovrd.m_type_name, "' is not registered with the factory."}, UVM_NONE); + end + return override; + end + return null; +endfunction +function uvm_object_wrapper uvm_default_factory::find_override_by_type(uvm_object_wrapper requested_type, + string full_inst_path); + uvm_object_wrapper override; + uvm_factory_override lindex; + uvm_factory_queue_class qc; + foreach (m_override_info[index]) begin + if ( + m_override_info[index].orig.m_type == requested_type) begin + uvm_report_error("OVRDLOOP", "Recursive loop detected while finding override.", UVM_NONE); + m_override_info[index].used++; + if (!m_debug_pass) + debug_create_by_type (requested_type, full_inst_path); + return requested_type; + end + end + if(full_inst_path != "") + begin + foreach(m_inst_overrides[i]) begin + if(m_matches_inst_override(.override(m_inst_overrides[i]), + .requested_type(requested_type), + .requested_type_name(requested_type.get_type_name()), + .full_inst_path(full_inst_path))) begin + m_override_info.push_back(m_inst_overrides[i]); + if (lindex == null) begin + lindex = m_inst_overrides[i]; + if (!m_debug_pass) begin + break; + end + end + end + end + end + if ((lindex == null) || m_debug_pass) begin + uvm_factory_override matched_overrides[$]; + foreach (m_type_overrides[index]) begin + if(m_matches_type_override(.override(m_type_overrides[index]), + .requested_type(requested_type), + .requested_type_name(requested_type.get_type_name()), + .full_inst_path(full_inst_path), + .resolve_null_type_by_inst(1))) begin + matched_overrides.push_back(m_type_overrides[index]); + if ((lindex == null) || (lindex.replace == 0)) begin + lindex = m_type_overrides[index]; + if (!m_debug_pass && lindex.replace) begin + break; + end + end + end + end + if(matched_overrides.size() != 0) begin + if (m_debug_pass) begin + m_override_info = {m_override_info,matched_overrides}; + end + else begin + m_override_info.push_back(matched_overrides[$]); + end + end + end + if (lindex != null) begin + uvm_object_wrapper override = lindex.ovrd.m_type; + lindex.used++; + if (m_debug_pass) begin + lindex.selected = 1; + end + if(!m_matches_type_override(.override(lindex), + .requested_type(requested_type), + .requested_type_name(requested_type.get_type_name()), + .full_inst_path(full_inst_path), + .match_original_type(0), + .resolve_null_type_by_inst(1))) begin + if(override == null) begin + override = find_override_by_name(lindex.ovrd.m_type_name,full_inst_path); + end + else begin + override = find_override_by_type(override,full_inst_path); + end + end + else if(override == null) begin + override = m_resolve_type_name_by_inst(lindex.ovrd.m_type_name,full_inst_path); + end + if(override == null) begin + uvm_report_error("TYPNTF", {"Cannot resolve override for original type '", + lindex.orig.m_type_name,"' because the override type '", + lindex.ovrd.m_type_name, "' is not registered with the factory."}, UVM_NONE); + end + return override; + end + return requested_type; +endfunction +function void uvm_default_factory::print (int all_types=1); + string key; + string qs[$]; + qs.push_back("\n#### Factory Configuration (*)\n\n"); + if(!m_type_overrides.size() && !m_inst_overrides.size()) + qs.push_back(" No instance or type overrides are registered with this factory\n"); + else begin + int max1,max2,max3; + string dash = "---------------------------------------------------------------------------------------------------"; + string space= " "; + if(!m_inst_overrides.size()) + qs.push_back("No instance overrides are registered with this factory\n"); + else begin + foreach(m_inst_overrides[j]) begin + if (m_inst_overrides[j].orig.m_type_name.len() > max1) + max1=m_inst_overrides[j].orig.m_type_name.len(); + if (m_inst_overrides[j].full_inst_path.len() > max2) + max2=m_inst_overrides[j].full_inst_path.len(); + if (m_inst_overrides[j].ovrd.m_type_name.len() > max3) + max3=m_inst_overrides[j].ovrd.m_type_name.len(); + end + if (max1 < 14) max1 = 14; + if (max2 < 13) max2 = 13; + if (max3 < 13) max3 = 13; + qs.push_back("Instance Overrides:\n\n"); + qs.push_back($sformatf(" %0s%0s %0s%0s %0s%0s\n","Requested Type",space.substr(1,max1-14), + "Override Path", space.substr(1,max2-13), + "Override Type", space.substr(1,max3-13))); + qs.push_back($sformatf(" %0s %0s %0s\n",dash.substr(1,max1), + dash.substr(1,max2), + dash.substr(1,max3))); + foreach(m_inst_overrides[j]) begin + qs.push_back($sformatf(" %0s%0s %0s%0s",m_inst_overrides[j].orig.m_type_name, + space.substr(1,max1-m_inst_overrides[j].orig.m_type_name.len()), + m_inst_overrides[j].full_inst_path, + space.substr(1,max2-m_inst_overrides[j].full_inst_path.len()))); + qs.push_back($sformatf(" %0s\n", m_inst_overrides[j].ovrd.m_type_name)); + end + end + if (!m_type_overrides.size()) + qs.push_back("\nNo type overrides are registered with this factory\n"); + else begin + if (max1 < 14) max1 = 14; + if (max2 < 13) max2 = 13; + if (max3 < 13) max3 = 13; + foreach (m_type_overrides[i]) begin + if (m_type_overrides[i].orig.m_type_name.len() > max1) + max1=m_type_overrides[i].orig.m_type_name.len(); + if (m_type_overrides[i].ovrd.m_type_name.len() > max2) + max2=m_type_overrides[i].ovrd.m_type_name.len(); + end + if (max1 < 14) max1 = 14; + if (max2 < 13) max2 = 13; + qs.push_back("\nType Overrides:\n\n"); + qs.push_back($sformatf(" %0s%0s %0s%0s\n","Requested Type",space.substr(1,max1-14), + "Override Type", space.substr(1,max2-13))); + qs.push_back($sformatf(" %0s %0s\n",dash.substr(1,max1), + dash.substr(1,max2))); + for (int index=m_type_overrides.size()-1; index>=0; index--) + qs.push_back($sformatf(" %0s%0s %0s\n", + m_type_overrides[index].orig.m_type_name, + space.substr(1,max1-m_type_overrides[index].orig.m_type_name.len()), + m_type_overrides[index].ovrd.m_type_name)); + end + end + if (all_types >= 1 && m_type_names.first(key)) begin + bit banner; + qs.push_back($sformatf("\nAll types registered with the factory: %0d total\n",m_types.num())); + do begin + if (!(all_types < 2 && uvm_is_match("uvm_*", + m_type_names[key].get_type_name())) && + key == m_type_names[key].get_type_name()) begin + if (!banner) begin + qs.push_back(" Type Name\n"); + qs.push_back(" ---------\n"); + banner=1; + end + qs.push_back($sformatf(" %s\n", m_type_names[key].get_type_name())); + end + end while(m_type_names.next(key)); + end + qs.push_back("(*) Types with no associated type name will be printed as \n\n####\n\n"); + begin + if (uvm_report_enabled(UVM_NONE,UVM_INFO,"UVM/FACTORY/PRINT")) + uvm_report_info ("UVM/FACTORY/PRINT", uvm_pkg::m_uvm_string_queue_join(qs), UVM_NONE, "t/uvm/src/base/uvm_factory.svh", 1875, "", 1); + end +endfunction +function void uvm_default_factory::debug_create_by_name (string requested_type_name, + string parent_inst_path="", + string name=""); + m_debug_create(requested_type_name, null, parent_inst_path, name); +endfunction +function void uvm_default_factory::debug_create_by_type (uvm_object_wrapper requested_type, + string parent_inst_path="", + string name=""); + m_debug_create("", requested_type, parent_inst_path, name); +endfunction +function void uvm_default_factory::m_debug_create (string requested_type_name, + uvm_object_wrapper requested_type, + string parent_inst_path, + string name); + string full_inst_path; + uvm_object_wrapper result; + if (parent_inst_path == "") + full_inst_path = name; + else if (name != "") + full_inst_path = {parent_inst_path,".",name}; + else + full_inst_path = parent_inst_path; + m_override_info.delete(); + if (requested_type == null) begin + if (!m_type_names.exists(requested_type_name) && + !m_lookup_strs.exists(requested_type_name)) begin + uvm_report_warning("Factory Warning", {"The factory does not recognize '", + requested_type_name,"' as a registered type."}, UVM_NONE); + return; + end + m_debug_pass = 1; + result = find_override_by_name(requested_type_name,full_inst_path); + end + else begin + m_debug_pass = 1; + if (!m_types.exists(requested_type)) + register(requested_type); + result = find_override_by_type(requested_type,full_inst_path); + if (requested_type_name == "") + requested_type_name = requested_type.get_type_name(); + end + m_debug_display(requested_type_name, result, full_inst_path); + m_debug_pass = 0; + foreach (m_override_info[index]) + m_override_info[index].selected = 0; +endfunction +function void uvm_default_factory::m_debug_display (string requested_type_name, + uvm_object_wrapper result, + string full_inst_path); + int max1,max2,max3; + string dash = "---------------------------------------------------------------------------------------------------"; + string space= " "; + string qs[$]; + qs.push_back("\n#### Factory Override Information (*)\n\n"); + qs.push_back( + $sformatf("Given a request for an object of type '%s' with an instance\npath of '%s' the factory encountered\n\n", + requested_type_name,full_inst_path)); + if (m_override_info.size() == 0) + qs.push_back("no relevant overrides.\n\n"); + else begin + qs.push_back("the following relevant overrides. An 'x' next to a match indicates a\nmatch that was ignored.\n\n"); + foreach (m_override_info[i]) begin + if (m_override_info[i].orig.m_type_name.len() > max1) + max1=m_override_info[i].orig.m_type_name.len(); + if (m_override_info[i].full_inst_path.len() > max2) + max2=m_override_info[i].full_inst_path.len(); + if (m_override_info[i].ovrd.m_type_name.len() > max3) + max3=m_override_info[i].ovrd.m_type_name.len(); + end + if (max1 < 13) max1 = 13; + if (max2 < 13) max2 = 13; + if (max3 < 13) max3 = 13; + qs.push_back($sformatf("Original Type%0s Instance Path%0s Override Type%0s\n", + space.substr(1,max1-13),space.substr(1,max2-13),space.substr(1,max3-13))); + qs.push_back($sformatf(" %0s %0s %0s\n",dash.substr(1,max1), + dash.substr(1,max2), + dash.substr(1,max3))); + foreach (m_override_info[i]) begin + qs.push_back($sformatf("%s%0s%0s\n", + m_override_info[i].selected ? " " : "x ", + m_override_info[i].orig.m_type_name, + space.substr(1,max1-m_override_info[i].orig.m_type_name.len()))); + qs.push_back($sformatf(" %0s%0s", m_override_info[i].full_inst_path, + space.substr(1,max2-m_override_info[i].full_inst_path.len()))); + qs.push_back($sformatf(" %0s%0s", m_override_info[i].ovrd.m_type_name, + space.substr(1,max3-m_override_info[i].ovrd.m_type_name.len()))); + if (m_override_info[i].full_inst_path == "*") + qs.push_back(" "); + else + qs.push_back("\n"); + end + qs.push_back("\n"); + end + qs.push_back("Result:\n\n"); + qs.push_back($sformatf(" The factory will produce an object of type '%0s'\n", + result == null ? requested_type_name : result.get_type_name())); + qs.push_back("\n(*) Types with no associated type name will be printed as \n\n####\n\n"); + begin + if (uvm_report_enabled(UVM_NONE,UVM_INFO,"UVM/FACTORY/DUMP")) + uvm_report_info ("UVM/FACTORY/DUMP", uvm_pkg::m_uvm_string_queue_join(qs), UVM_NONE, "t/uvm/src/base/uvm_factory.svh", 2015, "", 1); + end +endfunction +function uvm_object_wrapper uvm_default_factory::m_resolve_type_name(string requested_type_name); + uvm_object_wrapper wrapper=null; + if(m_type_names.exists(requested_type_name)) + wrapper = m_type_names[requested_type_name]; + return wrapper; +endfunction +function uvm_object_wrapper uvm_default_factory::m_resolve_type_name_by_inst(string requested_type_name, + string full_inst_path); + uvm_object_wrapper wrapper=null; + m_inst_typename_alias_t type_alias_inst[$]; + type_alias_inst = m_inst_aliases.find(i) with ((i.alias_type_name == requested_type_name) && uvm_is_match(i.full_inst_path,full_inst_path)); + if (type_alias_inst.size() > 0) begin + wrapper = type_alias_inst[0].orig.m_type; + end + else begin + wrapper = m_resolve_type_name(requested_type_name); + end + return wrapper; +endfunction +function bit uvm_default_factory::m_matches_type_pair(m_uvm_factory_type_pair_t match_type_pair, + uvm_object_wrapper requested_type, + string requested_type_name); + return ((match_type_pair.m_type != null) && + (match_type_pair.m_type == requested_type) || + (match_type_pair.m_type_name != "" && + match_type_pair.m_type_name != "" && + match_type_pair.m_type_name == requested_type_name)); +endfunction +function bit uvm_default_factory::m_matches_inst_override(uvm_factory_override override, + uvm_object_wrapper requested_type, + string requested_type_name, + string full_inst_path=""); + m_uvm_factory_type_pair_t match_type_pair = override.orig ; + if(match_type_pair.m_type == null) begin + match_type_pair.m_type = m_resolve_type_name_by_inst(match_type_pair.m_type_name, full_inst_path); + end + if (m_matches_type_pair(.match_type_pair(match_type_pair), + .requested_type(requested_type), + .requested_type_name(requested_type_name))) begin + if(override.has_wildcard) begin + return (override.full_inst_path == "*" || + uvm_is_match(override.full_inst_path,full_inst_path)); + end + else begin + return (override.full_inst_path == full_inst_path); + end + end + return 0; +endfunction +function bit uvm_default_factory::m_matches_type_override(uvm_factory_override override, + uvm_object_wrapper requested_type, + string requested_type_name, + string full_inst_path="", + bit match_original_type = 1, + bit resolve_null_type_by_inst=0); + m_uvm_factory_type_pair_t match_type_pair = match_original_type ? override.orig : override.ovrd; + if(match_type_pair.m_type == null) begin + if(resolve_null_type_by_inst) begin + match_type_pair.m_type = m_resolve_type_name_by_inst(match_type_pair.m_type_name,full_inst_path); + end + else begin + match_type_pair.m_type = m_resolve_type_name(match_type_pair.m_type_name); + end + end + return m_matches_type_pair(.match_type_pair(match_type_pair), + .requested_type(requested_type), + .requested_type_name(requested_type_name)); +endfunction +typedef class uvm_registry_common; +typedef class uvm_registry_component_creator; +typedef class uvm_registry_object_creator; +class uvm_component_registry #(type T=uvm_component, string Tname="") + extends uvm_object_wrapper; + typedef uvm_component_registry #(T,Tname) this_type; + typedef uvm_registry_common#( this_type, uvm_registry_component_creator, T, Tname ) common_type; + virtual function uvm_component create_component (string name, + uvm_component parent); + T obj; + obj = new(name, parent); + return obj; + endfunction + static function string type_name(); + return common_type::type_name(); + endfunction : type_name + virtual function string get_type_name(); + common_type common = common_type::get(); + return common.get_type_name(); + endfunction + static function this_type get(); + static this_type m_inst; + if (m_inst == null) + m_inst = new(); + return m_inst; + endfunction + virtual function void initialize(); + common_type common = common_type::get(); + common.initialize(); + endfunction + static function T create(string name, uvm_component parent, string contxt=""); + return common_type::create( name, parent, contxt ); + endfunction + static function void set_type_override (uvm_object_wrapper override_type, + bit replace=1); + common_type::set_type_override( override_type, replace ); + endfunction + static function void set_inst_override(uvm_object_wrapper override_type, + string inst_path, + uvm_component parent=null); + common_type::set_inst_override( override_type, inst_path, parent ); + endfunction + static function bit set_type_alias(string alias_name); + common_type::set_type_alias( alias_name ); + return 1; + endfunction +endclass +class uvm_object_registry #(type T=uvm_object, string Tname="") + extends uvm_object_wrapper; + typedef uvm_object_registry #(T,Tname) this_type; + typedef uvm_registry_common#( this_type, uvm_registry_object_creator, T, Tname ) common_type; + virtual function uvm_object create_object(string name=""); + T obj; + if (name=="") obj = new(); + else obj = new(name); + return obj; + endfunction + static function string type_name(); + return common_type::type_name(); + endfunction : type_name + virtual function string get_type_name(); + common_type common = common_type::get(); + return common.get_type_name(); + endfunction + static function this_type get(); + static this_type m_inst; + if (m_inst == null) + m_inst = new(); + return m_inst; + endfunction + static function T create (string name="", uvm_component parent=null, + string contxt=""); + return common_type::create( name, parent, contxt ); + endfunction + static function void set_type_override (uvm_object_wrapper override_type, + bit replace=1); + common_type::set_type_override( override_type, replace ); + endfunction + static function void set_inst_override(uvm_object_wrapper override_type, + string inst_path, + uvm_component parent=null); + common_type::set_inst_override( override_type, inst_path, parent ); + endfunction + static function bit set_type_alias(string alias_name); + common_type::set_type_alias( alias_name ); + return 1; + endfunction + virtual function void initialize(); + common_type common = common_type::get(); + common.initialize(); + endfunction +endclass +class uvm_abstract_component_registry #(type T=uvm_component, string Tname="") + extends uvm_object_wrapper; + typedef uvm_abstract_component_registry #(T,Tname) this_type; + typedef uvm_registry_common#( this_type, uvm_registry_component_creator, T, Tname ) common_type; + virtual function uvm_component create_component (string name, + uvm_component parent); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/ABST_RGTRY/CREATE_ABSTRACT_CMPNT")) + uvm_report_error ("UVM/ABST_RGTRY/CREATE_ABSTRACT_CMPNT", $sformatf( "Cannot create an instance of abstract class %s (with name %s and parent %s). Check for missing factory overrides for %s.", this.get_type_name(), name, parent.get_full_name(), this.get_type_name() ), UVM_NONE, "t/uvm/src/base/uvm_registry.svh", 308, "", 1); + end + return null; + endfunction + static function string type_name(); + return common_type::type_name(); + endfunction : type_name + virtual function string get_type_name(); + common_type common = common_type::get(); + return common.get_type_name(); + endfunction + static function this_type get(); + static this_type m_inst; + if (m_inst == null) + m_inst = new(); + return m_inst; + endfunction + static function T create(string name, uvm_component parent, string contxt=""); + return common_type::create( name, parent, contxt ); + endfunction + static function void set_type_override (uvm_object_wrapper override_type, + bit replace=1); + common_type::set_type_override( override_type, replace ); + endfunction + static function void set_inst_override(uvm_object_wrapper override_type, + string inst_path, + uvm_component parent=null); + common_type::set_inst_override( override_type, inst_path, parent ); + endfunction + static function bit set_type_alias(string alias_name); + common_type::set_type_alias( alias_name ); + return 1; + endfunction + virtual function void initialize(); + common_type common = common_type::get(); + common.initialize(); + endfunction +endclass +class uvm_abstract_object_registry #(type T=uvm_object, string Tname="") + extends uvm_object_wrapper; + typedef uvm_abstract_object_registry #(T,Tname) this_type; + typedef uvm_registry_common#( this_type, uvm_registry_object_creator, T, Tname ) common_type; + virtual function uvm_object create_object(string name=""); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/ABST_RGTRY/CREATE_ABSTRACT_OBJ")) + uvm_report_error ("UVM/ABST_RGTRY/CREATE_ABSTRACT_OBJ", $sformatf( "Cannot create an instance of abstract class %s (with name %s). Check for missing factory overrides for %s.", this.get_type_name(), name, this.get_type_name() ), UVM_NONE, "t/uvm/src/base/uvm_registry.svh", 428, "", 1); + end + return null; + endfunction + static function string type_name(); + return common_type::type_name(); + endfunction : type_name + virtual function string get_type_name(); + common_type common = common_type::get(); + return common.get_type_name(); + endfunction + static function this_type get(); + static this_type m_inst; + if (m_inst == null) + m_inst = new(); + return m_inst; + endfunction + static function T create (string name="", uvm_component parent=null, + string contxt=""); + return common_type::create( name, parent, contxt ); + endfunction + static function void set_type_override (uvm_object_wrapper override_type, + bit replace=1); + common_type::set_type_override( override_type, replace ); + endfunction + static function void set_inst_override(uvm_object_wrapper override_type, + string inst_path, + uvm_component parent=null); + common_type::set_inst_override( override_type, inst_path, parent ); + endfunction + static function bit set_type_alias(string alias_name); + common_type::set_type_alias( alias_name ); + return 1; + endfunction + virtual function void initialize(); + common_type common = common_type::get(); + common.initialize(); + endfunction +endclass +class uvm_registry_common #( type Tregistry=int, type Tcreator=int, type Tcreated=int, string Tname="" ); + typedef uvm_registry_common#(Tregistry,Tcreator,Tcreated,Tname) this_type; + local static string m__type_aliases[$]; + static function string type_name(); + if((Tname == "") && (m__type_aliases.size() != 0)) begin + return m__type_aliases[0]; + end + return Tname; + endfunction : type_name + virtual function string get_type_name(); + return type_name(); + endfunction + static function this_type get(); + static this_type m_inst; + if (m_inst == null) + m_inst = new(); + return m_inst; + endfunction : get + static function Tcreated create(string name, uvm_component parent, string contxt); + uvm_object obj; + if (contxt == "" && parent != null) + contxt = parent.get_full_name(); + obj = Tcreator::create_by_type( Tregistry::get(), contxt, name, parent ); + if (!$cast(create, obj)) begin + string msg; + msg = {"Factory did not return a ", Tcreator::base_type_name(), " of type '",Tregistry::type_name, + "'. A component of type '",obj == null ? "null" : obj.get_type_name(), + "' was returned instead. Name=",name," Parent=", + parent==null?"null":parent.get_type_name()," contxt=",contxt}; + uvm_report_fatal("FCTTYP", msg, UVM_NONE); + end + endfunction + static function void set_type_override (uvm_object_wrapper override_type, + bit replace); + uvm_factory factory=uvm_factory::get(); + factory.set_type_override_by_type(Tregistry::get(),override_type,replace); + endfunction + static function void set_inst_override(uvm_object_wrapper override_type, + string inst_path, + uvm_component parent); + string full_inst_path; + uvm_factory factory=uvm_factory::get(); + if (parent != null) begin + if (inst_path == "") + inst_path = parent.get_full_name(); + else + inst_path = {parent.get_full_name(),".",inst_path}; + end + factory.set_inst_override_by_type(Tregistry::get(),override_type,inst_path); + endfunction + static function void set_type_alias(string alias_name); + m__type_aliases.push_back(alias_name); + m__type_aliases.sort(); + if (uvm_pkg::get_core_state() != UVM_CORE_UNINITIALIZED) begin + uvm_factory factory = uvm_factory::get(); + Tregistry rgtry = Tregistry::get(); + if (factory.is_type_registered(rgtry)) begin + factory.set_type_alias(alias_name,rgtry); + end + end + endfunction + static function bit __deferred_init(); + Tregistry rgtry = Tregistry::get(); + if (uvm_pkg::get_core_state() == UVM_CORE_UNINITIALIZED) begin + uvm_pkg::uvm_deferred_init.push_back(rgtry); + end + else begin + rgtry.initialize(); + end + return 1; + endfunction + local static bit m__initialized=__deferred_init(); + virtual function void initialize(); + uvm_factory factory =uvm_factory::get(); + Tregistry rgtry = Tregistry::get(); + factory.register(rgtry); + foreach(m__type_aliases[i]) begin + factory.set_type_alias(m__type_aliases[i],rgtry); + end + endfunction +endclass +virtual class uvm_registry_component_creator; + static function uvm_component create_by_type( + uvm_object_wrapper obj_wrpr, + string contxt, + string name, + uvm_component parent + ); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory = cs.get_factory(); + return factory.create_component_by_type( obj_wrpr, contxt, name, parent ); + endfunction + static function string base_type_name(); return "component"; endfunction +endclass +virtual class uvm_registry_object_creator; + static function uvm_object create_by_type( + uvm_object_wrapper obj_wrpr, + string contxt, + string name, + uvm_object unused + ); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory = cs.get_factory(); + unused = unused; + return factory.create_object_by_type( obj_wrpr, contxt, name ); + endfunction + static function string base_type_name(); return "object"; endfunction +endclass +class uvm_pool #(type KEY=int, T=uvm_void) extends uvm_object; + typedef uvm_pool #(KEY,T) this_type; + static protected this_type m_global_pool; + protected T pool[KEY]; + typedef uvm_object_registry #(uvm_pool #(KEY,T)) type_id; + static function uvm_pool #(KEY,T) type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_pool #(KEY,T) tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_pool"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_pool"; + endfunction : get_type_name + function new (string name=""); + super.new(name); + endfunction + static function this_type get_global_pool (); + if (m_global_pool==null) + m_global_pool = new("pool"); + return m_global_pool; + endfunction + static function T get_global (KEY key); + this_type gpool; + gpool = get_global_pool(); + return gpool.get(key); + endfunction + virtual function T get (KEY key); + if (!pool.exists(key)) begin + T default_value; + pool[key] = default_value; + end + return pool[key]; + endfunction + virtual function void add (KEY key, T item); + pool[key] = item; + endfunction + virtual function int num (); + return pool.num(); + endfunction + virtual function void delete (KEY key); + if (!exists(key)) begin + uvm_report_warning("POOLDEL", + $sformatf("delete: pool key doesn't exist. Ignoring delete request")); + return; + end + pool.delete(key); + endfunction + virtual function int exists (KEY key); + return pool.exists(key); + endfunction + virtual function int first (ref KEY key); + return pool.first(key); + endfunction + virtual function int last (ref KEY key); + return pool.last(key); + endfunction + virtual function int next (ref KEY key); + return pool.next(key); + endfunction + virtual function int prev (ref KEY key); + return pool.prev(key); + endfunction + virtual function void do_copy (uvm_object rhs); + this_type p; + KEY key; + super.do_copy(rhs); + if (rhs==null || !$cast(p, rhs)) + return; + pool = p.pool; + endfunction + virtual function void do_print (uvm_printer printer); + string v; + int cnt; + string item; + KEY key; + printer.print_array_header("pool",pool.num(),"aa_object_string"); + if (pool.first(key)) + do begin + item.itoa(cnt); + item = {"[-key",item,"--]"}; + $swrite(v,pool[key]); + printer.print_generic(item,"",-1,v,"["); + end + while (pool.next(key)); + printer.print_array_footer(); + endfunction +endclass +class uvm_object_string_pool #(type T=uvm_object) extends uvm_pool #(string,T); + typedef uvm_object_string_pool #(T) this_type; + static protected this_type m_global_pool; + typedef uvm_object_registry #(uvm_object_string_pool#(T)) type_id; + static function uvm_object_string_pool#(T) type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_object_string_pool#(T) tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_obj_str_pool"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_obj_str_pool"; + endfunction : get_type_name + function new (string name=""); + super.new(name); + endfunction + static function this_type get_global_pool (); + if (m_global_pool==null) + m_global_pool = new("global_pool"); + return m_global_pool; + endfunction + static function T get_global (string key); + this_type gpool; + gpool = get_global_pool(); + return gpool.get(key); + endfunction + virtual function T get (string key); + if (!pool.exists(key)) + pool[key] = new (key); + return pool[key]; + endfunction + virtual function void delete (string key); + if (!exists(key)) begin + uvm_report_warning("POOLDEL", + $sformatf("delete: key '%s' doesn't exist", key)); + return; + end + pool.delete(key); + endfunction + virtual function void do_print (uvm_printer printer); + string key; + printer.print_array_header("pool",pool.num(),"aa_object_string"); + if (pool.first(key)) + do + printer.print_object({"[",key,"]"}, pool[key],"["); + while (pool.next(key)); + printer.print_array_footer(); + endfunction +endclass +typedef class uvm_barrier; +typedef class uvm_event; +typedef uvm_object_string_pool #(uvm_barrier) uvm_barrier_pool ; +typedef uvm_object_string_pool #(uvm_event#(uvm_object)) uvm_event_pool ; +class uvm_queue #(type T=int) extends uvm_object; + typedef uvm_queue #(T) this_type; + typedef uvm_object_registry #(uvm_queue#(T)) type_id; + static function uvm_queue#(T) type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_queue#(T) tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_queue"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_queue"; + endfunction : get_type_name + static local this_type m_global_queue; + protected T queue[$]; + function new (string name=""); + super.new(name); + endfunction + static function this_type get_global_queue (); + if (m_global_queue==null) + m_global_queue = new("global_queue"); + return m_global_queue; + endfunction + static function T get_global (int index); + this_type gqueue; + gqueue = get_global_queue(); + return gqueue.get(index); + endfunction + virtual function T get (int index); + T default_value; + if (index >= size() || index < 0) begin + uvm_report_warning("QUEUEGET", + $sformatf("get: given index out of range for queue of size %0d. Ignoring get request",size())); + return default_value; + end + return queue[index]; + endfunction + virtual function int size (); + return queue.size(); + endfunction + virtual function void insert (int index, T item); + if (index >= size() || index < 0) begin + uvm_report_warning("QUEUEINS", + $sformatf("insert: given index out of range for queue of size %0d. Ignoring insert request",size())); + return; + end + queue.insert(index,item); + endfunction + virtual function void delete (int index=-1); + if (index >= size() || index < -1) begin + uvm_report_warning("QUEUEDEL", + $sformatf("delete: given index out of range for queue of size %0d. Ignoring delete request",size())); + return; + end + if (index == -1) + queue.delete(); + else + queue.delete(index); + endfunction + virtual function T pop_front(); + return queue.pop_front(); + endfunction + virtual function T pop_back(); + return queue.pop_back(); + endfunction + virtual function void push_front(T item); + queue.push_front(item); + endfunction + virtual function void push_back(T item); + queue.push_back(item); + endfunction + virtual task wait_until_not_empty(); + wait(queue.size() > 0); + endtask + virtual function void do_copy (uvm_object rhs); + this_type p; + super.do_copy(rhs); + if (rhs == null || !$cast(p, rhs)) + return; + queue = p.queue; + endfunction + virtual function string convert2string(); + return $sformatf("%p",queue); + endfunction +endclass +class uvm_spell_chkr #(type T=int); + typedef T tab_t[string]; + static const int unsigned max = '1; + static function bit check ( ref tab_t strtab, input string s); + string key; + int distance; + int unsigned min; + string min_key[$]; + if(strtab.exists(s)) begin + return 1; + end + min = max; + foreach(strtab[key]) begin + distance = levenshtein_distance(key, s); + if(distance < 0) + continue; + if(distance < min) begin + min = distance; + min_key.delete(); + min_key.push_back(key); + continue; + end + if(distance == min) begin + min_key.push_back(key); + end + end + if(min == max) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_INFO,"UVM/CONFIGDB/SPELLCHK")) + uvm_report_info ("UVM/CONFIGDB/SPELLCHK", $sformatf("%s not located, no alternatives to suggest", s), UVM_NONE, "t/uvm/src/base/uvm_spell_chkr.svh", 110, "", 1); + end + end + else + begin + string q[$]; + foreach(min_key[i]) begin + q.push_back(min_key[i]); + q.push_back("|"); + end + if(q.size()) + void'(q.pop_back()); + begin + if (uvm_report_enabled(UVM_NONE,UVM_INFO,"UVM/CONFIGDB/SPELLCHK")) + uvm_report_info ("UVM/CONFIGDB/SPELLCHK", $sformatf("%s not located, did you mean %s", s, uvm_pkg::m_uvm_string_queue_join(q)), UVM_NONE, "t/uvm/src/base/uvm_spell_chkr.svh", 124, "", 1); + end + end + return 0; + endfunction + static local function int levenshtein_distance(string s, string t); + int k, i, j, n, m, cost, distance; + int d[]; + n = s.len() + 1; + m = t.len() + 1; + if(n == 1 || m == 1) + return -1; + d = new[m*n]; + for(k = 0; k < n; k++) + d[k] = k; + for(k = 0; k < m; k++) + d[k*n] = k; + for(i = 1; i < n; i++) begin + for(j = 1; j < m; j++) begin + cost = !(s[i-1] == t[j-1]); + d[j*n+i] = minimum(d[(j-1)*n+i]+1, d[j*n+i-1]+1, d[(j-1)*n+i-1]+cost); + end + end + distance = d[n*m-1]; + return distance; + endfunction + static local function int minimum(int a, int b, int c); + int min = a; + if(b < min) + min = b; + if(c < min) + min = c; + return min; + endfunction +endclass +typedef class uvm_resource_base; +class uvm_resource_types; + typedef bit[1:0] override_t; + typedef enum override_t { TYPE_OVERRIDE = 2'b01, + NAME_OVERRIDE = 2'b10 } override_e; + typedef uvm_queue#(uvm_resource_base) rsrc_q_t; + typedef enum { PRI_HIGH, PRI_LOW } priority_e; + typedef struct + { + time read_time; + time write_time; + int unsigned read_count; + int unsigned write_count; + } access_t; +endclass +class uvm_resource_options; + static local bit auditing = 1; + static function void turn_on_auditing(); + auditing = 1; + endfunction + static function void turn_off_auditing(); + auditing = 0; + endfunction + static function bit is_auditing(); + return auditing; + endfunction +endclass +virtual class uvm_resource_base extends uvm_object; + protected bit modified; + protected bit read_only; + uvm_resource_types::access_t access[string]; + function new(string name = ""); + super.new(name); + modified = 0; + read_only = 0; + endfunction + pure virtual function uvm_resource_base get_type_handle(); + function void set_read_only(); + read_only = 1; + endfunction + function void set_read_write(); + read_only = 0; + endfunction + function bit is_read_only(); + return read_only; + endfunction + task wait_modified(); + wait (modified == 1); + modified = 0; + endtask + function string convert2string(); + return $sformatf("(%s) %s", m_value_type_name(), m_value_as_string()); + endfunction + pure virtual function string m_value_type_name(); + pure virtual function string m_value_as_string(); + function void do_print(uvm_printer printer); + super.do_print(printer); + printer.print_generic_element("val", m_value_type_name(), "", m_value_as_string()); + endfunction : do_print + function void record_read_access(uvm_object accessor = null); + string str; + uvm_resource_types::access_t access_record; + if(!uvm_resource_options::is_auditing()) + return; + if(accessor != null) + str = accessor.get_full_name(); + else + str = ""; + if(access.exists(str)) + access_record = access[str]; + else + init_access_record(access_record); + access_record.read_count++; + access_record.read_time = $realtime; + access[str] = access_record; + endfunction + function void record_write_access(uvm_object accessor = null); + string str; + if(uvm_resource_options::is_auditing()) begin + if(accessor != null) begin + uvm_resource_types::access_t access_record; + string str; + str = accessor.get_full_name(); + if(access.exists(str)) + access_record = access[str]; + else + init_access_record(access_record); + access_record.write_count++; + access_record.write_time = $realtime; + access[str] = access_record; + end + end + endfunction + virtual function void print_accessors(); + string str; + uvm_component comp; + uvm_resource_types::access_t access_record; + string qs[$]; + if(access.num() == 0) + return; + foreach (access[i]) begin + str = i; + access_record = access[str]; + qs.push_back($sformatf("%s reads: %0d @ %0t writes: %0d @ %0t\n",str, + access_record.read_count, + access_record.read_time, + access_record.write_count, + access_record.write_time)); + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_INFO,"UVM/RESOURCE/ACCESSOR")) + uvm_report_info ("UVM/RESOURCE/ACCESSOR", uvm_pkg::m_uvm_string_queue_join(qs), UVM_NONE, "t/uvm/src/base/uvm_resource_base.svh", 532, "", 1); + end + endfunction + function void init_access_record (inout uvm_resource_types::access_t access_record); + access_record.read_time = 0; + access_record.write_time = 0; + access_record.read_count = 0; + access_record.write_count = 0; + endfunction +endclass +class get_t; + string name; + string scope; + uvm_resource_base rsrc; + time t; +endclass +typedef class uvm_tree_printer ; +class uvm_resource_pool; + uvm_resource_types::rsrc_q_t rtab [string]; + uvm_resource_types::rsrc_q_t ttab [uvm_resource_base]; + typedef struct { + string scope ; + int unsigned precedence; + } rsrc_info_t ; + static rsrc_info_t ri_tab [uvm_resource_base]; + get_t get_record [$]; + function new(); + endfunction + static function uvm_resource_pool get(); + uvm_resource_pool t_rp; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + t_rp = cs.get_resource_pool(); + return t_rp; + endfunction + function bit spell_check(string s); + return uvm_spell_chkr#(uvm_resource_types::rsrc_q_t)::check(rtab, s); + endfunction + function void set_scope (uvm_resource_base rsrc, string scope); + uvm_resource_types::rsrc_q_t rq; + string name; + uvm_resource_base type_handle; + uvm_resource_base r; + int unsigned i; + if(rsrc == null) begin + uvm_report_warning("NULLRASRC", "attempting to set scope of a null resource"); + return; + end + name = rsrc.get_name(); + if ((name != "") && rtab.exists(name)) begin + rq = rtab[name]; + for(i = 0; i < rq.size(); i++) begin + r = rq.get(i); + if(r == rsrc) begin + ri_tab[rsrc].scope = uvm_glob_to_re(scope); + return ; + end + end + end + if (rq == null) + rq = new(name); + rq.push_back(rsrc); + rtab[name] = rq; + type_handle = rsrc.get_type_handle(); + if(ttab.exists(type_handle)) + rq = ttab[type_handle]; + else + rq = new(); + rq.push_back(rsrc); + ttab[type_handle] = rq; + ri_tab[rsrc].scope = uvm_glob_to_re(scope); + ri_tab[rsrc].precedence = get_default_precedence(); + endfunction + function void set_override(uvm_resource_base rsrc, string scope = ""); + string s = scope; + set_scope(rsrc, s); + set_priority(rsrc, uvm_resource_types::PRI_HIGH); + endfunction + function void set_name_override(uvm_resource_base rsrc, string scope = ""); + string s = scope; + set_scope(rsrc, s); + set_priority_name(rsrc, uvm_resource_types::PRI_HIGH); + endfunction + function void set_type_override(uvm_resource_base rsrc, string scope = ""); + string s = scope; + set_scope(rsrc, s); + set_priority_type(rsrc, uvm_resource_types::PRI_HIGH); + endfunction + virtual function bit get_scope(uvm_resource_base rsrc, + output string scope); + uvm_resource_types::rsrc_q_t rq; + string name; + uvm_resource_base r; + int unsigned i; + if(rsrc == null) + return 0; + name = rsrc.get_name(); + if((name != "") && rtab.exists(name)) begin + rq = rtab[name]; + for(i = 0; i < rq.size(); i++) begin + r = rq.get(i); + if(r == rsrc) begin + scope = ri_tab[rsrc].scope; + return 1; + end + end + end + scope = ""; + return 0; + endfunction + virtual function void delete ( uvm_resource_base rsrc ); + string name; + uvm_resource_base type_handle; + if (rsrc != null) begin + name = rsrc.get_name(); + if(name != "") begin + if(rtab.exists(name)) + rtab.delete(name); + end + type_handle = rsrc.get_type_handle(); + if(ttab.exists(type_handle)) begin + int q_size = ttab[type_handle].size(); + if (q_size == 1) + ttab.delete(type_handle); + else begin + int i; + for (i=0; i prec) begin + rsrc = r; + prec = c_prec; + end + end + return rsrc; + endfunction + static function void sort_by_precedence(ref uvm_resource_types::rsrc_q_t q); + uvm_resource_types::rsrc_q_t all[int]; + uvm_resource_base r; + int unsigned prec; + for(int i=0; i", scope, null); + return null; + end + rsrc = q.get(0); + push_get_record("", scope, rsrc); + return rsrc; + endfunction + function uvm_resource_types::rsrc_q_t lookup_regex_names(string scope, + string name, + uvm_resource_base type_handle = null); + return lookup_name(scope, name, type_handle, 0); + endfunction + function uvm_resource_types::rsrc_q_t lookup_regex(string re, scope); + uvm_resource_types::rsrc_q_t rq; + uvm_resource_types::rsrc_q_t result_q; + int unsigned i; + uvm_resource_base r; + string s; + result_q = new(); + foreach (rtab[name]) begin + if ( ! uvm_is_match(re, name) ) + continue; + rq = rtab[name]; + for(i = 0; i < rq.size(); i++) begin + r = rq.get(i); + if(ri_tab.exists(r) && uvm_is_match(ri_tab[r].scope, scope)) + result_q.push_back(r); + end + end + return result_q; + endfunction + function uvm_resource_types::rsrc_q_t lookup_scope(string scope); + uvm_resource_types::rsrc_q_t rq; + uvm_resource_base r; + int unsigned i; + int unsigned err; + uvm_resource_types::rsrc_q_t q = new(); + string name; + if(rtab.last(name)) begin + do begin + rq = rtab[name]; + for(int i = 0; i < rq.size(); ++i) begin + r = rq.get(i); + if(ri_tab.exists(r) && uvm_is_match(ri_tab[r].scope, scope)) begin + q.push_back(r); + end + end + end while(rtab.prev(name)); + end + return q; + endfunction + local function void set_priority_queue(uvm_resource_base rsrc, + ref uvm_resource_types::rsrc_q_t q, + uvm_resource_types::priority_e pri); + uvm_resource_base r; + int unsigned i; + string msg; + string name = rsrc.get_name(); + for(i = 0; i < q.size(); i++) begin + r = q.get(i); + if(r == rsrc) break; + end + if(r != rsrc) begin + $sformat(msg, "Handle for resource named %s is not in the name name; cannot change its priority", name); + uvm_report_error("NORSRC", msg); + return; + end + q.delete(i); + case(pri) + uvm_resource_types::PRI_HIGH: q.push_front(rsrc); + uvm_resource_types::PRI_LOW: q.push_back(rsrc); + endcase + endfunction + function void set_priority_type(uvm_resource_base rsrc, + uvm_resource_types::priority_e pri); + uvm_resource_base type_handle; + string msg; + uvm_resource_types::rsrc_q_t q; + if(rsrc == null) begin + uvm_report_warning("NULLRASRC", "attempting to change the serach priority of a null resource"); + return; + end + type_handle = rsrc.get_type_handle(); + if(!ttab.exists(type_handle)) begin + $sformat(msg, "Type handle for resrouce named %s not found in type map; cannot change its search priority", rsrc.get_name()); + uvm_report_error("RNFTYPE", msg); + return; + end + q = ttab[type_handle]; + set_priority_queue(rsrc, q, pri); + endfunction + function void set_priority_name(uvm_resource_base rsrc, + uvm_resource_types::priority_e pri); + string name; + string msg; + uvm_resource_types::rsrc_q_t q; + if(rsrc == null) begin + uvm_report_warning("NULLRASRC", "attempting to change the serach priority of a null resource"); + return; + end + name = rsrc.get_name(); + if(!rtab.exists(name)) begin + $sformat(msg, "Resrouce named %s not found in name map; cannot change its search priority", name); + uvm_report_error("RNFNAME", msg); + return; + end + q = rtab[name]; + set_priority_queue(rsrc, q, pri); + endfunction + function void set_priority (uvm_resource_base rsrc, + uvm_resource_types::priority_e pri); + set_priority_type(rsrc, pri); + set_priority_name(rsrc, pri); + endfunction + static function void set_default_precedence( int unsigned precedence); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + cs.set_resource_pool_default_precedence(precedence); + endfunction + static function int unsigned get_default_precedence(); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + return cs.get_resource_pool_default_precedence(); + endfunction + virtual function void set_precedence(uvm_resource_base r, + int unsigned p=uvm_resource_pool::get_default_precedence()); + uvm_resource_types::rsrc_q_t q; + string name; + int unsigned i; + uvm_resource_base rsrc; + if(r == null) begin + uvm_report_warning("NULLRASRC", "attempting to set precedence of a null resource"); + return; + end + name = r.get_name(); + if(rtab.exists(name)) begin + q = rtab[name]; + for(i = 0; i < q.size(); i++) begin + rsrc = q.get(i); + if(rsrc == r) break; + end + end + if(r != rsrc) begin + uvm_report_warning("NORSRC", $sformatf("resource named %s is not placed within the pool", name)); + return; + end + ri_tab[r].precedence = p; + endfunction + virtual function int unsigned get_precedence(uvm_resource_base r); + uvm_resource_types::rsrc_q_t q; + string name; + int unsigned i; + uvm_resource_base rsrc; + if(r == null) begin + uvm_report_warning("NULLRASRC", "attempting to get precedence of a null resource"); + return uvm_resource_pool::get_default_precedence(); + end + name = r.get_name(); + if(rtab.exists(name)) begin + q = rtab[name]; + for(i = 0; i < q.size(); i++) begin + rsrc = q.get(i); + if(rsrc == r) break; + end + end + if(r != rsrc) begin + uvm_report_warning("NORSRC", $sformatf("resource named %s is not placed within the pool", name)); + return uvm_resource_pool::get_default_precedence(); + end + return ri_tab[r].precedence; + endfunction + function void m_print_resources(uvm_printer printer, + uvm_resource_types::rsrc_q_t rq, + bit audit = 0); + printer.push_element(rq.get_name(), + "uvm_queue#(uvm_resource_base)", + $sformatf("%0d",rq.size()), + uvm_object_value_str(rq)); + for(int i=0; i"); + else + m_print_resources(printer, rq, audit); + begin + if (uvm_report_enabled(UVM_NONE,UVM_INFO,"UVM/RESOURCE_POOL/PRINT_QUEUE")) + uvm_report_info ("UVM/RESOURCE_POOL/PRINT_QUEUE", printer.emit(), UVM_NONE, "t/uvm/src/base/uvm_resource.svh", 1071, "", 1); + end + endfunction + function void dump(bit audit = 0, uvm_printer printer = null); + string name; + static uvm_tree_printer m_printer; + if (m_printer == null) begin + m_printer = new(); + m_printer.set_type_name_enabled(1); + end + if (printer == null) + printer = m_printer; + printer.flush(); + printer.push_element("uvm_resource_pool", + "", + $sformatf("%0d",rtab.size()), + ""); + foreach (rtab[name]) begin + m_print_resources(printer, rtab[name], audit); + end + printer.pop_element(); + begin + if (uvm_report_enabled(UVM_NONE,UVM_INFO,"UVM/RESOURCE/DUMP")) + uvm_report_info ("UVM/RESOURCE/DUMP", printer.emit(), UVM_NONE, "t/uvm/src/base/uvm_resource.svh", 1108, "", 1); + end + endfunction +endclass +class uvm_resource #(type T=int) extends uvm_resource_base; + typedef uvm_resource#(T) this_type; + static this_type my_type = get_type(); + protected T val; + typedef uvm_object_registry#(this_type) type_id; + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction : get_object_type + virtual function uvm_object create (string name=""); + this_type tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction : create + static function string type_name(); + return $sformatf("uvm_resource#(%s)", $typename(T)); + endfunction : type_name + virtual function string get_type_name(); + return $sformatf("uvm_resource#(%s)", $typename(T)); + endfunction : get_type_name + function new(string name=""); + super.new(name); + endfunction + virtual function string m_value_type_name(); + return $typename(T); + endfunction : m_value_type_name + virtual function string m_value_as_string(); + return $sformatf("%0p", val); + endfunction : m_value_as_string + static function this_type get_type(); + if(my_type == null) + my_type = new(); + return my_type; + endfunction + function uvm_resource_base get_type_handle(); + return get_type(); + endfunction + function T read(uvm_object accessor = null); + record_read_access(accessor); + return val; + endfunction + function void write(T t, uvm_object accessor = null); + if(is_read_only()) begin + uvm_report_error("resource", $sformatf("resource %s is read only -- cannot modify", get_name())); + return; + end + if(val == t) + return; + record_write_access(accessor); + val = t; + modified = 1; + endfunction + static function this_type get_highest_precedence(ref uvm_resource_types::rsrc_q_t q); + this_type rsrc; + this_type r; + uvm_resource_types::rsrc_q_t tq; + uvm_resource_base rb; + uvm_resource_pool rp = uvm_resource_pool::get(); + if(q.size() == 0) + return null; + tq = new(); + rsrc = null; + for(int i = 0; i < q.size(); ++i) begin + if($cast(r, q.get(i))) begin + tq.push_back(r) ; + end + end + rb = rp.get_highest_precedence(tq); + if (!$cast(rsrc, rb)) + return null; + return rsrc; + endfunction +endclass +class uvm_int_rsrc extends uvm_resource #(int); + typedef uvm_int_rsrc this_subtype; + function new(string name, string s = "*"); + uvm_resource_pool rp; + super.new(name); + rp = uvm_resource_pool::get(); + rp.set_scope(this, s); + endfunction + function string convert2string(); + string s; + $sformat(s, "%0d", read()); + return s; + endfunction +endclass +class uvm_string_rsrc extends uvm_resource #(string); + typedef uvm_string_rsrc this_subtype; + function new(string name, string s = "*"); + uvm_resource_pool rp; + super.new(name); + rp = uvm_resource_pool::get(); + rp.set_scope(this, s); + endfunction + function string convert2string(); + return read(); + endfunction +endclass +class uvm_obj_rsrc extends uvm_resource #(uvm_object); + typedef uvm_obj_rsrc this_subtype; + function new(string name, string s = "*"); + uvm_resource_pool rp; + super.new(name); + rp = uvm_resource_pool::get(); + rp.set_scope(this, s); + endfunction +endclass +class uvm_bit_rsrc #(int unsigned N=1) extends uvm_resource #(bit[N-1:0]); + typedef uvm_bit_rsrc#(N) this_subtype; + function new(string name, string s = "*"); + uvm_resource_pool rp; + super.new(name); + rp = uvm_resource_pool::get(); + rp.set_scope(this, s); + endfunction + function string convert2string(); + string s; + $sformat(s, "%0b", read()); + return s; + endfunction +endclass +class uvm_byte_rsrc #(int unsigned N=1) extends uvm_resource #(bit[7:0][N-1:0]); + typedef uvm_byte_rsrc#(N) this_subtype; + function new(string name, string s = "*"); + uvm_resource_pool rp; + super.new(name); + rp = uvm_resource_pool::get(); + rp.set_scope(this, s); + endfunction + function string convert2string(); + string s; + $sformat(s, "%0x", read()); + return s; + endfunction +endclass +typedef class uvm_resource_db_options; +typedef class uvm_cmdline_processor; +class uvm_resource_db #(type T=uvm_object); + typedef uvm_resource #(T) rsrc_t; + protected function new(); + endfunction + static function rsrc_t get_by_type(string scope); + uvm_resource_pool rp = uvm_resource_pool::get(); + uvm_resource_base rsrc_base; + rsrc_t rsrc; + string msg; + uvm_resource_base type_handle = rsrc_t::get_type(); + if(type_handle == null) + return null; + rsrc_base = rp.get_by_type(scope, type_handle); + if(!$cast(rsrc, rsrc_base)) begin + $sformat(msg, "Resource with specified type handle in scope %s was not located", scope); + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RSRCNF")) + uvm_report_warning ("RSRCNF", msg, UVM_NONE, "t/uvm/src/base/uvm_resource_db.svh", 84, "", 1); + end + return null; + end + return rsrc; + endfunction + static function rsrc_t get_by_name(string scope, + string name, + bit rpterr=1); + uvm_resource_pool rp = uvm_resource_pool::get(); + uvm_resource_base rsrc_base; + rsrc_t rsrc; + string msg; + rsrc_base = rp.get_by_name(scope, name, rsrc_t::get_type(), rpterr); + if(rsrc_base == null) + return null; + if(!$cast(rsrc, rsrc_base)) begin + if(rpterr) begin + $sformat(msg, "Resource with name %s in scope %s has incorrect type", name, scope); + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RSRCTYPE")) + uvm_report_warning ("RSRCTYPE", msg, UVM_NONE, "t/uvm/src/base/uvm_resource_db.svh", 115, "", 1); + end + end + return null; + end + return rsrc; + endfunction + static function rsrc_t set_default(string scope, string name); + rsrc_t r; + uvm_resource_pool rp = uvm_resource_pool::get(); + r = new(name); + rp.set_scope(r, scope); + return r; + endfunction + protected static function void m_show_msg( + input string id, + input string rtype, + input string action, + input string scope, + input string name, + input uvm_object accessor, + input rsrc_t rsrc); + T foo; + string msg=$typename(foo); + $sformat(msg, "%s scope='%s' name='%s' (type %s) %s accessor=%s = %s", + rtype,scope,name, msg,action, + (accessor != null) ? accessor.get_full_name() : "", + rsrc==null?"null (failed lookup)":rsrc.convert2string()); + begin + if (uvm_report_enabled(UVM_LOW,UVM_INFO,id)) + uvm_report_info (id, msg, UVM_LOW, "t/uvm/src/base/uvm_resource_db.svh", 161, "", 1); + end + endfunction + static function void set(input string scope, input string name, + T val, input uvm_object accessor = null); + uvm_resource_pool rp = uvm_resource_pool::get(); + rsrc_t rsrc = new(name); + rsrc.write(val, accessor); + rp.set_scope(rsrc, scope); + if(uvm_resource_db_options::is_tracing()) + m_show_msg("RSRCDB/SET", "Resource","set", scope, name, accessor, rsrc); + endfunction + static function void set_anonymous(input string scope, + T val, input uvm_object accessor = null); + uvm_resource_pool rp = uvm_resource_pool::get(); + rsrc_t rsrc = new(""); + rsrc.write(val, accessor); + rp.set_scope(rsrc, scope); + if(uvm_resource_db_options::is_tracing()) + m_show_msg("RSRCDB/SETANON","Resource", "set", scope, "", accessor, rsrc); + endfunction + static function void set_override(input string scope, input string name, + T val, uvm_object accessor = null); + uvm_resource_pool rp = uvm_resource_pool::get(); + rsrc_t rsrc = new(name); + rsrc.write(val, accessor); + rp.set_override(rsrc, scope); + if(uvm_resource_db_options::is_tracing()) + m_show_msg("RSRCDB/SETOVRD", "Resource","set", scope, name, accessor, rsrc); + endfunction + static function void set_override_type(input string scope, input string name, + T val, uvm_object accessor = null); + uvm_resource_pool rp = uvm_resource_pool::get(); + rsrc_t rsrc = new(name); + rsrc.write(val, accessor); + rp.set_type_override(rsrc, scope); + if(uvm_resource_db_options::is_tracing()) + m_show_msg("RSRCDB/SETOVRDTYP","Resource", "set", scope, name, accessor, rsrc); + endfunction + static function void set_override_name(input string scope, input string name, + T val, uvm_object accessor = null); + uvm_resource_pool rp = uvm_resource_pool::get(); + rsrc_t rsrc = new(name); + rsrc.write(val, accessor); + rp.set_name_override(rsrc, scope); + if(uvm_resource_db_options::is_tracing()) + m_show_msg("RSRCDB/SETOVRDNAM","Resource", "set", scope, name, accessor, rsrc); + endfunction + static function bit read_by_name(input string scope, + input string name, + inout T val, input uvm_object accessor = null); + rsrc_t rsrc = get_by_name(scope, name); + if(uvm_resource_db_options::is_tracing()) + m_show_msg("RSRCDB/RDBYNAM","Resource", "read", scope, name, accessor, rsrc); + if(rsrc == null) + return 0; + val = rsrc.read(accessor); + return 1; + endfunction + static function bit read_by_type(input string scope, + inout T val, + input uvm_object accessor = null); + rsrc_t rsrc = get_by_type(scope); + if(uvm_resource_db_options::is_tracing()) + m_show_msg("RSRCDB/RDBYTYP", "Resource","read", scope, "", accessor, rsrc); + if(rsrc == null) + return 0; + val = rsrc.read(accessor); + return 1; + endfunction + static function bit write_by_name(input string scope, input string name, + input T val, input uvm_object accessor = null); + rsrc_t rsrc = get_by_name(scope, name); + if(uvm_resource_db_options::is_tracing()) + m_show_msg("RSRCDB/WR","Resource", "written", scope, name, accessor, rsrc); + if(rsrc == null) + return 0; + rsrc.write(val, accessor); + return 1; + endfunction + static function bit write_by_type(input string scope, + input T val, input uvm_object accessor = null); + rsrc_t rsrc = get_by_type(scope); + if(uvm_resource_db_options::is_tracing()) + m_show_msg("RSRCDB/WRTYP", "Resource","written", scope, "", accessor, rsrc); + if(rsrc == null) + return 0; + rsrc.write(val, accessor); + return 1; + endfunction + static function void dump(); + uvm_resource_pool rp = uvm_resource_pool::get(); + rp.dump(); + endfunction +endclass +class uvm_resource_db_options; + static local bit ready; + static local bit tracing; + static function void turn_on_tracing(); + if (!ready) init(); + tracing = 1; + endfunction + static function void turn_off_tracing(); + if (!ready) init(); + tracing = 0; + endfunction + static function bit is_tracing(); + if (!ready) init(); + return tracing; + endfunction + static local function void init(); + uvm_cmdline_processor clp; + string trace_args[$]; + clp = uvm_cmdline_processor::get_inst(); + if (clp.get_arg_matches("+UVM_RESOURCE_DB_TRACE", trace_args)) begin + tracing = 1; + end + ready = 1; + endfunction +endclass +typedef class uvm_phase; +class m_uvm_waiter; + string inst_name; + string field_name; + event trigger; + function new (string inst_name, string field_name); + this.inst_name = inst_name; + this.field_name = field_name; + endfunction +endclass +typedef class uvm_root; +typedef class uvm_config_db_options; +class uvm_config_db#(type T=int) extends uvm_resource_db#(T); + static uvm_pool#(string,uvm_resource#(T)) m_rsc[uvm_component]; + static local uvm_queue#(m_uvm_waiter) m_waiters[string]; + static function bit get(uvm_component cntxt, + string inst_name, + string field_name, + inout T value); + uvm_resource#(T) r; + uvm_resource_pool rp = uvm_resource_pool::get(); + uvm_resource_types::rsrc_q_t rq; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + if(cntxt == null) + cntxt = cs.get_root(); + if(inst_name == "") + inst_name = cntxt.get_full_name(); + else if(cntxt.get_full_name() != "") + inst_name = {cntxt.get_full_name(), ".", inst_name}; + rq = rp.lookup_regex_names(inst_name, field_name, uvm_resource#(T)::get_type()); + r = uvm_resource#(T)::get_highest_precedence(rq); + if(uvm_config_db_options::is_tracing()) + m_show_msg("CFGDB/GET", "Configuration","read", inst_name, field_name, cntxt, r); + if(r == null) + return 0; + value = r.read(cntxt); + return 1; + endfunction + static function void set(uvm_component cntxt, + string inst_name, + string field_name, + T value); + uvm_root top; + uvm_phase curr_phase; + uvm_resource#(T) r; + bit exists; + string lookup; + uvm_pool#(string,uvm_resource#(T)) pool; + string rstate; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_resource_pool rp = cs.get_resource_pool(); + int unsigned precedence; + process p = process::self(); + if(p != null) + rstate = p.get_randstate(); + top = cs.get_root(); + curr_phase = top.m_current_phase; + if(cntxt == null) + cntxt = top; + if(inst_name == "") + inst_name = cntxt.get_full_name(); + else if(cntxt.get_full_name() != "") + inst_name = {cntxt.get_full_name(), ".", inst_name}; + if(!m_rsc.exists(cntxt)) begin + m_rsc[cntxt] = new; + end + pool = m_rsc[cntxt]; + lookup = {inst_name, "__M_UVM__", field_name}; + if(!pool.exists(lookup)) begin + r = new(field_name); + rp.set_scope(r, inst_name); + pool.add(lookup, r); + end + else begin + r = pool.get(lookup); + exists = 1; + end + if(curr_phase != null && curr_phase.get_name() == "build") + precedence = cs.get_resource_pool_default_precedence() - (cntxt.get_depth()); + else + precedence = cs.get_resource_pool_default_precedence(); + rp.set_precedence(r, precedence); + r.write(value, cntxt); + rp.set_priority_name(r, uvm_resource_types::PRI_HIGH); + if(m_waiters.exists(field_name)) begin + m_uvm_waiter w; + for(int i=0; iw.trigger; + end + end + if(p != null) + p.set_randstate(rstate); + if(uvm_config_db_options::is_tracing()) + m_show_msg("CFGDB/SET", "Configuration","set", inst_name, field_name, cntxt, r); + endfunction + static function bit exists(uvm_component cntxt, string inst_name, + string field_name, bit spell_chk=0); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + if(cntxt == null) + cntxt = cs.get_root(); + if(inst_name == "") + inst_name = cntxt.get_full_name(); + else if(cntxt.get_full_name() != "") + inst_name = {cntxt.get_full_name(), ".", inst_name}; + return (uvm_resource_db#(T)::get_by_name(inst_name,field_name,spell_chk) != null); + endfunction + static task wait_modified(uvm_component cntxt, string inst_name, + string field_name); + process p = process::self(); + string rstate = p.get_randstate(); + m_uvm_waiter waiter; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + if(cntxt == null) + cntxt = cs.get_root(); + if(cntxt != cs.get_root()) begin + if(inst_name != "") + inst_name = {cntxt.get_full_name(),".",inst_name}; + else + inst_name = cntxt.get_full_name(); + end + waiter = new(inst_name, field_name); + if(!m_waiters.exists(field_name)) + m_waiters[field_name] = new; + m_waiters[field_name].push_back(waiter); + p.set_randstate(rstate); + @waiter.trigger; + for(int i=0; i 1) begin + string msg_queue[$]; + msg_queue.push_back("("); + foreach (matching_ops[i]) begin + msg_queue.push_back(matching_ops[i]); + if (i != matching_ops.size() - 1) + msg_queue.push_back(","); + end + msg_queue.push_back(")"); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/FIELD_OP/SET_BAD_OP_TYPE")) + uvm_report_error ("UVM/FIELD_OP/SET_BAD_OP_TYPE", {"set() was passed op_type matching multiple operations: ", uvm_pkg::m_uvm_string_queue_join(msg_queue)}, UVM_NONE, "t/uvm/src/base/uvm_field_op.svh", 88, "", 1); + end + end + if(m_is_set == 0) begin + m_op_type = op_type; + m_policy = policy; + m_object = rhs; + m_is_set = 1'b1; + end + else + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/FIELD_OP/SET")) + uvm_report_error ("UVM/FIELD_OP/SET", "Attempting to set values in policy without flushing", UVM_NONE, "t/uvm/src/base/uvm_field_op.svh", 98, "", 1); + end + endfunction + virtual function string get_op_name(); + case(m_op_type) + UVM_COPY : return "copy"; + UVM_COMPARE : return "compare"; + UVM_PRINT : return "print"; + UVM_RECORD : return "record"; + UVM_PACK : return "pack"; + UVM_UNPACK : return "unpack"; + UVM_SET : return "set"; + default: return ""; + endcase + endfunction + virtual function uvm_field_flag_t get_op_type(); + if(m_is_set == 1'b1) + return m_op_type; + else + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/FIELD_OP/GET_OP_TYPE")) + uvm_report_error ("UVM/FIELD_OP/GET_OP_TYPE", "Calling get_op_type() before calling set() is not allowed", UVM_NONE, "t/uvm/src/base/uvm_field_op.svh", 120, "", 1); + end + endfunction + virtual function uvm_policy get_policy(); + if(m_is_set == 1'b1) + return m_policy; + else + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/FIELD_OP/GET_POLICY")) + uvm_report_error ("UVM/FIELD_OP/GET_POLICY", "Attempting to call get_policy() before calling set() is not allowed", UVM_NONE, "t/uvm/src/base/uvm_field_op.svh", 129, "", 1); + end + endfunction + virtual function uvm_object get_rhs(); + if(m_is_set == 1'b1) + return m_object; + else + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/FIELD_OP/GET_RHS")) + uvm_report_error ("UVM/FIELD_OP/GET_RHS", "Calling get_rhs() before calling set() is not allowed", UVM_NONE, "t/uvm/src/base/uvm_field_op.svh", 137, "", 1); + end + endfunction + function bit user_hook_enabled(); + if(m_is_set == 1'b1) + return m_user_hook; + else + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/FIELD_OP/GET_USER_HOOK")) + uvm_report_error ("UVM/FIELD_OP/GET_USER_HOOK", "Attempting to get_user_hook before calling set() is not allowed", UVM_NONE, "t/uvm/src/base/uvm_field_op.svh", 145, "", 1); + end + endfunction + function void disable_user_hook(); + m_user_hook = 1'b0; + endfunction + static uvm_field_op m_recycled_op[$] ; + virtual function void flush(); + m_policy = null; + m_object = null; + m_user_hook = 1'b1; + m_is_set = 0; + endfunction + function void m_recycle(); + this.flush(); + m_recycled_op.push_back(this); + endfunction : m_recycle + static function uvm_field_op m_get_available_op() ; + uvm_field_op field_op ; + if (m_recycled_op.size() > 0) field_op = m_recycled_op.pop_back() ; + else field_op = uvm_field_op::type_id_create("field_op"); + return field_op ; + endfunction +endclass +class uvm_copier extends uvm_policy; + typedef uvm_object_registry#(uvm_copier,"uvm_copier") type_id; + static function uvm_copier type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_copier tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_copier"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_copier"; + endfunction : get_type_name + uvm_recursion_policy_enum policy = UVM_DEFAULT_POLICY; + function new(string name="uvm_copier") ; + super.new(name); + endfunction + recursion_state_e m_recur_states[uvm_object ][uvm_object ][uvm_recursion_policy_enum ]; + virtual function void copy_object ( + uvm_object lhs, + uvm_object rhs); + uvm_field_op field_op; + if (get_recursion_policy() == UVM_REFERENCE) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM_COPY_POLICY")) + uvm_report_error ("UVM_COPY_POLICY", "Attempting to make a copy of a object which is a reference", UVM_NONE, "t/uvm/src/base/uvm_copier.svh", 82, "", 1); + end + return; + end + if (rhs == null || lhs == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM_COPY_NULL_OBJ")) + uvm_report_error ("UVM_COPY_NULL_OBJ", "Attempting to make a copy of a object with null src/target", UVM_NONE, "t/uvm/src/base/uvm_copier.svh", 87, "", 1); + end + return; + end + push_active_object(lhs); + m_recur_states[rhs][lhs][get_recursion_policy()] = uvm_policy::STARTED; + field_op = uvm_field_op::m_get_available_op() ; + field_op.set(UVM_COPY,this,rhs); + lhs.do_execute_op(field_op); + if (field_op.user_hook_enabled()) begin + lhs.do_copy(rhs); + end + field_op.m_recycle(); + m_recur_states[rhs][lhs][get_recursion_policy()] = uvm_policy::FINISHED; + void'(pop_active_object()); + endfunction + virtual function recursion_state_e object_copied( + uvm_object lhs, + uvm_object rhs, + uvm_recursion_policy_enum recursion + ); + if (!m_recur_states.exists(rhs)) return NEVER ; + else if (!m_recur_states[rhs].exists(lhs)) return NEVER ; + else if (!m_recur_states[rhs][lhs].exists(recursion)) return NEVER ; + else begin + return m_recur_states[rhs][lhs][recursion]; + end +endfunction +function void flush(); + m_recur_states.delete(); +endfunction +virtual function void set_recursion_policy (uvm_recursion_policy_enum policy); + this.policy = policy; +endfunction +virtual function uvm_recursion_policy_enum get_recursion_policy(); + return policy; +endfunction +function int unsigned get_num_copies(uvm_object rhs); + if (m_recur_states.exists(rhs)) + return m_recur_states[rhs].size(); + return 0; +endfunction : get_num_copies +function int get_first_copy(uvm_object rhs, ref uvm_object lhs); + if (m_recur_states.exists(rhs)) + return m_recur_states[rhs].first(lhs); + return 0; +endfunction : get_first_copy +function int get_next_copy(uvm_object rhs, ref uvm_object lhs); + if (m_recur_states.exists(rhs)) + return m_recur_states[rhs].next(lhs); + return 0; +endfunction : get_next_copy +function int get_last_copy(uvm_object rhs, ref uvm_object lhs); + if (m_recur_states.exists(rhs)) + return m_recur_states[rhs].last(lhs); + return 0; +endfunction : get_last_copy +function int get_prev_copy(uvm_object rhs, ref uvm_object lhs); + if (m_recur_states.exists(rhs)) + return m_recur_states[rhs].prev(lhs); + return 0; +endfunction : get_prev_copy +static function void set_default (uvm_copier copier) ; + uvm_coreservice_t coreservice ; + coreservice = uvm_coreservice_t::get() ; + coreservice.set_default_copier(copier) ; +endfunction +static function uvm_copier get_default () ; + uvm_coreservice_t coreservice ; + coreservice = uvm_coreservice_t::get() ; + return coreservice.get_default_copier() ; +endfunction +endclass +typedef class m_uvm_printer_knobs; +typedef class uvm_printer_element; +typedef class uvm_structure_proxy; +virtual class uvm_printer extends uvm_policy; + typedef uvm_abstract_object_registry#(uvm_printer,"uvm_printer") type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_printer"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_printer"; + endfunction : get_type_name + extern function new(string name="") ; + bit m_flushed ; + local m_uvm_printer_knobs knobs ; +protected function m_uvm_printer_knobs get_knobs() ; return knobs; endfunction + extern static function void set_default(uvm_printer printer) ; + extern static function uvm_printer get_default() ; + extern virtual function void print_field (string name, + uvm_bitstream_t value, + int size, + uvm_radix_enum radix=UVM_NORADIX, + byte scope_separator=".", + string type_name=""); + extern virtual function void print_field_int (string name, + uvm_integral_t value, + int size, + uvm_radix_enum radix=UVM_NORADIX, + byte scope_separator=".", + string type_name=""); + extern virtual function void print_object (string name, + uvm_object value, + byte scope_separator="."); + extern virtual function void print_object_header (string name, + uvm_object value, + byte scope_separator="."); + extern virtual function void print_string (string name, + string value, + byte scope_separator="."); + uvm_policy::recursion_state_e m_recur_states[uvm_object][uvm_recursion_policy_enum ] ; + extern virtual function uvm_policy::recursion_state_e object_printed ( uvm_object value, + uvm_recursion_policy_enum recursion); + extern virtual function void print_time (string name, + time value, + byte scope_separator="."); + extern virtual function void print_real (string name, + real value, + byte scope_separator="."); + extern virtual function void print_generic (string name, + string type_name, + int size, + string value, + byte scope_separator="."); + extern virtual function void print_generic_element (string name, + string type_name, + string size, + string value); + extern virtual function string emit (); + extern virtual function void flush (); + extern virtual function void set_name_enabled (bit enabled); + extern virtual function bit get_name_enabled (); + extern virtual function void set_type_name_enabled (bit enabled); + extern virtual function bit get_type_name_enabled (); + extern virtual function void set_size_enabled (bit enabled); + extern virtual function bit get_size_enabled (); + extern virtual function void set_id_enabled (bit enabled); + extern virtual function bit get_id_enabled (); + extern virtual function void set_radix_enabled (bit enabled); + extern virtual function bit get_radix_enabled (); + extern virtual function void set_radix_string (uvm_radix_enum radix, string prefix); + extern virtual function string get_radix_string (uvm_radix_enum radix); + extern virtual function void set_default_radix (uvm_radix_enum radix); + extern virtual function uvm_radix_enum get_default_radix (); + extern virtual function void set_root_enabled (bit enabled); + extern virtual function bit get_root_enabled (); + extern virtual function void set_recursion_policy (uvm_recursion_policy_enum policy); + extern virtual function uvm_recursion_policy_enum get_recursion_policy (); + extern virtual function void set_max_depth (int depth); + extern virtual function int get_max_depth (); + extern virtual function void set_file (UVM_FILE fl); + extern virtual function UVM_FILE get_file (); + extern virtual function void set_line_prefix (string prefix); + extern virtual function string get_line_prefix (); + extern virtual function void set_begin_elements (int elements = 5); + extern virtual function int get_begin_elements (); + extern virtual function void set_end_elements (int elements = 5); + extern virtual function int get_end_elements (); + local uvm_printer_element m_element_stack[$] ; + protected function int m_get_stack_size(); return m_element_stack.size(); endfunction + extern protected virtual function uvm_printer_element get_bottom_element (); + extern protected virtual function uvm_printer_element get_top_element (); + extern virtual function void push_element ( string name, + string type_name, + string size, + string value="" + ); + extern virtual function void pop_element (); + extern function uvm_printer_element get_unused_element() ; + uvm_printer_element m_recycled_elements[$]; + extern virtual function void print_array_header(string name, + int size, + string arraytype="array", + byte scope_separator="."); + extern virtual function void print_array_range (int min, int max); + extern virtual function void print_array_footer (int size = 0); + extern function bit istop (); + extern function string index_string (int index, string name=""); + string m_string; +endclass +class uvm_printer_element extends uvm_object; + extern function new (string name=""); + extern virtual function void set (string element_name = "", + string element_type_name = "", + string element_size = "", + string element_value = "" + ); + extern virtual function void set_element_name (string element_name); + extern virtual function string get_element_name (); + extern virtual function void set_element_type_name (string element_type_name); + extern virtual function string get_element_type_name (); + extern virtual function void set_element_size (string element_size); + extern virtual function string get_element_size (); + extern virtual function void set_element_value (string element_value); + extern virtual function string get_element_value (); + extern function void add_child(uvm_printer_element child) ; + extern function void get_children(ref uvm_printer_element children[$], input bit recurse) ; + extern function void clear_children() ; + local string m_name ; + local string m_type_name ; + local string m_size ; + local string m_value ; + local uvm_printer_element m_children[$] ; +endclass +class uvm_printer_element_proxy extends uvm_structure_proxy#(uvm_printer_element); + extern function new (string name=""); + extern virtual function void get_immediate_children(uvm_printer_element s, ref uvm_printer_element children[$]); +endclass : uvm_printer_element_proxy +class uvm_table_printer extends uvm_printer; + typedef uvm_object_registry#(uvm_table_printer,"uvm_table_printer") type_id; + static function uvm_table_printer type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_table_printer tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_table_printer"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_table_printer"; + endfunction : get_type_name + extern function new(string name=""); + extern virtual function string emit(); + extern virtual function string m_emit_element(uvm_printer_element element, int unsigned level); + local static uvm_table_printer m_default_table_printer ; + local static string m_space ; + extern static function void set_default(uvm_table_printer printer) ; + extern static function uvm_table_printer get_default() ; + extern virtual function void set_indent(int indent) ; + extern virtual function int get_indent() ; + extern virtual function void flush() ; + protected int m_max_name=4; + protected int m_max_type=4; + protected int m_max_size=4; + protected int m_max_value=5; + extern virtual function void pop_element(); +endclass +class uvm_tree_printer extends uvm_printer; + protected string m_newline = "\n"; + protected string m_linefeed ; + typedef uvm_object_registry#(uvm_tree_printer,"uvm_tree_printer") type_id; + static function uvm_tree_printer type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_tree_printer tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_tree_printer"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_tree_printer"; + endfunction : get_type_name + extern function new(string name=""); + local static uvm_tree_printer m_default_tree_printer ; + extern static function void set_default(uvm_tree_printer printer) ; + extern static function uvm_tree_printer get_default() ; + extern virtual function void set_indent(int indent) ; + extern virtual function int get_indent() ; + extern virtual function void set_separators(string separators) ; + extern virtual function string get_separators() ; + extern virtual function void flush() ; + extern virtual function string emit(); + extern virtual function string m_emit_element(uvm_printer_element element, int unsigned level); +endclass +class uvm_line_printer extends uvm_tree_printer; + typedef uvm_object_registry#(uvm_line_printer,"uvm_line_printer") type_id; + static function uvm_line_printer type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_line_printer tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_line_printer"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_line_printer"; + endfunction : get_type_name + extern function new(string name=""); + local static uvm_line_printer m_default_line_printer ; + extern static function void set_default(uvm_line_printer printer) ; + extern static function uvm_line_printer get_default() ; + extern virtual function void set_separators(string separators) ; + extern virtual function string get_separators() ; + extern virtual function void flush() ; +endclass +class m_uvm_printer_knobs; + bit identifier = 1; + bit type_name = 1; + bit size = 1; + int depth = -1; + bit reference = 1; + int begin_elements = 5; + int end_elements = 5; + string prefix = ""; + int indent = 2; + bit show_root = 0; + int mcd = UVM_STDOUT; + string separator = "{}"; + bit show_radix = 1; + uvm_radix_enum default_radix = UVM_HEX; + string dec_radix = "'d"; + string bin_radix = "'b"; + string oct_radix = "'o"; + string unsigned_radix = "'d"; + string hex_radix = "'h"; + uvm_recursion_policy_enum recursion_policy ; +endclass +function uvm_printer::new(string name=""); + super.new(name); + knobs = new ; + flush(); +endfunction +function void uvm_printer::set_default(uvm_printer printer) ; + uvm_coreservice_t coreservice ; + coreservice = uvm_coreservice_t::get() ; + coreservice.set_default_printer(printer) ; +endfunction +function uvm_printer uvm_printer::get_default() ; + uvm_coreservice_t coreservice ; + coreservice = uvm_coreservice_t::get() ; + return coreservice.get_default_printer() ; +endfunction +function void uvm_printer::print_field (string name, + uvm_bitstream_t value, + int size, + uvm_radix_enum radix=UVM_NORADIX, + byte scope_separator=".", + string type_name=""); + string sz_str, val_str; + if(type_name == "") begin + if(radix == UVM_TIME) + type_name ="time"; + else if(radix == UVM_STRING) + type_name ="string"; + else + type_name ="integral"; + end + sz_str.itoa(size); + if(radix == UVM_NORADIX) + radix = get_default_radix(); + val_str = uvm_bitstream_to_string (value, size, radix, + get_radix_string(radix)); + name = uvm_leaf_scope(name,scope_separator); + push_element(name,type_name,sz_str,val_str); + pop_element() ; +endfunction +function void uvm_printer::print_field_int (string name, + uvm_integral_t value, + int size, + uvm_radix_enum radix=UVM_NORADIX, + byte scope_separator=".", + string type_name=""); + string sz_str, val_str; + if(type_name == "") begin + if(radix == UVM_TIME) + type_name ="time"; + else if(radix == UVM_STRING) + type_name ="string"; + else + type_name ="integral"; + end + sz_str.itoa(size); + if(radix == UVM_NORADIX) + radix = get_default_radix(); + val_str = uvm_integral_to_string (value, size, radix, + get_radix_string(radix)); + name = uvm_leaf_scope(name,scope_separator); + push_element(name,type_name,sz_str,val_str); + pop_element() ; +endfunction +function string uvm_printer::emit (); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"NO_OVERRIDE")) + uvm_report_error ("NO_OVERRIDE", "emit() method not overridden in printer subtype", UVM_NONE, "t/uvm/src/base/uvm_printer.svh", 999, "", 1); + end + return ""; +endfunction +function void uvm_printer::flush (); + uvm_printer_element element = get_bottom_element() ; + uvm_printer_element all_descendent_elements[$] ; + element = get_bottom_element() ; + if (element != null) begin + element.get_children(all_descendent_elements,1) ; + foreach (all_descendent_elements[i]) begin + m_recycled_elements.push_back(all_descendent_elements[i]) ; + all_descendent_elements[i].clear_children() ; + end + element.clear_children(); + m_recycled_elements.push_back(element) ; + m_element_stack.delete() ; + end + m_recur_states.delete(); + m_flushed = 1 ; +endfunction +function void uvm_printer::set_name_enabled (bit enabled); + knobs.identifier = enabled ; +endfunction +function bit uvm_printer::get_name_enabled (); + return knobs.identifier ; +endfunction +function void uvm_printer::set_type_name_enabled (bit enabled); + knobs.type_name = enabled ; +endfunction +function bit uvm_printer::get_type_name_enabled (); + return knobs.type_name ; +endfunction +function void uvm_printer::set_size_enabled (bit enabled); + knobs.size = enabled ; +endfunction +function bit uvm_printer::get_size_enabled (); + return knobs.size ; +endfunction +function void uvm_printer::set_id_enabled (bit enabled); + knobs.reference = enabled ; +endfunction +function bit uvm_printer::get_id_enabled (); + return knobs.reference ; +endfunction +function void uvm_printer::set_radix_enabled (bit enabled); + knobs.show_radix = enabled ; +endfunction +function bit uvm_printer::get_radix_enabled (); + return knobs.show_radix ; +endfunction +function void uvm_printer::set_radix_string (uvm_radix_enum radix, string prefix); + if (radix == UVM_DEC) knobs.dec_radix = prefix ; + else if (radix == UVM_BIN) knobs.bin_radix = prefix ; + else if (radix == UVM_OCT) knobs.oct_radix = prefix ; + else if (radix == UVM_UNSIGNED) knobs.unsigned_radix = prefix ; + else if (radix == UVM_HEX) knobs.hex_radix = prefix ; + else + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"PRINTER_UNKNOWN_RADIX")) + uvm_report_warning ("PRINTER_UNKNOWN_RADIX", $sformatf("set_radix_string called with unsupported radix %s",radix), UVM_NONE, "t/uvm/src/base/uvm_printer.svh", 1065, "", 1); + end +endfunction +function string uvm_printer::get_radix_string (uvm_radix_enum radix); + if (radix == UVM_DEC) return knobs.dec_radix ; + else if (radix == UVM_BIN) return knobs.bin_radix ; + else if (radix == UVM_OCT) return knobs.oct_radix ; + else if (radix == UVM_UNSIGNED) return knobs.unsigned_radix ; + else if (radix == UVM_HEX) return knobs.hex_radix ; + else return ""; +endfunction +function void uvm_printer::set_default_radix (uvm_radix_enum radix); + knobs.default_radix = radix ; +endfunction +function uvm_radix_enum uvm_printer::get_default_radix (); + return knobs.default_radix ; +endfunction +function void uvm_printer::set_root_enabled (bit enabled); + knobs.show_root = enabled ; +endfunction +function bit uvm_printer::get_root_enabled (); + return knobs.show_root ; +endfunction +function void uvm_printer::set_recursion_policy (uvm_recursion_policy_enum policy); + knobs.recursion_policy = policy ; +endfunction +function uvm_recursion_policy_enum uvm_printer::get_recursion_policy (); + return knobs.recursion_policy ; +endfunction +function void uvm_printer::set_max_depth (int depth); + knobs.depth = depth ; +endfunction +function int uvm_printer::get_max_depth (); + return knobs.depth ; +endfunction +function void uvm_printer::set_file (UVM_FILE fl); + knobs.mcd = fl ; +endfunction +function UVM_FILE uvm_printer::get_file (); + return knobs.mcd ; +endfunction +function void uvm_printer::set_line_prefix (string prefix); + knobs.prefix = prefix ; +endfunction +function string uvm_printer::get_line_prefix (); + return knobs.prefix ; +endfunction +function void uvm_printer::set_begin_elements (int elements = 5); + knobs.begin_elements = elements ; +endfunction +function int uvm_printer::get_begin_elements (); + return knobs.begin_elements ; +endfunction +function void uvm_printer::set_end_elements (int elements = 5); + knobs.end_elements = elements ; +endfunction +function int uvm_printer::get_end_elements (); + return knobs.end_elements ; +endfunction +function uvm_printer_element uvm_printer::get_bottom_element (); + if (m_element_stack.size() > 0) return m_element_stack[0] ; + else return null ; +endfunction +function uvm_printer_element uvm_printer::get_top_element (); + if (m_element_stack.size() > 0) return m_element_stack[$] ; + else return null ; +endfunction +function uvm_printer_element_proxy::new (string name=""); + super.new(name) ; +endfunction +function void uvm_printer_element_proxy::get_immediate_children(uvm_printer_element s, + ref uvm_printer_element children[$]); + s.get_children(children,0) ; +endfunction +function void uvm_printer::push_element ( string name, + string type_name, + string size, + string value=""); + uvm_printer_element element ; + uvm_printer_element parent ; + element = get_unused_element() ; + parent = get_top_element() ; + element.set(name,type_name,size,value); + if (parent != null) parent.add_child(element) ; + m_element_stack.push_back(element) ; +endfunction +function void uvm_printer::pop_element (); + if (m_element_stack.size() > 1) begin + void'(m_element_stack.pop_back()); + end +endfunction +function uvm_printer_element uvm_printer::get_unused_element() ; + uvm_printer_element element ; + if (m_recycled_elements.size() > 0) begin + element = m_recycled_elements.pop_back() ; + end + else begin + element = new() ; + end + return element ; +endfunction +function void uvm_printer::print_array_header (string name, + int size, + string arraytype="array", + byte scope_separator="."); + push_element(name,arraytype,$sformatf("%0d",size),"-"); +endfunction +function void uvm_printer::print_array_footer (int size=0); + pop_element() ; +endfunction +function void uvm_printer::print_array_range(int min, int max); + string tmpstr; + if(min == -1 && max == -1) + return; + if(min == -1) + min = max; + if(max == -1) + max = min; + if(max < min) + return; + print_generic_element("...", "...", "...", "..."); +endfunction +function void uvm_printer::print_object_header (string name, + uvm_object value, + byte scope_separator="."); + if(name == "") + name = ""; + push_element(name, + (value != null) ? value.get_type_name() : "object", + "-", + get_id_enabled() ? uvm_object_value_str(value) : "-"); +endfunction +function void uvm_printer::print_object (string name, uvm_object value, + byte scope_separator="."); + uvm_component comp, child_comp; + uvm_field_op field_op ; + uvm_recursion_policy_enum recursion_policy; + recursion_policy = get_recursion_policy(); + if ((value == null) || + (recursion_policy == UVM_REFERENCE) || + (get_max_depth() == get_active_object_depth())) begin + print_object_header(name,value,scope_separator); + pop_element(); + end + else begin + push_active_object(value); + m_recur_states[value][recursion_policy] = uvm_policy::STARTED ; + print_object_header(name,value,scope_separator); + if($cast(comp, value)) begin + string name; + if (comp.get_first_child(name)) + do begin + child_comp = comp.get_child(name); + if(child_comp.print_enabled) + this.print_object(name,child_comp); + end while (comp.get_next_child(name)); + end + field_op = uvm_field_op::m_get_available_op() ; + field_op.set(UVM_PRINT,this,null); + value.do_execute_op(field_op); + if (field_op.user_hook_enabled()) + value.do_print(this); + field_op.m_recycle(); + pop_element() ; + m_recur_states[value][recursion_policy] = uvm_policy::FINISHED ; + void'(pop_active_object()); + end +endfunction +function bit uvm_printer::istop (); + return (get_active_object_depth() == 0); +endfunction +function void uvm_printer::print_generic (string name, + string type_name, + int size, + string value, + byte scope_separator="."); + push_element(name, + type_name, + (size == -2 ? "..." : $sformatf("%0d",size)), + value); + pop_element(); +endfunction +function void uvm_printer::print_generic_element (string name, + string type_name, + string size, + string value); + push_element(name,type_name,size,value); + pop_element() ; +endfunction +function void uvm_printer::print_time (string name, + time value, + byte scope_separator="."); + print_field_int(name, value, 64, UVM_TIME, scope_separator); +endfunction +function void uvm_printer::print_string (string name, + string value, + byte scope_separator="."); + push_element(name, + "string", + $sformatf("%0d",value.len()), + (value == "" ? "\"\"" : value)); + pop_element() ; +endfunction +function uvm_policy::recursion_state_e uvm_printer::object_printed (uvm_object value, + uvm_recursion_policy_enum recursion); + if (!m_recur_states.exists(value)) return NEVER ; + if (!m_recur_states[value].exists(recursion)) return NEVER ; + else return m_recur_states[value][recursion] ; +endfunction +function void uvm_printer::print_real (string name, + real value, + byte scope_separator="."); + push_element(name,"real","64",$sformatf("%f",value)); + pop_element() ; +endfunction +function string uvm_printer::index_string(int index, string name=""); + index_string.itoa(index); + index_string = { name, "[", index_string, "]" }; +endfunction +function uvm_printer_element::new (string name = ""); + super.new(name) ; +endfunction +function void uvm_printer_element::set (string element_name = "", + string element_type_name = "", + string element_size = "", + string element_value = "" + ); + m_name = element_name ; + m_type_name = element_type_name ; + m_size = element_size ; + m_value = element_value ; +endfunction +function void uvm_printer_element::set_element_name (string element_name); + m_name = element_name ; +endfunction +function string uvm_printer_element::get_element_name (); + return m_name ; +endfunction +function void uvm_printer_element::set_element_type_name (string element_type_name); + m_type_name = element_type_name ; +endfunction +function string uvm_printer_element::get_element_type_name (); + return m_type_name ; +endfunction +function void uvm_printer_element::set_element_size (string element_size); + m_size = element_size ; +endfunction +function string uvm_printer_element::get_element_size (); + return m_size ; +endfunction +function void uvm_printer_element::set_element_value (string element_value); + m_value = element_value ; +endfunction +function string uvm_printer_element::get_element_value (); + return m_value ; +endfunction +function void uvm_printer_element::add_child(uvm_printer_element child) ; + m_children.push_back(child) ; +endfunction +function void uvm_printer_element::get_children(ref uvm_printer_element children[$], input bit recurse) ; + foreach (m_children[i]) begin + children.push_back(m_children[i]) ; + if (recurse) begin + m_children[i].get_children(children,1) ; + end + end +endfunction +function void uvm_printer_element::clear_children() ; + m_children.delete() ; +endfunction +function uvm_table_printer::new(string name=""); + super.new(name); +endfunction +function void uvm_table_printer::pop_element(); + int name_len; + int level ; + uvm_printer_element popped ; + string name_str ; + string type_name_str ; + string size_str ; + string value_str ; + popped = get_top_element() ; + level = m_get_stack_size() - 1 ; + name_str = popped.get_element_name() ; + type_name_str = popped.get_element_type_name() ; + size_str = popped.get_element_size() ; + value_str = popped.get_element_value() ; + if ((name_str.len() + (get_indent() * level)) > m_max_name) m_max_name = (name_str.len() + (get_indent() * level)); + if (type_name_str.len() > m_max_type) m_max_type = type_name_str.len(); + if (size_str.len() > m_max_size) m_max_size = size_str.len(); + if (value_str.len() > m_max_value) m_max_value = value_str.len(); + super.pop_element() ; +endfunction +function string uvm_table_printer::emit(); + string s; + string user_format; + static string dash; + string dashes; + string linefeed; + if (!m_flushed) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/PRINT/NO_FLUSH")) + uvm_report_error ("UVM/PRINT/NO_FLUSH", "printer emit() method called twice without intervening uvm_printer::flush()", UVM_NONE, "t/uvm/src/base/uvm_printer.svh", 1516, "", 1); + end + end + else m_flushed = 0 ; + linefeed = {"\n", get_line_prefix()}; + begin + int q[5]; + int m; + int qq[$]; + q = '{m_max_name,m_max_type,m_max_size,m_max_value,100}; + qq = q.max; + m = qq[0]; + if(dash.len() 0) && (value_str[0] == "@")) + result = {result,"(",element.get_element_type_name(),value_str,") "}; + else + if (get_type_name_enabled() && + (element.get_element_type_name() != "" || + element.get_element_type_name() != "-" || + element.get_element_type_name() != "...")) + result = {result,"(",element.get_element_type_name(),") "}; + if (get_size_enabled()) begin + if (element.get_element_size() != "" || element.get_element_size() != "-") + result = {result,"(",element.get_element_size(),") "}; + end + if (element_children.size() > 0) begin + result = {result, string'(separators[0]), m_linefeed}; + end + else result = {result, value_str, " ", m_linefeed}; + foreach (element_children[i]) begin + result = {result, m_emit_element(element_children[i],level+1)} ; + end + if (element_children.size() > 0) begin + result = {result, indent_str, string'(separators[1]), m_linefeed}; + end + end + return result ; +endfunction : m_emit_element +function void uvm_table_printer::set_default(uvm_table_printer printer) ; + m_default_table_printer = printer ; +endfunction +function uvm_table_printer uvm_table_printer::get_default() ; + if (m_default_table_printer == null) begin + m_default_table_printer = new("uvm_default_table_printer") ; + end + return m_default_table_printer ; +endfunction +function void uvm_table_printer::set_indent(int indent) ; + m_uvm_printer_knobs _knobs = get_knobs(); + _knobs.indent = indent ; +endfunction +function int uvm_table_printer::get_indent() ; + m_uvm_printer_knobs _knobs = get_knobs(); + return _knobs.indent ; +endfunction +function void uvm_table_printer::flush() ; + super.flush() ; + m_max_name=4; + m_max_type=4; + m_max_size=4; + m_max_value=5; +endfunction +function void uvm_tree_printer::set_default(uvm_tree_printer printer) ; + m_default_tree_printer = printer ; +endfunction +function uvm_tree_printer uvm_tree_printer::get_default() ; + if (m_default_tree_printer == null) begin + m_default_tree_printer = new("uvm_default_tree_printer") ; + end + return m_default_tree_printer ; +endfunction +function uvm_line_printer::new(string name="") ; + super.new(name); + m_newline = " "; + set_indent(0); +endfunction +function void uvm_line_printer::set_default(uvm_line_printer printer) ; + m_default_line_printer = printer ; +endfunction +function uvm_line_printer uvm_line_printer::get_default() ; + if (m_default_line_printer == null) begin + m_default_line_printer = new("uvm_default_line_printer") ; + end + return m_default_line_printer ; +endfunction +function void uvm_line_printer::set_separators(string separators) ; + m_uvm_printer_knobs _knobs = get_knobs(); + if (separators.len() < 2) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/PRINT/SHORT_SEP")) + uvm_report_error ("UVM/PRINT/SHORT_SEP", $sformatf("Bad call: set_separators(%s) (Argument must have at least 2 characters)",separators), UVM_NONE, "t/uvm/src/base/uvm_printer.svh", 1888, "", 1); + end + end + _knobs.separator = separators ; +endfunction +function string uvm_line_printer::get_separators() ; + m_uvm_printer_knobs _knobs = get_knobs(); + return _knobs.separator ; +endfunction +function void uvm_line_printer::flush() ; + super.flush() ; +endfunction +class uvm_comparer extends uvm_policy; + typedef uvm_object_registry#(uvm_comparer,"uvm_comparer") type_id; + static function uvm_comparer type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_comparer tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_comparer"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_comparer"; + endfunction : get_type_name + extern virtual function void flush(); + extern virtual function uvm_policy::recursion_state_e object_compared( + uvm_object lhs, + uvm_object rhs, + uvm_recursion_policy_enum recursion, + output bit ret_val + ); + extern virtual function string get_miscompares(); + extern virtual function int unsigned get_result(); + extern virtual function void set_result(int unsigned result) ; + extern virtual function void set_recursion_policy( uvm_recursion_policy_enum policy); + extern virtual function uvm_recursion_policy_enum get_recursion_policy(); + extern virtual function void set_check_type( bit enabled ); + extern virtual function bit get_check_type(); + extern virtual function void set_show_max (int unsigned show_max); + extern virtual function int unsigned get_show_max (); + extern virtual function void set_verbosity (int unsigned verbosity); + extern virtual function int unsigned get_verbosity (); + extern virtual function void set_severity (uvm_severity severity); + extern virtual function uvm_severity get_severity (); + extern virtual function void set_threshold (int unsigned threshold); + extern virtual function int unsigned get_threshold (); + typedef struct { + recursion_state_e state; + bit ret_val; + } state_info_t ; + state_info_t m_recur_states[uvm_object ][uvm_object ][uvm_recursion_policy_enum ]; + local uvm_recursion_policy_enum policy = UVM_DEFAULT_POLICY; + local int unsigned show_max = 1; + local int unsigned verbosity = UVM_LOW; + local uvm_severity sev = UVM_INFO; + local string miscompares = ""; + local bit check_type = 1; + local int unsigned result = 0; + local int unsigned m_threshold; + function new(string name=""); + super.new(name); + m_threshold = 1; + endfunction + static function void set_default (uvm_comparer comparer) ; + uvm_coreservice_t coreservice ; + coreservice = uvm_coreservice_t::get() ; + coreservice.set_default_comparer(comparer) ; + endfunction + static function uvm_comparer get_default () ; + uvm_coreservice_t coreservice ; + coreservice = uvm_coreservice_t::get() ; + return coreservice.get_default_comparer() ; + endfunction + virtual function bit compare_field (string name, + uvm_bitstream_t lhs, + uvm_bitstream_t rhs, + int size, + uvm_radix_enum radix=UVM_NORADIX); + uvm_bitstream_t mask; + string msg; + if(size <= 64) + return compare_field_int(name, lhs, rhs, size, radix); + mask = -1; + mask >>= (UVM_STREAMBITS-size); + if((lhs & mask) !== (rhs & mask)) begin + case (radix) + UVM_BIN: begin + $swrite(msg, "%s: lhs = 'b%0b : rhs = 'b%0b", + name, lhs&mask, rhs&mask); + end + UVM_OCT: begin + $swrite(msg, "%s: lhs = 'o%0o : rhs = 'o%0o", + name, lhs&mask, rhs&mask); + end + UVM_DEC: begin + $swrite(msg, "%s: lhs = %0d : rhs = %0d", + name, lhs&mask, rhs&mask); + end + UVM_TIME: begin + $swrite(msg, "%s: lhs = %0t : rhs = %0t", + name, lhs&mask, rhs&mask); + end + UVM_STRING: begin + $swrite(msg, "%s: lhs = %0s : rhs = %0s", + name, lhs&mask, rhs&mask); + end + UVM_ENUM: begin + $swrite(msg, "%s: lhs = %0d : rhs = %0d", + name, lhs&mask, rhs&mask); + end + default: begin + $swrite(msg, "%s: lhs = 'h%0x : rhs = 'h%0x", + name, lhs&mask, rhs&mask); + end + endcase + print_msg(msg); + return 0; + end + return 1; + endfunction + virtual function bit compare_field_int (string name, + uvm_integral_t lhs, + uvm_integral_t rhs, + int size, + uvm_radix_enum radix=UVM_NORADIX); + logic [63:0] mask; + string msg; + mask = -1; + mask >>= (64-size); + if((lhs & mask) !== (rhs & mask)) begin + case (radix) + UVM_BIN: begin + $swrite(msg, "%s: lhs = 'b%0b : rhs = 'b%0b", + name, lhs&mask, rhs&mask); + end + UVM_OCT: begin + $swrite(msg, "%s: lhs = 'o%0o : rhs = 'o%0o", + name, lhs&mask, rhs&mask); + end + UVM_DEC: begin + $swrite(msg, "%s: lhs = %0d : rhs = %0d", + name, lhs&mask, rhs&mask); + end + UVM_TIME: begin + $swrite(msg, "%s: lhs = %0t : rhs = %0t", + name, lhs&mask, rhs&mask); + end + UVM_STRING: begin + $swrite(msg, "%s: lhs = %0s : rhs = %0s", + name, lhs&mask, rhs&mask); + end + UVM_ENUM: begin + $swrite(msg, "%s: lhs = %0d : rhs = %0d", + name, lhs&mask, rhs&mask); + end + default: begin + $swrite(msg, "%s: lhs = 'h%0x : rhs = 'h%0x", + name, lhs&mask, rhs&mask); + end + endcase + print_msg(msg); + return 0; + end + return 1; + endfunction + virtual function bit compare_field_real (string name, + real lhs, + real rhs); + string msg; + if(lhs != rhs) begin + $swrite(msg, name, ": lhs = ", lhs, " : rhs = ", rhs); + print_msg(msg); + return 0; + end + return 1; + endfunction + local string m_object_names[$]; + local function string m_current_context(string name=""); + if (m_object_names.size() == 0) + return name; + else if ((m_object_names.size() == 1) && (name=="")) + return m_object_names[0]; + else begin + string full_name; + foreach(m_object_names[i]) begin + if (i == m_object_names.size() - 1) + full_name = {full_name, m_object_names[i]}; + else + full_name = {full_name, m_object_names[i], "."}; + end + if (name != "") + return {full_name, ".", name}; + else + return full_name; + end + endfunction : m_current_context + virtual function bit compare_object (string name, + uvm_object lhs, + uvm_object rhs); + int old_result ; + uvm_field_op field_op ; + uvm_policy::recursion_state_e prev_state; + bit ret_val = 1; + if (rhs == lhs) + return ret_val; + m_object_names.push_back(name); + if (policy == UVM_REFERENCE && lhs != rhs) begin + print_msg_object(lhs, rhs); + ret_val = 0; + end + if (ret_val && (rhs == null || lhs == null)) begin + print_msg_object(lhs, rhs); + ret_val = 0; + end + if (ret_val) begin + prev_state = object_compared(lhs,rhs,get_recursion_policy(),ret_val); + if (prev_state != uvm_policy::NEVER) + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/COPIER/LOOP")) + uvm_report_warning ("UVM/COPIER/LOOP", {"Possible loop when comparing '", lhs.get_full_name(), "' to '", rhs.get_full_name(), "'"}, UVM_NONE, "t/uvm/src/base/uvm_comparer.svh", 465, "", 1); + end + push_active_object(lhs); + m_recur_states[lhs][rhs][get_recursion_policy()] = '{uvm_policy::STARTED,0}; + old_result = get_result(); + if (get_check_type() && (lhs.get_object_type() != rhs.get_object_type())) begin + if(lhs.get_type_name() != rhs.get_type_name()) begin + print_msg({"type: lhs = \"", lhs.get_type_name(), "\" : rhs = \"", rhs.get_type_name(), "\""}); + end + else begin + print_msg({"get_object_type() for ",lhs.get_name()," does not match get_object_type() for ",rhs.get_name()}); + end + end + field_op = uvm_field_op::m_get_available_op(); + field_op.set(UVM_COMPARE,this,rhs); + lhs.do_execute_op(field_op); + if (field_op.user_hook_enabled()) begin + ret_val = lhs.do_compare(rhs,this); + end + field_op.m_recycle(); + if (ret_val && (get_result() > old_result)) + ret_val = 0; + m_recur_states[lhs][rhs][get_recursion_policy()] = '{uvm_policy::FINISHED,ret_val}; + void'(pop_active_object()); + end + void'(m_object_names.pop_back()); + if (!ret_val && (get_active_object_depth() == 0)) begin + string msg ; + if(get_result()) begin + if (get_show_max() && (get_show_max() < get_result())) + $swrite(msg, "%0d Miscompare(s) (%0d shown) for object ", + result, show_max); + else + $swrite(msg, "%0d Miscompare(s) for object ", result); + end + uvm_pkg::uvm_report(sev, "MISCMP", $sformatf("%s%s@%0d vs. %s@%0d", msg, + (lhs == null) ? "" : lhs.get_name(), + (lhs == null) ? 0 : lhs.get_inst_id(), + (rhs == null) ? "" : rhs.get_name(), + (rhs == null) ? 0 : rhs.get_inst_id()), + get_verbosity(), "t/uvm/src/base/uvm_comparer.svh", 525); + end + return ret_val; + endfunction + virtual function bit compare_string (string name, + string lhs, + string rhs); + string msg; + if(lhs != rhs) begin + msg = { name, ": lhs = \"", lhs, "\" : rhs = \"", rhs, "\""}; + print_msg(msg); + return 0; + end + return 1; + endfunction + function void print_msg (string msg); + string tmp = m_current_context(msg); + result++; + if((get_show_max() == 0) || + (get_result() <= get_show_max())) begin + msg = {"Miscompare for ", tmp}; + uvm_pkg::uvm_report(sev, "MISCMP", msg, get_verbosity(), "t/uvm/src/base/uvm_comparer.svh", 573); + end + miscompares = { miscompares, tmp, "\n" }; + endfunction + function void print_msg_object(uvm_object lhs, uvm_object rhs); + string tmp = $sformatf("%s: lhs = @%0d : rhs = @%0d", + m_current_context(), + (lhs != null ? lhs.get_inst_id() : 0), + (rhs != null ? rhs.get_inst_id() : 0)); + result++; + if((get_show_max() == 0) || + (get_result() <= get_show_max())) begin + uvm_pkg::uvm_report(sev, + "MISCMP", + {"Miscompare for ", tmp}, + get_verbosity(), + "t/uvm/src/base/uvm_comparer.svh", + 599); + end + miscompares = { miscompares, tmp, "\n" }; + endfunction + int depth; + bit compare_map[uvm_object][uvm_object]; +endclass +function void uvm_comparer::flush(); + miscompares = "" ; + check_type = 1 ; + result = 0 ; + m_recur_states.delete(); +endfunction +function uvm_policy::recursion_state_e uvm_comparer::object_compared( + uvm_object lhs, + uvm_object rhs, + uvm_recursion_policy_enum recursion, + output bit ret_val +); + if (!m_recur_states.exists(lhs)) return NEVER ; + else if (!m_recur_states[lhs].exists(rhs)) return NEVER ; + else if (!m_recur_states[lhs][rhs].exists(recursion)) return NEVER ; + else begin + if (m_recur_states[lhs][rhs][recursion].state == FINISHED) + ret_val = m_recur_states[lhs][rhs][recursion].ret_val; + return m_recur_states[lhs][rhs][recursion].state ; + end +endfunction +function string uvm_comparer::get_miscompares(); + return miscompares ; +endfunction +function int unsigned uvm_comparer::get_result(); + return result ; +endfunction +function void uvm_comparer::set_result(int unsigned result); + this.result = result ; +endfunction +function void uvm_comparer::set_recursion_policy( uvm_recursion_policy_enum policy); + this.policy = policy ; +endfunction +function uvm_recursion_policy_enum uvm_comparer::get_recursion_policy(); + return policy ; +endfunction +function void uvm_comparer::set_check_type( bit enabled ); + check_type = enabled ; +endfunction +function bit uvm_comparer::get_check_type(); + return check_type ; +endfunction +function void uvm_comparer::set_show_max (int unsigned show_max); + this.show_max = show_max ; +endfunction +function int unsigned uvm_comparer::get_show_max(); + return show_max ; +endfunction +function void uvm_comparer::set_verbosity (int unsigned verbosity); + this.verbosity = verbosity ; +endfunction +function int unsigned uvm_comparer::get_verbosity(); + return verbosity ; +endfunction +function void uvm_comparer::set_severity (uvm_severity severity); + sev = severity ; +endfunction +function uvm_severity uvm_comparer::get_severity(); + return sev ; +endfunction +function void uvm_comparer::set_threshold (int unsigned threshold); + m_threshold = threshold; +endfunction +function int unsigned uvm_comparer::get_threshold(); + return m_threshold; +endfunction +typedef bit signed [(4096*8)-1:0] uvm_pack_bitstream_t; +class uvm_packer extends uvm_policy; + typedef uvm_object_registry#(uvm_packer,"uvm_packer") type_id; + static function uvm_packer type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_packer tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_packer"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_packer"; + endfunction : get_type_name + uvm_factory m_factory; + local uvm_object m_object_references[int]; + extern virtual function void set_packed_bits (ref bit unsigned stream[]); + extern virtual function void set_packed_bytes (ref byte unsigned stream[]); + extern virtual function void set_packed_ints (ref int unsigned stream[]); + extern virtual function void set_packed_longints (ref longint unsigned stream[]); + extern virtual function void get_packed_bits (ref bit unsigned stream[]); + extern virtual function void get_packed_bytes (ref byte unsigned stream[]); + extern virtual function void get_packed_ints (ref int unsigned stream[]); + extern virtual function void get_packed_longints (ref longint unsigned stream[]); + static function void set_default (uvm_packer packer) ; + uvm_coreservice_t coreservice ; + coreservice = uvm_coreservice_t::get() ; + coreservice.set_default_packer(packer) ; + endfunction + static function uvm_packer get_default () ; + uvm_coreservice_t coreservice ; + coreservice = uvm_coreservice_t::get() ; + return coreservice.get_default_packer() ; + endfunction + extern virtual function void flush (); + extern virtual function void pack_field (uvm_bitstream_t value, int size); + extern function new(string name=""); + extern virtual function void pack_field_int (uvm_integral_t value, int size); + extern virtual function void pack_bits(ref bit value[], input int size = -1); + extern virtual function void pack_bytes(ref byte value[], input int size = -1); + extern virtual function void pack_ints(ref int value[], input int size = -1); + extern virtual function void pack_string (string value); + extern virtual function void pack_time (time value); + extern virtual function void pack_real (real value); + extern virtual function void pack_object (uvm_object value); + extern virtual function void pack_object_with_meta (uvm_object value); + extern virtual function void pack_object_wrapper (uvm_object_wrapper value); + extern virtual function bit is_null (); + extern virtual function bit is_object_wrapper(); + extern virtual function uvm_bitstream_t unpack_field (int size); + extern virtual function uvm_integral_t unpack_field_int (int size); + extern virtual function void unpack_bits(ref bit value[], input int size = -1); + extern virtual function void unpack_bytes(ref byte value[], input int size = -1); + extern virtual function void unpack_ints(ref int value[], input int size = -1); + extern virtual function string unpack_string (); + extern virtual function time unpack_time (); + extern virtual function real unpack_real (); + extern virtual function void unpack_object (uvm_object value); + extern virtual function void unpack_object_with_meta (inout uvm_object value); + extern virtual function uvm_object_wrapper unpack_object_wrapper(); + extern virtual function int get_packed_size(); + static bit bitstream[]; + static bit fabitstream[]; + int m_pack_iter; + int m_unpack_iter; + bit reverse_order; + byte byte_size = 8; + int word_size = 16; + bit nopack; + uvm_pack_bitstream_t m_bits; + extern function void index_error(int index, string id, int sz); + extern function bit enough_bits(int needed, string id); +endclass +function void uvm_packer::index_error(int index, string id, int sz); + uvm_report_error("PCKIDX", + $sformatf("index %0d for get_%0s too large; valid index range is 0-%0d.", + index,id,((m_pack_iter+sz-1)/sz)-1), UVM_NONE); +endfunction +function bit uvm_packer::enough_bits(int needed, string id); + if ((m_pack_iter - m_unpack_iter) < needed) begin + uvm_report_error("PCKSZ", + $sformatf("%0d bits needed to unpack %0s, yet only %0d available.", + needed, id, (m_pack_iter - m_unpack_iter)), UVM_NONE); + return 0; + end + return 1; +endfunction +function int uvm_packer::get_packed_size(); + return m_pack_iter - m_unpack_iter; +endfunction +function void uvm_packer::flush(); + m_pack_iter = 64; + m_unpack_iter = 64; + m_bits = 0; + m_object_references.delete(); + m_object_references[0] = null; + m_factory = null; + super.flush(); +endfunction : flush +function void uvm_packer::get_packed_bits(ref bit unsigned stream[]); + stream = new[m_pack_iter]; + m_bits[31:0] = m_pack_iter; + m_bits[63:32] = m_unpack_iter; + for (int i=0;i> ($bits(byte)-(m_pack_iter%$bits(byte)))); + stream[i] = v; + end +endfunction +function void uvm_packer::get_packed_ints (ref int unsigned stream[] ); + int sz; + int v; + sz = (m_pack_iter + $high(v)) / $bits(int); + m_bits[31:0] = m_pack_iter; + m_bits[63:32] = m_unpack_iter; + stream = new[sz]; + foreach (stream[i]) begin + if (i != sz-1 || (m_pack_iter % $bits(int)) == 0) + v = m_bits[ i* $bits(int) +: $bits(int) ]; + else + v = m_bits[ i* $bits(int) +: $bits(int) ] & ({$bits(int){1'b1}} >> ($bits(int)-(m_pack_iter%$bits(int)))); + stream[i] = v; + end +endfunction +function void uvm_packer::get_packed_longints (ref longint unsigned stream[] ); + int sz; + longint v; + sz = (m_pack_iter + $high(v)) / $bits(longint); + m_bits[31:0] = m_pack_iter; + m_bits[63:32] = m_unpack_iter; + stream = new[sz]; + foreach (stream[i]) begin + if (i != sz-1 || (m_pack_iter % $bits(longint)) == 0) + v = m_bits[ i* $bits(longint) +: $bits(longint) ]; + else + v = m_bits[ i* $bits(longint) +: $bits(longint) ] & ({$bits(longint){1'b1}} >> ($bits(longint)-(m_pack_iter%$bits(longint)))); + stream[i] = v; + end +endfunction +function void uvm_packer::set_packed_bits (ref bit stream []); + int bit_size; + bit_size = stream.size(); + for (int i=0;i value.size()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/BASE/PACKER/BAD_SIZE")) + uvm_report_error ("UVM/BASE/PACKER/BAD_SIZE", $sformatf("pack_bits called with size '%0d', which exceeds value.size() of '%0d'", size, value.size()), UVM_NONE, "t/uvm/src/base/uvm_packer.svh", 797, "", 1); + end + return; + end + for (int i=0; i max_size) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/BASE/PACKER/BAD_SIZE")) + uvm_report_error ("UVM/BASE/PACKER/BAD_SIZE", $sformatf("pack_bytes called with size '%0d', which exceeds value size of '%0d'", size, max_size), UVM_NONE, "t/uvm/src/base/uvm_packer.svh", 824, "", 1); + end + return; + end + else begin + int idx_select; + for (int i=0; i max_size) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/BASE/PACKER/BAD_SIZE")) + uvm_report_error ("UVM/BASE/PACKER/BAD_SIZE", $sformatf("pack_ints called with size '%0d', which exceeds value size of '%0d'", size, max_size), UVM_NONE, "t/uvm/src/base/uvm_packer.svh", 858, "", 1); + end + return; + end + else begin + int idx_select; + for (int i=0; i value.size()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/BASE/PACKER/BAD_SIZE")) + uvm_report_error ("UVM/BASE/PACKER/BAD_SIZE", $sformatf("unpack_bits called with size '%0d', which exceeds value.size() of '%0d'", size, value.size()), UVM_NONE, "t/uvm/src/base/uvm_packer.svh", 1076, "", 1); + end + return; + end + if (enough_bits(size, "integral")) begin + m_unpack_iter += size; + for (int i=0; i max_size) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/BASE/PACKER/BAD_SIZE")) + uvm_report_error ("UVM/BASE/PACKER/BAD_SIZE", $sformatf("unpack_bytes called with size '%0d', which exceeds value size of '%0d'", size, value.size()), UVM_NONE, "t/uvm/src/base/uvm_packer.svh", 1104, "", 1); + end + return; + end + else begin + if (enough_bits(size, "integral")) begin + m_unpack_iter += size; + for (int i=0; i max_size) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/BASE/PACKER/BAD_SIZE")) + uvm_report_error ("UVM/BASE/PACKER/BAD_SIZE", $sformatf("unpack_ints called with size '%0d', which exceeds value size of '%0d'", size, value.size()), UVM_NONE, "t/uvm/src/base/uvm_packer.svh", 1136, "", 1); + end + return; + end + else begin + if (enough_bits(size, "integral")) begin + m_unpack_iter += size; + for (int i=0; i' is not supported in links for 'uvm_tr_database'", UVM_NONE, "t/uvm/src/base/uvm_tr_database.svh", 158, "", 1); + end + return; + end + if (rhs == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/TR_DB/BAD_LINK")) + uvm_report_warning ("UVM/TR_DB/BAD_LINK", "right hand side '' is not supported in links for 'uvm_tr_database'", UVM_NONE, "t/uvm/src/base/uvm_tr_database.svh", 163, "", 1); + end + return; + end + if (!$cast(s_lhs, lhs) && + !$cast(r_lhs, lhs)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/TR_DB/BAD_LINK")) + uvm_report_warning ("UVM/TR_DB/BAD_LINK", $sformatf("left hand side of type '%s' not supported in links for 'uvm_tr_database'", lhs.get_type_name()), UVM_NONE, "t/uvm/src/base/uvm_tr_database.svh", 171, "", 1); + end + return; + end + if (!$cast(s_rhs, rhs) && + !$cast(r_rhs, rhs)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/TR_DB/BAD_LINK")) + uvm_report_warning ("UVM/TR_DB/BAD_LINK", $sformatf("right hand side of type '%s' not supported in links for 'uvm_record_datbasae'", rhs.get_type_name()), UVM_NONE, "t/uvm/src/base/uvm_tr_database.svh", 178, "", 1); + end + return; + end + if (r_lhs != null) begin + s_lhs = r_lhs.get_stream(); + end + if (r_rhs != null) begin + s_rhs = r_rhs.get_stream(); + end + if ((s_lhs != null) && (s_lhs.get_db() != this)) begin + db = s_lhs.get_db(); + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/TR_DB/BAD_LINK")) + uvm_report_warning ("UVM/TR_DB/BAD_LINK", $sformatf("attempt to link stream from '%s' into '%s'", db.get_name(), this.get_name()), UVM_NONE, "t/uvm/src/base/uvm_tr_database.svh", 193, "", 1); + end + return; + end + if ((s_rhs != null) && (s_rhs.get_db() != this)) begin + db = s_rhs.get_db(); + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/TR_DB/BAD_LINK")) + uvm_report_warning ("UVM/TR_DB/BAD_LINK", $sformatf("attempt to link stream from '%s' into '%s'", db.get_name(), this.get_name()), UVM_NONE, "t/uvm/src/base/uvm_tr_database.svh", 200, "", 1); + end + return; + end + do_establish_link(link); + endfunction : establish_link + pure virtual protected function bit do_open_db(); + pure virtual protected function bit do_close_db(); + pure virtual protected function uvm_tr_stream do_open_stream(string name, + string scope, + string type_name); + pure virtual protected function void do_establish_link(uvm_link_base link); +endclass : uvm_tr_database +typedef class uvm_recorder; +typedef class uvm_tr_stream; +typedef class uvm_link_base; +typedef class uvm_simple_lock_dap; +typedef class uvm_text_tr_stream; +class uvm_text_tr_database extends uvm_tr_database; + local uvm_simple_lock_dap#(string) m_filename_dap; + UVM_FILE m_file; + typedef uvm_object_registry#(uvm_text_tr_database,"uvm_text_tr_database") type_id; + static function uvm_text_tr_database type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_text_tr_database tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_text_tr_database"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_text_tr_database"; + endfunction : get_type_name + function new(string name="unnamed-uvm_text_tr_database"); + super.new(name); + m_filename_dap = new("filename_dap"); + m_filename_dap.set("tr_db.log"); + endfunction : new + protected virtual function bit do_open_db(); + if (m_file == 0) begin + m_file = $fopen(m_filename_dap.get(), "a+"); + if (m_file != 0) + m_filename_dap.lock(); + end + return (m_file != 0); + endfunction : do_open_db + protected virtual function bit do_close_db(); + if (m_file != 0) begin + fork + $fclose(m_file); + join_none + m_filename_dap.unlock(); + end + return 1; + endfunction : do_close_db + protected virtual function uvm_tr_stream do_open_stream(string name, + string scope, + string type_name); + uvm_text_tr_stream m_stream = uvm_text_tr_stream::type_id_create(name); + return m_stream; + endfunction : do_open_stream + protected virtual function void do_establish_link(uvm_link_base link); + uvm_recorder r_lhs, r_rhs; + uvm_object lhs = link.get_lhs(); + uvm_object rhs = link.get_rhs(); + void'($cast(r_lhs, lhs)); + void'($cast(r_rhs, rhs)); + if ((r_lhs == null) || + (r_rhs == null)) + return; + else begin + uvm_parent_child_link pc_link; + uvm_related_link re_link; + if ($cast(pc_link, link)) begin + $fdisplay(m_file," LINK @%0t {TXH1:%0d TXH2:%0d RELATION=%0s}", + $time, + r_lhs.get_handle(), + r_rhs.get_handle(), + "child"); + end + else if ($cast(re_link, link)) begin + $fdisplay(m_file," LINK @%0t {TXH1:%0d TXH2:%0d RELATION=%0s}", + $time, + r_lhs.get_handle(), + r_rhs.get_handle(), + ""); + end + end + endfunction : do_establish_link + function void set_file_name(string filename); + if (filename == "") begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/TXT_DB/EMPTY_NAME")) + uvm_report_warning ("UVM/TXT_DB/EMPTY_NAME", "Ignoring attempt to set file name to ''!", UVM_NONE, "t/uvm/src/base/uvm_text_tr_database.svh", 195, "", 1); + end + return; + end + if (!m_filename_dap.try_set(filename)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/TXT_DB/SET_AFTER_OPEN")) + uvm_report_warning ("UVM/TXT_DB/SET_AFTER_OPEN", "Ignoring attempt to change file name after opening the db!", UVM_NONE, "t/uvm/src/base/uvm_text_tr_database.svh", 201, "", 1); + end + return; + end + endfunction : set_file_name +endclass : uvm_text_tr_database +class m_uvm_tr_stream_cfg; + uvm_tr_database db; + string scope; + string stream_type_name; +endclass : m_uvm_tr_stream_cfg +typedef class uvm_set_before_get_dap; +typedef class uvm_text_recorder; +virtual class uvm_tr_stream extends uvm_object; + local uvm_set_before_get_dap#(m_uvm_tr_stream_cfg) m_cfg_dap; + local bit m_records[uvm_recorder]; + local bit m_warn_null_cfg; + local bit m_is_opened; + local bit m_is_closed; + function new(string name="unnamed-uvm_tr_stream"); + super.new(name); + m_cfg_dap = new("cfg_dap"); + endfunction : new + local static int m_ids_by_stream[uvm_tr_stream]; + function uvm_tr_database get_db(); + m_uvm_tr_stream_cfg m_cfg; + if (!m_cfg_dap.try_get(m_cfg)) begin + if (m_warn_null_cfg == 1) + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/REC_STR/NO_CFG")) + uvm_report_warning ("UVM/REC_STR/NO_CFG", $sformatf("attempt to retrieve DB from '%s' before it was set!", get_name()), UVM_NONE, "t/uvm/src/base/uvm_tr_stream.svh", 94, "", 1); + end + m_warn_null_cfg = 0; + return null; + end + return m_cfg.db; + endfunction : get_db + function string get_scope(); + m_uvm_tr_stream_cfg m_cfg; + if (!m_cfg_dap.try_get(m_cfg)) begin + if (m_warn_null_cfg == 1) + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/REC_STR/NO_CFG")) + uvm_report_warning ("UVM/REC_STR/NO_CFG", $sformatf("attempt to retrieve scope from '%s' before it was set!", get_name()), UVM_NONE, "t/uvm/src/base/uvm_tr_stream.svh", 109, "", 1); + end + m_warn_null_cfg = 0; + return ""; + end + return m_cfg.scope; + endfunction : get_scope + function string get_stream_type_name(); + m_uvm_tr_stream_cfg m_cfg; + if (!m_cfg_dap.try_get(m_cfg)) begin + if (m_warn_null_cfg == 1) + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/REC_STR/NO_CFG")) + uvm_report_warning ("UVM/REC_STR/NO_CFG", $sformatf("attempt to retrieve STREAM_TYPE_NAME from '%s' before it was set!", get_name()), UVM_NONE, "t/uvm/src/base/uvm_tr_stream.svh", 124, "", 1); + end + m_warn_null_cfg = 0; + return ""; + end + return m_cfg.stream_type_name; + endfunction : get_stream_type_name + function void close(); + if (!is_open()) + return; + do_close(); + foreach (m_records[idx]) + if (idx.is_open()) + idx.close(); + m_is_opened = 0; + m_is_closed = 1; + endfunction : close + function void free(); + process p; + string s; + uvm_tr_database db; + if (!is_open() && !is_closed()) + return; + if (is_open()) + close(); + do_free(); + foreach (m_records[idx]) + idx.free(); + db = get_db(); + m_is_closed = 0; + p = process::self(); + if(p != null) + s = p.get_randstate(); + m_cfg_dap = new("cfg_dap"); + if(p != null) + p.set_randstate(s); + m_warn_null_cfg = 1; + if (m_ids_by_stream.exists(this)) + m_free_id(m_ids_by_stream[this]); + if (db != null) + db.m_free_stream(this); + endfunction : free + function void m_do_open(uvm_tr_database db, + string scope="", + string stream_type_name=""); + m_uvm_tr_stream_cfg m_cfg; + uvm_tr_database m_db; + if (db == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/REC_STR/NULL_DB")) + uvm_report_error ("UVM/REC_STR/NULL_DB", $sformatf("Illegal attempt to set DB for '%s' to ''", this.get_full_name()), UVM_NONE, "t/uvm/src/base/uvm_tr_stream.svh", 217, "", 1); + end + return; + end + if (m_cfg_dap.try_get(m_cfg)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/REC_STR/RE_CFG")) + uvm_report_error ("UVM/REC_STR/RE_CFG", $sformatf("Illegal attempt to re-open '%s'", this.get_full_name()), UVM_NONE, "t/uvm/src/base/uvm_tr_stream.svh", 224, "", 1); + end + end + else begin + m_cfg = new(); + m_cfg.db = db; + m_cfg.scope = scope; + m_cfg.stream_type_name = stream_type_name; + m_cfg_dap.set(m_cfg); + m_is_opened = 1; + do_open(db, scope, stream_type_name); + end + endfunction : m_do_open + function bit is_open(); + return m_is_opened; + endfunction : is_open + function bit is_closed(); + return m_is_closed; + endfunction : is_closed + function uvm_recorder open_recorder(string name, + time open_time = 0, + string type_name=""); + time m_time = (open_time == 0) ? $time : open_time; + if (!is_open()) + return null; + else begin + process p = process::self(); + string s; + if (p != null) + s = p.get_randstate(); + open_recorder = do_open_recorder(name, + m_time, + type_name); + if (open_recorder != null) begin + m_records[open_recorder] = 1; + open_recorder.m_do_open(this, m_time, type_name); + end + if (p != null) + p.set_randstate(s); + end + endfunction : open_recorder + function void m_free_recorder(uvm_recorder recorder); + if (m_records.exists(recorder)) + m_records.delete(recorder); + endfunction : m_free_recorder + function unsigned get_recorders(ref uvm_recorder q[$]); + q.delete(); + foreach (m_records[idx]) + q.push_back(idx); + return q.size(); + endfunction : get_recorders + local static uvm_tr_stream m_streams_by_id[int]; + function int get_handle(); + if (!is_open() && !is_closed()) begin + return 0; + end + else begin + int handle = get_inst_id(); + if (m_ids_by_stream.exists(this) && m_ids_by_stream[this] != handle) + m_streams_by_id.delete(m_ids_by_stream[this]); + m_streams_by_id[handle] = this; + m_ids_by_stream[this] = handle; + return handle; + end + endfunction : get_handle + static function uvm_tr_stream get_stream_from_handle(int id); + if (id == 0) + return null; + if ($isunknown(id) || !m_streams_by_id.exists(id)) + return null; + return m_streams_by_id[id]; + endfunction : get_stream_from_handle + static function void m_free_id(int id); + uvm_tr_stream stream; + if (!$isunknown(id) && m_streams_by_id.exists(id)) + stream = m_streams_by_id[id]; + if (stream != null) begin + m_streams_by_id.delete(id); + m_ids_by_stream.delete(stream); + end + endfunction : m_free_id + protected virtual function void do_open(uvm_tr_database db, + string scope, + string stream_type_name); + endfunction : do_open + protected virtual function void do_close(); + endfunction : do_close + protected virtual function void do_free(); + endfunction : do_free + protected virtual function uvm_recorder do_open_recorder(string name, + time open_time, + string type_name); + return null; + endfunction : do_open_recorder +endclass : uvm_tr_stream +class uvm_text_tr_stream extends uvm_tr_stream; + local uvm_text_tr_database m_text_db; + typedef uvm_object_registry#(uvm_text_tr_stream,"uvm_text_tr_stream") type_id; + static function uvm_text_tr_stream type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_text_tr_stream tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_text_tr_stream"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_text_tr_stream"; + endfunction : get_type_name +function void do_execute_op( uvm_field_op op ); + super.do_execute_op(op); + __m_uvm_execute_field_op(op); +endfunction : do_execute_op +local function void __m_uvm_execute_field_op( uvm_field_op __local_op__ ); + uvm_field_flag_t local_op_type__; + uvm_text_tr_stream local_rhs__; + uvm_resource_base local_rsrc__; + string local_rsrc_name__; + uvm_object local_obj__; + bit local_success__; + typedef uvm_text_tr_stream __local_type__; + int local_size__; + uvm_printer __local_printer__; + uvm_comparer __local_comparer__; + uvm_recorder __local_recorder__; + uvm_packer __local_packer__; + uvm_copier __local_copier__; + void'($cast(local_rhs__, __local_op__.get_rhs())); + if (($cast(local_rsrc__, __local_op__.get_rhs())) && + (local_rsrc__ != null)) + local_rsrc_name__ = local_rsrc__.get_name(); + local_op_type__ = __local_op__.get_op_type(); + case (local_op_type__) + UVM_PRINT: begin + $cast(__local_printer__, __local_op__.get_policy()); + end + UVM_COMPARE: begin + if (local_rhs__ == null) return; + $cast(__local_comparer__, __local_op__.get_policy()); + end + UVM_RECORD: begin + $cast(__local_recorder__, __local_op__.get_policy()); + end + UVM_PACK, UVM_UNPACK: begin + $cast(__local_packer__, __local_op__.get_policy()); + end + UVM_COPY: begin + if (local_rhs__ == null) return; + $cast(__local_copier__, __local_op__.get_policy()); + end + UVM_SET: begin + if (local_rsrc__ == null) return; + end + default: + return; + endcase +endfunction : __m_uvm_execute_field_op + function new(string name="unnamed-uvm_text_tr_stream"); + super.new(name); + endfunction : new + protected virtual function void do_open(uvm_tr_database db, + string scope, + string stream_type_name); + $cast(m_text_db, db); + if (m_text_db.open_db()) + $fdisplay(m_text_db.m_file, + " CREATE_STREAM @%0t {NAME:%s T:%s SCOPE:%s STREAM:%0d}", + $time, + this.get_name(), + stream_type_name, + scope, + this.get_handle()); + endfunction : do_open + protected virtual function void do_close(); + if (m_text_db.open_db()) + $fdisplay(m_text_db.m_file, + " CLOSE_STREAM @%0t {NAME:%s T:%s SCOPE:%s STREAM:%0d}", + $time, + this.get_name(), + this.get_stream_type_name(), + this.get_scope(), + this.get_handle()); + endfunction : do_close + protected virtual function void do_free(); + if (m_text_db.open_db()) + $fdisplay(m_text_db.m_file, + " FREE_STREAM @%0t {NAME:%s T:%s SCOPE:%s STREAM:%0d}", + $time, + this.get_name(), + this.get_stream_type_name(), + this.get_scope(), + this.get_handle()); + m_text_db = null; + return; + endfunction : do_free + protected virtual function uvm_recorder do_open_recorder(string name, + time open_time, + string type_name); + if (m_text_db.open_db()) begin + return uvm_text_recorder::type_id_create(name); + end + return null; + endfunction : do_open_recorder +endclass : uvm_text_tr_stream +typedef class uvm_report_message; +virtual class uvm_recorder extends uvm_policy; + typedef uvm_abstract_object_registry#(uvm_recorder,"uvm_recorder") type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_recorder"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_recorder"; + endfunction : get_type_name + local uvm_set_before_get_dap#(uvm_tr_stream) m_stream_dap; + local bit m_warn_null_stream; + local bit m_is_opened; + local bit m_is_closed; + local time m_open_time; + local time m_close_time; + int recording_depth; + uvm_radix_enum default_radix = UVM_HEX; + bit identifier = 1; + local + uvm_recursion_policy_enum policy = UVM_DEFAULT_POLICY; + virtual function void set_recursion_policy(uvm_recursion_policy_enum policy); + this.policy = policy; + endfunction : set_recursion_policy + virtual function uvm_recursion_policy_enum get_recursion_policy(); + return this.policy; + endfunction : get_recursion_policy + virtual function void flush(); + policy = UVM_DEFAULT_POLICY; + identifier = 1; + free(); + endfunction : flush + local static int m_ids_by_recorder[uvm_recorder]; + function new(string name = "uvm_recorder"); + super.new(name); + m_stream_dap = new("stream_dap"); + m_warn_null_stream = 1; + endfunction + function uvm_tr_stream get_stream(); + if (!m_stream_dap.try_get(get_stream)) begin + if (m_warn_null_stream == 1) + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/REC/NO_CFG")) + uvm_report_warning ("UVM/REC/NO_CFG", $sformatf("attempt to retrieve STREAM from '%s' before it was set!", get_name()), UVM_NONE, "t/uvm/src/base/uvm_recorder.svh", 178, "", 1); + end + m_warn_null_stream = 0; + end + endfunction : get_stream + function void close(time close_time = 0); + if (close_time == 0) + close_time = $realtime; + if (!is_open()) + return; + do_close(close_time); + m_is_opened = 0; + m_is_closed = 1; + m_close_time = close_time; + endfunction : close + function void free(time close_time = 0); + process p=process::self(); + string s; + uvm_tr_stream stream; + if (!is_open() && !is_closed()) + return; + if (is_open()) begin + close(close_time); + end + do_free(); + stream = get_stream(); + m_is_closed = 0; + if(p != null) + s=p.get_randstate(); + m_stream_dap = new("stream_dap"); + if(p != null) + p.set_randstate(s); + m_warn_null_stream = 1; + if (m_ids_by_recorder.exists(this)) + m_free_id(m_ids_by_recorder[this]); + if (stream != null) + stream.m_free_recorder(this); + endfunction : free + function bit is_open(); + return m_is_opened; + endfunction : is_open + function time get_open_time(); + return m_open_time; + endfunction : get_open_time + function bit is_closed(); + return m_is_closed; + endfunction : is_closed + function time get_close_time(); + return m_close_time; + endfunction : get_close_time + function void m_do_open(uvm_tr_stream stream, time open_time, string type_name); + uvm_tr_stream m_stream; + if (stream == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/REC/NULL_STREAM")) + uvm_report_error ("UVM/REC/NULL_STREAM", $sformatf("Illegal attempt to set STREAM for '%s' to ''", this.get_name()), UVM_NONE, "t/uvm/src/base/uvm_recorder.svh", 287, "", 1); + end + return; + end + if (m_stream_dap.try_get(m_stream)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/REC/RE_INIT")) + uvm_report_error ("UVM/REC/RE_INIT", $sformatf("Illegal attempt to re-initialize '%s'", this.get_name()), UVM_NONE, "t/uvm/src/base/uvm_recorder.svh", 294, "", 1); + end + return; + end + m_stream_dap.set(stream); + m_open_time = open_time; + m_is_opened = 1; + do_open(stream, open_time, type_name); + endfunction : m_do_open + local static uvm_recorder m_recorders_by_id[int]; + local static int m_id; + static function void m_free_id(int id); + uvm_recorder recorder; + if ((!$isunknown(id)) && (m_recorders_by_id.exists(id))) + recorder = m_recorders_by_id[id]; + if (recorder != null) begin + m_recorders_by_id.delete(id); + m_ids_by_recorder.delete(recorder); + end + endfunction : m_free_id + function int get_handle(); + if (!is_open() && !is_closed()) begin + return 0; + end + else begin + int handle = get_inst_id(); + if (m_ids_by_recorder.exists(this) && m_ids_by_recorder[this] != handle) + m_recorders_by_id.delete(m_ids_by_recorder[this]); + m_recorders_by_id[handle] = this; + m_ids_by_recorder[this] = handle; + return handle; + end + endfunction : get_handle + static function uvm_recorder get_recorder_from_handle(int id); + if (id == 0) + return null; + if (($isunknown(id)) || (!m_recorders_by_id.exists(id))) + return null; + return m_recorders_by_id[id]; + endfunction : get_recorder_from_handle + function void record_field(string name, + uvm_bitstream_t value, + int size, + uvm_radix_enum radix=UVM_NORADIX); + if (get_stream() == null) begin + return; + end + do_record_field(name, value, size, radix); + endfunction : record_field + function void record_field_int(string name, + uvm_integral_t value, + int size, + uvm_radix_enum radix=UVM_NORADIX); + if (get_stream() == null) begin + return; + end + do_record_field_int(name, value, size, radix); + endfunction : record_field_int + function void record_field_real(string name, + real value); + if (get_stream() == null) begin + return; + end + do_record_field_real(name, value); + endfunction : record_field_real + function void record_object(string name, + uvm_object value); + if (get_stream() == null) begin + return; + end + if (value == null) + do_record_object(name, value); + else begin + push_active_object(value); + do_record_object(name, value); + void'(pop_active_object()); + end + endfunction : record_object + function void record_string(string name, + string value); + if (get_stream() == null) begin + return; + end + do_record_string(name, value); + endfunction : record_string + function void record_time(string name, + time value); + if (get_stream() == null) begin + return; + end + do_record_time(name, value); + endfunction : record_time + function void record_generic(string name, + string value, + string type_name=""); + if (get_stream() == null) begin + return; + end + do_record_generic(name, value, type_name); + endfunction : record_generic + virtual function bit use_record_attribute(); + return 0; + endfunction : use_record_attribute + virtual function int get_record_attribute_handle(); + return get_handle(); + endfunction : get_record_attribute_handle + protected virtual function void do_open(uvm_tr_stream stream, + time open_time, + string type_name); + endfunction : do_open + protected virtual function void do_close(time close_time); + endfunction : do_close + protected virtual function void do_free(); + endfunction : do_free + pure virtual protected function void do_record_field(string name, + uvm_bitstream_t value, + int size, + uvm_radix_enum radix); + pure virtual protected function void do_record_field_int(string name, + uvm_integral_t value, + int size, + uvm_radix_enum radix); + pure virtual protected function void do_record_field_real(string name, + real value); + virtual protected function void do_record_object(string name, + uvm_object value); + if ((get_recursion_policy() != UVM_REFERENCE) && + (value != null)) begin + uvm_field_op field_op = uvm_field_op::m_get_available_op(); + field_op.set(UVM_RECORD, this, null); + value.do_execute_op(field_op); + if (field_op.user_hook_enabled()) + value.do_record(this); + field_op.m_recycle(); + end + endfunction : do_record_object + pure virtual protected function void do_record_string(string name, + string value); + pure virtual protected function void do_record_time(string name, + time value); + pure virtual protected function void do_record_generic(string name, + string value, + string type_name); + virtual function bit open_file(); + return 0; + endfunction + virtual function int create_stream (string name, + string t, + string scope); + return -1; + endfunction + virtual function void m_set_attribute (int txh, + string nm, + string value); + endfunction + virtual function void set_attribute (int txh, + string nm, + logic [1023:0] value, + uvm_radix_enum radix, + int numbits=1024); + endfunction + virtual function int check_handle_kind (string htype, int handle); + return 0; + endfunction + virtual function int begin_tr(string txtype, + int stream, + string nm, + string label="", + string desc="", + time begin_time=0); + return -1; + endfunction + virtual function void end_tr (int handle, time end_time=0); + endfunction + virtual function void link_tr(int h1, + int h2, + string relation=""); + endfunction + virtual function void free_tr(int handle); + endfunction +endclass +class uvm_text_recorder extends uvm_recorder; + typedef uvm_object_registry#(uvm_text_recorder,"uvm_text_recorder") type_id; + static function uvm_text_recorder type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_text_recorder tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_text_recorder"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_text_recorder"; + endfunction : get_type_name + uvm_text_tr_database m_text_db; + function new(string name="unnamed-uvm_text_recorder"); + super.new(name); + endfunction : new + protected virtual function void do_open(uvm_tr_stream stream, + time open_time, + string type_name); + $cast(m_text_db, stream.get_db()); + if (m_text_db.open_db()) + $fdisplay(m_text_db.m_file, + " OPEN_RECORDER @%0t {TXH:%0d STREAM:%0d NAME:%s TIME:%0t TYPE=\"%0s\"}", + $realtime, + this.get_handle(), + stream.get_handle(), + this.get_name(), + open_time, + type_name); + endfunction : do_open + protected virtual function void do_close(time close_time); + if (m_text_db.open_db()) begin + $fdisplay(m_text_db.m_file, + " CLOSE_RECORDER @%0t {TXH:%0d TIME=%0t}", + $realtime, + this.get_handle(), + close_time); + end + endfunction : do_close + protected virtual function void do_free(); + if (m_text_db.open_db()) begin + $fdisplay(m_text_db.m_file, + " FREE_RECORDER @%0t {TXH:%0d}", + $realtime, + this.get_handle()); + end + m_text_db = null; + endfunction : do_free + protected virtual function void do_record_field(string name, + uvm_bitstream_t value, + int size, + uvm_radix_enum radix); + if (!radix) + radix = default_radix; + write_attribute(m_current_context(name), + value, + radix, + size); + endfunction : do_record_field + protected virtual function void do_record_field_int(string name, + uvm_integral_t value, + int size, + uvm_radix_enum radix); + if (!radix) + radix = default_radix; + write_attribute_int(m_current_context(name), + value, + radix, + size); + endfunction : do_record_field_int + protected virtual function void do_record_field_real(string name, + real value); + bit [63:0] ival = $realtobits(value); + write_attribute_int(m_current_context(name), + ival, + UVM_REAL, + 64); + endfunction : do_record_field_real + local string m_object_names[$]; + local function string m_current_context(string name=""); + if (m_object_names.size() == 0) + return name; + else if ((m_object_names.size() == 1) && (name=="")) + return m_object_names[0]; + else begin + string full_name; + foreach(m_object_names[i]) begin + if (i == m_object_names.size() - 1) + full_name = {full_name, m_object_names[i]}; + else + full_name = {full_name, m_object_names[i], "."}; + end + if (name != "") + return {full_name, ".", name}; + else + return full_name; + end + endfunction : m_current_context + protected virtual function void do_record_object(string name, + uvm_object value); + int v; + string str; + if(identifier) begin + if(value != null) begin + v = value.get_inst_id(); + end + write_attribute_int("inst_id", + v, + UVM_DEC, + 32); + end + if (get_active_object_depth() > 1) + m_object_names.push_back(name); + super.do_record_object(name, value); + if (get_active_object_depth() > 1) + void'(m_object_names.pop_back()); + endfunction : do_record_object + protected virtual function void do_record_string(string name, + string value); + if (m_text_db.open_db()) begin + $fdisplay(m_text_db.m_file, + " SET_ATTR @%0t {TXH:%0d NAME:%s VALUE:%s RADIX:%s BITS=%0d}", + $realtime, + this.get_handle(), + m_current_context(name), + value, + "UVM_STRING", + 8+value.len()); + end + endfunction : do_record_string + protected virtual function void do_record_time(string name, + time value); + write_attribute_int(m_current_context(name), + value, + UVM_TIME, + 64); + endfunction : do_record_time + protected virtual function void do_record_generic(string name, + string value, + string type_name); + write_attribute(m_current_context(name), + uvm_string_to_bits(value), + UVM_STRING, + 8+value.len()); + endfunction : do_record_generic + function void write_attribute(string nm, + uvm_bitstream_t value, + uvm_radix_enum radix, + int numbits=$bits(uvm_bitstream_t)); + if (m_text_db.open_db()) begin + $fdisplay(m_text_db.m_file, + " SET_ATTR @%0t {TXH:%0d NAME:%s VALUE:%s RADIX:%s BITS=%0d}", + $realtime, + this.get_handle(), + nm, + uvm_bitstream_to_string(value, numbits, radix), + radix.name(), + numbits); + end + endfunction : write_attribute + function void write_attribute_int(string nm, + uvm_integral_t value, + uvm_radix_enum radix, + int numbits=$bits(uvm_bitstream_t)); + if (m_text_db.open_db()) begin + $fdisplay(m_text_db.m_file, + " SET_ATTR @%0t {TXH:%0d NAME:%s VALUE:%s RADIX:%s BITS=%0d}", + $realtime, + this.get_handle(), + nm, + uvm_integral_to_string(value, numbits, radix), + radix.name(), + numbits); + end + endfunction : write_attribute_int + string filename; + bit filename_set; + virtual function bit open_file(); + if (!filename_set) begin + m_text_db.set_file_name(filename); + end + return m_text_db.open_db(); + endfunction + virtual function int create_stream (string name, + string t, + string scope); + uvm_text_tr_stream stream; + if (open_file()) begin + $cast(stream,m_text_db.open_stream(name, scope, t)); + return stream.get_handle(); + end + return 0; + endfunction + virtual function void m_set_attribute (int txh, + string nm, + string value); + if (open_file()) begin + UVM_FILE file = m_text_db.m_file; + $fdisplay(file," SET_ATTR @%0t {TXH:%0d NAME:%s VALUE:%s}", $realtime,txh,nm,value); + end + endfunction + virtual function void set_attribute (int txh, + string nm, + logic [1023:0] value, + uvm_radix_enum radix, + int numbits=1024); + if (open_file()) begin + UVM_FILE file = m_text_db.m_file; + $fdisplay(file, + " SET_ATTR @%0t {TXH:%0d NAME:%s VALUE:%s RADIX:%s BITS=%0d}", + $realtime, + txh, + nm, + uvm_bitstream_to_string(value, numbits, radix), + radix.name(), + numbits); + end + endfunction + virtual function int check_handle_kind (string htype, int handle); + return ((uvm_recorder::get_recorder_from_handle(handle) != null) || + (uvm_tr_stream::get_stream_from_handle(handle) != null)); + endfunction + virtual function int begin_tr(string txtype, + int stream, + string nm, + string label="", + string desc="", + time begin_time=0); + if (open_file()) begin + uvm_tr_stream stream_obj = uvm_tr_stream::get_stream_from_handle(stream); + uvm_recorder recorder; + if (stream_obj == null) + return -1; + recorder = stream_obj.open_recorder(nm, begin_time, txtype); + return recorder.get_handle(); + end + return -1; + endfunction + virtual function void end_tr (int handle, time end_time=0); + if (open_file()) begin + uvm_recorder record = uvm_recorder::get_recorder_from_handle(handle); + if (record != null) begin + record.close(end_time); + end + end + endfunction + virtual function void link_tr(int h1, + int h2, + string relation=""); + if (open_file()) + $fdisplay(m_text_db.m_file," LINK @%0t {TXH1:%0d TXH2:%0d RELATION=%0s}", $realtime,h1,h2,relation); + endfunction + virtual function void free_tr(int handle); + if (open_file()) begin + uvm_recorder record = uvm_recorder::get_recorder_from_handle(handle); + if (record != null) begin + record.free(); + end + end + endfunction +endclass : uvm_text_recorder +typedef class uvm_object; +typedef class uvm_event; +typedef class uvm_callback; +typedef class uvm_callbacks; +virtual class uvm_event_callback#(type T=uvm_object) extends uvm_callback; + function new (string name=""); + super.new(name); + endfunction + virtual function bit pre_trigger (uvm_event#(T) e, T data); + return 0; + endfunction + virtual function void post_trigger (uvm_event#(T) e, T data); + return; + endfunction + virtual function uvm_object create (string name=""); + return null; + endfunction +endclass +virtual class uvm_event_base extends uvm_object; + typedef uvm_abstract_object_registry#(uvm_event_base,"uvm_event_base") type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_event_base"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_event_base"; + endfunction : get_type_name + protected event m_event; + protected int num_waiters; + protected bit on; + protected time trigger_time=0; + function new (string name=""); + super.new(name); + endfunction + virtual task wait_on (bit delta = 0); + if (on) begin + if (delta) + #0; + return; + end + num_waiters++; + @on; + endtask + virtual task wait_off (bit delta = 0); + if (!on) begin + if (delta) + #0; + return; + end + num_waiters++; + @on; + endtask + virtual task wait_trigger (); + num_waiters++; + @m_event; + endtask + virtual task wait_ptrigger (); + if (m_event.triggered) + return; + num_waiters++; + @m_event; + endtask + virtual function time get_trigger_time (); + return trigger_time; + endfunction + virtual function bit is_on (); + return (on == 1); + endfunction + virtual function bit is_off (); + return (on == 0); + endfunction + virtual function void reset (bit wakeup = 0); + event e; + if (wakeup) + ->m_event; + m_event = e; + num_waiters = 0; + on = 0; + trigger_time = 0; + endfunction + virtual function void cancel (); + if (num_waiters > 0) + num_waiters--; + endfunction + virtual function int get_num_waiters (); + return num_waiters; + endfunction + virtual function void do_print (uvm_printer printer); + printer.print_field_int("num_waiters", num_waiters, $bits(num_waiters), UVM_DEC, ".", "int"); + printer.print_field_int("on", on, $bits(on), UVM_BIN, ".", "bit"); + printer.print_time("trigger_time", trigger_time); + endfunction + virtual function void do_copy (uvm_object rhs); + uvm_event_base e; + super.do_copy(rhs); + if(!$cast(e, rhs) || (e==null)) return; + m_event = e.m_event; + num_waiters = e.num_waiters; + on = e.on; + trigger_time = e.trigger_time; + endfunction +endclass +class uvm_event#(type T=uvm_object) extends uvm_event_base; + typedef uvm_event#(T) this_type; + typedef uvm_event_callback#(T) cb_type; + typedef uvm_callbacks#(this_type, cb_type) cbs_type; + static local function bit m_register_cb(); + return uvm_callbacks#(this_type,cb_type)::m_register_pair( + "uvm_pkg::uvm_event#(T)", + "uvm_pkg::uvm_event_callback#(T)" + ); + endfunction : m_register_cb + static local bit m_cb_registered = m_register_cb(); + typedef uvm_object_registry #(this_type) type_id; + static function this_type type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + this_type tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + virtual function string get_type_name(); + return "uvm_pkg::uvm_event#(T)"; + endfunction : get_type_name + local T trigger_data; + local T default_data; + function new (string name=""); + super.new(name); + endfunction + virtual task wait_trigger_data (output T data); + wait_trigger(); + data = get_trigger_data(); + endtask + virtual task wait_ptrigger_data (output T data); + wait_ptrigger(); + data = get_trigger_data(); + endtask + virtual function void trigger (T data=get_default_data()); + int skip; + cb_type cb_q[$]; + skip=0; + cbs_type::get_all(cb_q, this); + foreach (cb_q[i]) + skip += cb_q[i].pre_trigger(this, data); + if (skip==0) begin + ->m_event; + foreach (cb_q[i]) + cb_q[i].post_trigger(this, data); + num_waiters = 0; + on = 1; + trigger_time = $realtime; + trigger_data = data; + end + endfunction + virtual function T get_trigger_data (); + return trigger_data; + endfunction + virtual function T get_default_data(); + return default_data; + endfunction : get_default_data + virtual function void set_default_data(T data); + default_data = data; + endfunction : set_default_data + virtual function void do_print (uvm_printer printer); + uvm_event#(uvm_object) oe; + cb_type cb_q[$]; + super.do_print(printer); + cbs_type::get_all(cb_q, this); + printer.print_array_header("callbacks", cb_q.size(), "queue"); + foreach(cb_q[e]) + printer.print_object($sformatf("[%0d]", e), cb_q[e], "["); + printer.print_array_footer(cb_q.size()); + if ($cast(oe, this)) begin + printer.print_object("trigger_data", oe.get_trigger_data()); + end + else begin + uvm_event#(string) se; + if ($cast(se, this)) + printer.print_string("trigger_data", se.get_trigger_data()); + end + endfunction + virtual function void do_copy (uvm_object rhs); + this_type e; + cb_type cb_q[$]; + super.do_copy(rhs); + if(!$cast(e, rhs) || (e==null)) return; + trigger_data = e.trigger_data; + begin + cbs_type::get_all(cb_q, this); + foreach(cb_q[i]) + cbs_type::delete(this, cb_q[i]); + cb_q.delete(); + cbs_type::get_all(cb_q, e); + foreach(cb_q[i]) + cbs_type::add(this, cb_q[i]); + end + endfunction +endclass +class uvm_barrier extends uvm_object; + local int threshold; + local int num_waiters; + local bit at_threshold; + local bit auto_reset; + local uvm_event#(uvm_object) m_event; + typedef uvm_object_registry#(uvm_barrier,"uvm_barrier") type_id; + static function uvm_barrier type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_barrier tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_barrier"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_barrier"; + endfunction : get_type_name + function new (string name="", int threshold=0); + super.new(name); + m_event = new({"barrier_",name}); + this.threshold = threshold; + num_waiters = 0; + auto_reset = 1; + at_threshold = 0; + endfunction + virtual task wait_for(); + if (at_threshold) + return; + num_waiters++; + if (num_waiters >= threshold) begin + if (!auto_reset) + at_threshold=1; + m_trigger(); + return; + end + m_event.wait_trigger(); + endtask + virtual function void reset (bit wakeup=1); + at_threshold = 0; + if (num_waiters) begin + if (wakeup) + m_event.trigger(); + else + m_event.reset(); + end + num_waiters = 0; + endfunction + virtual function void set_auto_reset (bit value=1); + at_threshold = 0; + auto_reset = value; + endfunction + virtual function void set_threshold (int threshold); + this.threshold = threshold; + if (threshold <= num_waiters) + reset(1); + endfunction + virtual function int get_threshold (); + return threshold; + endfunction + virtual function int get_num_waiters (); + return num_waiters; + endfunction + virtual function void cancel (); + m_event.cancel(); + num_waiters = m_event.get_num_waiters(); + endfunction + local task m_trigger(); + m_event.trigger(); + num_waiters=0; + #0; + endtask + virtual function void do_print (uvm_printer printer); + printer.print_field_int("threshold", threshold, $bits(threshold), UVM_DEC, ".", "int"); + printer.print_field_int("num_waiters", num_waiters, $bits(num_waiters), UVM_DEC, ".", "int"); + printer.print_field_int("at_threshold", at_threshold, $bits(at_threshold), UVM_BIN, ".", "bit"); + printer.print_field_int("auto_reset", auto_reset, $bits(auto_reset), UVM_BIN, ".", "bit"); + endfunction + virtual function void do_copy (uvm_object rhs); + uvm_barrier b; + super.do_copy(rhs); + if(!$cast(b, rhs) || (b==null)) return; + threshold = b.threshold; + num_waiters = b.num_waiters; + at_threshold = b.at_threshold; + auto_reset = b.auto_reset; + m_event = b.m_event; + endfunction +endclass +typedef class uvm_root; +typedef class uvm_callback; +typedef class uvm_callbacks_base; +class uvm_typeid_base; + static string typename; + static uvm_callbacks_base typeid_map[uvm_typeid_base]; + static uvm_typeid_base type_map[uvm_callbacks_base]; +endclass +class uvm_typeid#(type T=uvm_object) extends uvm_typeid_base; + static uvm_typeid#(T) m_b_inst; + static function uvm_typeid#(T) get(); + if(m_b_inst == null) + m_b_inst = new; + return m_b_inst; + endfunction +endclass +class uvm_callbacks_base extends uvm_object; + typedef uvm_callbacks_base this_type; + static bit m_tracing = 1; + static this_type m_b_inst; + static uvm_pool#(uvm_object,uvm_queue#(uvm_callback)) m_pool; + static function this_type m_initialize(); + if(m_b_inst == null) begin + m_b_inst = new; + m_pool = new; + end + return m_b_inst; + endfunction + this_type m_this_type[$]; + uvm_typeid_base m_super_type; + uvm_typeid_base m_derived_types[$]; + virtual function bit m_am_i_a(uvm_object obj); + return 0; + endfunction + virtual function bit m_is_for_me(uvm_callback cb); + return 0; + endfunction + virtual function bit m_is_registered(uvm_object obj, uvm_callback cb); + return 0; + endfunction + virtual function uvm_queue#(uvm_callback) m_get_tw_cb_q(uvm_object obj); + return null; + endfunction + virtual function void m_add_tw_cbs(uvm_callback cb, uvm_apprepend ordering); + endfunction + virtual function bit m_delete_tw_cbs(uvm_callback cb); + return 0; + endfunction + function bit check_registration(uvm_object obj, uvm_callback cb); + this_type dt; + if (m_is_registered(obj,cb)) + return 1; + foreach(m_this_type[i]) + if(m_b_inst != m_this_type[i] && m_this_type[i].m_is_registered(obj,cb)) + return 1; + if(obj == null) begin + foreach(m_derived_types[i]) begin + dt = uvm_typeid_base::typeid_map[m_derived_types[i] ]; + if(dt != null && dt.check_registration(null,cb)) + return 1; + end + end + return 0; + endfunction +endclass +class uvm_typed_callbacks#(type T=uvm_object) extends uvm_callbacks_base; + static uvm_queue#(uvm_callback) m_tw_cb_q; + static string m_typename; + typedef uvm_typed_callbacks#(T) this_type; + typedef uvm_callbacks_base super_type; + static this_type m_t_inst; + static function this_type m_initialize(); + if(m_t_inst == null) begin + void'(super_type::m_initialize()); + m_t_inst = new; + m_t_inst.m_tw_cb_q = new("typewide_queue"); + end + return m_t_inst; + endfunction + virtual function bit m_am_i_a(uvm_object obj); + T casted_obj; + if (obj == null) + return 1; + return($cast(casted_obj,obj)); + endfunction + virtual function uvm_queue#(uvm_callback) m_get_tw_cb_q(uvm_object obj); + if(m_am_i_a(obj)) begin + foreach(m_derived_types[i]) begin + super_type dt; + dt = uvm_typeid_base::typeid_map[m_derived_types[i] ]; + if(dt != null && dt != this) begin + m_get_tw_cb_q = dt.m_get_tw_cb_q(obj); + if(m_get_tw_cb_q != null) + return m_get_tw_cb_q; + end + end + return m_t_inst.m_tw_cb_q; + end + else + return null; + endfunction + static function int m_cb_find(uvm_queue#(uvm_callback) q, uvm_callback cb); + for(int i=0; i str.len() ? max_cb_name : str.len(); + str = "(*)"; + max_inst_name = max_inst_name > str.len() ? max_inst_name : str.len(); + end + if(obj ==null) begin + if(m_t_inst.m_pool.first(bobj)) begin + do + if($cast(me,bobj)) break; + while(m_t_inst.m_pool.next(bobj)); + end + if(me != null || m_t_inst.m_tw_cb_q.size()) begin + qs.push_back($sformatf("Registered callbacks for all instances of %s\n", tname)); + qs.push_back("---------------------------------------------------------------\n"); + end + if(me != null) begin + do begin + if($cast(me,bobj)) begin + q = m_t_inst.m_pool.get(bobj); + if (q==null) begin + q=new; + m_t_inst.m_pool.add(bobj,q); + end + for(int i=0; i str.len() ? max_cb_name : str.len(); + str = bobj.get_full_name(); + max_inst_name = max_inst_name > str.len() ? max_inst_name : str.len(); + end + end + end while (m_t_inst.m_pool.next(bobj)); + end + else begin + qs.push_back($sformatf("No callbacks registered for any instances of type %s\n", tname)); + end + end + else begin + if(m_t_inst.m_pool.exists(bobj) || m_t_inst.m_tw_cb_q.size()) begin + qs.push_back($sformatf("Registered callbacks for instance %s of %s\n", obj.get_full_name(), tname)); + qs.push_back("---------------------------------------------------------------\n"); + end + if(m_t_inst.m_pool.exists(bobj)) begin + q = m_t_inst.m_pool.get(bobj); + if(q==null) begin + q=new; + m_t_inst.m_pool.add(bobj,q); + end + for(int i=0; i str.len() ? max_cb_name : str.len(); + str = bobj.get_full_name(); + max_inst_name = max_inst_name > str.len() ? max_inst_name : str.len(); + end + end + end + if(!cbq.size()) begin + if(obj == null) str = "*"; + else str = obj.get_full_name(); + qs.push_back($sformatf("No callbacks registered for instance %s of type %s\n", str, tname)); + end + foreach (cbq[i]) begin + qs.push_back($sformatf("%s %s %s on %s %s\n", cbq[i], blanks.substr(0,max_cb_name-cbq[i].len()-1), inst_q[i], blanks.substr(0,max_inst_name - inst_q[i].len()-1), mode_q[i])); + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_INFO,"UVM/CB/DISPLAY")) + uvm_report_info ("UVM/CB/DISPLAY", uvm_pkg::m_uvm_string_queue_join(qs), UVM_NONE, "t/uvm/src/base/uvm_callback.svh", 435, "", 1); + end + m_tracing = 1; + endfunction +endclass +class uvm_callbacks #(type T=uvm_object, type CB=uvm_callback) + extends uvm_typed_callbacks#(T); + typedef uvm_typed_callbacks#(T) super_type; + typedef uvm_callbacks#(T,CB) this_type; + local static this_type m_inst; + static uvm_typeid_base m_typeid; + static uvm_typeid_base m_cb_typeid; + static string m_typename; + static string m_cb_typename; + static uvm_callbacks#(T,uvm_callback) m_base_inst; + bit m_registered; + static function this_type get(); + if (m_inst == null) begin + uvm_typeid_base cb_base_type; + void'(super_type::m_initialize()); + cb_base_type = uvm_typeid#(uvm_callback)::get(); + m_cb_typeid = uvm_typeid#(CB)::get(); + m_typeid = uvm_typeid#(T)::get(); + m_inst = new; + if (cb_base_type == m_cb_typeid) begin + $cast(m_base_inst, m_inst); + m_t_inst = m_base_inst; + uvm_typeid_base::typeid_map[m_typeid] = m_inst; + uvm_typeid_base::type_map[m_b_inst] = m_typeid; + end + else begin + m_base_inst = uvm_callbacks#(T,uvm_callback)::get(); + m_base_inst.m_this_type.push_back(m_inst); + end + if (m_inst == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"CB/INTERNAL")) + uvm_report_fatal ("CB/INTERNAL", "get(): m_inst is null", UVM_NONE, "t/uvm/src/base/uvm_callback.svh", 547, "", 1); + end + end + return m_inst; + endfunction + static function bit m_register_pair(string tname="", cbname=""); + this_type inst = get(); + m_typename = tname; + super_type::m_typename = tname; + m_typeid.typename = tname; + m_cb_typename = cbname; + m_cb_typeid.typename = cbname; + inst.m_registered = 1; + return 1; + endfunction + virtual function bit m_is_registered(uvm_object obj, uvm_callback cb); + if(m_is_for_me(cb) && m_am_i_a(obj)) begin + return m_registered; + end + endfunction + virtual function bit m_is_for_me(uvm_callback cb); + CB this_cb; + return($cast(this_cb,cb)); + endfunction + static function void add(T obj, uvm_callback cb, uvm_apprepend ordering=UVM_APPEND); + uvm_queue#(uvm_callback) q; + string nm,tnm; + void'(get()); + if (cb==null) begin + if (obj==null) + nm = "(*)"; + else + nm = obj.get_full_name(); + if (m_base_inst.m_typename!="") + tnm = m_base_inst.m_typename; + else if (obj != null) + tnm = obj.get_type_name(); + else + tnm = "uvm_object"; + uvm_report_error("CBUNREG", + {"Null callback object cannot be registered with object ", + nm, " (", tnm, ")"}, UVM_NONE); + return; + end + if (!m_base_inst.check_registration(obj,cb)) begin + if (obj==null) + nm = "(*)"; + else + nm = obj.get_full_name(); + if (m_base_inst.m_typename!="") + tnm = m_base_inst.m_typename; + else if(obj != null) + tnm = obj.get_type_name(); + else + tnm = "uvm_object"; + uvm_report_warning("CBUNREG", + {"Callback ", cb.get_name(), " cannot be registered with object ", + nm, " because callback type ", cb.get_type_name(), + " is not registered with object type ", tnm }, UVM_NONE); + end + if(obj == null) begin + if (m_cb_find(m_t_inst.m_tw_cb_q,cb) != -1) begin + if (m_base_inst.m_typename!="") + tnm = m_base_inst.m_typename; + else tnm = "uvm_object"; + uvm_report_warning("CBPREG", + {"Callback object ", cb.get_name(), + " is already registered with type ", tnm }, UVM_NONE); + end + else begin + m_t_inst.m_add_tw_cbs(cb,ordering); + end + end + else begin + q = m_base_inst.m_pool.get(obj); + if (q==null) begin + q=new; + m_base_inst.m_pool.add(obj,q); + end + if(q.size() == 0) begin + uvm_report_object o; + if($cast(o,obj)) begin + uvm_queue#(uvm_callback) qr; + void'(uvm_callbacks#(uvm_report_object, uvm_callback)::get()); + qr = uvm_callbacks#(uvm_report_object,uvm_callback)::m_t_inst.m_tw_cb_q; + for(int i=0; i=0; --itr) + if ($cast(cb, q.get(itr)) && cb.callback_mode()) + return cb; + return null; + endfunction + static function CB get_next (ref int itr, input T obj); + uvm_queue#(uvm_callback) q; + CB cb; + void'(get()); + m_get_q(q,obj); + for(itr = itr+1; itr= 0; --itr) + if($cast(cb, q.get(itr)) && cb.callback_mode()) + return cb; + return null; + endfunction + static function void get_all ( ref CB all_callbacks[$], input T obj=null ); + uvm_queue#(uvm_callback) q; + CB cb; + CB callbacks_to_append[$]; + CB unique_callbacks_to_append[$]; + void'( get() ); + if ((obj == null) || (!m_pool.exists(obj))) begin + for (int qi=0; qi= m_max_quit_count); + endfunction + function int get_severity_count(uvm_severity severity); + return m_severity_count[severity]; + endfunction + function void set_severity_count(uvm_severity severity, int count); + m_severity_count[severity] = count < 0 ? 0 : count; + endfunction + function void incr_severity_count(uvm_severity severity); + m_severity_count[severity]++; + endfunction + function void reset_severity_counts(); + uvm_severity s; + s = s.first(); + forever begin + m_severity_count[s] = 0; + if(s == s.last()) break; + s = s.next(); + end + endfunction + function int get_id_count(string id); + if(m_id_count.exists(id)) + return m_id_count[id]; + return 0; + endfunction + function void set_id_count(string id, int count); + m_id_count[id] = count < 0 ? 0 : count; + endfunction + function void incr_id_count(string id); + if(m_id_count.exists(id)) + m_id_count[id]++; + else + m_id_count[id] = 1; + endfunction + virtual function void set_message_database(uvm_tr_database database); + m_message_db = database; + endfunction : set_message_database + virtual function uvm_tr_database get_message_database(); + return m_message_db; + endfunction : get_message_database + virtual function void get_severity_set(output uvm_severity q[$]); + foreach(m_severity_count[idx]) + q.push_back(idx); + endfunction + virtual function void get_id_set(output string q[$]); + foreach(m_id_count[idx]) + q.push_back(idx); + endfunction + function void f_display(UVM_FILE file, string str); + if (file == 0) + $display("%s", str); + else + $fdisplay(file, "%s", str); + endfunction + virtual function void process_report_message(uvm_report_message report_message); + uvm_report_handler l_report_handler = report_message.get_report_handler(); + process p = process::self(); + bit report_ok = 1; + report_message.set_report_server(this); + if(report_ok) + report_ok = uvm_report_catcher::process_all_report_catchers(report_message); + if(uvm_action_type'(report_message.get_action()) == UVM_NO_ACTION) + report_ok = 0; + if(report_ok) begin + string m; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_report_server svr = cs.get_report_server(); + if (report_message.get_action() & (UVM_LOG|UVM_DISPLAY)) + m = svr.compose_report_message(report_message); + svr.execute_report_message(report_message, m); + end + endfunction + virtual function void execute_report_message(uvm_report_message report_message, + string composed_message); + process p = process::self(); + incr_severity_count(report_message.get_severity()); + incr_id_count(report_message.get_id()); + if (record_all_messages) + report_message.set_action(report_message.get_action() | UVM_RM_RECORD); + if(report_message.get_action() & UVM_RM_RECORD) begin + uvm_tr_stream stream; + uvm_report_object ro = report_message.get_report_object(); + uvm_report_handler rh = report_message.get_report_handler(); + if (m_streams.exists(ro.get_name()) && (m_streams[ro.get_name()].exists(rh.get_name()))) + stream = m_streams[ro.get_name()][rh.get_name()]; + if (stream == null) begin + uvm_tr_database db; + db = get_message_database(); + if (db == null) begin + uvm_coreservice_t cs = uvm_coreservice_t::get(); + db = cs.get_default_tr_database(); + end + if (db != null) begin + stream = db.open_stream(ro.get_name(), rh.get_name(), "MESSAGES"); + m_streams[ro.get_name()][rh.get_name()] = stream; + end + end + if (stream != null) begin + uvm_recorder recorder = stream.open_recorder(report_message.get_name(),,report_message.get_type_name()); + if (recorder != null) begin + report_message.record(recorder); + recorder.free(); + end + end + end + if(report_message.get_action() & UVM_DISPLAY) + $display("%s", composed_message); + if(report_message.get_action() & UVM_LOG) + if( (report_message.get_file() == 0) || + (report_message.get_file() != 32'h8000_0001) ) begin + UVM_FILE tmp_file = report_message.get_file(); + if((report_message.get_file() & 32'h8000_0000) == 0) begin + tmp_file = report_message.get_file() & 32'hffff_fffe; + end + f_display(tmp_file, composed_message); + end + if(report_message.get_action() & UVM_COUNT) begin + if(get_max_quit_count() != 0) begin + incr_quit_count(); + if(is_quit_count_reached()) begin + report_message.set_action(report_message.get_action() | UVM_EXIT); + end + end + end + if(report_message.get_action() & UVM_EXIT) begin + uvm_root l_root; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + l_root = cs.get_root(); + l_root.die(); + end + if (report_message.get_action() & UVM_STOP) + $stop; + endfunction + virtual function string compose_report_message(uvm_report_message report_message, + string report_object_name = ""); + string sev_string; + uvm_severity l_severity; + uvm_verbosity l_verbosity; + string filename_line_string; + string time_str; + string line_str; + string context_str; + string verbosity_str; + string terminator_str; + string msg_body_str; + uvm_report_message_element_container el_container; + string prefix; + uvm_report_handler l_report_handler; + l_severity = report_message.get_severity(); + sev_string = l_severity.name(); + if (report_message.get_filename() != "") begin + line_str.itoa(report_message.get_line()); + filename_line_string = {report_message.get_filename(), "(", line_str, ") "}; + end + $swrite(time_str, "%0t", $time); + if (report_message.get_context() != "") + context_str = {"@@", report_message.get_context()}; + if (show_verbosity) begin + if ($cast(l_verbosity, report_message.get_verbosity())) + verbosity_str = l_verbosity.name(); + else + verbosity_str.itoa(report_message.get_verbosity()); + verbosity_str = {"(", verbosity_str, ")"}; + end + if (show_terminator) + terminator_str = {" -",sev_string}; + el_container = report_message.get_element_container(); + if (el_container.size() == 0) + msg_body_str = report_message.get_message(); + else begin + uvm_printer uvm_default_printer = uvm_printer::get_default() ; + prefix = uvm_default_printer.get_line_prefix(); + uvm_default_printer.set_line_prefix(" +"); + msg_body_str = {report_message.get_message(), "\n", el_container.sprint()}; + uvm_default_printer.set_line_prefix(prefix); + end + if (report_object_name == "") begin + l_report_handler = report_message.get_report_handler(); + report_object_name = l_report_handler.get_full_name(); + end + compose_report_message = {sev_string, verbosity_str, " ", filename_line_string, "@ ", + time_str, ": ", report_object_name, context_str, + " [", report_message.get_id(), "] ", msg_body_str, terminator_str}; + endfunction + virtual function void report_summarize(UVM_FILE file = UVM_STDOUT); + string id; + string name; + string output_str; + string q[$]; + uvm_report_catcher::summarize(); + q.push_back("\n--- UVM Report Summary ---\n\n"); + if(m_max_quit_count != 0) begin + if ( m_quit_count >= m_max_quit_count ) + q.push_back("Quit count reached!\n"); + q.push_back($sformatf("Quit count : %5d of %5d\n",m_quit_count, m_max_quit_count)); + end + q.push_back("** Report counts by severity\n"); + foreach(m_severity_count[s]) begin + q.push_back($sformatf("%s :%5d\n", s.name(), m_severity_count[s])); + end + if (enable_report_id_count_summary) begin + q.push_back("** Report counts by id\n"); + foreach(m_id_count[id]) + q.push_back($sformatf("[%s] %5d\n", id, m_id_count[id])); + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_INFO,"UVM/REPORT/SERVER")) + uvm_report_info ("UVM/REPORT/SERVER", uvm_pkg::m_uvm_string_queue_join(q), UVM_NONE, "t/uvm/src/base/uvm_report_server.svh", 864, "", 1); + end + endfunction +endclass +typedef class uvm_report_object; +typedef class uvm_report_server; +typedef uvm_pool#(string, uvm_action) uvm_id_actions_array; +typedef uvm_pool#(string, UVM_FILE) uvm_id_file_array; +typedef uvm_pool#(string, int) uvm_id_verbosities_array; +typedef uvm_pool#(uvm_severity, uvm_severity) uvm_sev_override_array; +class uvm_report_handler extends uvm_object; + int m_max_verbosity_level; + uvm_id_verbosities_array id_verbosities; + uvm_id_verbosities_array severity_id_verbosities[uvm_severity]; + uvm_id_actions_array id_actions; + uvm_action severity_actions[uvm_severity]; + uvm_id_actions_array severity_id_actions[uvm_severity]; + uvm_sev_override_array sev_overrides; + uvm_sev_override_array sev_id_overrides [string]; + UVM_FILE default_file_handle; + uvm_id_file_array id_file_handles; + UVM_FILE severity_file_handles[uvm_severity]; + uvm_id_file_array severity_id_file_handles[uvm_severity]; + typedef uvm_object_registry#(uvm_report_handler,"uvm_report_handler") type_id; + static function uvm_report_handler type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_report_handler tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_report_handler"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_report_handler"; + endfunction : get_type_name + function new(string name = "uvm_report_handler"); + super.new(name); + initialize(); + endfunction + virtual function void do_print (uvm_printer printer); + uvm_verbosity l_verbosity; + uvm_severity l_severity; + string idx; + int l_int; + if ($cast(l_verbosity, m_max_verbosity_level)) + printer.print_generic("max_verbosity_level", "uvm_verbosity", 32, + l_verbosity.name()); + else + printer.print_field("max_verbosity_level", m_max_verbosity_level, 32, UVM_DEC, + ".", "int"); + if(id_verbosities.first(idx)) begin + printer.print_array_header("id_verbosities",id_verbosities.num(), + "uvm_pool"); + do begin + l_int = id_verbosities.get(idx); + if ($cast(l_verbosity, l_int)) + printer.print_generic($sformatf("[%s]", idx), "uvm_verbosity", 32, + l_verbosity.name()); + else begin + string l_str; + l_str.itoa(l_int); + printer.print_generic($sformatf("[%s]", idx), "int", 32, + l_str); + end + end while(id_verbosities.next(idx)); + printer.print_array_footer(); + end + if(severity_id_verbosities.size() != 0) begin + int _total_cnt; + foreach (severity_id_verbosities[l_severity]) + _total_cnt += severity_id_verbosities[l_severity].num(); + printer.print_array_header("severity_id_verbosities", _total_cnt, + "array"); + if(severity_id_verbosities.first(l_severity)) begin + do begin + uvm_id_verbosities_array id_v_ary = severity_id_verbosities[l_severity]; + if(id_v_ary.first(idx)) + do begin + l_int = id_v_ary.get(idx); + if ($cast(l_verbosity, l_int)) + printer.print_generic($sformatf("[%s:%s]", l_severity.name(), idx), + "uvm_verbosity", 32, l_verbosity.name()); + else begin + string l_str; + l_str.itoa(l_int); + printer.print_generic($sformatf("[%s:%s]", l_severity.name(), idx), + "int", 32, l_str); + end + end while(id_v_ary.next(idx)); + end while(severity_id_verbosities.next(l_severity)); + end + printer.print_array_footer(); + end + if(id_actions.first(idx)) begin + printer.print_array_header("id_actions",id_actions.num(), + "uvm_pool"); + do begin + l_int = id_actions.get(idx); + printer.print_generic($sformatf("[%s]", idx), "uvm_action", 32, + format_action(l_int)); + end while(id_actions.next(idx)); + printer.print_array_footer(); + end + if(severity_actions.first(l_severity)) begin + printer.print_array_header("severity_actions",4,"array"); + do begin + printer.print_generic($sformatf("[%s]", l_severity.name()), "uvm_action", 32, + format_action(severity_actions[l_severity])); + end while(severity_actions.next(l_severity)); + printer.print_array_footer(); + end + if(severity_id_actions.size() != 0) begin + int _total_cnt; + foreach (severity_id_actions[l_severity]) + _total_cnt += severity_id_actions[l_severity].num(); + printer.print_array_header("severity_id_actions", _total_cnt, + "array"); + if(severity_id_actions.first(l_severity)) begin + do begin + uvm_id_actions_array id_a_ary = severity_id_actions[l_severity]; + if(id_a_ary.first(idx)) + do begin + printer.print_generic($sformatf("[%s:%s]", l_severity.name(), idx), + "uvm_action", 32, format_action(id_a_ary.get(idx))); + end while(id_a_ary.next(idx)); + end while(severity_id_actions.next(l_severity)); + end + printer.print_array_footer(); + end + if(sev_overrides.first(l_severity)) begin + printer.print_array_header("sev_overrides",sev_overrides.num(), + "uvm_pool"); + do begin + uvm_severity l_severity_new = sev_overrides.get(l_severity); + printer.print_generic($sformatf("[%s]", l_severity.name()), + "uvm_severity", 32, l_severity_new.name()); + end while(sev_overrides.next(l_severity)); + printer.print_array_footer(); + end + if(sev_id_overrides.size() != 0) begin + int _total_cnt; + foreach (sev_id_overrides[idx]) + _total_cnt += sev_id_overrides[idx].num(); + printer.print_array_header("sev_id_overrides", _total_cnt, + "array"); + if(sev_id_overrides.first(idx)) begin + do begin + uvm_sev_override_array sev_o_ary = sev_id_overrides[idx]; + if(sev_o_ary.first(l_severity)) + do begin + uvm_severity new_sev = sev_o_ary.get(l_severity); + printer.print_generic($sformatf("[%s:%s]", l_severity.name(), idx), + "uvm_severity", 32, new_sev.name()); + end while(sev_o_ary.next(l_severity)); + end while(sev_id_overrides.next(idx)); + end + printer.print_array_footer(); + end + printer.print_field("default_file_handle", default_file_handle, 32, UVM_HEX, + ".", "int"); + if(id_file_handles.first(idx)) begin + printer.print_array_header("id_file_handles",id_file_handles.num(), + "uvm_pool"); + do begin + printer.print_field($sformatf("[%s]", idx), id_file_handles.get(idx), 32, + UVM_HEX, ".", "UVM_FILE"); + end while(id_file_handles.next(idx)); + printer.print_array_footer(); + end + if(severity_file_handles.first(l_severity)) begin + printer.print_array_header("severity_file_handles",4,"array"); + do begin + printer.print_field($sformatf("[%s]", l_severity.name()), + severity_file_handles[l_severity], 32, UVM_HEX, ".", "UVM_FILE"); + end while(severity_file_handles.next(l_severity)); + printer.print_array_footer(); + end + if(severity_id_file_handles.size() != 0) begin + int _total_cnt; + foreach (severity_id_file_handles[l_severity]) + _total_cnt += severity_id_file_handles[l_severity].num(); + printer.print_array_header("severity_id_file_handles", _total_cnt, + "array"); + if(severity_id_file_handles.first(l_severity)) begin + do begin + uvm_id_file_array id_f_ary = severity_id_file_handles[l_severity]; + if(id_f_ary.first(idx)) + do begin + printer.print_field($sformatf("[%s:%s]", l_severity.name(), idx), + id_f_ary.get(idx), 32, UVM_HEX, ".", "UVM_FILE"); + end while(id_f_ary.next(idx)); + end while(severity_id_file_handles.next(l_severity)); + end + printer.print_array_footer(); + end + endfunction + virtual function void process_report_message(uvm_report_message report_message); + process p = process::self(); + uvm_report_server srvr = uvm_report_server::get_server(); + string id = report_message.get_id(); + uvm_severity severity = report_message.get_severity(); + if(sev_id_overrides.exists(id)) begin + if(sev_id_overrides[id].exists(uvm_severity'(severity))) begin + severity = sev_id_overrides[id].get(severity); + report_message.set_severity(severity); + end + end + else begin + if(sev_overrides.exists(severity)) begin + severity = sev_overrides.get(severity); + report_message.set_severity(severity); + end + end + report_message.set_file(get_file_handle(severity, id)); + report_message.set_report_handler(this); + report_message.set_action(get_action(severity, id)); + srvr.process_report_message(report_message); + endfunction + static function string format_action(uvm_action action); + string s; + if(uvm_action_type'(action) == UVM_NO_ACTION) begin + s = "NO ACTION"; + end + else begin + s = ""; + if(action & UVM_DISPLAY) s = {s, "DISPLAY "}; + if(action & UVM_LOG) s = {s, "LOG "}; + if(action & UVM_RM_RECORD) s = {s, "RM_RECORD "}; + if(action & UVM_COUNT) s = {s, "COUNT "}; + if(action & UVM_CALL_HOOK) s = {s, "CALL_HOOK "}; + if(action & UVM_EXIT) s = {s, "EXIT "}; + if(action & UVM_STOP) s = {s, "STOP "}; + end + return s; + endfunction + function void initialize(); + set_default_file(0); + m_max_verbosity_level = UVM_MEDIUM; + id_actions=new(); + id_verbosities=new(); + id_file_handles=new(); + sev_overrides=new(); + set_severity_action(UVM_INFO, UVM_DISPLAY); + set_severity_action(UVM_WARNING, UVM_DISPLAY); + set_severity_action(UVM_ERROR, UVM_DISPLAY | UVM_COUNT); + set_severity_action(UVM_FATAL, UVM_DISPLAY | UVM_EXIT); + set_severity_file(UVM_INFO, default_file_handle); + set_severity_file(UVM_WARNING, default_file_handle); + set_severity_file(UVM_ERROR, default_file_handle); + set_severity_file(UVM_FATAL, default_file_handle); + endfunction + local function UVM_FILE get_severity_id_file(uvm_severity severity, string id); + uvm_id_file_array array; + if(severity_id_file_handles.exists(severity)) begin + array = severity_id_file_handles[severity]; + if(array.exists(id)) + return array.get(id); + end + if(id_file_handles.exists(id)) + return id_file_handles.get(id); + if(severity_file_handles.exists(severity)) + return severity_file_handles[severity]; + return default_file_handle; + endfunction + function void set_verbosity_level(int verbosity_level); + m_max_verbosity_level = verbosity_level; + endfunction + function int get_verbosity_level(uvm_severity severity=UVM_INFO, string id="" ); + uvm_id_verbosities_array array; + if(severity_id_verbosities.exists(severity)) begin + array = severity_id_verbosities[severity]; + if(array.exists(id)) begin + return array.get(id); + end + end + if(id_verbosities.exists(id)) begin + return id_verbosities.get(id); + end + return m_max_verbosity_level; + endfunction + function uvm_action get_action(uvm_severity severity, string id); + uvm_id_actions_array array; + if(severity_id_actions.exists(severity)) begin + array = severity_id_actions[severity]; + if(array.exists(id)) + return array.get(id); + end + if(id_actions.exists(id)) + return id_actions.get(id); + return severity_actions[severity]; + endfunction + function UVM_FILE get_file_handle(uvm_severity severity, string id); + UVM_FILE file; + file = get_severity_id_file(severity, id); + if (file != 0) + return file; + if (id_file_handles.exists(id)) begin + file = id_file_handles.get(id); + if (file != 0) + return file; + end + if (severity_file_handles.exists(severity)) begin + file = severity_file_handles[severity]; + if(file != 0) + return file; + end + return default_file_handle; + endfunction + function void set_severity_action(input uvm_severity severity, + input uvm_action action); + severity_actions[severity] = action; + endfunction + function void set_id_action(input string id, input uvm_action action); + id_actions.add(id, action); + endfunction + function void set_severity_id_action(uvm_severity severity, + string id, + uvm_action action); + if(!severity_id_actions.exists(severity)) + severity_id_actions[severity] = new; + severity_id_actions[severity].add(id,action); + endfunction + function void set_id_verbosity(input string id, input int verbosity); + id_verbosities.add(id, verbosity); + endfunction + function void set_severity_id_verbosity(uvm_severity severity, + string id, + int verbosity); + if(!severity_id_verbosities.exists(severity)) + severity_id_verbosities[severity] = new; + severity_id_verbosities[severity].add(id,verbosity); + endfunction + function void set_default_file (UVM_FILE file); + default_file_handle = file; + endfunction + function void set_severity_file (uvm_severity severity, UVM_FILE file); + severity_file_handles[severity] = file; + endfunction + function void set_id_file (string id, UVM_FILE file); + id_file_handles.add(id, file); + endfunction + function void set_severity_id_file(uvm_severity severity, + string id, UVM_FILE file); + if(!severity_id_file_handles.exists(severity)) + severity_id_file_handles[severity] = new; + severity_id_file_handles[severity].add(id, file); + endfunction + function void set_severity_override(uvm_severity cur_severity, + uvm_severity new_severity); + sev_overrides.add(cur_severity, new_severity); + endfunction + function void set_severity_id_override(uvm_severity cur_severity, + string id, + uvm_severity new_severity); + uvm_sev_override_array arr; + if(!sev_id_overrides.exists(id)) + sev_id_overrides[id] = new; + sev_id_overrides[id].add(cur_severity, new_severity); + endfunction + virtual function void report( + uvm_severity severity, + string name, + string id, + string message, + int verbosity_level=UVM_MEDIUM, + string filename="", + int line=0, + uvm_report_object client=null + ); + bit l_report_enabled = 0; + uvm_report_message l_report_message; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + if (!uvm_report_enabled(verbosity_level, UVM_INFO, id)) + return; + if (client==null) + client = cs.get_root(); + l_report_message = uvm_report_message::new_report_message(); + l_report_message.set_report_message(severity, id, message, + verbosity_level, filename, line, name); + l_report_message.set_report_object(client); + l_report_message.set_action(get_action(severity,id)); + process_report_message(l_report_message); + endfunction +endclass : uvm_report_handler +typedef class uvm_component; +typedef class uvm_env; +typedef class uvm_root; +class uvm_report_object extends uvm_object; + uvm_report_handler m_rh; + local bit m_rh_set; + local function void m_rh_init(); + if (!m_rh_set) + set_report_handler(uvm_report_handler::type_id_create(get_name())); + endfunction : m_rh_init + function new(string name = ""); + super.new(name); + endfunction + function uvm_report_object uvm_get_report_object(); + return this; + endfunction + function int uvm_report_enabled(int verbosity, + uvm_severity severity = UVM_INFO, string id = ""); + if (get_report_verbosity_level(severity, id) < verbosity) + return 0; + return 1; + endfunction + virtual function void uvm_report( uvm_severity severity, + string id, + string message, + 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 = "", + bit report_enabled_checked =0); + uvm_report_message l_report_message; + if ((severity == UVM_INFO) && (report_enabled_checked == 0)) begin + if (!uvm_report_enabled(verbosity, severity, id)) + return; + end + l_report_message = uvm_report_message::new_report_message(); + l_report_message.set_report_message(severity, id, message, + verbosity, filename, line, context_name); + uvm_process_report_message(l_report_message); + endfunction + virtual function void uvm_report_info( string id, + string message, + int verbosity = UVM_MEDIUM, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + uvm_report (UVM_INFO, id, message, verbosity, + filename, line, context_name, report_enabled_checked); + endfunction + virtual function void uvm_report_warning( string id, + string message, + int verbosity = UVM_MEDIUM, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + uvm_report (UVM_WARNING, id, message, verbosity, + filename, line, context_name, report_enabled_checked); + endfunction + virtual function void uvm_report_error( string id, + string message, + int verbosity = UVM_NONE, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + uvm_report (UVM_ERROR, id, message, verbosity, + filename, line, context_name, report_enabled_checked); + endfunction + virtual function void uvm_report_fatal( string id, + string message, + int verbosity = UVM_NONE, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + uvm_report (UVM_FATAL, id, message, verbosity, + filename, line, context_name, report_enabled_checked); + endfunction + virtual function void uvm_process_report_message(uvm_report_message report_message); + m_rh_init(); + report_message.set_report_object(this); + m_rh.process_report_message(report_message); + endfunction + function int get_report_verbosity_level(uvm_severity severity=UVM_INFO, string id=""); + m_rh_init(); + return m_rh.get_verbosity_level(severity, id); + endfunction + function int get_report_max_verbosity_level(); + m_rh_init(); + return m_rh.m_max_verbosity_level; + endfunction + function void set_report_verbosity_level (int verbosity_level); + m_rh_init(); + m_rh.set_verbosity_level(verbosity_level); + endfunction + function void set_report_id_verbosity (string id, int verbosity); + m_rh_init(); + m_rh.set_id_verbosity(id, verbosity); + endfunction + function void set_report_severity_id_verbosity (uvm_severity severity, + string id, int verbosity); + m_rh_init(); + m_rh.set_severity_id_verbosity(severity, id, verbosity); + endfunction + function int get_report_action(uvm_severity severity, string id); + m_rh_init(); + return m_rh.get_action(severity,id); + endfunction + function void set_report_severity_action (uvm_severity severity, + uvm_action action); + m_rh_init(); + m_rh.set_severity_action(severity, action); + endfunction + function void set_report_id_action (string id, uvm_action action); + m_rh_init(); + m_rh.set_id_action(id, action); + endfunction + function void set_report_severity_id_action (uvm_severity severity, + string id, uvm_action action); + m_rh_init(); + m_rh.set_severity_id_action(severity, id, action); + endfunction + function int get_report_file_handle(uvm_severity severity, string id); + m_rh_init(); + return m_rh.get_file_handle(severity,id); + endfunction + function void set_report_default_file (UVM_FILE file); + m_rh_init(); + m_rh.set_default_file(file); + endfunction + function void set_report_id_file (string id, UVM_FILE file); + m_rh_init(); + m_rh.set_id_file(id, file); + endfunction + function void set_report_severity_file (uvm_severity severity, UVM_FILE file); + m_rh_init(); + m_rh.set_severity_file(severity, file); + endfunction + function void set_report_severity_id_file (uvm_severity severity, string id, + UVM_FILE file); + m_rh_init(); + m_rh.set_severity_id_file(severity, id, file); + endfunction + function void set_report_severity_override(uvm_severity cur_severity, + uvm_severity new_severity); + m_rh_init(); + m_rh.set_severity_override(cur_severity, new_severity); + endfunction + function void set_report_severity_id_override(uvm_severity cur_severity, + string id, + uvm_severity new_severity); + m_rh_init(); + m_rh.set_severity_id_override(cur_severity, id, new_severity); + endfunction + function void set_report_handler(uvm_report_handler handler); + m_rh = handler; + m_rh_set = 1; + endfunction + function uvm_report_handler get_report_handler(); + m_rh_init(); + return m_rh; + endfunction + function void reset_report_handler; + m_rh_init(); + m_rh.initialize(); + endfunction +endclass +typedef class uvm_event; +typedef class uvm_event_pool; +typedef class uvm_component; +typedef class uvm_parent_child_link; +virtual class uvm_transaction extends uvm_object; + extern function new (string name="", uvm_component initiator=null); + extern function void accept_tr (time accept_time = 0); + extern virtual protected function void do_accept_tr (); + extern function int begin_tr (time begin_time = 0); + extern function int begin_child_tr (time begin_time = 0, + int parent_handle = 0); + extern virtual protected function void do_begin_tr (); + extern function void end_tr (time end_time=0, bit free_handle=1); + extern virtual protected function void do_end_tr (); + extern function int get_tr_handle (); + extern function void disable_recording (); + extern function void enable_recording (uvm_tr_stream stream); + extern function bit is_recording_enabled(); + extern function bit is_active (); + extern function uvm_event_pool get_event_pool (); + extern function void set_initiator (uvm_component initiator); + extern function uvm_component get_initiator (); + extern function time get_accept_time (); + extern function time get_begin_time (); + extern function time get_end_time (); + extern function void set_transaction_id(int id); + extern function int get_transaction_id(); + const local uvm_event_pool events = new("events"); + extern virtual function void do_print (uvm_printer printer); + extern virtual function void do_record (uvm_recorder recorder); + extern virtual function void do_copy (uvm_object rhs); + extern protected function int m_begin_tr (time begin_time=0, + int parent_handle=0); + local int m_transaction_id = -1; + local time begin_time=-1; + local time end_time=-1; + local time accept_time=-1; + local uvm_component initiator; + local uvm_tr_stream stream_handle; + local uvm_recorder tr_recorder; +endclass +function uvm_transaction::new (string name="", + uvm_component initiator = null); + super.new(name); + this.initiator = initiator; + m_transaction_id = -1; +endfunction +function void uvm_transaction::set_transaction_id(int id); + m_transaction_id = id; +endfunction +function int uvm_transaction::get_transaction_id(); + return (m_transaction_id); +endfunction +function void uvm_transaction::set_initiator(uvm_component initiator); + this.initiator = initiator; +endfunction +function uvm_component uvm_transaction::get_initiator(); + return initiator; +endfunction +function uvm_event_pool uvm_transaction::get_event_pool(); + return events; +endfunction +function bit uvm_transaction::is_active(); + return (end_time == -1); +endfunction +function time uvm_transaction::get_begin_time (); + return begin_time; +endfunction +function time uvm_transaction::get_end_time (); + return end_time; +endfunction +function time uvm_transaction::get_accept_time (); + return accept_time; +endfunction +function void uvm_transaction::do_accept_tr(); + return; +endfunction +function void uvm_transaction::do_begin_tr(); + return; +endfunction +function void uvm_transaction::do_end_tr(); + return; +endfunction +function void uvm_transaction::do_print (uvm_printer printer); + string str; + uvm_component tmp_initiator; + super.do_print(printer); + if(accept_time != -1) + printer.print_time("accept_time", accept_time); + if(begin_time != -1) + printer.print_time("begin_time", begin_time); + if(end_time != -1) + printer.print_time("end_time", end_time); + if(initiator != null) begin + tmp_initiator = initiator; + $swrite(str,"@%0d", tmp_initiator.get_inst_id()); + printer.print_generic("initiator", initiator.get_type_name(), -1, str); + end +endfunction +function void uvm_transaction::do_copy (uvm_object rhs); + uvm_transaction txn; + super.do_copy(rhs); + if(rhs == null) return; + if(!$cast(txn, rhs) ) return; + accept_time = txn.accept_time; + begin_time = txn.begin_time; + end_time = txn.end_time; + initiator = txn.initiator; + stream_handle = txn.stream_handle; + tr_recorder = txn.tr_recorder; +endfunction +function void uvm_transaction::do_record (uvm_recorder recorder); + string s; + super.do_record(recorder); + if(accept_time != -1) + recorder.record_field("accept_time", accept_time, $bits(accept_time), UVM_TIME); + if(initiator != null) begin + uvm_recursion_policy_enum p = recorder.get_recursion_policy(); + recorder.set_recursion_policy(UVM_REFERENCE); + recorder.record_object("initiator", initiator); + recorder.set_recursion_policy(p); + end +endfunction +function int uvm_transaction::get_tr_handle (); + if (tr_recorder != null) + return tr_recorder.get_handle(); + else + return 0; +endfunction +function void uvm_transaction::disable_recording (); + this.stream_handle = null; +endfunction +function void uvm_transaction::enable_recording (uvm_tr_stream stream); + this.stream_handle = stream; +endfunction : enable_recording +function bit uvm_transaction::is_recording_enabled (); + return (this.stream_handle != null); +endfunction +function void uvm_transaction::accept_tr (time accept_time = 0); + uvm_event#(uvm_object) e; + if(accept_time != 0) + this.accept_time = accept_time; + else + this.accept_time = $realtime; + do_accept_tr(); + e = events.get("accept"); + if(e!=null) + e.trigger(); +endfunction +function int uvm_transaction::begin_tr (time begin_time=0); + return m_begin_tr(begin_time); +endfunction +function int uvm_transaction::begin_child_tr (time begin_time=0, + int parent_handle=0); + return m_begin_tr(begin_time, parent_handle); +endfunction +function int uvm_transaction::m_begin_tr (time begin_time=0, + int parent_handle=0); + time tmp_time = (begin_time == 0) ? $realtime : begin_time; + uvm_recorder parent_recorder; + if (parent_handle != 0) + parent_recorder = uvm_recorder::get_recorder_from_handle(parent_handle); + if (tr_recorder != null) + end_tr(tmp_time); + if(is_recording_enabled()) begin + uvm_tr_database db = stream_handle.get_db(); + this.end_time = -1; + this.begin_time = tmp_time; + if(parent_recorder == null) + tr_recorder = stream_handle.open_recorder(get_type_name(), + this.begin_time, + "Begin_No_Parent, Link"); + else begin + tr_recorder = stream_handle.open_recorder(get_type_name(), + this.begin_time, + "Begin_End, Link"); + if (tr_recorder != null) + db.establish_link(uvm_parent_child_link::get_link(parent_recorder, tr_recorder)); + end + if (tr_recorder != null) + m_begin_tr = tr_recorder.get_handle(); + else + m_begin_tr = 0; + end + else begin + tr_recorder = null; + this.end_time = -1; + this.begin_time = tmp_time; + m_begin_tr = 0; + end + do_begin_tr(); + begin + uvm_event#(uvm_object) begin_event ; + begin_event = events.get("begin"); + begin_event.trigger(); + end +endfunction +function void uvm_transaction::end_tr (time end_time=0, bit free_handle=1); + this.end_time = (end_time == 0) ? $realtime : end_time; + do_end_tr(); + if(is_recording_enabled() && (tr_recorder != null)) begin + record(tr_recorder); + tr_recorder.close(this.end_time); + if(free_handle) + begin + tr_recorder.free(); + end + end + tr_recorder = null; + begin + uvm_event#(uvm_object) end_event ; + end_event = events.get("end") ; + end_event.trigger(); + end +endfunction +typedef class uvm_sequencer_base; +typedef class uvm_domain; +typedef class uvm_task_phase; +typedef class uvm_phase_cb; +class uvm_phase extends uvm_object; + static local bit m_register_cb_uvm_phase_cb = uvm_callbacks#(uvm_phase,uvm_phase_cb)::m_register_pair("uvm_phase","uvm_phase_cb"); + extern function new(string name="uvm_phase", + uvm_phase_type phase_type=UVM_PHASE_SCHEDULE, + uvm_phase parent=null); + extern function uvm_phase_type get_phase_type(); + extern virtual function void set_max_ready_to_end_iterations(int max); + extern virtual function int get_max_ready_to_end_iterations(); + extern static function void set_default_max_ready_to_end_iterations(int max); + extern static function int get_default_max_ready_to_end_iterations(); + extern function uvm_phase_state get_state(); + extern function int get_run_count(); + extern function uvm_phase find_by_name(string name, bit stay_in_scope=1); + extern function uvm_phase find(uvm_phase phase, bit stay_in_scope=1); + extern function bit is(uvm_phase phase); + extern function bit is_before(uvm_phase phase); + extern function bit is_after(uvm_phase phase); + virtual function void exec_func(uvm_component comp, uvm_phase phase); endfunction + virtual task exec_task(uvm_component comp, uvm_phase phase); endtask + extern function void add(uvm_phase phase, + uvm_phase with_phase=null, + uvm_phase after_phase=null, + uvm_phase before_phase=null, + uvm_phase start_with_phase=null, + uvm_phase end_with_phase=null + ); + extern function uvm_phase get_parent(); + extern virtual function string get_full_name(); + extern function uvm_phase get_schedule(bit hier = 0); + extern function string get_schedule_name(bit hier = 0); + extern function uvm_domain get_domain(); + extern function uvm_phase get_imp(); + extern function string get_domain_name(); + extern function void get_adjacent_predecessor_nodes(ref uvm_phase pred[]); + extern function void get_adjacent_successor_nodes(ref uvm_phase succ[]); + extern function void m_report_null_objection(uvm_object obj, + string description, + int count, + string action); + extern virtual function void raise_objection (uvm_object obj, + string description="", + int count=1); + extern virtual function void drop_objection (uvm_object obj, + string description="", + int count=1); + extern virtual function int get_objection_count( uvm_object obj=null ); + extern function void sync(uvm_domain target, + uvm_phase phase=null, + uvm_phase with_phase=null); + extern function void unsync(uvm_domain target, + uvm_phase phase=null, + uvm_phase with_phase=null); + extern task wait_for_state(uvm_phase_state state, uvm_wait_op op=UVM_EQ); + extern function void jump(uvm_phase phase); + extern function void set_jump_phase(uvm_phase phase) ; + extern function void end_prematurely() ; + extern static function void jump_all(uvm_phase phase); + extern function uvm_phase get_jump_target(); + protected uvm_phase_type m_phase_type; + protected uvm_phase m_parent; + uvm_phase m_imp; + local uvm_phase_state m_state; + local int m_run_count; + local process m_phase_proc; + local static int m_default_max_ready_to_end_iters = 20; + local + int max_ready_to_end_iters = get_default_max_ready_to_end_iterations(); + int m_num_procs_not_yet_returned; + extern function uvm_phase m_find_predecessor(uvm_phase phase, bit stay_in_scope=1, uvm_phase orig_phase=null); + extern function uvm_phase m_find_successor(uvm_phase phase, bit stay_in_scope=1, uvm_phase orig_phase=null); + extern function uvm_phase m_find_predecessor_by_name(string name, bit stay_in_scope=1, uvm_phase orig_phase=null); + extern function uvm_phase m_find_successor_by_name(string name, bit stay_in_scope=1, uvm_phase orig_phase=null); + extern function void m_print_successors(); + virtual function void traverse(uvm_component comp, + uvm_phase phase, + uvm_phase_state state); + endfunction + virtual function void execute(uvm_component comp, + uvm_phase phase); + endfunction + protected bit m_predecessors[uvm_phase]; + protected bit m_successors[uvm_phase]; + protected uvm_phase m_end_node; + static protected bit m_executing_phases[uvm_phase]; + function uvm_phase get_begin_node(); if (m_imp != null) return this; return null; endfunction + function uvm_phase get_end_node(); return m_end_node; endfunction + local uvm_phase m_sync[$]; + local uvm_objection phase_done; + local int unsigned m_ready_to_end_count; + function int unsigned get_ready_to_end_count(); + return m_ready_to_end_count; + endfunction + extern local function void get_predecessors_for_successors(output bit pred_of_succ[uvm_phase]); + extern local task m_wait_for_pred(); + local bit m_jump_bkwd; + local bit m_jump_fwd; + local uvm_phase m_jump_phase; + local bit m_premature_end; + extern function void clear(uvm_phase_state state = UVM_PHASE_DORMANT); + extern function void clear_successors( + uvm_phase_state state = UVM_PHASE_DORMANT, + uvm_phase end_state=null); + local static mailbox #(uvm_phase) m_phase_hopper = new(); + extern static task m_run_phases(); + extern local task execute_phase(); + extern local function void m_terminate_phase(); + extern local function void m_print_termination_state(); + extern local task wait_for_self_and_siblings_to_drop(); + extern function void kill(); + extern function void kill_successors(); + protected static bit m_phase_trace; + local static bit m_use_ovm_run_semantic; + function string convert2string(); + string s; + s = $sformatf("phase: %s parent=%s pred=%s succ=%s",get_name(), + (m_parent==null) ? "null" : get_schedule_name(), + m_aa2string(m_predecessors), + m_aa2string(m_successors)); + return s; + endfunction + local function string m_aa2string(bit aa[uvm_phase]); + string s; + int i; + s = "'{ "; + foreach (aa[ph]) begin + uvm_phase n = ph; + s = {s, (n == null) ? "null" : n.get_name(), + (i == aa.num()-1) ? "" : ", "}; + i++; + end + s = {s, " }"}; + return s; + endfunction + function bit is_domain(); + return (m_phase_type == UVM_PHASE_DOMAIN); + endfunction + virtual function void m_get_transitive_children(ref uvm_phase phases[$]); + foreach (m_successors[succ]) + begin + phases.push_back(succ); + succ.m_get_transitive_children(phases); + end + endfunction + function uvm_objection get_objection(); + uvm_phase imp; + uvm_task_phase tp; + imp = get_imp(); + if ((get_phase_type() != UVM_PHASE_NODE) || (imp == null) || !$cast(tp, imp)) begin + return null; + end + if (phase_done == null) begin + phase_done = uvm_objection::type_id_create({get_name(), "_objection"}); + end + return phase_done; + endfunction +endclass +class uvm_phase_state_change extends uvm_object; + typedef uvm_object_registry#(uvm_phase_state_change,"uvm_phase_state_change") type_id; + static function uvm_phase_state_change type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_phase_state_change tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_phase_state_change"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_phase_state_change"; + endfunction : get_type_name + uvm_phase m_phase; + uvm_phase_state m_prev_state; + uvm_phase m_jump_to; + function new(string name = "uvm_phase_state_change"); + super.new(name); + endfunction + virtual function uvm_phase_state get_state(); + return m_phase.get_state(); + endfunction + virtual function uvm_phase_state get_prev_state(); + return m_prev_state; + endfunction + function uvm_phase jump_to(); + return m_jump_to; + endfunction +endclass +class uvm_phase_cb extends uvm_callback; + function new(string name="unnamed-uvm_phase_cb"); + super.new(name); + endfunction : new + virtual function void phase_state_change(uvm_phase phase, + uvm_phase_state_change change); + endfunction +endclass +typedef uvm_callbacks#(uvm_phase, uvm_phase_cb) uvm_phase_cb_pool ; +typedef class uvm_cmdline_processor; +function uvm_phase::new(string name="uvm_phase", + uvm_phase_type phase_type=UVM_PHASE_SCHEDULE, + uvm_phase parent=null); + super.new(name); + m_phase_type = phase_type; + if ((name == "common") && + (phase_type == UVM_PHASE_DOMAIN)) + m_state = UVM_PHASE_DORMANT; + m_run_count = 0; + m_parent = parent; + begin + uvm_cmdline_processor clp = uvm_cmdline_processor::get_inst(); + string val; + if (clp.get_arg_value("+UVM_PHASE_TRACE", val)) + m_phase_trace = 1; + else + m_phase_trace = 0; + if (clp.get_arg_value("+UVM_USE_OVM_RUN_SEMANTIC", val)) + m_use_ovm_run_semantic = 1; + else + m_use_ovm_run_semantic = 0; + end + if (parent == null && (phase_type == UVM_PHASE_SCHEDULE || + phase_type == UVM_PHASE_DOMAIN )) begin + m_end_node = new({name,"_end"}, UVM_PHASE_TERMINAL, this); + this.m_successors[m_end_node] = 1; + m_end_node.m_predecessors[this] = 1; + end +endfunction +function void uvm_phase::add(uvm_phase phase, + uvm_phase with_phase=null, + uvm_phase after_phase=null, + uvm_phase before_phase=null, + uvm_phase start_with_phase=null, + uvm_phase end_with_phase=null + ); + uvm_phase new_node, begin_node, end_node, tmp_node; + uvm_phase_state_change state_chg; + if (phase == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH/NULL")) + uvm_report_fatal ("PH/NULL", "add: phase argument is null", UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 762, "", 1); + end + if (with_phase != null && with_phase.get_phase_type() == UVM_PHASE_IMP) begin + string nm = with_phase.get_name(); + with_phase = find(with_phase); + if (with_phase == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BAD_ADD")) + uvm_report_fatal ("PH_BAD_ADD", {"cannot find with_phase '",nm,"' within node '",get_name(),"'"}, UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 769, "", 1); + end + end + if (before_phase != null && before_phase.get_phase_type() == UVM_PHASE_IMP) begin + string nm = before_phase.get_name(); + before_phase = find(before_phase); + if (before_phase == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BAD_ADD")) + uvm_report_fatal ("PH_BAD_ADD", {"cannot find before_phase '",nm,"' within node '",get_name(),"'"}, UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 777, "", 1); + end + end + if (after_phase != null && after_phase.get_phase_type() == UVM_PHASE_IMP) begin + string nm = after_phase.get_name(); + after_phase = find(after_phase); + if (after_phase == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BAD_ADD")) + uvm_report_fatal ("PH_BAD_ADD", {"cannot find after_phase '",nm,"' within node '",get_name(),"'"}, UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 785, "", 1); + end + end + if (start_with_phase != null && start_with_phase.get_phase_type() == UVM_PHASE_IMP) begin + string nm = start_with_phase.get_name(); + start_with_phase = find(start_with_phase); + if (start_with_phase == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BAD_ADD")) + uvm_report_fatal ("PH_BAD_ADD", {"cannot find start_with_phase '",nm,"' within node '",get_name(),"'"}, UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 793, "", 1); + end + end + if (end_with_phase != null && end_with_phase.get_phase_type() == UVM_PHASE_IMP) begin + string nm = end_with_phase.get_name(); + end_with_phase = find(end_with_phase); + if (end_with_phase == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BAD_ADD")) + uvm_report_fatal ("PH_BAD_ADD", {"cannot find end_with_phase '",nm,"' within node '",get_name(),"'"}, UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 801, "", 1); + end + end + if (((with_phase != null) + (after_phase != null) + (start_with_phase != null)) > 1) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BAD_ADD")) + uvm_report_fatal ("PH_BAD_ADD", "only one of with_phase/after_phase/start_with_phase may be specified as they all specify predecessor", UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 806, "", 1); + end + if (((with_phase != null) + (before_phase != null) + (end_with_phase != null)) > 1) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BAD_ADD")) + uvm_report_fatal ("PH_BAD_ADD", "only one of with_phase/before_phase/end_with_phase may be specified as they all specify successor", UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 810, "", 1); + end + if (before_phase == this || + after_phase == m_end_node || + with_phase == m_end_node || + start_with_phase == m_end_node || + end_with_phase == m_end_node) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BAD_ADD")) + uvm_report_fatal ("PH_BAD_ADD", "cannot add before begin node, after end node, or with end nodes", UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 818, "", 1); + end + if (before_phase != null && after_phase != null) begin + if (!after_phase.is_before(before_phase)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BAD_ADD")) + uvm_report_fatal ("PH_BAD_ADD", {"Phase '",before_phase.get_name(), "' is not before phase '",after_phase.get_name(),"'"}, UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 823, "", 1); + end + end + end + if (before_phase != null && start_with_phase != null) begin + if (!start_with_phase.is_before(before_phase)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BAD_ADD")) + uvm_report_fatal ("PH_BAD_ADD", {"Phase '",before_phase.get_name(), "' is not before phase '",start_with_phase.get_name(),"'"}, UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 830, "", 1); + end + end + end + if (end_with_phase != null && after_phase != null) begin + if (!after_phase.is_before(end_with_phase)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BAD_ADD")) + uvm_report_fatal ("PH_BAD_ADD", {"Phase '",end_with_phase.get_name(), "' is not before phase '",after_phase.get_name(),"'"}, UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 837, "", 1); + end + end + end + if (phase.get_phase_type() == UVM_PHASE_IMP) begin + uvm_task_phase tp; + new_node = new(phase.get_name(),UVM_PHASE_NODE,this); + new_node.m_imp = phase; + begin_node = new_node; + end_node = new_node; + end + else begin + begin_node = phase; + end_node = phase.m_end_node; + phase.m_parent = this; + end + if (with_phase==null && after_phase==null && before_phase==null && + start_with_phase==null && end_with_phase==null) begin + before_phase = m_end_node; + end + if (m_phase_trace) begin + uvm_phase_type typ = phase.get_phase_type(); + begin + if (uvm_report_enabled(UVM_DEBUG,UVM_INFO,"PH/TRC/ADD_PH")) + uvm_report_info ("PH/TRC/ADD_PH", {get_name()," (",m_phase_type.name(),") ADD_PHASE: phase=",phase.get_full_name()," (", typ.name(),", inst_id=",$sformatf("%0d",phase.get_inst_id()),")", " with_phase=", (with_phase == null) ? "null" : with_phase.get_name(), " start_with_phase=", (start_with_phase == null) ? "null" : start_with_phase.get_name(), " end_with_phase=", (end_with_phase == null) ? "null" : end_with_phase.get_name(), " after_phase=", (after_phase == null) ? "null" : after_phase.get_name(), " before_phase=", (before_phase == null) ? "null" : before_phase.get_name(), " new_node=", (new_node == null) ? "null" : {new_node.get_name(), " inst_id=", $sformatf("%0d",new_node.get_inst_id())}, " begin_node=", (begin_node == null) ? "null" : begin_node.get_name(), " end_node=", (end_node == null) ? "null" : end_node.get_name()}, UVM_DEBUG, "t/uvm/src/base/uvm_phase.svh", 886, "", 1); + end + end + if (with_phase != null) begin + begin_node.m_predecessors = with_phase.m_predecessors; + foreach (with_phase.m_predecessors[pred]) pred.m_successors[begin_node] = 1; + end_node.m_successors = with_phase.m_successors; + foreach (with_phase.m_successors[succ]) succ.m_predecessors[end_node] = 1; + end + if (start_with_phase != null) begin + begin_node.m_predecessors = start_with_phase.m_predecessors; + foreach (start_with_phase.m_predecessors[pred]) begin + pred.m_successors[begin_node] = 1; + end + if (before_phase == null && end_with_phase == null) begin + end_node.m_successors = m_end_node.m_successors ; + foreach (m_end_node.m_successors[succ]) begin + succ.m_predecessors[end_node] = 1; + end + end + end + if (end_with_phase != null) begin + end_node.m_successors = end_with_phase.m_successors; + foreach (end_with_phase.m_successors[succ]) begin + succ.m_predecessors[end_node] = 1; + end + if (after_phase == null && start_with_phase == null) begin + begin_node.m_predecessors = this.m_predecessors ; + foreach (this.m_predecessors[pred]) begin + pred.m_successors[begin_node] = 1; + end + end + end + if (before_phase != null) begin + if (after_phase == null && start_with_phase == null) begin + foreach (before_phase.m_predecessors[pred]) begin + pred.m_successors.delete(before_phase); + pred.m_successors[begin_node] = 1; + end + begin_node.m_predecessors = before_phase.m_predecessors; + before_phase.m_predecessors.delete(); + end + else if (before_phase.m_predecessors.exists(after_phase)) begin + before_phase.m_predecessors.delete(after_phase); + end + before_phase.m_predecessors[end_node] = 1; + end_node.m_successors.delete() ; + end_node.m_successors[before_phase] = 1; + end + if (after_phase != null) begin + if (before_phase == null && end_with_phase == null) begin + foreach (after_phase.m_successors[succ]) begin + succ.m_predecessors.delete(after_phase); + succ.m_predecessors[end_node] = 1; + end + end_node.m_successors = after_phase.m_successors; + after_phase.m_successors.delete(); + end + else if (after_phase.m_successors.exists(before_phase)) begin + after_phase.m_successors.delete(before_phase); + end + after_phase.m_successors[begin_node] = 1; + begin_node.m_predecessors.delete(); + begin_node.m_predecessors[after_phase] = 1; + end + if (new_node == null) + tmp_node = phase; + else + tmp_node = new_node; + state_chg = uvm_phase_state_change::type_id_create(tmp_node.get_name()); + state_chg.m_phase = tmp_node; + state_chg.m_jump_to = null; + state_chg.m_prev_state = tmp_node.m_state; + tmp_node.m_state = UVM_PHASE_DORMANT; + begin + uvm_callback_iter#(uvm_phase,uvm_phase_cb) iter = new(this); + uvm_phase_cb cb = iter.first(); + while(cb != null) begin + cb.phase_state_change(tmp_node, state_chg); + cb = iter.next(); + end + end +endfunction +function uvm_phase uvm_phase::get_parent(); + return m_parent; +endfunction +function uvm_phase uvm_phase::get_imp(); + return m_imp; +endfunction +function uvm_phase uvm_phase::get_schedule(bit hier=0); + uvm_phase sched; + sched = this; + if (hier) + while (sched.m_parent != null && (sched.m_parent.get_phase_type() == UVM_PHASE_SCHEDULE)) + sched = sched.m_parent; + if (sched.m_phase_type == UVM_PHASE_SCHEDULE) + return sched; + if (sched.m_phase_type == UVM_PHASE_NODE) + if (m_parent != null && m_parent.m_phase_type != UVM_PHASE_DOMAIN) + return m_parent; + return null; +endfunction +function uvm_domain uvm_phase::get_domain(); + uvm_phase phase; + phase = this; + while (phase != null && phase.m_phase_type != UVM_PHASE_DOMAIN) + phase = phase.m_parent; + if (phase == null) + return null; + if(!$cast(get_domain,phase)) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH/INTERNAL")) + uvm_report_fatal ("PH/INTERNAL", "get_domain: m_phase_type is DOMAIN but $cast to uvm_domain fails", UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 1047, "", 1); + end +endfunction +function string uvm_phase::get_domain_name(); + uvm_domain domain; + domain = get_domain(); + if (domain == null) + return "unknown"; + return domain.get_name(); +endfunction +function string uvm_phase::get_schedule_name(bit hier=0); + uvm_phase sched; + string s; + sched = get_schedule(hier); + if (sched == null) + return ""; + s = sched.get_name(); + while (sched.m_parent != null && sched.m_parent != sched && + (sched.m_parent.get_phase_type() == UVM_PHASE_SCHEDULE)) begin + sched = sched.m_parent; + s = {sched.get_name(),(s.len()>0?".":""),s}; + end + return s; +endfunction +function string uvm_phase::get_full_name(); + string dom, sch; + if (m_phase_type == UVM_PHASE_IMP) + return get_name(); + get_full_name = get_domain_name(); + sch = get_schedule_name(); + if (sch != "") + get_full_name = {get_full_name, ".", sch}; + if (m_phase_type != UVM_PHASE_DOMAIN && m_phase_type != UVM_PHASE_SCHEDULE) + get_full_name = {get_full_name, ".", get_name()}; +endfunction +function uvm_phase_type uvm_phase::get_phase_type(); + return m_phase_type; +endfunction +function void uvm_phase::set_max_ready_to_end_iterations(int max); + max_ready_to_end_iters = max; +endfunction +function int uvm_phase::get_max_ready_to_end_iterations(); + return max_ready_to_end_iters; +endfunction +function void uvm_phase::set_default_max_ready_to_end_iterations(int max); + m_default_max_ready_to_end_iters = max; +endfunction +function int uvm_phase::get_default_max_ready_to_end_iterations(); + return m_default_max_ready_to_end_iters; +endfunction +function uvm_phase_state uvm_phase::get_state(); + return m_state; +endfunction +function int uvm_phase::get_run_count(); + return m_run_count; +endfunction +function void uvm_phase::m_print_successors(); + uvm_phase found; + static string spaces = " "; + static int level; + if (m_phase_type == UVM_PHASE_DOMAIN) + level = 0; + begin + if (uvm_report_enabled(UVM_NONE,UVM_INFO,"UVM/PHASE/SUCC")) + uvm_report_info ("UVM/PHASE/SUCC", $sformatf("%s%s (%s) id=%0d",spaces.substr(0,level*2),get_name(), m_phase_type.name(),get_inst_id()), UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 1162, "", 1); + end + level++; + foreach (m_successors[succ]) begin + succ.m_print_successors(); + end + level--; +endfunction +function uvm_phase uvm_phase::m_find_predecessor(uvm_phase phase, bit stay_in_scope=1, uvm_phase orig_phase=null); + uvm_phase found; + if (phase == null) begin + return null ; + end + if (phase == m_imp || phase == this) + return this; + foreach (m_predecessors[pred]) begin + uvm_phase orig; + orig = (orig_phase==null) ? this : orig_phase; + if (!stay_in_scope || + (pred.get_schedule() == orig.get_schedule()) || + (pred.get_domain() == orig.get_domain())) begin + found = pred.m_find_predecessor(phase,stay_in_scope,orig); + if (found != null) + return found; + end + end + return null; +endfunction +function uvm_phase uvm_phase::m_find_predecessor_by_name(string name, bit stay_in_scope=1, uvm_phase orig_phase=null); + uvm_phase found; + if (get_name() == name) + return this; + foreach (m_predecessors[pred]) begin + uvm_phase orig; + orig = (orig_phase==null) ? this : orig_phase; + if (!stay_in_scope || + (pred.get_schedule() == orig.get_schedule()) || + (pred.get_domain() == orig.get_domain())) begin + found = pred.m_find_predecessor_by_name(name,stay_in_scope,orig); + if (found != null) + return found; + end + end + return null; +endfunction +function uvm_phase uvm_phase::m_find_successor(uvm_phase phase, bit stay_in_scope=1, uvm_phase orig_phase=null); + uvm_phase found; + if (phase == null) begin + return null ; + end + if (phase == m_imp || phase == this) begin + return this; + end + foreach (m_successors[succ]) begin + uvm_phase orig; + orig = (orig_phase==null) ? this : orig_phase; + if (!stay_in_scope || + (succ.get_schedule() == orig.get_schedule()) || + (succ.get_domain() == orig.get_domain())) begin + found = succ.m_find_successor(phase,stay_in_scope,orig); + if (found != null) begin + return found; + end + end + end + return null; +endfunction +function uvm_phase uvm_phase::m_find_successor_by_name(string name, bit stay_in_scope=1, uvm_phase orig_phase=null); + uvm_phase found; + if (get_name() == name) + return this; + foreach (m_successors[succ]) begin + uvm_phase orig; + orig = (orig_phase==null) ? this : orig_phase; + if (!stay_in_scope || + (succ.get_schedule() == orig.get_schedule()) || + (succ.get_domain() == orig.get_domain())) begin + found = succ.m_find_successor_by_name(name,stay_in_scope,orig); + if (found != null) + return found; + end + end + return null; +endfunction +function uvm_phase uvm_phase::find(uvm_phase phase, bit stay_in_scope=1); + if (phase == m_imp || phase == this) + return phase; + find = m_find_predecessor(phase,stay_in_scope,this); + if (find == null) + find = m_find_successor(phase,stay_in_scope,this); +endfunction +function uvm_phase uvm_phase::find_by_name(string name, bit stay_in_scope=1); + if (get_name() == name) + return this; + find_by_name = m_find_predecessor_by_name(name,stay_in_scope,this); + if (find_by_name == null) + find_by_name = m_find_successor_by_name(name,stay_in_scope,this); +endfunction +function bit uvm_phase::is(uvm_phase phase); + return (m_imp == phase || this == phase); +endfunction +function bit uvm_phase::is_before(uvm_phase phase); + return (!is(phase) && m_find_successor(phase,0,this) != null); +endfunction +function bit uvm_phase::is_after(uvm_phase phase); + return (!is(phase) && m_find_predecessor(phase,0,this) != null); +endfunction +task uvm_phase::execute_phase(); + uvm_task_phase task_phase; + uvm_root top; + uvm_phase_state_change state_chg; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + foreach (m_predecessors[pred]) + wait (pred.m_state == UVM_PHASE_DONE); + if (m_state == UVM_PHASE_DONE) + return; + state_chg = uvm_phase_state_change::type_id_create(get_name()); + state_chg.m_phase = this; + state_chg.m_jump_to = null; + state_chg.m_prev_state = m_state; + m_state = UVM_PHASE_SYNCING; + begin + uvm_callback_iter#(uvm_phase,uvm_phase_cb) iter = new(this); + uvm_phase_cb cb = iter.first(); + while(cb != null) begin + cb.phase_state_change(this, state_chg); + cb = iter.next(); + end + end + #0; + if (m_sync.size()) begin + foreach (m_sync[i]) begin + wait (m_sync[i].m_state >= UVM_PHASE_SYNCING); + end + end + m_run_count++; + if (m_phase_trace) begin + begin + if (uvm_report_enabled(UVM_LOW,UVM_INFO,"PH/TRC/STRT")) + uvm_report_info ("PH/TRC/STRT", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),"Starting phase"}, UVM_LOW, "t/uvm/src/base/uvm_phase.svh", 1382, "", 1); + end + end + if (m_phase_type != UVM_PHASE_NODE) begin + state_chg.m_prev_state = m_state; + m_state = UVM_PHASE_STARTED; + begin + uvm_callback_iter#(uvm_phase,uvm_phase_cb) iter = new(this); + uvm_phase_cb cb = iter.first(); + while(cb != null) begin + cb.phase_state_change(this, state_chg); + cb = iter.next(); + end + end + #0; + state_chg.m_prev_state = m_state; + m_state = UVM_PHASE_EXECUTING; + begin + uvm_callback_iter#(uvm_phase,uvm_phase_cb) iter = new(this); + uvm_phase_cb cb = iter.first(); + while(cb != null) begin + cb.phase_state_change(this, state_chg); + cb = iter.next(); + end + end + #0; + end + else begin + state_chg.m_prev_state = m_state; + m_state = UVM_PHASE_STARTED; + begin + uvm_callback_iter#(uvm_phase,uvm_phase_cb) iter = new(this); + uvm_phase_cb cb = iter.first(); + while(cb != null) begin + cb.phase_state_change(this, state_chg); + cb = iter.next(); + end + end + m_imp.traverse(top,this,UVM_PHASE_STARTED); + m_ready_to_end_count = 0 ; + #0; + if (!$cast(task_phase,m_imp)) begin + state_chg.m_prev_state = m_state; + m_state = UVM_PHASE_EXECUTING; + begin + uvm_callback_iter#(uvm_phase,uvm_phase_cb) iter = new(this); + uvm_phase_cb cb = iter.first(); + while(cb != null) begin + cb.phase_state_change(this, state_chg); + cb = iter.next(); + end + end + #0; + m_imp.traverse(top,this,UVM_PHASE_EXECUTING); + end + else begin + m_executing_phases[this] = 1; + state_chg.m_prev_state = m_state; + m_state = UVM_PHASE_EXECUTING; + begin + uvm_callback_iter#(uvm_phase,uvm_phase_cb) iter = new(this); + uvm_phase_cb cb = iter.first(); + while(cb != null) begin + cb.phase_state_change(this, state_chg); + cb = iter.next(); + end + end + fork : master_phase_process + begin + m_phase_proc = process::self(); + task_phase.traverse(top,this,UVM_PHASE_EXECUTING); + wait(0); + end + join_none + uvm_wait_for_nba_region(); + fork + begin + fork + begin + wait (m_premature_end); + begin + if (uvm_report_enabled(UVM_DEBUG,UVM_INFO,"PH/TRC/EXE/JUMP")) + uvm_report_info ("PH/TRC/EXE/JUMP", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),"PHASE EXIT ON JUMP REQUEST"}, UVM_DEBUG, "t/uvm/src/base/uvm_phase.svh", 1462, "", 1); + end + end + begin + bit do_ready_to_end ; + uvm_objection phase_done; + phase_done = get_objection(); + if (phase_done.get_objection_total(top) || + m_use_ovm_run_semantic && m_imp.get_name() == "run") begin + if (!phase_done.m_top_all_dropped) + phase_done.wait_for(UVM_ALL_DROPPED, top); + begin + if (uvm_report_enabled(UVM_DEBUG,UVM_INFO,"PH/TRC/EXE/ALLDROP")) + uvm_report_info ("PH/TRC/EXE/ALLDROP", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),"PHASE EXIT ALL_DROPPED"}, UVM_DEBUG, "t/uvm/src/base/uvm_phase.svh", 1475, "", 1); + end + end + else begin + if (m_phase_trace) + begin + if (uvm_report_enabled(UVM_LOW,UVM_INFO,"PH/TRC/SKIP")) + uvm_report_info ("PH/TRC/SKIP", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),"No objections raised, skipping phase"}, UVM_LOW, "t/uvm/src/base/uvm_phase.svh", 1478, "", 1); + end + end + wait_for_self_and_siblings_to_drop() ; + do_ready_to_end = 1; + while (do_ready_to_end) begin + uvm_wait_for_nba_region(); + begin + if (uvm_report_enabled(UVM_DEBUG,UVM_INFO,"PH_READY_TO_END")) + uvm_report_info ("PH_READY_TO_END", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),"PHASE READY TO END"}, UVM_DEBUG, "t/uvm/src/base/uvm_phase.svh", 1490, "", 1); + end + m_ready_to_end_count++; + if (m_phase_trace) + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"PH_READY_TO_END_CB")) + uvm_report_info ("PH_READY_TO_END_CB", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),"CALLING READY_TO_END CB"}, UVM_HIGH, "t/uvm/src/base/uvm_phase.svh", 1493, "", 1); + end + state_chg.m_prev_state = m_state; + m_state = UVM_PHASE_READY_TO_END; + begin + uvm_callback_iter#(uvm_phase,uvm_phase_cb) iter = new(this); + uvm_phase_cb cb = iter.first(); + while(cb != null) begin + cb.phase_state_change(this, state_chg); + cb = iter.next(); + end + end + if (m_imp != null) + m_imp.traverse(top,this,UVM_PHASE_READY_TO_END); + uvm_wait_for_nba_region(); + wait_for_self_and_siblings_to_drop(); + do_ready_to_end = (m_state == UVM_PHASE_EXECUTING) && (m_ready_to_end_count < get_max_ready_to_end_iterations()) ; + end + end + begin + if (this.get_name() == "run") begin + if (top.phase_timeout == 0) + wait(top.phase_timeout != 0); + if (m_phase_trace) + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"PH/TRC/TO_WAIT")) + uvm_report_info ("PH/TRC/TO_WAIT", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),$sformatf("STARTING PHASE TIMEOUT WATCHDOG (timeout == %t)", top.phase_timeout)}, UVM_HIGH, "t/uvm/src/base/uvm_phase.svh", 1513, "", 1); + end + #(top.phase_timeout); + if ($time == 9200s) begin + if (m_phase_trace) + begin + if (uvm_report_enabled(UVM_LOW,UVM_INFO,"PH/TRC/TIMEOUT")) + uvm_report_info ("PH/TRC/TIMEOUT", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),"PHASE TIMEOUT WATCHDOG EXPIRED"}, UVM_LOW, "t/uvm/src/base/uvm_phase.svh", 1517, "", 1); + end + foreach (m_executing_phases[p]) begin + uvm_objection p_phase_done; + p_phase_done = p.get_objection(); + if ((p_phase_done != null) && (p_phase_done.get_objection_total() > 0)) begin + if (m_phase_trace) + begin + if (uvm_report_enabled(UVM_LOW,UVM_INFO,"PH/TRC/TIMEOUT/OBJCTN")) + uvm_report_info ("PH/TRC/TIMEOUT/OBJCTN", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),$sformatf("Phase '%s' has outstanding objections:\n%s", p.get_full_name(), p_phase_done.convert2string())}, UVM_LOW, "t/uvm/src/base/uvm_phase.svh", 1526, "", 1); + end + end + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_TIMEOUT")) + uvm_report_fatal ("PH_TIMEOUT", $sformatf("Default timeout of %0t hit, indicating a probable testbench issue", 9200s), UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 1532, "", 1); + end + end + else begin + if (m_phase_trace) + begin + if (uvm_report_enabled(UVM_LOW,UVM_INFO,"PH/TRC/TIMEOUT")) + uvm_report_info ("PH/TRC/TIMEOUT", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),"PHASE TIMEOUT WATCHDOG EXPIRED"}, UVM_LOW, "t/uvm/src/base/uvm_phase.svh", 1536, "", 1); + end + foreach (m_executing_phases[p]) begin + uvm_objection p_phase_done; + p_phase_done = p.get_objection(); + if ((p_phase_done != null) && (p_phase_done.get_objection_total() > 0)) begin + if (m_phase_trace) + begin + if (uvm_report_enabled(UVM_LOW,UVM_INFO,"PH/TRC/TIMEOUT/OBJCTN")) + uvm_report_info ("PH/TRC/TIMEOUT/OBJCTN", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),$sformatf("Phase '%s' has outstanding objections:\n%s", p.get_full_name(), p_phase_done.convert2string())}, UVM_LOW, "t/uvm/src/base/uvm_phase.svh", 1545, "", 1); + end + end + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_TIMEOUT")) + uvm_report_fatal ("PH_TIMEOUT", $sformatf("Explicit timeout of %0t hit, indicating a probable testbench issue", top.phase_timeout), UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 1551, "", 1); + end + end + if (m_phase_trace) + begin + if (uvm_report_enabled(UVM_DEBUG,UVM_INFO,"PH/TRC/EXE/3")) + uvm_report_info ("PH/TRC/EXE/3", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),"PHASE EXIT TIMEOUT"}, UVM_DEBUG, "t/uvm/src/base/uvm_phase.svh", 1554, "", 1); + end + end + else begin + wait (0); + end + end + join_any + disable fork; + end + join + end + end + m_executing_phases.delete(this); + if (m_phase_type == UVM_PHASE_NODE) begin + if(m_premature_end) begin + if(m_jump_phase != null) begin + state_chg.m_jump_to = m_jump_phase; + begin + if (uvm_report_enabled(UVM_MEDIUM,UVM_INFO,"PH_JUMP")) + uvm_report_info ("PH_JUMP", $sformatf("phase %s (schedule %s, domain %s) is jumping to phase %s", get_name(), get_schedule_name(), get_domain_name(), m_jump_phase.get_name()), UVM_MEDIUM, "t/uvm/src/base/uvm_phase.svh", 1598, "", 1); + end + end + else begin + begin + if (uvm_report_enabled(UVM_MEDIUM,UVM_INFO,"PH_JUMP")) + uvm_report_info ("PH_JUMP", $sformatf("phase %s (schedule %s, domain %s) is ending prematurely", get_name(), get_schedule_name(), get_domain_name()), UVM_MEDIUM, "t/uvm/src/base/uvm_phase.svh", 1604, "", 1); + end + end + #0; + if (m_phase_trace) + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"PH_END")) + uvm_report_info ("PH_END", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),"ENDING PHASE PREMATURELY"}, UVM_HIGH, "t/uvm/src/base/uvm_phase.svh", 1610, "", 1); + end + end + else begin + if (task_phase == null) + m_wait_for_pred(); + end + if (m_phase_trace) + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"PH_END")) + uvm_report_info ("PH_END", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),"ENDING PHASE"}, UVM_HIGH, "t/uvm/src/base/uvm_phase.svh", 1624, "", 1); + end + state_chg.m_prev_state = m_state; + m_state = UVM_PHASE_ENDED; + begin + uvm_callback_iter#(uvm_phase,uvm_phase_cb) iter = new(this); + uvm_phase_cb cb = iter.first(); + while(cb != null) begin + cb.phase_state_change(this, state_chg); + cb = iter.next(); + end + end + if (m_imp != null) + m_imp.traverse(top,this,UVM_PHASE_ENDED); + #0; + state_chg.m_prev_state = m_state; + if(m_premature_end) m_state = UVM_PHASE_JUMPING; + else m_state = UVM_PHASE_CLEANUP ; + begin + uvm_callback_iter#(uvm_phase,uvm_phase_cb) iter = new(this); + uvm_phase_cb cb = iter.first(); + while(cb != null) begin + cb.phase_state_change(this, state_chg); + cb = iter.next(); + end + end + if (m_phase_proc != null) begin + m_phase_proc.kill(); + m_phase_proc = null; + end + #0; + begin + uvm_objection objection = get_objection(); + if (objection != null) + objection.clear(); + end + end + m_premature_end = 0 ; + if(m_jump_fwd || m_jump_bkwd) begin + if(m_jump_fwd) begin + clear_successors(UVM_PHASE_DONE,m_jump_phase); + end + m_jump_phase.clear_successors(); + end + else begin + if (m_phase_trace) + begin + if (uvm_report_enabled(UVM_LOW,UVM_INFO,"PH/TRC/DONE")) + uvm_report_info ("PH/TRC/DONE", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),"Completed phase"}, UVM_LOW, "t/uvm/src/base/uvm_phase.svh", 1666, "", 1); + end + state_chg.m_prev_state = m_state; + m_state = UVM_PHASE_DONE; + begin + uvm_callback_iter#(uvm_phase,uvm_phase_cb) iter = new(this); + uvm_phase_cb cb = iter.first(); + while(cb != null) begin + cb.phase_state_change(this, state_chg); + cb = iter.next(); + end + end + m_phase_proc = null; + #0; + end + #0; + begin + uvm_objection objection; + objection = get_objection(); + if (objection != null) + objection.clear(); + end + if(m_jump_fwd || m_jump_bkwd) begin + void'(m_phase_hopper.try_put(m_jump_phase)); + m_jump_phase = null; + m_jump_fwd = 0; + m_jump_bkwd = 0; + end + else if (m_successors.size() == 0) begin + top.m_phase_all_done=1; + end + else begin + foreach (m_successors[succ]) begin + if(succ.m_state < UVM_PHASE_SCHEDULED) begin + state_chg.m_prev_state = succ.m_state; + state_chg.m_phase = succ; + succ.m_state = UVM_PHASE_SCHEDULED; + begin + uvm_callback_iter#(uvm_phase,uvm_phase_cb) iter = new(this); + uvm_phase_cb cb = iter.first(); + while(cb != null) begin + cb.phase_state_change(succ, state_chg); + cb = iter.next(); + end + end + #0; + void'(m_phase_hopper.try_put(succ)); + if (m_phase_trace) + begin + if (uvm_report_enabled(UVM_LOW,UVM_INFO,"PH/TRC/SCHEDULED")) + uvm_report_info ("PH/TRC/SCHEDULED", {$sformatf("Phase '%0s' (id=%0d) ", succ.get_full_name(), succ.get_inst_id()),{"Scheduled from phase ",get_full_name()}}, UVM_LOW, "t/uvm/src/base/uvm_phase.svh", 1705, "", 1); + end + end + end + end +endtask +function void uvm_phase::get_adjacent_predecessor_nodes(ref uvm_phase pred[]); + bit done; + bit predecessors[uvm_phase]; + int idx; + foreach (m_predecessors[p]) + predecessors[p] = 1; + do begin + done = 1; + foreach (predecessors[p]) begin + if (p.get_phase_type() != UVM_PHASE_NODE) begin + predecessors.delete(p); + foreach (p.m_predecessors[next_p]) + predecessors[next_p] = 1; + done = 0; + end + end + end while (!done); + pred = new [predecessors.size()]; + foreach (predecessors[p]) begin + pred[idx++] = p; + end +endfunction : get_adjacent_predecessor_nodes +function void uvm_phase::get_adjacent_successor_nodes(ref uvm_phase succ[]); + bit done; + bit successors[uvm_phase]; + int idx; + foreach (m_successors[s]) + successors[s] = 1; + do begin + done = 1; + foreach (successors[s]) begin + if (s.get_phase_type() != UVM_PHASE_NODE) begin + successors.delete(s); + foreach (s.m_successors[next_s]) + successors[next_s] = 1; + done = 0; + end + end + end while (!done); + succ = new [successors.size()]; + foreach (successors[s]) begin + succ[idx++] = s; + end +endfunction : get_adjacent_successor_nodes +function void uvm_phase::get_predecessors_for_successors(output bit pred_of_succ[uvm_phase]); + bit done; + uvm_phase successors[]; + get_adjacent_successor_nodes(successors); + foreach (successors[s]) + foreach (successors[s].m_predecessors[pred]) + pred_of_succ[pred] = 1; + do begin + done=1; + foreach (pred_of_succ[pred]) begin + if (pred.get_phase_type() != UVM_PHASE_NODE) begin + pred_of_succ.delete(pred); + foreach (pred.m_predecessors[next_pred]) + pred_of_succ[next_pred] = 1; + done =0; + end + end + end while (!done); + pred_of_succ.delete(this); +endfunction +task uvm_phase::m_wait_for_pred(); + bit pred_of_succ[uvm_phase]; + get_predecessors_for_successors(pred_of_succ); + foreach (pred_of_succ[sibling]) begin + if (m_phase_trace) begin + string s; + s = $sformatf("Waiting for phase '%s' (%0d) to be READY_TO_END. Current state is %s", + sibling.get_name(),sibling.get_inst_id(),sibling.m_state.name()); + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"PH/TRC/WAIT_PRED_OF_SUCC")) + uvm_report_info ("PH/TRC/WAIT_PRED_OF_SUCC", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),s}, UVM_HIGH, "t/uvm/src/base/uvm_phase.svh", 1819, "", 1); + end + end + sibling.wait_for_state(UVM_PHASE_READY_TO_END, UVM_GTE); + if (m_phase_trace) begin + string s; + s = $sformatf("Phase '%s' (%0d) is now READY_TO_END. Releasing phase", + sibling.get_name(),sibling.get_inst_id()); + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"PH/TRC/WAIT_PRED_OF_SUCC")) + uvm_report_info ("PH/TRC/WAIT_PRED_OF_SUCC", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),s}, UVM_HIGH, "t/uvm/src/base/uvm_phase.svh", 1828, "", 1); + end + end + end + if (m_phase_trace) begin + if (pred_of_succ.num()) begin + string s = "( "; + foreach (pred_of_succ[pred]) + s = {s, pred.get_full_name()," "}; + s = {s, ")"}; + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"PH/TRC/WAIT_PRED_OF_SUCC")) + uvm_report_info ("PH/TRC/WAIT_PRED_OF_SUCC", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),{"*** All pred to succ ",s," in READY_TO_END state, so ending phase ***"}}, UVM_HIGH, "t/uvm/src/base/uvm_phase.svh", 1840, "", 1); + end + end + else begin + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"PH/TRC/WAIT_PRED_OF_SUCC")) + uvm_report_info ("PH/TRC/WAIT_PRED_OF_SUCC", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),"*** No pred to succ other than myself, so ending phase ***"}, UVM_HIGH, "t/uvm/src/base/uvm_phase.svh", 1844, "", 1); + end + end + end + #0; +endtask +function void uvm_phase::m_report_null_objection(uvm_object obj, + string description, + int count, + string action); + string m_action; + string m_addon; + string m_obj_name = (obj == null) ? "uvm_top" : obj.get_full_name(); + if ((action == "raise") || (action == "drop")) begin + if (count != 1) + m_action = $sformatf("%s %0d objections", action, count); + else + m_action = $sformatf("%s an objection", action); + end + else if (action == "get_objection_count") begin + m_action = "call get_objection_count"; + end + if (this.get_phase_type() == UVM_PHASE_IMP) begin + m_addon = " (This is a UVM_PHASE_IMP, you have to query the schedule to find the UVM_PHASE_NODE)"; + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/PH/NULL_OBJECTION")) + uvm_report_error ("UVM/PH/NULL_OBJECTION", $sformatf("'%s' attempted to %s on '%s', however '%s' is not a task-based phase node! %s", m_obj_name, m_action, get_name(), get_name(), m_addon), UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 1885, "", 1); + end +endfunction : m_report_null_objection +function void uvm_phase::raise_objection (uvm_object obj, + string description="", + int count=1); + uvm_objection phase_done; + phase_done = get_objection(); + if (phase_done != null) + phase_done.raise_objection(obj,description,count); + else + m_report_null_objection(obj, description, count, "raise"); +endfunction +function void uvm_phase::drop_objection (uvm_object obj, + string description="", + int count=1); + uvm_objection phase_done; + phase_done = get_objection(); + if (phase_done != null) + phase_done.drop_objection(obj,description,count); + else + m_report_null_objection(obj, description, count, "drop"); +endfunction +function int uvm_phase::get_objection_count (uvm_object obj=null); + uvm_objection phase_done; + phase_done = get_objection(); + if (phase_done != null) + return phase_done.get_objection_count(obj); + else begin + m_report_null_objection(obj, "" , 0, "get_objection_count"); + return 0; + end +endfunction : get_objection_count +function void uvm_phase::sync(uvm_domain target, + uvm_phase phase=null, + uvm_phase with_phase=null); + if (!this.is_domain()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BADSYNC")) + uvm_report_fatal ("PH_BADSYNC", "sync() called from a non-domain phase schedule node", UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 1939, "", 1); + end + end + else if (target == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BADSYNC")) + uvm_report_fatal ("PH_BADSYNC", "sync() called with a null target domain", UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 1942, "", 1); + end + end + else if (!target.is_domain()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BADSYNC")) + uvm_report_fatal ("PH_BADSYNC", "sync() called with a non-domain phase schedule node as target", UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 1945, "", 1); + end + end + else if (phase == null && with_phase != null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BADSYNC")) + uvm_report_fatal ("PH_BADSYNC", "sync() called with null phase and non-null with phase", UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 1948, "", 1); + end + end + else if (phase == null) begin + int visited[uvm_phase]; + uvm_phase queue[$]; + queue.push_back(this); + visited[this] = 1; + while (queue.size()) begin + uvm_phase node; + node = queue.pop_front(); + if (node.m_imp != null) begin + sync(target, node.m_imp); + end + foreach (node.m_successors[succ]) begin + if (!visited.exists(succ)) begin + queue.push_back(succ); + visited[succ] = 1; + end + end + end + end else begin + uvm_phase from_node, to_node; + int found_to[$], found_from[$]; + if(with_phase == null) with_phase = phase; + from_node = find(phase); + to_node = target.find(with_phase); + if(from_node == null || to_node == null) return; + found_to = from_node.m_sync.find_index(node) with (node == to_node); + found_from = to_node.m_sync.find_index(node) with (node == from_node); + if (found_to.size() == 0) from_node.m_sync.push_back(to_node); + if (found_from.size() == 0) to_node.m_sync.push_back(from_node); + end +endfunction +function void uvm_phase::unsync(uvm_domain target, + uvm_phase phase=null, + uvm_phase with_phase=null); + if (!this.is_domain()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BADSYNC")) + uvm_report_fatal ("PH_BADSYNC", "unsync() called from a non-domain phase schedule node", UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 1993, "", 1); + end + end else if (target == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BADSYNC")) + uvm_report_fatal ("PH_BADSYNC", "unsync() called with a null target domain", UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 1995, "", 1); + end + end else if (!target.is_domain()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BADSYNC")) + uvm_report_fatal ("PH_BADSYNC", "unsync() called with a non-domain phase schedule node as target", UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 1997, "", 1); + end + end else if (phase == null && with_phase != null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BADSYNC")) + uvm_report_fatal ("PH_BADSYNC", "unsync() called with null phase and non-null with phase", UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 1999, "", 1); + end + end else if (phase == null) begin + int visited[uvm_phase]; + uvm_phase queue[$]; + queue.push_back(this); + visited[this] = 1; + while (queue.size()) begin + uvm_phase node; + node = queue.pop_front(); + if (node.m_imp != null) unsync(target,node.m_imp); + foreach (node.m_successors[succ]) begin + if (!visited.exists(succ)) begin + queue.push_back(succ); + visited[succ] = 1; + end + end + end + end else begin + uvm_phase from_node, to_node; + int found_to[$], found_from[$]; + if(with_phase == null) with_phase = phase; + from_node = find(phase); + to_node = target.find(with_phase); + if(from_node == null || to_node == null) return; + found_to = from_node.m_sync.find_index(node) with (node == to_node); + found_from = to_node.m_sync.find_index(node) with (node == from_node); + if (found_to.size()) from_node.m_sync.delete(found_to[0]); + if (found_from.size()) to_node.m_sync.delete(found_from[0]); + end +endfunction +task uvm_phase::wait_for_state(uvm_phase_state state, uvm_wait_op op=UVM_EQ); + case (op) + UVM_EQ: wait((state&m_state) != 0); + UVM_NE: wait((state&m_state) == 0); + UVM_LT: wait(m_state < state); + UVM_LTE: wait(m_state <= state); + UVM_GT: wait(m_state > state); + UVM_GTE: wait(m_state >= state); + endcase +endtask +function void uvm_phase::set_jump_phase(uvm_phase phase) ; + uvm_phase d; + if ((m_state < UVM_PHASE_STARTED) || + (m_state > UVM_PHASE_ENDED) ) + begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"JMPPHIDL")) + uvm_report_error ("JMPPHIDL", { "Attempting to jump from phase \"", get_name(), "\" which is not currently active (current state is ", m_state.name(), "). The jump will not happen until the phase becomes ", "active."}, UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 2067, "", 1); + end + end + d = m_find_predecessor(phase,0); + if (d == null) begin + d = m_find_successor(phase,0); + if (d == null) begin + string msg; + $sformat(msg,{"phase %s is neither a predecessor or successor of ", + "phase %s or is non-existant, so we cannot jump to it. ", + "Phase control flow is now undefined so the simulation ", + "must terminate"}, phase.get_name(), get_name()); + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BADJUMP")) + uvm_report_fatal ("PH_BADJUMP", msg, UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 2093, "", 1); + end + end + else begin + m_jump_fwd = 1; + begin + if (uvm_report_enabled(UVM_DEBUG,UVM_INFO,"PH_JUMPF")) + uvm_report_info ("PH_JUMPF", $sformatf("jumping forward to phase %s", phase.get_name()), UVM_DEBUG, "t/uvm/src/base/uvm_phase.svh", 2098, "", 1); + end + end + end + else begin + m_jump_bkwd = 1; + begin + if (uvm_report_enabled(UVM_DEBUG,UVM_INFO,"PH_JUMPB")) + uvm_report_info ("PH_JUMPB", $sformatf("jumping backward to phase %s", phase.get_name()), UVM_DEBUG, "t/uvm/src/base/uvm_phase.svh", 2104, "", 1); + end + end + m_jump_phase = d; +endfunction +function void uvm_phase::end_prematurely() ; + m_premature_end = 1 ; +endfunction +function void uvm_phase::jump(uvm_phase phase); + set_jump_phase(phase) ; + end_prematurely() ; +endfunction +function void uvm_phase::jump_all(uvm_phase phase); + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"NOTIMPL")) + uvm_report_warning ("NOTIMPL", "uvm_phase::jump_all is not implemented and has been replaced by uvm_domain::jump_all", UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 2136, "", 1); + end +endfunction +function uvm_phase uvm_phase::get_jump_target(); + return m_jump_phase; +endfunction +function void uvm_phase::clear(uvm_phase_state state = UVM_PHASE_DORMANT); + uvm_objection phase_done; + phase_done = get_objection(); + m_state = state; + m_phase_proc = null; + if (phase_done != null) + phase_done.clear(this); +endfunction +function void uvm_phase::clear_successors(uvm_phase_state state = UVM_PHASE_DORMANT, + uvm_phase end_state=null); + if(this == end_state) + return; + clear(state); + foreach(m_successors[succ]) begin + succ.clear_successors(state, end_state); + end +endfunction +task uvm_phase::wait_for_self_and_siblings_to_drop() ; + bit need_to_check_all = 1 ; + uvm_root top; + uvm_coreservice_t cs; + bit siblings[uvm_phase]; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + get_predecessors_for_successors(siblings); + foreach (m_sync[i]) begin + siblings[m_sync[i]] = 1; + end + while (need_to_check_all) begin + uvm_objection phase_done; + phase_done = get_objection(); + need_to_check_all = 0 ; + if ((phase_done != null) && (phase_done.get_objection_total(top) != 0)) begin + m_state = UVM_PHASE_EXECUTING ; + phase_done.wait_for(UVM_ALL_DROPPED, top); + need_to_check_all = 1 ; + end + foreach(siblings[sib]) begin + uvm_objection sib_phase_done; + sib_phase_done = sib.get_objection(); + sib.wait_for_state(UVM_PHASE_EXECUTING, UVM_GTE); + if ((sib_phase_done != null) && (sib_phase_done.get_objection_total(top) != 0)) begin + m_state = UVM_PHASE_EXECUTING ; + sib_phase_done.wait_for(UVM_ALL_DROPPED, top); + need_to_check_all = 1 ; + end + end + end +endtask +function void uvm_phase::kill(); + begin + if (uvm_report_enabled(UVM_DEBUG,UVM_INFO,"PH_KILL")) + uvm_report_info ("PH_KILL", {"killing phase '", get_name(),"'"}, UVM_DEBUG, "t/uvm/src/base/uvm_phase.svh", 2230, "", 1); + end + if (m_phase_proc != null) begin + m_phase_proc.kill(); + m_phase_proc = null; + end +endfunction +function void uvm_phase::kill_successors(); + foreach (m_successors[succ]) + succ.kill_successors(); + kill(); +endfunction +task uvm_phase::m_run_phases(); + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + begin + uvm_phase ph = uvm_domain::get_common_domain(); + void'(m_phase_hopper.try_put(ph)); + end + m_uvm_core_state=UVM_CORE_RUNNING; + forever begin + uvm_phase phase; + m_phase_hopper.get(phase); + fork + begin + phase.execute_phase(); + end + join_none + #0; + end +endtask +function void uvm_phase::m_terminate_phase(); + uvm_objection phase_done; + phase_done = get_objection(); + if (phase_done != null) + phase_done.clear(this); +endfunction +function void uvm_phase::m_print_termination_state(); + uvm_root top; + uvm_coreservice_t cs; + uvm_objection phase_done; + phase_done = get_objection(); + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + if (phase_done != null) begin + begin + if (uvm_report_enabled(UVM_DEBUG,UVM_INFO,"PH_TERMSTATE")) + uvm_report_info ("PH_TERMSTATE", $sformatf("phase %s outstanding objections = %0d", get_name(), phase_done.get_objection_total(top)), UVM_DEBUG, "t/uvm/src/base/uvm_phase.svh", 2309, "", 1); + end + end + else begin + begin + if (uvm_report_enabled(UVM_DEBUG,UVM_INFO,"PH_TERMSTATE")) + uvm_report_info ("PH_TERMSTATE", $sformatf("phase %s has no outstanding objections", get_name()), UVM_DEBUG, "t/uvm/src/base/uvm_phase.svh", 2315, "", 1); + end + end +endfunction +typedef class uvm_build_phase; +typedef class uvm_connect_phase; +typedef class uvm_end_of_elaboration_phase; +typedef class uvm_start_of_simulation_phase; +typedef class uvm_run_phase; +typedef class uvm_extract_phase; +typedef class uvm_check_phase; +typedef class uvm_report_phase; +typedef class uvm_final_phase; +typedef class uvm_pre_reset_phase; +typedef class uvm_reset_phase; +typedef class uvm_post_reset_phase; +typedef class uvm_pre_configure_phase; +typedef class uvm_configure_phase; +typedef class uvm_post_configure_phase; +typedef class uvm_pre_main_phase; +typedef class uvm_main_phase; +typedef class uvm_post_main_phase; +typedef class uvm_pre_shutdown_phase; +typedef class uvm_shutdown_phase; +typedef class uvm_post_shutdown_phase; +uvm_phase build_ph; +uvm_phase connect_ph; +uvm_phase end_of_elaboration_ph; +uvm_phase start_of_simulation_ph; +uvm_phase run_ph; +uvm_phase extract_ph; +uvm_phase check_ph; +uvm_phase report_ph; +class uvm_domain extends uvm_phase; + static local uvm_domain m_uvm_domain; + static local uvm_domain m_domains[string]; + static local uvm_phase m_uvm_schedule; + static function void get_domains(output uvm_domain domains[string]); + domains = m_domains; + endfunction + static function uvm_phase get_uvm_schedule(); + void'(get_uvm_domain()); + return m_uvm_schedule; + endfunction + static function uvm_domain get_common_domain(); + uvm_domain domain; + if(m_domains.exists("common")) + domain = m_domains["common"]; + if (domain != null) + return domain; + domain = new("common"); + domain.add(uvm_build_phase::get()); + domain.add(uvm_connect_phase::get()); + domain.add(uvm_end_of_elaboration_phase::get()); + domain.add(uvm_start_of_simulation_phase::get()); + domain.add(uvm_run_phase::get()); + domain.add(uvm_extract_phase::get()); + domain.add(uvm_check_phase::get()); + domain.add(uvm_report_phase::get()); + domain.add(uvm_final_phase::get()); + build_ph = domain.find(uvm_build_phase::get()); + connect_ph = domain.find(uvm_connect_phase::get()); + end_of_elaboration_ph = domain.find(uvm_end_of_elaboration_phase::get()); + start_of_simulation_ph = domain.find(uvm_start_of_simulation_phase::get()); + run_ph = domain.find(uvm_run_phase::get()); + extract_ph = domain.find(uvm_extract_phase::get()); + check_ph = domain.find(uvm_check_phase::get()); + report_ph = domain.find(uvm_report_phase::get()); + domain = get_uvm_domain(); + m_domains["common"].add(domain, + .with_phase(m_domains["common"].find(uvm_run_phase::get()))); + return m_domains["common"]; + endfunction + static function void add_uvm_phases(uvm_phase schedule); + schedule.add(uvm_pre_reset_phase::get()); + schedule.add(uvm_reset_phase::get()); + schedule.add(uvm_post_reset_phase::get()); + schedule.add(uvm_pre_configure_phase::get()); + schedule.add(uvm_configure_phase::get()); + schedule.add(uvm_post_configure_phase::get()); + schedule.add(uvm_pre_main_phase::get()); + schedule.add(uvm_main_phase::get()); + schedule.add(uvm_post_main_phase::get()); + schedule.add(uvm_pre_shutdown_phase::get()); + schedule.add(uvm_shutdown_phase::get()); + schedule.add(uvm_post_shutdown_phase::get()); + endfunction + static function uvm_domain get_uvm_domain(); + if (m_uvm_domain == null) begin + m_uvm_domain = new("uvm"); + m_uvm_schedule = new("uvm_sched", UVM_PHASE_SCHEDULE); + add_uvm_phases(m_uvm_schedule); + m_uvm_domain.add(m_uvm_schedule); + end + return m_uvm_domain; + endfunction + function new(string name); + super.new(name,UVM_PHASE_DOMAIN); + if (m_domains.exists(name)) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UNIQDOMNAM")) + uvm_report_error ("UNIQDOMNAM", $sformatf("Domain created with non-unique name '%s'", name), UVM_NONE, "t/uvm/src/base/uvm_domain.svh", 183, "", 1); + end + m_domains[name] = this; + endfunction + function void jump(uvm_phase phase); + uvm_phase phases[$]; + m_get_transitive_children(phases); + phases = phases.find(item) with (item.get_state() inside {[UVM_PHASE_STARTED:UVM_PHASE_CLEANUP]}); + foreach(phases[idx]) + if(phases[idx].is_before(phase) || phases[idx].is_after(phase)) + phases[idx].jump(phase); + endfunction + static function void jump_all(uvm_phase phase); + uvm_domain domains[string]; + uvm_domain::get_domains(domains); + foreach(domains[idx]) + domains[idx].jump(phase); + endfunction +endclass +virtual class uvm_bottomup_phase extends uvm_phase; + function new(string name); + super.new(name,UVM_PHASE_IMP); + endfunction + virtual function void traverse(uvm_component comp, + uvm_phase phase, + uvm_phase_state state); + string name; + uvm_domain phase_domain =phase.get_domain(); + uvm_domain comp_domain = comp.get_domain(); + if (comp.get_first_child(name)) + do + traverse(comp.get_child(name), phase, state); + while(comp.get_next_child(name)); + if (m_phase_trace) + begin + if (uvm_report_enabled(UVM_DEBUG,UVM_INFO,"PH_TRACE")) + uvm_report_info ("PH_TRACE", $sformatf("bottomup-phase phase=%s state=%s comp=%s comp.domain=%s phase.domain=%s", phase.get_name(), state.name(), comp.get_full_name(),comp_domain.get_name(),phase_domain.get_name()), UVM_DEBUG, "t/uvm/src/base/uvm_bottomup_phase.svh", 64, "", 1); + end + if (phase_domain == uvm_domain::get_common_domain() || + phase_domain == comp_domain) begin + case (state) + UVM_PHASE_STARTED: begin + comp.m_current_phase = phase; + comp.m_apply_verbosity_settings(phase); + comp.phase_started(phase); + end + UVM_PHASE_EXECUTING: begin + uvm_phase ph = this; + if (comp.m_phase_imps.exists(this)) + ph = comp.m_phase_imps[this]; + ph.execute(comp, phase); + end + UVM_PHASE_READY_TO_END: begin + comp.phase_ready_to_end(phase); + end + UVM_PHASE_ENDED: begin + comp.phase_ended(phase); + comp.m_current_phase = null; + end + default: + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BADEXEC")) + uvm_report_fatal ("PH_BADEXEC", "bottomup phase traverse internal error", UVM_NONE, "t/uvm/src/base/uvm_bottomup_phase.svh", 88, "", 1); + end + endcase + end + endfunction + virtual function void execute(uvm_component comp, + uvm_phase phase); + process proc = process::self(); + proc.srandom(uvm_create_random_seed(phase.get_type_name(), comp.get_full_name())); + comp.m_current_phase = phase; + exec_func(comp,phase); + endfunction +endclass +virtual class uvm_topdown_phase extends uvm_phase; + function new(string name); + super.new(name,UVM_PHASE_IMP); + endfunction + virtual function void traverse(uvm_component comp, + uvm_phase phase, + uvm_phase_state state); + string name; + uvm_domain phase_domain = phase.get_domain(); + uvm_domain comp_domain = comp.get_domain(); + if (m_phase_trace) + begin + if (uvm_report_enabled(UVM_DEBUG,UVM_INFO,"PH_TRACE")) + uvm_report_info ("PH_TRACE", $sformatf("topdown-phase phase=%s state=%s comp=%s comp.domain=%s phase.domain=%s", phase.get_name(), state.name(), comp.get_full_name(),comp_domain.get_name(),phase_domain.get_name()), UVM_DEBUG, "t/uvm/src/base/uvm_topdown_phase.svh", 59, "", 1); + end + if (phase_domain == uvm_domain::get_common_domain() || + phase_domain == comp_domain) begin + case (state) + UVM_PHASE_STARTED: begin + comp.m_current_phase = phase; + comp.m_apply_verbosity_settings(phase); + comp.phase_started(phase); + end + UVM_PHASE_EXECUTING: begin + if (!(phase.get_name() == "build" && comp.m_build_done)) begin + uvm_phase ph = this; + comp.m_phasing_active++; + if (comp.m_phase_imps.exists(this)) + ph = comp.m_phase_imps[this]; + ph.execute(comp, phase); + comp.m_phasing_active--; + end + end + UVM_PHASE_READY_TO_END: begin + comp.phase_ready_to_end(phase); + end + UVM_PHASE_ENDED: begin + comp.phase_ended(phase); + comp.m_current_phase = null; + end + default: + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BADEXEC")) + uvm_report_fatal ("PH_BADEXEC", "topdown phase traverse internal error", UVM_NONE, "t/uvm/src/base/uvm_topdown_phase.svh", 87, "", 1); + end + endcase + end + if(comp.get_first_child(name)) + do + traverse(comp.get_child(name), phase, state); + while(comp.get_next_child(name)); + endfunction + virtual function void execute(uvm_component comp, + uvm_phase phase); + process proc = process::self(); + proc.srandom(uvm_create_random_seed(phase.get_type_name(), comp.get_full_name())); + comp.m_current_phase = phase; + exec_func(comp,phase); + endfunction +endclass +virtual class uvm_task_phase extends uvm_phase; + function new(string name); + super.new(name,UVM_PHASE_IMP); + endfunction + virtual function void traverse(uvm_component comp, + uvm_phase phase, + uvm_phase_state state); + phase.m_num_procs_not_yet_returned = 0; + m_traverse(comp, phase, state); + endfunction + function void m_traverse(uvm_component comp, + uvm_phase phase, + uvm_phase_state state); + string name; + uvm_domain phase_domain =phase.get_domain(); + uvm_domain comp_domain = comp.get_domain(); + uvm_sequencer_base seqr; + if (comp.get_first_child(name)) + do + m_traverse(comp.get_child(name), phase, state); + while(comp.get_next_child(name)); + if (m_phase_trace) + begin + if (uvm_report_enabled(UVM_DEBUG,UVM_INFO,"PH_TRACE")) + uvm_report_info ("PH_TRACE", $sformatf("topdown-phase phase=%s state=%s comp=%s comp.domain=%s phase.domain=%s", phase.get_name(), state.name(), comp.get_full_name(),comp_domain.get_name(),phase_domain.get_name()), UVM_DEBUG, "t/uvm/src/base/uvm_task_phase.svh", 94, "", 1); + end + if (phase_domain == uvm_domain::get_common_domain() || + phase_domain == comp_domain) begin + case (state) + UVM_PHASE_STARTED: begin + comp.m_current_phase = phase; + comp.m_apply_verbosity_settings(phase); + comp.phase_started(phase); + if ($cast(seqr, comp)) + seqr.start_phase_sequence(phase); + end + UVM_PHASE_EXECUTING: begin + uvm_phase ph = this; + if (comp.m_phase_imps.exists(this)) + ph = comp.m_phase_imps[this]; + ph.execute(comp, phase); + end + UVM_PHASE_READY_TO_END: begin + comp.phase_ready_to_end(phase); + end + UVM_PHASE_ENDED: begin + if ($cast(seqr, comp)) + seqr.stop_phase_sequence(phase); + comp.phase_ended(phase); + comp.m_current_phase = null; + end + default: + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BADEXEC")) + uvm_report_fatal ("PH_BADEXEC", "task phase traverse internal error", UVM_NONE, "t/uvm/src/base/uvm_task_phase.svh", 122, "", 1); + end + endcase + end + endfunction + virtual function void execute(uvm_component comp, + uvm_phase phase); + fork + begin + process proc; + proc = process::self(); + proc.srandom(uvm_create_random_seed(phase.get_type_name(), comp.get_full_name())); + phase.m_num_procs_not_yet_returned++; + exec_task(comp,phase); + phase.m_num_procs_not_yet_returned--; + end + join_none + endfunction +endclass +class uvm_build_phase extends uvm_topdown_phase; + virtual function void exec_func(uvm_component comp, uvm_phase phase); + comp.build_phase(phase); + endfunction + local static uvm_build_phase m_inst; + static function string type_name(); + return "uvm_build_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_build_phase"; + endfunction : get_type_name + static function uvm_build_phase get(); + if(m_inst == null) + m_inst = new(); + return m_inst; + endfunction + protected function new(string name="build"); + super.new(name); + endfunction +endclass +class uvm_connect_phase extends uvm_bottomup_phase; + virtual function void exec_func(uvm_component comp, uvm_phase phase); + comp.connect_phase(phase); + endfunction + local static uvm_connect_phase m_inst; + static function string type_name(); + return "uvm_connect_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_connect_phase"; + endfunction : get_type_name + static function uvm_connect_phase get(); + if(m_inst == null) + m_inst = new(); + return m_inst; + endfunction + protected function new(string name="connect"); + super.new(name); + endfunction +endclass +class uvm_end_of_elaboration_phase extends uvm_bottomup_phase; + virtual function void exec_func(uvm_component comp, uvm_phase phase); + comp.end_of_elaboration_phase(phase); + endfunction + local static uvm_end_of_elaboration_phase m_inst; + static function string type_name(); + return "uvm_end_of_elaboration_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_end_of_elaboration_phase"; + endfunction : get_type_name + static function uvm_end_of_elaboration_phase get(); + if(m_inst == null) begin + m_inst = new(); + end + return m_inst; + endfunction + protected function new(string name="end_of_elaboration"); + super.new(name); + endfunction +endclass +class uvm_start_of_simulation_phase extends uvm_bottomup_phase; + virtual function void exec_func(uvm_component comp, uvm_phase phase); + comp.start_of_simulation_phase(phase); + endfunction + local static uvm_start_of_simulation_phase m_inst; + static function string type_name(); + return "uvm_start_of_simulation_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_start_of_simulation_phase"; + endfunction : get_type_name + static function uvm_start_of_simulation_phase get(); + if(m_inst == null) + m_inst = new(); + return m_inst; + endfunction + protected function new(string name="start_of_simulation"); + super.new(name); + endfunction +endclass +class uvm_run_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.run_phase(phase); + endtask + local static uvm_run_phase m_inst; + static function string type_name(); + return "uvm_run_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_run_phase"; + endfunction : get_type_name + static function uvm_run_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="run"); + super.new(name); + endfunction +endclass +class uvm_extract_phase extends uvm_bottomup_phase; + virtual function void exec_func(uvm_component comp, uvm_phase phase); + comp.extract_phase(phase); + endfunction + local static uvm_extract_phase m_inst; + static function string type_name(); + return "uvm_extract_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_extract_phase"; + endfunction : get_type_name + static function uvm_extract_phase get(); + if(m_inst == null) + m_inst = new(); + return m_inst; + endfunction + protected function new(string name="extract"); + super.new(name); + endfunction +endclass +class uvm_check_phase extends uvm_bottomup_phase; + virtual function void exec_func(uvm_component comp, uvm_phase phase); + comp.check_phase(phase); + endfunction + local static uvm_check_phase m_inst; + static function string type_name(); + return "uvm_check_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_check_phase"; + endfunction : get_type_name + static function uvm_check_phase get(); + if(m_inst == null) + m_inst = new(); + return m_inst; + endfunction + protected function new(string name="check"); + super.new(name); + endfunction +endclass +class uvm_report_phase extends uvm_bottomup_phase; + virtual function void exec_func(uvm_component comp, uvm_phase phase); + comp.report_phase(phase); + endfunction + local static uvm_report_phase m_inst; + static function string type_name(); + return "uvm_report_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_report_phase"; + endfunction : get_type_name + static function uvm_report_phase get(); + if(m_inst == null) + m_inst = new(); + return m_inst; + endfunction + protected function new(string name="report"); + super.new(name); + endfunction +endclass +class uvm_final_phase extends uvm_topdown_phase; + virtual function void exec_func(uvm_component comp, uvm_phase phase); + comp.final_phase(phase); + endfunction + local static uvm_final_phase m_inst; + static function string type_name(); + return "uvm_final_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_final_phase"; + endfunction : get_type_name + static function uvm_final_phase get(); + if(m_inst == null) + m_inst = new(); + return m_inst; + endfunction + protected function new(string name="final"); + super.new(name); + endfunction +endclass +class uvm_pre_reset_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.pre_reset_phase(phase); + endtask + local static uvm_pre_reset_phase m_inst; + static function string type_name(); + return "uvm_pre_reset_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_pre_reset_phase"; + endfunction : get_type_name + static function uvm_pre_reset_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="pre_reset"); + super.new(name); + endfunction +endclass +class uvm_reset_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.reset_phase(phase); + endtask + local static uvm_reset_phase m_inst; + static function string type_name(); + return "uvm_reset_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_reset_phase"; + endfunction : get_type_name + static function uvm_reset_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="reset"); + super.new(name); + endfunction +endclass +class uvm_post_reset_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.post_reset_phase(phase); + endtask + local static uvm_post_reset_phase m_inst; + static function string type_name(); + return "uvm_post_reset_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_post_reset_phase"; + endfunction : get_type_name + static function uvm_post_reset_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="post_reset"); + super.new(name); + endfunction +endclass +class uvm_pre_configure_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.pre_configure_phase(phase); + endtask + local static uvm_pre_configure_phase m_inst; + static function string type_name(); + return "uvm_pre_configure_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_pre_configure_phase"; + endfunction : get_type_name + static function uvm_pre_configure_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="pre_configure"); + super.new(name); + endfunction +endclass +class uvm_configure_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.configure_phase(phase); + endtask + local static uvm_configure_phase m_inst; + static function string type_name(); + return "uvm_configure_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_configure_phase"; + endfunction : get_type_name + static function uvm_configure_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="configure"); + super.new(name); + endfunction +endclass +class uvm_post_configure_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.post_configure_phase(phase); + endtask + local static uvm_post_configure_phase m_inst; + static function string type_name(); + return "uvm_post_configure_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_post_configure_phase"; + endfunction : get_type_name + static function uvm_post_configure_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="post_configure"); + super.new(name); + endfunction +endclass +class uvm_pre_main_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.pre_main_phase(phase); + endtask + local static uvm_pre_main_phase m_inst; + static function string type_name(); + return "uvm_pre_main_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_pre_main_phase"; + endfunction : get_type_name + static function uvm_pre_main_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="pre_main"); + super.new(name); + endfunction +endclass +class uvm_main_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.main_phase(phase); + endtask + local static uvm_main_phase m_inst; + static function string type_name(); + return "uvm_main_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_main_phase"; + endfunction : get_type_name + static function uvm_main_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="main"); + super.new(name); + endfunction +endclass +class uvm_post_main_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.post_main_phase(phase); + endtask + local static uvm_post_main_phase m_inst; + static function string type_name(); + return "uvm_post_main_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_post_main_phase"; + endfunction : get_type_name + static function uvm_post_main_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="post_main"); + super.new(name); + endfunction +endclass +class uvm_pre_shutdown_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.pre_shutdown_phase(phase); + endtask + local static uvm_pre_shutdown_phase m_inst; + static function string type_name(); + return "uvm_pre_shutdown_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_pre_shutdown_phase"; + endfunction : get_type_name + static function uvm_pre_shutdown_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="pre_shutdown"); + super.new(name); + endfunction +endclass +class uvm_shutdown_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.shutdown_phase(phase); + endtask + local static uvm_shutdown_phase m_inst; + static function string type_name(); + return "uvm_shutdown_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_shutdown_phase"; + endfunction : get_type_name + static function uvm_shutdown_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="shutdown"); + super.new(name); + endfunction +endclass +class uvm_post_shutdown_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.post_shutdown_phase(phase); + endtask + local static uvm_post_shutdown_phase m_inst; + static function string type_name(); + return "uvm_post_shutdown_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_post_shutdown_phase"; + endfunction : get_type_name + static function uvm_post_shutdown_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="post_shutdown"); + super.new(name); + endfunction +endclass +virtual class uvm_run_test_callback extends uvm_callback; + extern function new( string name="uvm_run_test_callback"); + virtual function void pre_run_test(); + endfunction + virtual function void post_run_test(); + endfunction + virtual function void pre_abort(); + endfunction + extern static function bit add( uvm_run_test_callback cb ); + extern static function bit delete( uvm_run_test_callback cb ); + extern static function void m_do_pre_run_test(); + extern static function void m_do_post_run_test(); + extern static function void m_do_pre_abort(); + local static uvm_run_test_callback m_registered_cbs[$]; +endclass : uvm_run_test_callback +function uvm_run_test_callback::new( string name="uvm_run_test_callback"); + super.new( name ); +endfunction +function bit uvm_run_test_callback::add( uvm_run_test_callback cb ); + bit found; + int unsigned i; + if ( cb == null ) begin + return 0; + end + found = 0; + i = 0; + while ( ! found && ( i < m_registered_cbs.size() ) ) begin + if ( m_registered_cbs[ i ] == cb ) begin + found = 1; + end + ++i; + end + if ( ! found ) begin + m_registered_cbs.push_back( cb ); + end + return ! found; +endfunction +function bit uvm_run_test_callback::delete( uvm_run_test_callback cb ); + int cb_idxs[$]; + if ( cb == null ) begin + return 0; + end + cb_idxs = m_registered_cbs.find_index( item ) with ( item == cb ); + foreach ( cb_idxs[ i ] ) begin + m_registered_cbs.delete( i ); + end + return ( cb_idxs.size() > 0 ); +endfunction +function void uvm_run_test_callback::m_do_pre_run_test(); + foreach ( m_registered_cbs[ i ] ) begin + m_registered_cbs[ i ].pre_run_test(); + end +endfunction +function void uvm_run_test_callback::m_do_post_run_test(); + foreach ( m_registered_cbs[ i ] ) begin + m_registered_cbs[ i ].post_run_test(); + end +endfunction +function void uvm_run_test_callback::m_do_pre_abort(); + foreach ( m_registered_cbs[ i ] ) begin + m_registered_cbs[ i ].pre_abort(); + end +endfunction +typedef class uvm_objection; +typedef class uvm_sequence_base; +typedef class uvm_sequence_item; +virtual class uvm_component extends uvm_report_object; + extern function new (string name, uvm_component parent); + extern virtual function uvm_component get_parent (); + extern virtual function string get_full_name (); + extern function void get_children(ref uvm_component children[$]); + extern function uvm_component get_child (string name); + extern function int get_next_child (ref string name); + extern function int get_first_child (ref string name); + extern function int get_num_children (); + extern function int has_child (string name); + extern virtual function void set_name (string name); + extern function uvm_component lookup (string name); + extern function int unsigned get_depth(); + extern virtual function void build_phase(uvm_phase phase); + extern virtual function void connect_phase(uvm_phase phase); + extern virtual function void end_of_elaboration_phase(uvm_phase phase); + extern virtual function void start_of_simulation_phase(uvm_phase phase); + extern virtual task run_phase(uvm_phase phase); + extern virtual task pre_reset_phase(uvm_phase phase); + extern virtual task reset_phase(uvm_phase phase); + extern virtual task post_reset_phase(uvm_phase phase); + extern virtual task pre_configure_phase(uvm_phase phase); + extern virtual task configure_phase(uvm_phase phase); + extern virtual task post_configure_phase(uvm_phase phase); + extern virtual task pre_main_phase(uvm_phase phase); + extern virtual task main_phase(uvm_phase phase); + extern virtual task post_main_phase(uvm_phase phase); + extern virtual task pre_shutdown_phase(uvm_phase phase); + extern virtual task shutdown_phase(uvm_phase phase); + extern virtual task post_shutdown_phase(uvm_phase phase); + extern virtual function void extract_phase(uvm_phase phase); + extern virtual function void check_phase(uvm_phase phase); + extern virtual function void report_phase(uvm_phase phase); + extern virtual function void final_phase(uvm_phase phase); + extern virtual function void phase_started (uvm_phase phase); + extern virtual function void phase_ready_to_end (uvm_phase phase); + extern virtual function void phase_ended (uvm_phase phase); + extern function void set_domain(uvm_domain domain, int hier=1); + extern function uvm_domain get_domain(); + extern virtual protected function void define_domain(uvm_domain domain); + extern virtual task suspend (); + extern virtual task resume (); + extern virtual function void resolve_bindings (); + extern function string massage_scope(string scope); + extern virtual function void apply_config_settings (bit verbose = 0); + extern virtual function bit use_automatic_config(); + extern function void print_config(bit recurse = 0, bit audit = 0); + extern function void print_config_with_audit(bit recurse = 0); + static bit print_config_matches; + virtual function void raised (uvm_objection objection, uvm_object source_obj, + string description, int count); + endfunction + virtual function void dropped (uvm_objection objection, uvm_object source_obj, + string description, int count); + endfunction + virtual task all_dropped (uvm_objection objection, uvm_object source_obj, + string description, int count); + endtask + extern function uvm_component create_component (string requested_type_name, + string name); + extern function uvm_object create_object (string requested_type_name, + string name=""); + extern static function void set_type_override_by_type + (uvm_object_wrapper original_type, + uvm_object_wrapper override_type, + bit replace=1); + extern function void set_inst_override_by_type(string relative_inst_path, + uvm_object_wrapper original_type, + uvm_object_wrapper override_type); + extern static function void set_type_override(string original_type_name, + string override_type_name, + bit replace=1); + extern function void set_inst_override(string relative_inst_path, + string original_type_name, + string override_type_name); + extern function void print_override_info(string requested_type_name, + string name=""); + extern function void set_report_id_verbosity_hier (string id, + int verbosity); + extern function void set_report_severity_id_verbosity_hier(uvm_severity severity, + string id, + int verbosity); + extern function void set_report_severity_action_hier (uvm_severity severity, + uvm_action action); + extern function void set_report_id_action_hier (string id, + uvm_action action); + extern function void set_report_severity_id_action_hier(uvm_severity severity, + string id, + uvm_action action); + extern function void set_report_default_file_hier (UVM_FILE file); + extern function void set_report_severity_file_hier (uvm_severity severity, + UVM_FILE file); + extern function void set_report_id_file_hier (string id, + UVM_FILE file); + extern function void set_report_severity_id_file_hier(uvm_severity severity, + string id, + UVM_FILE file); + extern function void set_report_verbosity_level_hier (int verbosity); + virtual function void pre_abort; + endfunction + extern function void accept_tr (uvm_transaction tr, time accept_time = 0); + extern virtual protected function void do_accept_tr (uvm_transaction tr); + extern function int begin_tr (uvm_transaction tr, + string stream_name="main", + string label="", + string desc="", + time begin_time=0, + int parent_handle=0); + extern virtual protected + function void do_begin_tr (uvm_transaction tr, + string stream_name, + int tr_handle); + extern function void end_tr (uvm_transaction tr, + time end_time=0, + bit free_handle=1); + extern virtual protected function void do_end_tr (uvm_transaction tr, + int tr_handle); + extern function int record_error_tr (string stream_name="main", + uvm_object info=null, + string label="error_tr", + string desc="", + time error_time=0, + bit keep_active=0); + extern function int record_event_tr (string stream_name="main", + uvm_object info=null, + string label="event_tr", + string desc="", + time event_time=0, + bit keep_active=0); + extern virtual function uvm_tr_stream get_tr_stream(string name, + string stream_type_name=""); + extern virtual function void free_tr_stream(uvm_tr_stream stream); + bit print_enabled = 1; + uvm_tr_database tr_database; + extern virtual function uvm_tr_database get_tr_database(); + extern virtual function void set_tr_database(uvm_tr_database db); + protected uvm_domain m_domain; + uvm_phase m_phase_imps[uvm_phase]; + uvm_phase m_current_phase; + protected process m_phase_process; + bit m_build_done; + int m_phasing_active; + extern function void set_local(uvm_resource_base rsrc) ; + uvm_component m_parent; + protected uvm_component m_children[string]; + protected uvm_component m_children_by_handle[uvm_component]; + extern protected virtual function bit m_add_child(uvm_component child); + extern local virtual function void m_set_full_name(); + extern function void do_resolve_bindings(); + extern function void do_flush(); + extern virtual function void flush (); + extern local function void m_extract_name(string name , + output string leaf , + output string remainder ); + extern virtual function uvm_object create (string name=""); + extern virtual function uvm_object clone (); + local uvm_tr_stream m_streams[string][string]; + local uvm_recorder m_tr_h[uvm_transaction]; + extern protected function int m_begin_tr (uvm_transaction tr, + int parent_handle=0, + string stream_name="main", string label="", + string desc="", time begin_time=0); + string m_name; + typedef uvm_abstract_component_registry#(uvm_component, "uvm_component") type_id; + static function string type_name(); + return "uvm_component"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_component"; + endfunction : get_type_name + protected uvm_event_pool event_pool; + int unsigned recording_detail = UVM_NONE; + extern function void do_print(uvm_printer printer); + extern function void m_set_cl_msg_args; + extern function void m_set_cl_verb; + extern function void m_set_cl_action; + extern function void m_set_cl_sev; + extern function void m_apply_verbosity_settings(uvm_phase phase); + typedef struct { + string comp; + string phase; + time offset; + uvm_verbosity verbosity; + string id; + } m_verbosity_setting; + m_verbosity_setting m_verbosity_settings[$]; + static m_verbosity_setting m_time_settings[$]; + extern function void m_do_pre_abort; + uvm_resource_base m_unsupported_resource_base = null; + extern function void m_unsupported_set_local(uvm_resource_base rsrc); +typedef struct { + string arg; + string args[$]; + int unsigned used; +} uvm_cmdline_parsed_arg_t; +static uvm_cmdline_parsed_arg_t m_uvm_applied_cl_action[$]; +static uvm_cmdline_parsed_arg_t m_uvm_applied_cl_sev[$]; +endclass : uvm_component +typedef class uvm_cmdline_processor; +typedef class uvm_component_proxy; +typedef class uvm_top_down_visitor_adapter; +typedef class uvm_report_message; +typedef class uvm_report_object; +typedef class uvm_report_handler; +typedef class uvm_default_report_server; +class uvm_root extends uvm_component; + extern static function uvm_root get(); + uvm_cmdline_processor clp; + virtual function string get_type_name(); + return "uvm_root"; + endfunction + extern virtual task run_test (string test_name=""); + virtual function void die(); + uvm_report_server l_rs = uvm_report_server::get_server(); + m_uvm_core_state=UVM_CORE_PRE_ABORT; + m_do_pre_abort(); + uvm_run_test_callback::m_do_pre_abort(); + l_rs.report_summarize(); + m_uvm_core_state=UVM_CORE_ABORTED; + $finish; + endfunction + extern function void set_timeout(time timeout, bit overridable=1); + local bit finish_on_completion = 1; + virtual function bit get_finish_on_completion(); + return finish_on_completion; + endfunction : get_finish_on_completion + virtual function void set_finish_on_completion(bit f); + finish_on_completion = f; + endfunction : set_finish_on_completion + extern function uvm_component find (string comp_match); + extern function void find_all (string comp_match, + ref uvm_component comps[$], + input uvm_component comp=null); + extern function void print_topology (uvm_printer printer=null); + bit enable_print_topology = 0; + extern function void set_enable_print_topology (bit enable); + extern function bit get_enable_print_topology (); + time phase_timeout = 9200s; + extern function void m_find_all_recurse(string comp_match, + ref uvm_component comps[$], + input uvm_component comp=null); + extern protected function new (); + extern protected virtual function bit m_add_child (uvm_component child); + extern function void build_phase(uvm_phase phase); + extern local function void m_do_verbosity_settings(); + extern local function void m_do_timeout_settings(); + extern local function void m_do_factory_settings(); + extern local function void m_process_inst_override(string ovr); + extern local function void m_process_type_override(string ovr); + extern local function void m_do_config_settings(); + extern local function void m_do_max_quit_settings(); + extern local function void m_do_dump_args(); + extern local function void m_process_config(string cfg, bit is_int); + extern local function void m_process_default_sequence(string cfg); + extern function void m_check_verbosity(); + extern function void m_check_uvm_field_flag_size(); + extern virtual function void report_header(UVM_FILE file = 0); + static local uvm_root m_inst; + extern virtual task run_phase (uvm_phase phase); + function void phase_started(uvm_phase phase); + if (phase == end_of_elaboration_ph) begin + do_resolve_bindings(); + if (enable_print_topology) print_topology(); + begin + uvm_report_server srvr; + srvr = uvm_report_server::get_server(); + if(srvr.get_severity_count(UVM_ERROR) > 0) begin + uvm_report_fatal("BUILDERR", "stopping due to build errors", UVM_NONE); + end + end + end + endfunction + bit m_phase_all_done; + extern static function uvm_root m_uvm_get_root(); + static local bit m_relnotes_done=0; + function void end_of_elaboration_phase(uvm_phase phase); + uvm_component_proxy p = new("proxy"); + uvm_top_down_visitor_adapter#(uvm_component) adapter = new("adapter"); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_visitor#(uvm_component) v = cs.get_component_visitor(); + adapter.accept(this, v, p); + endfunction +endclass +function uvm_root uvm_root::get(); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + return cs.get_root(); +endfunction +function uvm_root::new(); + uvm_report_handler rh; + super.new("__top__", null); + rh = new("reporter"); + set_report_handler(rh); + if (m_inst != null) begin + begin + if (m_inst.uvm_report_enabled(UVM_NONE,UVM_FATAL,"UVM/ROOT/MULTI")) + m_inst.uvm_report_fatal ("UVM/ROOT/MULTI", "Attempting to construct multiple roots", UVM_NONE, "t/uvm/src/base/uvm_root.svh", 378, "", 1); + end + return; + end + m_inst = this; + clp = uvm_cmdline_processor::get_inst(); +endfunction +function uvm_root uvm_root::m_uvm_get_root(); + if (m_inst == null) begin + uvm_root top; + top = new(); + if (top != m_inst) + return null; + top.m_domain = uvm_domain::get_uvm_domain(); + end + return m_inst; +endfunction +function void uvm_root::report_header(UVM_FILE file = 0); + string q[$]; + uvm_report_server srvr; + uvm_cmdline_processor clp; + string args[$]; + srvr = uvm_report_server::get_server(); + clp = uvm_cmdline_processor::get_inst(); + if (clp.get_arg_matches("+UVM_NO_RELNOTES", args)) return; + if (!m_relnotes_done) begin + q.push_back("\n *********** IMPORTANT RELEASE NOTES ************\n"); + m_relnotes_done = 1; + q.push_back("\n This implementation of the UVM Library deviates from the 1800.2-2017\n"); + q.push_back(" standard. See the DEVIATIONS.md file contained in the release\n"); + q.push_back(" for more details.\n"); + end + q.push_back("\n----------------------------------------------------------------\n"); + q.push_back({uvm_revision_string(),"\n"}); + q.push_back("\n"); + q.push_back("All copyright owners for this kit are listed in NOTICE.txt\n"); + q.push_back("All Rights Reserved Worldwide\n"); + q.push_back("----------------------------------------------------------------\n"); + if(m_relnotes_done) + q.push_back("\n (Specify +UVM_NO_RELNOTES to turn off this notice)\n"); + begin + if (uvm_report_enabled(UVM_LOW,UVM_INFO,"UVM/RELNOTES")) + uvm_report_info ("UVM/RELNOTES", uvm_pkg::m_uvm_string_queue_join(q), UVM_LOW, "t/uvm/src/base/uvm_root.svh", 449, "", 1); + end +endfunction +task uvm_root::run_test(string test_name=""); + uvm_report_server l_rs; + uvm_factory factory; + bit testname_plusarg; + int test_name_count; + string test_names[$]; + string msg; + uvm_component uvm_test_top; + process phase_runner_proc; + uvm_run_test_callback::m_do_pre_run_test(); + factory=uvm_factory::get(); + m_uvm_core_state=UVM_CORE_PRE_RUN; + testname_plusarg = 0; + uvm_objection::m_init_objections(); + m_do_dump_args(); + test_name_count = clp.get_arg_values("+UVM_TESTNAME=", test_names); + if (test_name_count > 0) begin + test_name = test_names[0]; + testname_plusarg = 1; + end + if (test_name_count > 1) begin + string test_list; + string sep; + for (int i = 0; i < test_names.size(); i++) begin + if (i != 0) + sep = ", "; + test_list = {test_list, sep, test_names[i]}; + end + uvm_report_warning("MULTTST", + $sformatf("Multiple (%0d) +UVM_TESTNAME arguments provided on the command line. '%s' will be used. Provided list: %s.", test_name_count, test_name, test_list), UVM_NONE); + end + if (test_name != "") begin + if(m_children.exists("uvm_test_top")) begin + uvm_report_fatal("TTINST", + "An uvm_test_top already exists via a previous call to run_test", UVM_NONE); + #0; + end + $cast(uvm_test_top, factory.create_component_by_name(test_name, + "", "uvm_test_top", null)); + if (uvm_test_top == null) begin + msg = testname_plusarg ? {"command line +UVM_TESTNAME=",test_name} : + {"call to run_test(",test_name,")"}; + uvm_report_fatal("INVTST", + {"Requested test from ",msg, " not found." }, UVM_NONE); + end + end + if (m_children.num() == 0) begin + uvm_report_fatal("NOCOMP", + {"No components instantiated. You must either instantiate", + " at least one component before calling run_test or use", + " run_test to do so. To run a test using run_test,", + " use +UVM_TESTNAME or supply the test name in", + " the argument to run_test(). Exiting simulation."}, UVM_NONE); + return; + end + begin + if(test_name=="") + uvm_report_info("RNTST", "Running test ...", UVM_LOW); + else if (test_name == uvm_test_top.get_type_name()) + uvm_report_info("RNTST", {"Running test ",test_name,"..."}, UVM_LOW); + else + uvm_report_info("RNTST", {"Running test ",uvm_test_top.get_type_name()," (via factory override for test \"",test_name,"\")..."}, UVM_LOW); + end + fork begin + phase_runner_proc = process::self(); + uvm_phase::m_run_phases(); + end + join_none + #0; + wait (m_phase_all_done == 1); + m_uvm_core_state=UVM_CORE_POST_RUN; + phase_runner_proc.kill(); + l_rs = uvm_report_server::get_server(); + uvm_run_test_callback::m_do_post_run_test(); + l_rs.report_summarize(); + m_uvm_core_state=UVM_CORE_FINISHED; + if (get_finish_on_completion()) + $finish; +endtask +function void uvm_root::find_all(string comp_match, ref uvm_component comps[$], + input uvm_component comp=null); + if (comp==null) + comp = this; + m_find_all_recurse(comp_match, comps, comp); +endfunction +function uvm_component uvm_root::find (string comp_match); + uvm_component comp_list[$]; + find_all(comp_match,comp_list); + if (comp_list.size() > 1) + uvm_report_warning("MMATCH", + $sformatf("Found %0d components matching '%s'. Returning first match, %0s.", + comp_list.size(),comp_match,comp_list[0].get_full_name()), UVM_NONE); + if (comp_list.size() == 0) begin + uvm_report_warning("CMPNFD", + {"Component matching '",comp_match, + "' was not found in the list of uvm_components"}, UVM_NONE); + return null; + end + return comp_list[0]; +endfunction +function void uvm_root::print_topology(uvm_printer printer=null); + if (m_children.num()==0) begin + uvm_report_warning("EMTCOMP", "print_topology - No UVM components to print.", UVM_NONE); + return; + end + if (printer==null) + printer = uvm_printer::get_default(); + begin + if (uvm_report_enabled(UVM_NONE,UVM_INFO,"UVMTOP")) + uvm_report_info ("UVMTOP", "UVM testbench topology:", UVM_NONE, "t/uvm/src/base/uvm_root.svh", 640, "", 1); + end + print(printer) ; +endfunction +function void uvm_root::set_timeout(time timeout, bit overridable=1); + static bit m_uvm_timeout_overridable = 1; + if (m_uvm_timeout_overridable == 0) begin + uvm_report_info("NOTIMOUTOVR", + $sformatf("The global timeout setting of %0d is not overridable to %0d due to a previous setting.", + phase_timeout, timeout), UVM_NONE); + return; + end + m_uvm_timeout_overridable = overridable; + phase_timeout = timeout; +endfunction +function void uvm_root::m_find_all_recurse(string comp_match, ref uvm_component comps[$], + input uvm_component comp=null); + string name; + if (comp.get_first_child(name)) + do begin + this.m_find_all_recurse(comp_match, comps, comp.get_child(name)); + end + while (comp.get_next_child(name)); + if (uvm_is_match(comp_match, comp.get_full_name()) && + comp.get_name() != "") + comps.push_back(comp); +endfunction +function bit uvm_root::m_add_child (uvm_component child); + if(super.m_add_child(child)) begin + return 1; + end + else + return 0; +endfunction +function void uvm_root::build_phase(uvm_phase phase); + super.build_phase(phase); + m_set_cl_msg_args(); + m_do_verbosity_settings(); + m_do_timeout_settings(); + m_do_factory_settings(); + m_do_config_settings(); + m_do_max_quit_settings(); +endfunction +function void uvm_root::m_do_verbosity_settings(); + string set_verbosity_settings[$]; + string split_vals[$]; + uvm_verbosity tmp_verb; + void'(clp.get_arg_values("+uvm_set_verbosity=", set_verbosity_settings)); + for(int i = 0; i < set_verbosity_settings.size(); i++) begin + uvm_split_string(set_verbosity_settings[i], ",", split_vals); + if(split_vals.size() < 4 || split_vals.size() > 5) begin + uvm_report_warning("INVLCMDARGS", + $sformatf("Invalid number of arguments found on the command line for setting '+uvm_set_verbosity=%s'. Setting ignored.", + set_verbosity_settings[i]), UVM_NONE, "", ""); + end + if(!clp.m_convert_verb(split_vals[2], tmp_verb)) begin + uvm_report_warning("INVLCMDVERB", + $sformatf("Invalid verbosity found on the command line for setting '%s'.", + set_verbosity_settings[i]), UVM_NONE, "", ""); + end + end +endfunction +function void uvm_root::m_do_timeout_settings(); + string timeout_settings[$]; + string timeout; + string split_timeout[$]; + int timeout_count; + time timeout_int; + string override_spec; + timeout_count = clp.get_arg_values("+UVM_TIMEOUT=", timeout_settings); + if (timeout_count == 0) + return; + else begin + timeout = timeout_settings[0]; + if (timeout_count > 1) begin + string timeout_list; + string sep; + for (int i = 0; i < timeout_settings.size(); i++) begin + if (i != 0) + sep = "; "; + timeout_list = {timeout_list, sep, timeout_settings[i]}; + end + uvm_report_warning("MULTTIMOUT", + $sformatf("Multiple (%0d) +UVM_TIMEOUT arguments provided on the command line. '%s' will be used. Provided list: %s.", + timeout_count, timeout, timeout_list), UVM_NONE); + end + uvm_report_info("TIMOUTSET", + $sformatf("'+UVM_TIMEOUT=%s' provided on the command line is being applied.", timeout), UVM_NONE); + void'($sscanf(timeout,"%d,%s",timeout_int,override_spec)); + case(override_spec) + "YES" : set_timeout(timeout_int, 1); + "NO" : set_timeout(timeout_int, 0); + default : set_timeout(timeout_int, 1); + endcase + end +endfunction +function void uvm_root::m_do_factory_settings(); + string args[$]; + void'(clp.get_arg_matches("/^\\+(UVM_SET_INST_OVERRIDE|uvm_set_inst_override)=/",args)); + foreach(args[i]) begin + m_process_inst_override(args[i].substr(23, args[i].len()-1)); + end + void'(clp.get_arg_matches("/^\\+(UVM_SET_TYPE_OVERRIDE|uvm_set_type_override)=/",args)); + foreach(args[i]) begin + m_process_type_override(args[i].substr(23, args[i].len()-1)); + end +endfunction +function void uvm_root::m_process_inst_override(string ovr); + string split_val[$]; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory=cs.get_factory(); + uvm_split_string(ovr, ",", split_val); + if(split_val.size() != 3 ) begin + uvm_report_error("UVM_CMDLINE_PROC", {"Invalid setting for +uvm_set_inst_override=", ovr, + ", setting must specify ,,"}, UVM_NONE); + return; + end + uvm_report_info("INSTOVR", {"Applying instance override from the command line: +uvm_set_inst_override=", ovr}, UVM_NONE); + factory.set_inst_override_by_name(split_val[0], split_val[1], split_val[2]); +endfunction +function void uvm_root::m_process_type_override(string ovr); + string split_val[$]; + int replace=1; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory=cs.get_factory(); + uvm_split_string(ovr, ",", split_val); + if(split_val.size() > 3 || split_val.size() < 2) begin + uvm_report_error("UVM_CMDLINE_PROC", {"Invalid setting for +uvm_set_type_override=", ovr, + ", setting must specify ,[,]"}, UVM_NONE); + return; + end + if(split_val.size() == 3) begin + if(split_val[2]=="0") replace = 0; + else if (split_val[2] == "1") replace = 1; + else begin + uvm_report_error("UVM_CMDLINE_PROC", {"Invalid replace arg for +uvm_set_type_override=", ovr ," value must be 0 or 1"}, UVM_NONE); + return; + end + end + uvm_report_info("UVM_CMDLINE_PROC", {"Applying type override from the command line: +uvm_set_type_override=", ovr}, UVM_NONE); + factory.set_type_override_by_name(split_val[0], split_val[1], replace); +endfunction +function void uvm_root::m_process_config(string cfg, bit is_int); + uvm_bitstream_t v; + string split_val[$]; + uvm_root m_uvm_top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + m_uvm_top = cs.get_root(); + uvm_split_string(cfg, ",", split_val); + if(split_val.size() == 1) begin + uvm_report_error("UVM_CMDLINE_PROC", {"Invalid +uvm_set_config command\"", cfg, + "\" missing field and value: component is \"", split_val[0], "\""}, UVM_NONE); + return; + end + if(split_val.size() == 2) begin + uvm_report_error("UVM_CMDLINE_PROC", {"Invalid +uvm_set_config command\"", cfg, + "\" missing value: component is \"", split_val[0], "\" field is \"", split_val[1], "\""}, UVM_NONE); + return; + end + if(split_val.size() > 3) begin + uvm_report_error("UVM_CMDLINE_PROC", + $sformatf("Invalid +uvm_set_config command\"%s\" : expected only 3 fields (component, field and value).", cfg), UVM_NONE); + return; + end + if(is_int) begin + if(split_val[2].len() > 2) begin + string base, extval; + base = split_val[2].substr(0,1); + extval = split_val[2].substr(2,split_val[2].len()-1); + case(base) + "'b" : v = extval.atobin(); + "0b" : v = extval.atobin(); + "'o" : v = extval.atooct(); + "'d" : v = extval.atoi(); + "'h" : v = extval.atohex(); + "'x" : v = extval.atohex(); + "0x" : v = extval.atohex(); + default : v = split_val[2].atoi(); + endcase + end + else begin + v = split_val[2].atoi(); + end + uvm_report_info("UVM_CMDLINE_PROC", {"Applying config setting from the command line: +uvm_set_config_int=", cfg}, UVM_NONE); + uvm_config_int::set(m_uvm_top, split_val[0], split_val[1], v); + end + else begin + uvm_report_info("UVM_CMDLINE_PROC", {"Applying config setting from the command line: +uvm_set_config_string=", cfg}, UVM_NONE); + uvm_config_string::set(m_uvm_top, split_val[0], split_val[1], split_val[2]); + end +endfunction +function void uvm_root::m_process_default_sequence(string cfg); + string split_val[$]; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_root m_uvm_top = cs.get_root(); + uvm_factory f = cs.get_factory(); + uvm_object_wrapper w; + uvm_split_string(cfg, ",", split_val); + if(split_val.size() == 1) begin + uvm_report_error("UVM_CMDLINE_PROC", {"Invalid +uvm_set_default_sequence command\"", cfg, + "\" missing phase and type: sequencer is \"", split_val[0], "\""}, UVM_NONE); + return; + end + if(split_val.size() == 2) begin + uvm_report_error("UVM_CMDLINE_PROC", {"Invalid +uvm_set_default_sequence command\"", cfg, + "\" missing type: sequencer is \"", split_val[0], "\" phase is \"", split_val[1], "\""}, UVM_NONE); + return; + end + if(split_val.size() > 3) begin + uvm_report_error("UVM_CMDLINE_PROC", + $sformatf("Invalid +uvm_set_default_sequence command\"%s\" : expected only 3 fields (sequencer, phase and type).", cfg), UVM_NONE); + return; + end + w = f.find_wrapper_by_name(split_val[2]); + if (w == null) begin + uvm_report_error("UVM_CMDLINE_PROC", + $sformatf("Invalid type '%s' provided to +uvm_set_default_sequence", split_val[2]), + UVM_NONE); + return; + end + else begin + uvm_report_info("UVM_CMDLINE_PROC", {"Setting default sequence from the command line: +uvm_set_default_sequence=", cfg}, UVM_NONE); + uvm_config_db#(uvm_object_wrapper)::set(this, {split_val[0], ".", split_val[1]}, "default_sequence", w); + end +endfunction : m_process_default_sequence +function void uvm_root::m_do_config_settings(); + string args[$]; + void'(clp.get_arg_matches("/^\\+(UVM_SET_CONFIG_INT|uvm_set_config_int)=/",args)); + foreach(args[i]) begin + m_process_config(args[i].substr(20, args[i].len()-1), 1); + end + void'(clp.get_arg_matches("/^\\+(UVM_SET_CONFIG_STRING|uvm_set_config_string)=/",args)); + foreach(args[i]) begin + m_process_config(args[i].substr(23, args[i].len()-1), 0); + end + void'(clp.get_arg_matches("/^\\+(UVM_SET_DEFAULT_SEQUENCE|uvm_set_default_sequence)=/", args)); + foreach(args[i]) begin + m_process_default_sequence(args[i].substr(26, args[i].len()-1)); + end +endfunction +function void uvm_root::m_do_max_quit_settings(); + uvm_report_server srvr; + string max_quit_settings[$]; + int max_quit_count; + string max_quit; + string split_max_quit[$]; + int max_quit_int; + srvr = uvm_report_server::get_server(); + max_quit_count = clp.get_arg_values("+UVM_MAX_QUIT_COUNT=", max_quit_settings); + if (max_quit_count == 0) + return; + else begin + max_quit = max_quit_settings[0]; + if (max_quit_count > 1) begin + string max_quit_list; + string sep; + for (int i = 0; i < max_quit_settings.size(); i++) begin + if (i != 0) + sep = "; "; + max_quit_list = {max_quit_list, sep, max_quit_settings[i]}; + end + uvm_report_warning("MULTMAXQUIT", + $sformatf("Multiple (%0d) +UVM_MAX_QUIT_COUNT arguments provided on the command line. '%s' will be used. Provided list: %s.", + max_quit_count, max_quit, max_quit_list), UVM_NONE); + end + uvm_report_info("MAXQUITSET", + $sformatf("'+UVM_MAX_QUIT_COUNT=%s' provided on the command line is being applied.", max_quit), UVM_NONE); + uvm_split_string(max_quit, ",", split_max_quit); + max_quit_int = split_max_quit[0].atoi(); + case(split_max_quit[1]) + "YES" : srvr.set_max_quit_count(max_quit_int, 1); + "NO" : srvr.set_max_quit_count(max_quit_int, 0); + default : srvr.set_max_quit_count(max_quit_int, 1); + endcase + end +endfunction +function void uvm_root::m_do_dump_args(); + string dump_args[$]; + string all_args[$]; + string out_string; + if(clp.get_arg_matches("+UVM_DUMP_CMDLINE_ARGS", dump_args)) begin + clp.get_args(all_args); + foreach (all_args[idx]) begin + uvm_report_info("DUMPARGS", $sformatf("idx=%0d arg=[%s]",idx,all_args[idx]), UVM_NONE); + end + end +endfunction +function void uvm_root::m_check_verbosity(); + string verb_string; + string verb_settings[$]; + int verb_count; + int plusarg; + int verbosity = UVM_MEDIUM; + verb_count = clp.get_arg_values("+UVM_VERBOSITY=", verb_settings); + if (verb_count > 0) begin + verb_string = verb_settings[0]; + plusarg = 1; + end + if (verb_count > 1) begin + string verb_list; + string sep; + for (int i = 0; i < verb_settings.size(); i++) begin + if (i != 0) + sep = ", "; + verb_list = {verb_list, sep, verb_settings[i]}; + end + uvm_report_warning("MULTVERB", + $sformatf("Multiple (%0d) +UVM_VERBOSITY arguments provided on the command line. '%s' will be used. Provided list: %s.", verb_count, verb_string, verb_list), UVM_NONE); + end + if(plusarg == 1) begin + case(verb_string) + "UVM_NONE" : verbosity = UVM_NONE; + "NONE" : verbosity = UVM_NONE; + "UVM_LOW" : verbosity = UVM_LOW; + "LOW" : verbosity = UVM_LOW; + "UVM_MEDIUM" : verbosity = UVM_MEDIUM; + "MEDIUM" : verbosity = UVM_MEDIUM; + "UVM_HIGH" : verbosity = UVM_HIGH; + "HIGH" : verbosity = UVM_HIGH; + "UVM_FULL" : verbosity = UVM_FULL; + "FULL" : verbosity = UVM_FULL; + "UVM_DEBUG" : verbosity = UVM_DEBUG; + "DEBUG" : verbosity = UVM_DEBUG; + default : begin + verbosity = verb_string.atoi(); + if(verbosity > 0) + uvm_report_info("NSTVERB", $sformatf("Non-standard verbosity value, using provided '%0d'.", verbosity), UVM_NONE); + if(verbosity == 0) begin + verbosity = UVM_MEDIUM; + uvm_report_warning("ILLVERB", "Illegal verbosity value, using default of UVM_MEDIUM.", UVM_NONE); + end + end + endcase + end + set_report_verbosity_level_hier(verbosity); +endfunction +function void uvm_root::m_check_uvm_field_flag_size(); + if ( (UVM_FIELD_FLAG_RESERVED_BITS) < UVM_FIELD_FLAG_RESERVED_BITS ) begin + uvm_report_fatal( "BAD_FIELD_FLAG_SZ", + $sformatf( + "Macro UVM_FIELD_FLAG_SIZE is set to %0d which is less than the required minimum of UVM_FIELD_FLAG_RESERVED_BITS (%0d).", + UVM_FIELD_FLAG_RESERVED_BITS, UVM_FIELD_FLAG_RESERVED_BITS + ) + ); + end +endfunction +task uvm_root::run_phase (uvm_phase phase); + foreach(m_uvm_applied_cl_action[idx]) + if(m_uvm_applied_cl_action[idx].used==0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"INVLCMDARGS")) + uvm_report_warning ("INVLCMDARGS", $sformatf("\"+uvm_set_action=%s\" never took effect due to a mismatching component pattern",m_uvm_applied_cl_action[idx].arg), UVM_NONE, "t/uvm/src/base/uvm_root.svh", 1130, "", 1); + end + end + foreach(m_uvm_applied_cl_sev[idx]) + if(m_uvm_applied_cl_sev[idx].used==0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"INVLCMDARGS")) + uvm_report_warning ("INVLCMDARGS", $sformatf("\"+uvm_set_severity=%s\" never took effect due to a mismatching component pattern",m_uvm_applied_cl_sev[idx].arg), UVM_NONE, "t/uvm/src/base/uvm_root.svh", 1134, "", 1); + end + end + if($time > 0) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"RUNPHSTIME")) + uvm_report_fatal ("RUNPHSTIME", {"The run phase must start at time 0, current time is ", $sformatf("%0t", $realtime), ". No non-zero delays are allowed before ", "run_test(), and pre-run user defined phases may not consume ", "simulation time before the start of the run phase."}, UVM_NONE, "t/uvm/src/base/uvm_root.svh", 1141, "", 1); + end +endtask +function void uvm_root::set_enable_print_topology (bit enable); + enable_print_topology = enable; +endfunction +function bit uvm_root::get_enable_print_topology(); + return enable_print_topology; +endfunction +function uvm_component::new (string name, uvm_component parent); + string error_str; + uvm_root top; + uvm_coreservice_t cs; + super.new(name); + if (parent==null && name == "__top__") begin + set_name(""); + return; + end + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + begin + uvm_phase bld; + uvm_domain common; + common = uvm_domain::get_common_domain(); + bld = common.find(uvm_build_phase::get()); + if (bld == null) + uvm_report_fatal("COMP/INTERNAL", + "attempt to find build phase object failed",UVM_NONE); + if (bld.get_state() == UVM_PHASE_DONE) begin + uvm_report_fatal("ILLCRT", {"It is illegal to create a component ('", + name,"' under '", + (parent == null ? top.get_full_name() : parent.get_full_name()), + "') after the build phase has ended."}, + UVM_NONE); + end + end + if (name == "") begin + name.itoa(m_inst_count); + name = {"COMP_", name}; + end + if(parent == this) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"THISPARENT")) + uvm_report_fatal ("THISPARENT", "cannot set the parent of a component to itself", UVM_NONE, "t/uvm/src/base/uvm_component.svh", 1635, "", 1); + end + end + if (parent == null) + parent = top; + if(uvm_report_enabled(UVM_MEDIUM+1, UVM_INFO, "NEWCOMP")) + begin + if (uvm_report_enabled(UVM_MEDIUM+1,UVM_INFO,"NEWCOMP")) + uvm_report_info ("NEWCOMP", {"Creating ", (parent==top?"uvm_top":parent.get_full_name()),".",name}, UVM_MEDIUM+1, "t/uvm/src/base/uvm_component.svh", 1643, "", 1); + end + if (parent.has_child(name) && this != parent.get_child(name)) begin + if (parent == top) begin + error_str = {"Name '",name,"' is not unique to other top-level ", + "instances. If parent is a module, build a unique name by combining the ", + "the module name and component name: $sformatf(\"\%m.\%s\",\"",name,"\")."}; + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"CLDEXT")) + uvm_report_fatal ("CLDEXT", error_str, UVM_NONE, "t/uvm/src/base/uvm_component.svh", 1650, "", 1); + end + end + else + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"CLDEXT")) + uvm_report_fatal ("CLDEXT", $sformatf("Cannot set '%s' as a child of '%s', %s", name, parent.get_full_name(), "which already has a child by that name."), UVM_NONE, "t/uvm/src/base/uvm_component.svh", 1656, "", 1); + end + return; + end + m_parent = parent; + set_name(name); + if (!m_parent.m_add_child(this)) + m_parent = null; + event_pool = new("event_pool"); + m_domain = parent.m_domain; + reseed(); + if (!uvm_config_db #(uvm_bitstream_t)::get(this, "", "recording_detail", recording_detail)) + void'(uvm_config_db #(int)::get(this, "", "recording_detail", recording_detail)); + m_rh.set_name(get_full_name()); + set_report_verbosity_level(parent.get_report_verbosity_level()); + m_set_cl_msg_args(); +endfunction +function bit uvm_component::m_add_child(uvm_component child); + if (m_children.exists(child.get_name()) && + m_children[child.get_name()] != child) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"BDCLD")) + uvm_report_warning ("BDCLD", $sformatf("A child with the name '%0s' (type=%0s) already exists.", child.get_name(), m_children[child.get_name()].get_type_name()), UVM_NONE, "t/uvm/src/base/uvm_component.svh", 1695, "", 1); + end + return 0; + end + if (m_children_by_handle.exists(child)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"BDCHLD")) + uvm_report_warning ("BDCHLD", $sformatf("A child with the name '%0s' %0s %0s'", child.get_name(), "already exists in parent under name '", m_children_by_handle[child].get_name()), UVM_NONE, "t/uvm/src/base/uvm_component.svh", 1704, "", 1); + end + return 0; + end + m_children[child.get_name()] = child; + m_children_by_handle[child] = child; + return 1; +endfunction +function void uvm_component::get_children(ref uvm_component children[$]); + foreach(m_children[i]) + children.push_back(m_children[i]); +endfunction +function int uvm_component::get_first_child(ref string name); + return m_children.first(name); +endfunction +function int uvm_component::get_next_child(ref string name); + return m_children.next(name); +endfunction +function uvm_component uvm_component::get_child(string name); + if (m_children.exists(name)) + return m_children[name]; + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"NOCHILD")) + uvm_report_warning ("NOCHILD", {"Component with name '",name, "' is not a child of component '",get_full_name(),"'"}, UVM_NONE, "t/uvm/src/base/uvm_component.svh", 1754, "", 1); + end + return null; +endfunction +function int uvm_component::has_child(string name); + return m_children.exists(name); +endfunction +function int uvm_component::get_num_children(); + return m_children.num(); +endfunction +function string uvm_component::get_full_name (); + if(m_name == "") + return get_name(); + else + return m_name; +endfunction +function uvm_component uvm_component::get_parent (); + return m_parent; +endfunction +function void uvm_component::set_name (string name); + if(m_name != "") begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"INVSTNM")) + uvm_report_error ("INVSTNM", $sformatf("It is illegal to change the name of a component. The component name will not be changed to \"%s\"", name), UVM_NONE, "t/uvm/src/base/uvm_component.svh", 1801, "", 1); + end + return; + end + super.set_name(name); + m_set_full_name(); +endfunction +function void uvm_component::m_set_full_name(); + uvm_root top; + if ($cast(top, m_parent) || m_parent==null) + m_name = get_name(); + else + m_name = {m_parent.get_full_name(), ".", get_name()}; + foreach (m_children[c]) begin + uvm_component tmp; + tmp = m_children[c]; + tmp.m_set_full_name(); + end +endfunction +function uvm_component uvm_component::lookup( string name ); + string leaf , remainder; + uvm_component comp; + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + comp = this; + m_extract_name(name, leaf, remainder); + if (leaf == "") begin + comp = top; + m_extract_name(remainder, leaf, remainder); + end + if (!comp.has_child(leaf)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"Lookup Error")) + uvm_report_warning ("Lookup Error", $sformatf("Cannot find child %0s",leaf), UVM_NONE, "t/uvm/src/base/uvm_component.svh", 1852, "", 1); + end + return null; + end + if( remainder != "" ) + return comp.m_children[leaf].lookup(remainder); + return comp.m_children[leaf]; +endfunction +function int unsigned uvm_component::get_depth(); + if(m_name == "") return 0; + get_depth = 1; + foreach(m_name[i]) + if(m_name[i] == ".") ++get_depth; +endfunction +function void uvm_component::m_extract_name(input string name , + output string leaf , + output string remainder ); + int i , len; + len = name.len(); + for( i = 0; i < name.len(); i++ ) begin + if( name[i] == "." ) begin + break; + end + end + if( i == len ) begin + leaf = name; + remainder = ""; + return; + end + leaf = name.substr( 0 , i - 1 ); + remainder = name.substr( i + 1 , len - 1 ); + return; +endfunction +function void uvm_component::flush(); + return; +endfunction +function void uvm_component::do_flush(); + foreach( m_children[s] ) + m_children[s].do_flush(); + flush(); +endfunction +function uvm_object uvm_component::create (string name =""); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"ILLCRT")) + uvm_report_error ("ILLCRT", "create cannot be called on a uvm_component. Use create_component instead.", UVM_NONE, "t/uvm/src/base/uvm_component.svh", 1934, "", 1); + end + return null; +endfunction +function uvm_object uvm_component::clone (); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"ILLCLN")) + uvm_report_error ("ILLCLN", $sformatf("Attempting to clone '%s'. Clone cannot be called on a uvm_component. The clone target variable will be set to null.", get_full_name()), UVM_NONE, "t/uvm/src/base/uvm_component.svh", 1943, "", 1); + end + return null; +endfunction +function void uvm_component::print_override_info (string requested_type_name, + string name=""); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory=cs.get_factory(); + factory.debug_create_by_name(requested_type_name, get_full_name(), name); +endfunction +function uvm_component uvm_component::create_component (string requested_type_name, + string name); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory=cs.get_factory(); + return factory.create_component_by_name(requested_type_name, get_full_name(), + name, this); +endfunction +function uvm_object uvm_component::create_object (string requested_type_name, + string name=""); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory=cs.get_factory(); + return factory.create_object_by_name(requested_type_name, + get_full_name(), name); +endfunction +function void uvm_component::set_type_override (string original_type_name, + string override_type_name, + bit replace=1); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory=cs.get_factory(); + factory.set_type_override_by_name(original_type_name,override_type_name, replace); +endfunction +function void uvm_component::set_type_override_by_type (uvm_object_wrapper original_type, + uvm_object_wrapper override_type, + bit replace=1); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory=cs.get_factory(); + factory.set_type_override_by_type(original_type, override_type, replace); +endfunction +function void uvm_component::set_inst_override (string relative_inst_path, + string original_type_name, + string override_type_name); + string full_inst_path; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory=cs.get_factory(); + if (relative_inst_path == "") + full_inst_path = get_full_name(); + else + full_inst_path = {get_full_name(), ".", relative_inst_path}; + factory.set_inst_override_by_name( + original_type_name, + override_type_name, + full_inst_path); +endfunction +function void uvm_component::set_inst_override_by_type (string relative_inst_path, + uvm_object_wrapper original_type, + uvm_object_wrapper override_type); + string full_inst_path; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory=cs.get_factory(); + if (relative_inst_path == "") + full_inst_path = get_full_name(); + else + full_inst_path = {get_full_name(), ".", relative_inst_path}; + factory.set_inst_override_by_type(original_type, override_type, full_inst_path); +endfunction +function void uvm_component::set_report_id_verbosity_hier( string id, int verbosity); + set_report_id_verbosity(id, verbosity); + foreach( m_children[c] ) + m_children[c].set_report_id_verbosity_hier(id, verbosity); +endfunction +function void uvm_component::set_report_severity_id_verbosity_hier( uvm_severity severity, + string id, + int verbosity); + set_report_severity_id_verbosity(severity, id, verbosity); + foreach( m_children[c] ) + m_children[c].set_report_severity_id_verbosity_hier(severity, id, verbosity); +endfunction +function void uvm_component::set_report_severity_action_hier( uvm_severity severity, + uvm_action action); + set_report_severity_action(severity, action); + foreach( m_children[c] ) + m_children[c].set_report_severity_action_hier(severity, action); +endfunction +function void uvm_component::set_report_id_action_hier( string id, uvm_action action); + set_report_id_action(id, action); + foreach( m_children[c] ) + m_children[c].set_report_id_action_hier(id, action); +endfunction +function void uvm_component::set_report_severity_id_action_hier( uvm_severity severity, + string id, + uvm_action action); + set_report_severity_id_action(severity, id, action); + foreach( m_children[c] ) + m_children[c].set_report_severity_id_action_hier(severity, id, action); +endfunction +function void uvm_component::set_report_severity_file_hier( uvm_severity severity, + UVM_FILE file); + set_report_severity_file(severity, file); + foreach( m_children[c] ) + m_children[c].set_report_severity_file_hier(severity, file); +endfunction +function void uvm_component::set_report_default_file_hier( UVM_FILE file); + set_report_default_file(file); + foreach( m_children[c] ) + m_children[c].set_report_default_file_hier(file); +endfunction +function void uvm_component::set_report_id_file_hier( string id, UVM_FILE file); + set_report_id_file(id, file); + foreach( m_children[c] ) + m_children[c].set_report_id_file_hier(id, file); +endfunction +function void uvm_component::set_report_severity_id_file_hier ( uvm_severity severity, + string id, + UVM_FILE file); + set_report_severity_id_file(severity, id, file); + foreach( m_children[c] ) + m_children[c].set_report_severity_id_file_hier(severity, id, file); +endfunction +function void uvm_component::set_report_verbosity_level_hier(int verbosity); + set_report_verbosity_level(verbosity); + foreach( m_children[c] ) + m_children[c].set_report_verbosity_level_hier(verbosity); +endfunction +function void uvm_component::build_phase(uvm_phase phase); + m_build_done = 1; + if (use_automatic_config()) + apply_config_settings(print_config_matches); +endfunction +function void uvm_component::connect_phase(uvm_phase phase); + return; +endfunction +function void uvm_component::start_of_simulation_phase(uvm_phase phase); + return; +endfunction +function void uvm_component::end_of_elaboration_phase(uvm_phase phase); + return; +endfunction +task uvm_component::run_phase(uvm_phase phase); + return; +endtask +function void uvm_component::extract_phase(uvm_phase phase); + return; +endfunction +function void uvm_component::check_phase(uvm_phase phase); + return; +endfunction +function void uvm_component::report_phase(uvm_phase phase); + return; +endfunction +function void uvm_component::final_phase(uvm_phase phase); return; endfunction +task uvm_component::pre_reset_phase(uvm_phase phase); return; endtask +task uvm_component::reset_phase(uvm_phase phase); return; endtask +task uvm_component::post_reset_phase(uvm_phase phase); return; endtask +task uvm_component::pre_configure_phase(uvm_phase phase); return; endtask +task uvm_component::configure_phase(uvm_phase phase); return; endtask +task uvm_component::post_configure_phase(uvm_phase phase); return; endtask +task uvm_component::pre_main_phase(uvm_phase phase); return; endtask +task uvm_component::main_phase(uvm_phase phase); return; endtask +task uvm_component::post_main_phase(uvm_phase phase); return; endtask +task uvm_component::pre_shutdown_phase(uvm_phase phase); return; endtask +task uvm_component::shutdown_phase(uvm_phase phase); return; endtask +task uvm_component::post_shutdown_phase(uvm_phase phase); return; endtask +function void uvm_component::phase_started(uvm_phase phase); +endfunction +function void uvm_component::phase_ended(uvm_phase phase); +endfunction +function void uvm_component::phase_ready_to_end (uvm_phase phase); +endfunction +function void uvm_component::define_domain(uvm_domain domain); + uvm_phase schedule; + schedule = domain.find_by_name("uvm_sched"); + if (schedule == null) begin + uvm_domain common; + schedule = new("uvm_sched", UVM_PHASE_SCHEDULE); + uvm_domain::add_uvm_phases(schedule); + domain.add(schedule); + common = uvm_domain::get_common_domain(); + if (common.find(domain,0) == null) + common.add(domain,.with_phase(uvm_run_phase::get())); + end +endfunction +function void uvm_component::set_domain(uvm_domain domain, int hier=1); + m_domain = domain; + define_domain(domain); + if (hier) + foreach (m_children[c]) + m_children[c].set_domain(domain); +endfunction +function uvm_domain uvm_component::get_domain(); + return m_domain; +endfunction +task uvm_component::suspend(); + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"COMP/SPND/UNIMP")) + uvm_report_warning ("COMP/SPND/UNIMP", "suspend() not implemented", UVM_NONE, "t/uvm/src/base/uvm_component.svh", 2395, "", 1); + end +endtask +task uvm_component::resume(); + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"COMP/RSUM/UNIMP")) + uvm_report_warning ("COMP/RSUM/UNIMP", "resume() not implemented", UVM_NONE, "t/uvm/src/base/uvm_component.svh", 2403, "", 1); + end +endtask +function void uvm_component::resolve_bindings(); + return; +endfunction +function void uvm_component::do_resolve_bindings(); + foreach( m_children[s] ) + m_children[s].do_resolve_bindings(); + resolve_bindings(); +endfunction +function void uvm_component::accept_tr (uvm_transaction tr, + time accept_time=0); + uvm_event#(uvm_object) e; + if(tr == null) + return; + tr.accept_tr(accept_time); + do_accept_tr(tr); + e = event_pool.get("accept_tr"); + if(e!=null) + e.trigger(); +endfunction +function int uvm_component::begin_tr (uvm_transaction tr, + string stream_name="main", + string label="", + string desc="", + time begin_time=0, + int parent_handle=0); + return m_begin_tr(tr, parent_handle, stream_name, label, desc, begin_time); +endfunction + function uvm_tr_database uvm_component::get_tr_database(); + if (tr_database == null) begin + uvm_coreservice_t cs = uvm_coreservice_t::get(); + tr_database = cs.get_default_tr_database(); + end + return tr_database; + endfunction : get_tr_database + function void uvm_component::set_tr_database(uvm_tr_database db); + tr_database = db; + endfunction : set_tr_database +function uvm_tr_stream uvm_component::get_tr_stream( string name, + string stream_type_name="" ); + uvm_tr_database db = get_tr_database(); + if (!m_streams.exists(name) || !m_streams[name].exists(stream_type_name)) + m_streams[name][stream_type_name] = db.open_stream(name, this.get_full_name(), stream_type_name); + return m_streams[name][stream_type_name]; +endfunction : get_tr_stream +function void uvm_component::free_tr_stream(uvm_tr_stream stream); + if (stream == null) + return; + if (!m_streams.exists(stream.get_name()) || + !m_streams[stream.get_name()].exists(stream.get_stream_type_name())) + return; + if (m_streams[stream.get_name()][stream.get_stream_type_name()] != stream) + return; + m_streams[stream.get_name()].delete(stream.get_type_name()); + if (m_streams[stream.get_name()].size() == 0) + m_streams.delete(stream.get_name()); + if (stream.is_open() || stream.is_closed()) begin + stream.free(); + end +endfunction : free_tr_stream +function int uvm_component::m_begin_tr (uvm_transaction tr, + int parent_handle=0, + string stream_name="main", + string label="", + string desc="", + time begin_time=0); + uvm_event#(uvm_object) e; + string name; + string kind; + uvm_tr_database db; + int handle, link_handle; + uvm_tr_stream stream; + uvm_recorder recorder, parent_recorder, link_recorder; + if (tr == null) + return 0; + db = get_tr_database(); + if (parent_handle != 0) + parent_recorder = uvm_recorder::get_recorder_from_handle(parent_handle); + if (parent_recorder == null) begin + uvm_sequence_item seq; + if ($cast(seq,tr)) begin + uvm_sequence_base parent_seq = seq.get_parent_sequence(); + if (parent_seq != null) begin + parent_recorder = parent_seq.m_tr_recorder; + end + end + end + if(parent_recorder != null) begin + link_handle = tr.begin_child_tr(begin_time, parent_recorder.get_handle()); + end + else begin + link_handle = tr.begin_tr(begin_time); + end + if (link_handle != 0) + link_recorder = uvm_recorder::get_recorder_from_handle(link_handle); + if (tr.get_name() != "") + name = tr.get_name(); + else + name = tr.get_type_name(); + if (uvm_verbosity'(recording_detail) != UVM_NONE) begin + if (stream_name == "") + stream_name = "main"; + stream = get_tr_stream(stream_name, "TVM"); + if (stream != null ) begin + kind = (parent_recorder == null) ? "Begin_No_Parent, Link" : "Begin_End, Link"; + recorder = stream.open_recorder(name, begin_time, kind); + if (recorder != null) begin + if (label != "") + recorder.record_string("label", label); + if (desc != "") + recorder.record_string("desc", desc); + if (parent_recorder != null) begin + tr_database.establish_link(uvm_parent_child_link::get_link(parent_recorder, + recorder)); + end + if (link_recorder != null) begin + tr_database.establish_link(uvm_related_link::get_link(recorder, + link_recorder)); + end + m_tr_h[tr] = recorder; + end + end + handle = (recorder == null) ? 0 : recorder.get_handle(); + do_begin_tr(tr, stream_name, handle); + end + e = event_pool.get("begin_tr"); + if (e!=null) + e.trigger(tr); + return handle; +endfunction +function void uvm_component::end_tr (uvm_transaction tr, + time end_time=0, + bit free_handle=1); + uvm_event#(uvm_object) e; + uvm_recorder recorder; + if (tr == null) + return; + tr.end_tr(end_time,free_handle); + if (uvm_verbosity'(recording_detail) != UVM_NONE) begin + if (m_tr_h.exists(tr)) begin + recorder = m_tr_h[tr]; + do_end_tr(tr, recorder.get_handle()); + m_tr_h.delete(tr); + tr.record(recorder); + recorder.close(end_time); + if (free_handle) + recorder.free(); + end + else begin + do_end_tr(tr, 0); + end + end + e = event_pool.get("end_tr"); + if(e!=null) + e.trigger(); +endfunction +function int uvm_component::record_error_tr (string stream_name="main", + uvm_object info=null, + string label="error_tr", + string desc="", + time error_time=0, + bit keep_active=0); + uvm_recorder recorder; + string etype; + uvm_tr_stream stream; + int handle; + if(keep_active) etype = "Error, Link"; + else etype = "Error"; + if(error_time == 0) error_time = $realtime; + if (stream_name == "") + stream_name = "main"; + stream = get_tr_stream(stream_name, "TVM"); + handle = 0; + if (stream != null) begin + recorder = stream.open_recorder(label, + error_time, + etype); + if (recorder != null) begin + if (label != "") + recorder.record_string("label", label); + if (desc != "") + recorder.record_string("desc", desc); + if (info!=null) + info.record(recorder); + recorder.close(error_time); + if (keep_active == 0) begin + recorder.free(); + end + else begin + handle = recorder.get_handle(); + end + end + end + return handle; +endfunction +function int uvm_component::record_event_tr (string stream_name="main", + uvm_object info=null, + string label="event_tr", + string desc="", + time event_time=0, + bit keep_active=0); + uvm_recorder recorder; + string etype; + int handle; + uvm_tr_stream stream; + if(keep_active) etype = "Event, Link"; + else etype = "Event"; + if(event_time == 0) event_time = $realtime; + if (stream_name == "") + stream_name = "main"; + stream = get_tr_stream(stream_name, "TVM"); + handle = 0; + if (stream != null) begin + recorder = stream.open_recorder(label, + event_time, + etype); + if (recorder != null) begin + if (label != "") + recorder.record_string("label", label); + if (desc != "") + recorder.record_string("desc", desc); + if (info!=null) + info.record(recorder); + recorder.close(event_time); + if (keep_active == 0) begin + recorder.free(); + end + else begin + handle = recorder.get_handle(); + end + end + end + return handle; +endfunction +function void uvm_component::do_accept_tr (uvm_transaction tr); + return; +endfunction +function void uvm_component::do_begin_tr (uvm_transaction tr, + string stream_name, + int tr_handle); + return; +endfunction +function void uvm_component::do_end_tr (uvm_transaction tr, + int tr_handle); + return; +endfunction +function string uvm_component::massage_scope(string scope); + if(scope == "") + return "^$"; + if(scope == "*") + return {get_full_name(), ".*"}; + if(scope == "uvm_test_top") + return "uvm_test_top"; + if(scope[0] == ".") + return {get_full_name(), scope}; + return {get_full_name(), ".", scope}; +endfunction +function bit uvm_component::use_automatic_config(); + return 1; +endfunction +function void uvm_component::apply_config_settings (bit verbose=0); + uvm_resource_pool rp = uvm_resource_pool::get(); + uvm_queue#(uvm_resource_base) rq; + uvm_resource_base r; + rq = rp.lookup_scope(get_full_name()); + rp.sort_by_precedence(rq); + for(int i=rq.size()-1; i>=0; --i) begin + r = rq.get(i); + if(verbose) + uvm_report_info("CFGAPL",$sformatf("applying configuration to field %s", r.get_name()),UVM_NONE); + set_local(r); + end +endfunction +function void uvm_component::print_config(bit recurse = 0, audit = 0); + uvm_resource_pool rp = uvm_resource_pool::get(); + uvm_report_info("CFGPRT","visible resources:",UVM_INFO); + rp.print_resources(rp.lookup_scope(get_full_name()), audit); + if(recurse) begin + uvm_component c; + foreach(m_children[name]) begin + c = m_children[name]; + c.print_config(recurse, audit); + end + end +endfunction +function void uvm_component::print_config_with_audit(bit recurse = 0); + print_config(recurse, 1); +endfunction +function void uvm_component::do_print(uvm_printer printer); + super.do_print(printer); + if(uvm_verbosity'(recording_detail) != UVM_NONE) + case (recording_detail) + UVM_LOW : printer.print_generic("recording_detail", "uvm_verbosity", + $bits(recording_detail), "UVM_LOW"); + UVM_MEDIUM : printer.print_generic("recording_detail", "uvm_verbosity", + $bits(recording_detail), "UVM_MEDIUM"); + UVM_HIGH : printer.print_generic("recording_detail", "uvm_verbosity", + $bits(recording_detail), "UVM_HIGH"); + UVM_FULL : printer.print_generic("recording_detail", "uvm_verbosity", + $bits(recording_detail), "UVM_FULL"); + default : printer.print_field_int("recording_detail", recording_detail, + $bits(recording_detail), UVM_DEC, , "integral"); + endcase +endfunction +function void uvm_component::set_local(uvm_resource_base rsrc) ; + bit success; + if((rsrc != null) && (rsrc.get_name() == "recording_detail")) begin +begin +begin + uvm_resource#(uvm_integral_t) __tmp_rsrc__; + success = $cast(__tmp_rsrc__, rsrc); + if (success) begin + recording_detail = __tmp_rsrc__.read(this); + end +end + if (!success) +begin + uvm_resource#(uvm_bitstream_t) __tmp_rsrc__; + success = $cast(__tmp_rsrc__, rsrc); + if (success) begin + recording_detail = __tmp_rsrc__.read(this); + end +end + if (!success) +begin + uvm_resource#(int) __tmp_rsrc__; + success = $cast(__tmp_rsrc__, rsrc); + if (success) begin + recording_detail = __tmp_rsrc__.read(this); + end +end + if (!success) +begin + uvm_resource#(int unsigned) __tmp_rsrc__; + success = $cast(__tmp_rsrc__, rsrc); + if (success) begin + recording_detail = __tmp_rsrc__.read(this); + end +end +end + end + if (!success) + super.set_local(rsrc); +endfunction +function void uvm_component::m_unsupported_set_local(uvm_resource_base rsrc); + m_unsupported_resource_base = rsrc; +endfunction +typedef class uvm_cmdline_processor; +function void uvm_component::m_set_cl_msg_args; + string s_; + process p_; + p_=process::self(); + if(p_!=null) + s_=p_.get_randstate(); + else + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM")) + uvm_report_warning ("UVM", "run_test() invoked from a non process context", UVM_NONE, "t/uvm/src/base/uvm_component.svh", 3043, "", 1); + end + m_set_cl_verb(); + m_set_cl_action(); + m_set_cl_sev(); + if(p_!=null) + p_.set_randstate(s_); +endfunction +function void uvm_component::m_set_cl_verb; + static string values[$]; + static bit first = 1; + string args[$]; + uvm_cmdline_processor clp = uvm_cmdline_processor::get_inst(); + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + if(first) begin + string t[$]; + m_verbosity_setting setting; + void'(clp.get_arg_values("+uvm_set_verbosity=",values)); + foreach(values[i]) begin + args.delete(); + uvm_split_string(values[i], ",", args); + if(((args.size() == 4) || (args.size() == 5)) && (clp.m_convert_verb(args[2], setting.verbosity) == 1) ) + t.push_back(values[i]); + else + uvm_report_warning("UVM/CMDLINE",$sformatf("argument %s not recognized and therefore dropped",values[i])); + end + values=t; + first=0; + end + foreach(values[i]) begin + m_verbosity_setting setting; + args.delete(); + uvm_split_string(values[i], ",", args); + begin + setting.comp = args[0]; + setting.id = args[1]; + void'(clp.m_convert_verb(args[2],setting.verbosity)); + setting.phase = args[3]; + setting.offset = 0; + if(args.size() == 5) setting.offset = args[4].atoi(); + if((setting.phase == "time") && (this == top)) begin + m_time_settings.push_back(setting); + end + if (uvm_is_match(setting.comp, get_full_name()) ) begin + if((setting.phase == "" || setting.phase == "build" || setting.phase == "time") && + (setting.offset == 0) ) + begin + if(setting.id == "_ALL_") + set_report_verbosity_level(setting.verbosity); + else + set_report_id_verbosity(setting.id, setting.verbosity); + end + else begin + if(setting.phase != "time") begin + m_verbosity_settings.push_back(setting); + end + end + end + end + end + if(this == top) begin + fork begin + time last_time = 0; + if (m_time_settings.size() > 0) + m_time_settings.sort() with ( item.offset ); + foreach(m_time_settings[i]) begin + uvm_component comps[$]; + top.find_all(m_time_settings[i].comp,comps); + #(m_time_settings[i].offset - last_time); + last_time = m_time_settings[i].offset; + if(m_time_settings[i].id == "_ALL_") begin + foreach(comps[j]) begin + comps[j].set_report_verbosity_level(m_time_settings[i].verbosity); + end + end + else begin + foreach(comps[j]) begin + comps[j].set_report_id_verbosity(m_time_settings[i].id, m_time_settings[i].verbosity); + end + end + end + end join_none + end +endfunction +function void uvm_component::m_set_cl_action; + static bit initialized = 0; + uvm_severity sev; + uvm_action action; + uvm_cmdline_processor uvm_cmdline_proc = uvm_cmdline_processor::get_inst(); + if(!initialized) begin + string values[$]; + void'(uvm_cmdline_proc.get_arg_values("+uvm_set_action=",values)); + foreach(values[idx]) begin + uvm_cmdline_parsed_arg_t t; + string args[$]; + uvm_split_string(values[idx], ",", args); + if(args.size() != 4) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"INVLCMDARGS")) + uvm_report_warning ("INVLCMDARGS", $sformatf("+uvm_set_action requires 4 arguments, but %0d given for command +uvm_set_action=%s, Usage: +uvm_set_action=,,,", args.size(), values[idx]), UVM_NONE, "t/uvm/src/base/uvm_component.svh", 3169, "", 1); + end + continue; + end + if((args[2] != "_ALL_") && !uvm_string_to_severity(args[2], sev)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"INVLCMDARGS")) + uvm_report_warning ("INVLCMDARGS", $sformatf("Bad severity argument \"%s\" given to command +uvm_set_action=%s, Usage: +uvm_set_action=,,,", args[2], values[idx]), UVM_NONE, "t/uvm/src/base/uvm_component.svh", 3173, "", 1); + end + continue; + end + if(!uvm_string_to_action(args[3], action)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"INVLCMDARGS")) + uvm_report_warning ("INVLCMDARGS", $sformatf("Bad action argument \"%s\" given to command +uvm_set_action=%s, Usage: +uvm_set_action=,,,", args[3], values[idx]), UVM_NONE, "t/uvm/src/base/uvm_component.svh", 3177, "", 1); + end + continue; + end + t.args=args; + t.arg=values[idx]; + m_uvm_applied_cl_action.push_back(t); + end + initialized=1; + end + foreach(m_uvm_applied_cl_action[i]) begin + string args[$] = m_uvm_applied_cl_action[i].args; + if (!uvm_is_match(args[0], get_full_name()) ) continue; + void'(uvm_string_to_severity(args[2], sev)); + void'(uvm_string_to_action(args[3], action)); + m_uvm_applied_cl_action[i].used++; + if(args[1] == "_ALL_") begin + if(args[2] == "_ALL_") begin + set_report_severity_action(UVM_INFO, action); + set_report_severity_action(UVM_WARNING, action); + set_report_severity_action(UVM_ERROR, action); + set_report_severity_action(UVM_FATAL, action); + end + else begin + set_report_severity_action(sev, action); + end + end + else begin + if(args[2] == "_ALL_") begin + set_report_id_action(args[1], action); + end + else begin + set_report_severity_id_action(sev, args[1], action); + end + end + end +endfunction +function void uvm_component::m_set_cl_sev; + static bit initialized; + uvm_severity orig_sev, sev; + uvm_cmdline_processor uvm_cmdline_proc = uvm_cmdline_processor::get_inst(); + if(!initialized) begin + string values[$]; + void'(uvm_cmdline_proc.get_arg_values("+uvm_set_severity=",values)); + foreach(values[idx]) begin + uvm_cmdline_parsed_arg_t t; + string args[$]; + uvm_split_string(values[idx], ",", args); + if(args.size() != 4) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"INVLCMDARGS")) + uvm_report_warning ("INVLCMDARGS", $sformatf("+uvm_set_severity requires 4 arguments, but %0d given for command +uvm_set_severity=%s, Usage: +uvm_set_severity=,,,", args.size(), values[idx]), UVM_NONE, "t/uvm/src/base/uvm_component.svh", 3240, "", 1); + end + continue; + end + if(args[2] != "_ALL_" && !uvm_string_to_severity(args[2], orig_sev)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"INVLCMDARGS")) + uvm_report_warning ("INVLCMDARGS", $sformatf("Bad severity argument \"%s\" given to command +uvm_set_severity=%s, Usage: +uvm_set_severity=,,,", args[2], values[idx]), UVM_NONE, "t/uvm/src/base/uvm_component.svh", 3244, "", 1); + end + continue; + end + if(!uvm_string_to_severity(args[3], sev)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"INVLCMDARGS")) + uvm_report_warning ("INVLCMDARGS", $sformatf("Bad severity argument \"%s\" given to command +uvm_set_severity=%s, Usage: +uvm_set_severity=,,,", args[3], values[idx]), UVM_NONE, "t/uvm/src/base/uvm_component.svh", 3248, "", 1); + end + continue; + end + t.args=args; + t.arg=values[idx]; + m_uvm_applied_cl_sev.push_back(t); + end + initialized=1; + end + foreach(m_uvm_applied_cl_sev[i]) begin + string args[$]=m_uvm_applied_cl_sev[i].args; + if (!uvm_is_match(args[0], get_full_name()) ) continue; + void'(uvm_string_to_severity(args[2], orig_sev)); + void'(uvm_string_to_severity(args[3], sev)); + m_uvm_applied_cl_sev[i].used++; + if(args[1] == "_ALL_" && args[2] == "_ALL_") begin + set_report_severity_override(UVM_INFO,sev); + set_report_severity_override(UVM_WARNING,sev); + set_report_severity_override(UVM_ERROR,sev); + set_report_severity_override(UVM_FATAL,sev); + end + else if(args[1] == "_ALL_") begin + set_report_severity_override(orig_sev,sev); + end + else if(args[2] == "_ALL_") begin + set_report_severity_id_override(UVM_INFO,args[1],sev); + set_report_severity_id_override(UVM_WARNING,args[1],sev); + set_report_severity_id_override(UVM_ERROR,args[1],sev); + set_report_severity_id_override(UVM_FATAL,args[1],sev); + end + else begin + set_report_severity_id_override(orig_sev,args[1],sev); + end + end +endfunction +function void uvm_component::m_apply_verbosity_settings(uvm_phase phase); + int i; + while (i < m_verbosity_settings.size()) begin + if(phase.get_name() == m_verbosity_settings[i].phase) begin + if( m_verbosity_settings[i].offset == 0 ) begin + if(m_verbosity_settings[i].id == "_ALL_") + set_report_verbosity_level(m_verbosity_settings[i].verbosity); + else + set_report_id_verbosity(m_verbosity_settings[i].id, m_verbosity_settings[i].verbosity); + end + else begin + process p = process::self(); + string p_rand = p.get_randstate(); + fork begin + m_verbosity_setting setting = m_verbosity_settings[i]; + #(setting.offset); + if(setting.id == "_ALL_") + set_report_verbosity_level(setting.verbosity); + else + set_report_id_verbosity(setting.id, setting.verbosity); + end join_none + p.set_randstate(p_rand); + end + m_verbosity_settings.delete(i); + continue; + end + i++; + end +endfunction +function void uvm_component::m_do_pre_abort; + foreach(m_children[i]) + m_children[i].m_do_pre_abort(); + pre_abort(); +endfunction +typedef class uvm_objection_context_object; +typedef class uvm_objection; +typedef class uvm_sequence_base; +typedef class uvm_objection_callback; +typedef uvm_callbacks #(uvm_objection,uvm_objection_callback) uvm_objection_cbs_t; +typedef class uvm_cmdline_processor; +class uvm_objection_events; + int waiters; + event raised; + event dropped; + event all_dropped; +endclass +class uvm_objection extends uvm_report_object; + static local bit m_register_cb_uvm_objection_callback = uvm_callbacks#(uvm_objection,uvm_objection_callback)::m_register_pair("uvm_objection","uvm_objection_callback"); + protected bit m_trace_mode; + protected int m_source_count[uvm_object]; + protected int m_total_count [uvm_object]; + protected time m_drain_time [uvm_object]; + protected uvm_objection_events m_events [uvm_object]; + bit m_top_all_dropped; + protected uvm_root m_top; + static uvm_objection m_objections[$]; + local static uvm_objection_context_object m_context_pool[$]; + local process m_drain_proc[uvm_object]; + local static uvm_objection_context_object m_scheduled_list[$]; + local uvm_objection_context_object m_scheduled_contexts[uvm_object]; + local uvm_objection_context_object m_forked_list[$]; + local uvm_objection_context_object m_forked_contexts[uvm_object]; + protected bit m_prop_mode = 1; + protected bit m_cleared; + function new(string name=""); + uvm_cmdline_processor clp; + uvm_coreservice_t cs_ ; + string trace_args[$]; + super.new(name); + cs_ = uvm_coreservice_t::get(); + m_top = cs_.get_root(); + set_report_verbosity_level(m_top.get_report_verbosity_level()); + clp = uvm_cmdline_processor::get_inst(); + if(clp.get_arg_matches("+UVM_OBJECTION_TRACE", trace_args)) begin + m_trace_mode=1; + end + m_objections.push_back(this); + endfunction + function bit trace_mode (int mode=-1); + trace_mode = m_trace_mode; + if(mode == 0) m_trace_mode = 0; + else if(mode == 1) m_trace_mode = 1; + endfunction + function void m_report(uvm_object obj, uvm_object source_obj, string description, int count, string action); + int _count = m_source_count.exists(obj) ? m_source_count[obj] : 0; + int _total = m_total_count.exists(obj) ? m_total_count[obj] : 0; + if (!uvm_report_enabled(UVM_NONE,UVM_INFO,"OBJTN_TRC") || !m_trace_mode) return; + if (source_obj == obj) + uvm_report_info("OBJTN_TRC", + $sformatf("Object %0s %0s %0d objection(s)%s: count=%0d total=%0d", + obj.get_full_name()==""?"uvm_top":obj.get_full_name(), action, + count, description != ""? {" (",description,")"}:"", _count, _total), UVM_NONE); + else begin + int cpath = 0, last_dot=0; + string sname = source_obj.get_full_name(), nm = obj.get_full_name(); + int max = sname.len() > nm.len() ? nm.len() : sname.len(); + while((sname[cpath] == nm[cpath]) && (cpath < max)) begin + if(sname[cpath] == ".") last_dot = cpath; + cpath++; + end + if(last_dot) sname = sname.substr(last_dot+1, sname.len()); + uvm_report_info("OBJTN_TRC", + $sformatf("Object %0s %0s %0d objection(s) %0s its total (%s from source object %s%s): count=%0d total=%0d", + obj.get_full_name()==""?"uvm_top":obj.get_full_name(), action=="raised"?"added":"subtracted", + count, action=="raised"?"to":"from", action, sname, + description != ""?{", ",description}:"", _count, _total), UVM_NONE); + end + endfunction + function uvm_object m_get_parent(uvm_object obj); + uvm_component comp; + uvm_sequence_base seq; + if ($cast(comp, obj)) begin + obj = comp.get_parent(); + end + else if ($cast(seq, obj)) begin + obj = seq.get_sequencer(); + end + else + obj = m_top; + if (obj == null) + obj = m_top; + return obj; + endfunction + function void m_propagate (uvm_object obj, + uvm_object source_obj, + string description, + int count, + bit raise, + int in_top_thread); + if (obj != null && obj != m_top) begin + obj = m_get_parent(obj); + if(raise) + m_raise(obj, source_obj, description, count); + else + m_drop(obj, source_obj, description, count, in_top_thread); + end + endfunction + function void set_propagate_mode (bit prop_mode); + if (!m_top_all_dropped && (get_objection_total() != 0)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/BASE/OBJTN/PROP_MODE")) + uvm_report_error ("UVM/BASE/OBJTN/PROP_MODE", {"The propagation mode of '", this.get_full_name(), "' cannot be changed while the objection is raised ", "or draining!"}, UVM_NONE, "t/uvm/src/base/uvm_objection.svh", 265, "", 1); + end + return; + end + m_prop_mode = prop_mode; + endfunction : set_propagate_mode + function bit get_propagate_mode(); + return m_prop_mode; + endfunction : get_propagate_mode + virtual function void raise_objection (uvm_object obj=null, + string description="", + int count=1); + if(obj == null) + obj = m_top; + m_cleared = 0; + m_top_all_dropped = 0; + m_raise (obj, obj, description, count); + endfunction + function void m_raise (uvm_object obj, + uvm_object source_obj, + string description="", + int count=1); + int idx; + uvm_objection_context_object ctxt; + if (count == 0) + return; + if (m_total_count.exists(obj)) + m_total_count[obj] += count; + else + m_total_count[obj] = count; + if (source_obj==obj) begin + if (m_source_count.exists(obj)) + m_source_count[obj] += count; + else + m_source_count[obj] = count; + end + if (m_trace_mode) + m_report(obj,source_obj,description,count,"raised"); + raised(obj, source_obj, description, count); + idx = 0; + while (idx < m_scheduled_list.size()) begin + if ((m_scheduled_list[idx].obj == obj) && + (m_scheduled_list[idx].objection == this)) begin + ctxt = m_scheduled_list[idx]; + m_scheduled_list.delete(idx); + break; + end + idx++; + end + if (ctxt == null) begin + idx = 0; + while (idx < m_forked_list.size()) begin + if (m_forked_list[idx].obj == obj) begin + ctxt = m_forked_list[idx]; + m_forked_list.delete(idx); + m_scheduled_contexts.delete(ctxt.obj); + break; + end + idx++; + end + end + if (ctxt == null) begin + if (m_forked_contexts.exists(obj)) begin + ctxt = m_forked_contexts[obj]; + m_forked_contexts.delete(obj); + m_drain_proc[obj].kill(); + m_drain_proc.delete(obj); + end + end + if (ctxt == null) begin + if (!m_prop_mode && obj != m_top) + m_raise(m_top,source_obj,description,count); + else if (obj != m_top) + m_propagate(obj, source_obj, description, count, 1, 0); + end + else begin + int diff_count; + diff_count = count - ctxt.count; + if (diff_count != 0) begin + if (diff_count > 0) begin + if (!m_prop_mode && obj != m_top) + m_raise(m_top, source_obj, description, diff_count); + else if (obj != m_top) + m_propagate(obj, source_obj, description, diff_count, 1, 0); + end + else begin + diff_count = -diff_count; + if (!m_prop_mode && obj != m_top) + m_drop(m_top, source_obj, description, diff_count); + else if (obj != m_top) + m_propagate(obj, source_obj, description, diff_count, 0, 0); + end + end + ctxt.clear(); + m_context_pool.push_back(ctxt); + end + endfunction + virtual function void drop_objection (uvm_object obj=null, + string description="", + int count=1); + if(obj == null) + obj = m_top; + m_drop (obj, obj, description, count, 0); + endfunction + function void m_drop (uvm_object obj, + uvm_object source_obj, + string description="", + int count=1, + int in_top_thread=0); + if (count == 0) + return; + if (!m_total_count.exists(obj) || (count > m_total_count[obj])) begin + if(m_cleared) + return; + uvm_report_fatal("OBJTN_ZERO", {"Object \"", obj.get_full_name(), + "\" attempted to drop objection '",this.get_name(),"' count below zero"}); + return; + end + if (obj == source_obj) begin + if (!m_source_count.exists(obj) || (count > m_source_count[obj])) begin + if(m_cleared) + return; + uvm_report_fatal("OBJTN_ZERO", {"Object \"", obj.get_full_name(), + "\" attempted to drop objection '",this.get_name(),"' count below zero"}); + return; + end + m_source_count[obj] -= count; + end + m_total_count[obj] -= count; + if (m_trace_mode) + m_report(obj,source_obj,description,count,"dropped"); + dropped(obj, source_obj, description, count); + if (m_total_count[obj] != 0) begin + if (!m_prop_mode && obj != m_top) + m_drop(m_top,source_obj,description, count, in_top_thread); + else if (obj != m_top) begin + this.m_propagate(obj, source_obj, description, count, 0, in_top_thread); + end + end + else begin + uvm_objection_context_object ctxt; + if (m_context_pool.size()) + ctxt = m_context_pool.pop_front(); + else + ctxt = new; + ctxt.obj = obj; + ctxt.source_obj = source_obj; + ctxt.description = description; + ctxt.count = count; + ctxt.objection = this; + m_scheduled_list.push_back(ctxt); + end + endfunction + virtual function void clear(uvm_object obj=null); + string name; + int idx; + if (obj==null) + obj=m_top; + name = obj.get_full_name(); + if (name == "") + name = "uvm_top"; + else + name = obj.get_full_name(); + if (!m_top_all_dropped && get_objection_total(m_top)) + uvm_report_warning("OBJTN_CLEAR",{"Object '",name, + "' cleared objection counts for ",get_name()}); + m_source_count.delete(); + m_total_count.delete(); + idx = 0; + while (idx < m_scheduled_list.size()) begin + if (m_scheduled_list[idx].objection == this) begin + m_scheduled_list[idx].clear(); + m_context_pool.push_back(m_scheduled_list[idx]); + m_scheduled_list.delete(idx); + end + else begin + idx++; + end + end + m_scheduled_contexts.delete(); + while (m_forked_list.size()) begin + m_forked_list[0].clear(); + m_context_pool.push_back(m_forked_list[0]); + void'(m_forked_list.pop_front()); + end + foreach (m_forked_contexts[o]) begin + m_drain_proc[o].kill(); + m_drain_proc.delete(o); + m_forked_contexts[o].clear(); + m_context_pool.push_back(m_forked_contexts[o]); + m_forked_contexts.delete(o); + end + m_top_all_dropped = 0; + m_cleared = 1; + if (m_events.exists(m_top)) + ->m_events[m_top].all_dropped; + endfunction + static task m_execute_scheduled_forks(); + while(1) begin + wait(m_scheduled_list.size() != 0); + if(m_scheduled_list.size() != 0) begin + uvm_objection_context_object c; + c = m_scheduled_list.pop_front(); + c.objection.m_scheduled_contexts[c.obj] = c; + c.objection.m_forked_list.push_back(c); + fork : guard + automatic uvm_objection objection = c.objection; + begin + if (objection.m_forked_list.size() > 0) begin + uvm_objection_context_object ctxt; + ctxt = objection.m_forked_list.pop_front(); + objection.m_scheduled_contexts.delete(ctxt.obj); + objection.m_forked_contexts[ctxt.obj] = ctxt; + objection.m_drain_proc[ctxt.obj] = process::self(); + objection.m_forked_drain(ctxt.obj, ctxt.source_obj, ctxt.description, ctxt.count, 1); + objection.m_drain_proc.delete(ctxt.obj); + objection.m_forked_contexts.delete(ctxt.obj); + ctxt.clear(); + m_context_pool.push_back(ctxt); + end + end + join_none : guard + end + end + endtask + task m_forked_drain (uvm_object obj, + uvm_object source_obj, + string description="", + int count=1, + int in_top_thread=0); + if (m_drain_time.exists(obj)) + #(m_drain_time[obj]); + if (m_trace_mode) + m_report(obj,source_obj,description,count,"all_dropped"); + all_dropped(obj,source_obj,description, count); + wait fork; + if (m_source_count.exists(obj) && m_source_count[obj] == 0) + m_source_count.delete(obj); + if (m_total_count.exists(obj) && m_total_count[obj] == 0) + m_total_count.delete(obj); + if (!m_prop_mode && obj != m_top) + m_drop(m_top,source_obj,description, count, 1); + else if (obj != m_top) + m_propagate(obj, source_obj, description, count, 0, 1); + endtask + static function void m_init_objections(); + fork + uvm_objection::m_execute_scheduled_forks(); + join_none + endfunction + function void set_drain_time (uvm_object obj=null, time drain); + if (obj==null) + obj = m_top; + m_drain_time[obj] = drain; + endfunction + virtual function void raised (uvm_object obj, + uvm_object source_obj, + string description, + int count); + uvm_component comp; + if ($cast(comp,obj)) + comp.raised(this, source_obj, description, count); + begin + uvm_callback_iter#(uvm_objection,uvm_objection_callback) iter = new(this); + uvm_objection_callback cb = iter.first(); + while(cb != null) begin + cb.raised(this,obj,source_obj,description,count); + cb = iter.next(); + end + end + if (m_events.exists(obj)) + ->m_events[obj].raised; + endfunction + virtual function void dropped (uvm_object obj, + uvm_object source_obj, + string description, + int count); + uvm_component comp; + if($cast(comp,obj)) + comp.dropped(this, source_obj, description, count); + begin + uvm_callback_iter#(uvm_objection,uvm_objection_callback) iter = new(this); + uvm_objection_callback cb = iter.first(); + while(cb != null) begin + cb.dropped(this,obj,source_obj,description,count); + cb = iter.next(); + end + end + if (m_events.exists(obj)) + ->m_events[obj].dropped; + endfunction + virtual task all_dropped (uvm_object obj, + uvm_object source_obj, + string description, + int count); + uvm_component comp; + if($cast(comp,obj)) + comp.all_dropped(this, source_obj, description, count); + begin + uvm_callback_iter#(uvm_objection,uvm_objection_callback) iter = new(this); + uvm_objection_callback cb = iter.first(); + while(cb != null) begin + cb.all_dropped(this,obj,source_obj,description,count); + cb = iter.next(); + end + end + if (m_events.exists(obj)) + ->m_events[obj].all_dropped; + if (obj == m_top) + m_top_all_dropped = 1; + endtask + function void get_objectors(ref uvm_object list[$]); + list.delete(); + foreach (m_source_count[obj]) list.push_back(obj); + endfunction + task wait_for(uvm_objection_event objt_event, uvm_object obj=null); + if (obj==null) + obj = m_top; + if (!m_events.exists(obj)) begin + m_events[obj] = new; + end + m_events[obj].waiters++; + case (objt_event) + UVM_RAISED: @(m_events[obj].raised); + UVM_DROPPED: @(m_events[obj].dropped); + UVM_ALL_DROPPED: @(m_events[obj].all_dropped); + endcase + m_events[obj].waiters--; + if (m_events[obj].waiters == 0) + m_events.delete(obj); + endtask + task wait_for_total_count(uvm_object obj=null, int count=0); + if (obj==null) + obj = m_top; + if(!m_total_count.exists(obj) && count == 0) + return; + if (count == 0) + wait (!m_total_count.exists(obj) && count == 0); + else + wait (m_total_count.exists(obj) && m_total_count[obj] == count); + endtask + function int get_objection_count (uvm_object obj=null); + if (obj==null) + obj = m_top; + if (!m_source_count.exists(obj)) + return 0; + return m_source_count[obj]; + endfunction + function int get_objection_total (uvm_object obj=null); + if (obj==null) + obj = m_top; + if (!m_total_count.exists(obj)) + return 0; + else + return m_total_count[obj]; + endfunction + function time get_drain_time (uvm_object obj=null); + if (obj==null) + obj = m_top; + if (!m_drain_time.exists(obj)) + return 0; + return m_drain_time[obj]; + endfunction + protected function string m_display_objections(uvm_object obj=null, bit show_header=1); + static string blank=" "; + string s; + int total; + uvm_object list[string]; + uvm_object curr_obj; + int depth; + string name; + string this_obj_name; + string curr_obj_name; + foreach (m_total_count[o]) begin + uvm_object theobj = o; + if ( m_total_count[o] > 0) + list[theobj.get_full_name()] = theobj; + end + if (obj==null) + obj = m_top; + total = get_objection_total(obj); + s = $sformatf("The total objection count is %0d\n",total); + if (total == 0) + return s; + s = {s,"---------------------------------------------------------\n"}; + s = {s,"Source Total \n"}; + s = {s,"Count Count Object\n"}; + s = {s,"---------------------------------------------------------\n"}; + this_obj_name = obj.get_full_name(); + curr_obj_name = this_obj_name; + do begin + curr_obj = list[curr_obj_name]; + depth=0; + foreach (curr_obj_name[i]) + if (curr_obj_name[i] == ".") + depth++; + name = curr_obj_name; + for (int i=curr_obj_name.len()-1;i >= 0; i--) + if (curr_obj_name[i] == ".") begin + name = curr_obj_name.substr(i+1,curr_obj_name.len()-1); + break; + end + if (curr_obj_name == "") + name = "uvm_top"; + else + depth++; + s = {s, $sformatf("%-6d %-6d %s%s\n", + m_source_count.exists(curr_obj) ? m_source_count[curr_obj] : 0, + m_total_count.exists(curr_obj) ? m_total_count[curr_obj] : 0, + blank.substr(0,2*depth), name)}; + end while (list.next(curr_obj_name) && + curr_obj_name.substr(0,this_obj_name.len()-1) == this_obj_name); + s = {s,"---------------------------------------------------------\n"}; + return s; + endfunction + function string convert2string(); + return m_display_objections(m_top,1); + endfunction + function void display_objections(uvm_object obj=null, bit show_header=1); + string m = m_display_objections(obj,show_header); + begin + if (uvm_report_enabled(UVM_NONE,UVM_INFO,"UVM/OBJ/DISPLAY")) + uvm_report_info ("UVM/OBJ/DISPLAY", m, UVM_NONE, "t/uvm/src/base/uvm_objection.svh", 1033, "", 1); + end + endfunction + typedef uvm_object_registry#(uvm_objection,"uvm_objection") type_id; + static function uvm_objection type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_objection tmp = new(name); + return tmp; + endfunction + virtual function string get_type_name (); + return "uvm_objection"; + endfunction + function void do_copy (uvm_object rhs); + uvm_objection _rhs; + $cast(_rhs, rhs); + m_source_count = _rhs.m_source_count; + m_total_count = _rhs.m_total_count; + m_drain_time = _rhs.m_drain_time; + m_prop_mode = _rhs.m_prop_mode; + endfunction +endclass +typedef class uvm_cmdline_processor; +class uvm_objection_context_object; + uvm_object obj; + uvm_object source_obj; + string description; + int count; + uvm_objection objection; + function void clear(); + obj = null; + source_obj = null; + description = ""; + count = 0; + objection = null; + endfunction : clear +endclass +typedef uvm_objection uvm_callbacks_objection; +class uvm_objection_callback extends uvm_callback; + function new(string name); + super.new(name); + endfunction + virtual function void raised (uvm_objection objection, uvm_object obj, + uvm_object source_obj, string description, int count); + endfunction + virtual function void dropped (uvm_objection objection, uvm_object obj, + uvm_object source_obj, string description, int count); + endfunction + virtual task all_dropped (uvm_objection objection, uvm_object obj, + uvm_object source_obj, string description, int count); + endtask +endclass +typedef enum { + UVM_ALL_ACTIVE, + UVM_ONE_ACTIVE, + UVM_ANY_ACTIVE, + UVM_NO_HB_MODE +} uvm_heartbeat_modes; +typedef class uvm_heartbeat_callback; +typedef uvm_callbacks #(uvm_objection,uvm_heartbeat_callback) uvm_heartbeat_cbs_t ; +typedef class uvm_objection_callback; +class uvm_heartbeat extends uvm_object; + protected uvm_objection m_objection; + protected uvm_heartbeat_callback m_cb; + protected uvm_component m_cntxt; + protected uvm_heartbeat_modes m_mode; + protected uvm_component m_hblist[$]; + protected uvm_event#(uvm_object) m_event; + protected bit m_started; + protected event m_stop_event; + function new(string name, uvm_component cntxt, uvm_objection objection=null); + uvm_coreservice_t cs; + super.new(name); + m_objection = objection; + cs = uvm_coreservice_t::get(); + if(cntxt != null) m_cntxt = cntxt; + else m_cntxt = cs.get_root(); + m_cb = new({name,"_cb"},m_cntxt); + endfunction + function uvm_heartbeat_modes set_mode (uvm_heartbeat_modes mode = UVM_NO_HB_MODE); + set_mode = m_mode; + if(mode == UVM_ANY_ACTIVE || mode == UVM_ONE_ACTIVE || mode == UVM_ALL_ACTIVE) + m_mode = mode; + endfunction + function void set_heartbeat (uvm_event#(uvm_object) e, ref uvm_component comps[$]); + uvm_object c; + foreach(comps[i]) begin + c = comps[i]; + if(!m_cb.cnt.exists(c)) + m_cb.cnt[c]=0; + if(!m_cb.last_trigger.exists(c)) + m_cb.last_trigger[c]=0; + end + if(e==null && m_event==null) return; + start(e); + endfunction + function void add (uvm_component comp); + uvm_object c = comp; + if(m_cb.cnt.exists(c)) return; + m_cb.cnt[c]=0; + m_cb.last_trigger[c]=0; + endfunction + function void remove (uvm_component comp); + uvm_object c = comp; + if(m_cb.cnt.exists(c)) m_cb.cnt.delete(c); + if(m_cb.last_trigger.exists(c)) m_cb.last_trigger.delete(c); + endfunction + function void start (uvm_event#(uvm_object) e=null); + if(m_event == null && e == null) begin + m_cntxt.uvm_report_warning("NOEVNT", { "start() was called for: ", + get_name(), " with a null trigger and no currently set trigger" }, + UVM_NONE); + return; + end + if((m_event != null) && (e != m_event) && m_started) begin + m_cntxt.uvm_report_error("ILHBVNT", { "start() was called for: ", + get_name(), " with trigger ", e.get_name(), " which is different ", + "from the original trigger ", m_event.get_name() }, UVM_NONE); + return; + end + if(e != null) m_event = e; + m_enable_cb(); + m_start_hb_process(); + endfunction + function void stop (); + m_started = 0; + ->m_stop_event; + m_disable_cb(); + endfunction + function void m_start_hb_process(); + if(m_started) return; + m_started = 1; + fork + m_hb_process; + join_none + endfunction + protected bit m_added; + function void m_enable_cb; + void'(m_cb.callback_mode(1)); + if(m_objection == null) return; + if(!m_added) + uvm_heartbeat_cbs_t::add(m_objection, m_cb); + m_added = 1; + endfunction + function void m_disable_cb; + void'(m_cb.callback_mode(0)); + endfunction + task m_hb_process; + uvm_object obj; + bit triggered; + time last_trigger=0; + fork + begin + while(1) begin + m_event.wait_trigger(); + if(triggered) begin + case (m_mode) + UVM_ALL_ACTIVE: + begin + foreach(m_cb.cnt[idx]) begin + obj = idx; + if(!m_cb.cnt[obj]) begin + m_cntxt.uvm_report_fatal("HBFAIL", $sformatf("Did not recieve an update of %s for component %s since last event trigger at time %0t : last update time was %0t", + m_objection.get_name(), obj.get_full_name(), + last_trigger, m_cb.last_trigger[obj]), UVM_NONE); + end + end + end + UVM_ANY_ACTIVE: + begin + if(m_cb.cnt.num() && !m_cb.objects_triggered()) begin + string s; + foreach(m_cb.cnt[idx]) begin + obj = idx; + s={s,"\n ",obj.get_full_name()}; + end + m_cntxt.uvm_report_fatal("HBFAIL", $sformatf("Did not recieve an update of %s on any component since last event trigger at time %0t. The list of registered components is:%s", + m_objection.get_name(), last_trigger, s), UVM_NONE); + end + end + UVM_ONE_ACTIVE: + begin + if(m_cb.objects_triggered() > 1) begin + string s; + foreach(m_cb.cnt[idx]) begin + obj = idx; + if(m_cb.cnt[obj]) $swrite(s,"%s\n %s (updated: %0t)", + s, obj.get_full_name(), m_cb.last_trigger[obj]); + end + m_cntxt.uvm_report_fatal("HBFAIL", $sformatf("Recieved update of %s from more than one component since last event trigger at time %0t. The list of triggered components is:%s", + m_objection.get_name(), last_trigger, s), UVM_NONE); + end + if(m_cb.cnt.num() && !m_cb.objects_triggered()) begin + string s; + foreach(m_cb.cnt[idx]) begin + obj = idx; + s={s,"\n ",obj.get_full_name()}; + end + m_cntxt.uvm_report_fatal("HBFAIL", $sformatf("Did not recieve an update of %s on any component since last event trigger at time %0t. The list of registered components is:%s", + m_objection.get_name(), last_trigger, s), UVM_NONE); + end + end + endcase + end + m_cb.reset_counts(); + last_trigger = $realtime; + triggered = 1; + end + end + @(m_stop_event); + join_any + disable fork; + endtask +endclass +class uvm_heartbeat_callback extends uvm_objection_callback; + int cnt [uvm_object]; + time last_trigger [uvm_object]; + uvm_object target; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + function new(string name, uvm_object target); + super.new(name); + if (target != null) + this.target = target; + else + this.target = cs.get_root(); + endfunction + virtual function void raised (uvm_objection objection, + uvm_object obj, + uvm_object source_obj, + string description, + int count); + if(obj == target) begin + if(!cnt.exists(source_obj)) + cnt[source_obj] = 0; + cnt[source_obj] = cnt[source_obj]+1; + last_trigger[source_obj] = $realtime; + end + endfunction + virtual function void dropped (uvm_objection objection, + uvm_object obj, + uvm_object source_obj, + string description, + int count); + raised(objection,obj,source_obj,description,count); + endfunction + function void reset_counts; + foreach(cnt[i]) cnt[i] = 0; + endfunction + function int objects_triggered; + objects_triggered = 0; + foreach(cnt[i]) + if (cnt[i] != 0) + objects_triggered++; + endfunction +endclass +class uvm_cmd_line_verb; + string comp_path; + string id; + uvm_verbosity verb; + int exec_time; +endclass +typedef class uvm_cmdline_processor; +uvm_cmdline_processor uvm_cmdline_proc; +class uvm_cmdline_processor extends uvm_report_object; + static local uvm_cmdline_processor m_inst; + static function uvm_cmdline_processor get_inst(); + if(m_inst == null) + m_inst = new("uvm_cmdline_proc"); + uvm_cmdline_proc = m_inst; + return m_inst; + endfunction + protected string m_argv[$]; + protected string m_plus_argv[$]; + protected string m_uvm_argv[$]; + function void get_args (output string args[$]); + args = m_argv; + endfunction + function void get_plusargs (output string args[$]); + args = m_plus_argv; + endfunction + function void get_uvm_args (output string args[$]); + args = m_uvm_argv; + endfunction + function int get_arg_matches (string match, ref string args[$]); + bit match_is_regex = (match.len() > 2) && (match[0] == "/") && (match[match.len()-1] == "/"); + int len = match.len(); + args.delete(); + foreach (m_argv[i]) begin + if ( match_is_regex && uvm_is_match( match, m_argv[i] ) ) begin + args.push_back( m_argv[i] ); + end + else if((m_argv[i].len() >= len) && (m_argv[i].substr(0,len - 1) == match)) begin + args.push_back(m_argv[i]); + end + end + return args.size(); + endfunction + function int get_arg_value (string match, ref string value); + int chars = match.len(); + get_arg_value = 0; + foreach (m_argv[i]) begin + if(m_argv[i].len() >= chars) begin + if(m_argv[i].substr(0,chars-1) == match) begin + get_arg_value++; + if(get_arg_value == 1) + value = m_argv[i].substr(chars,m_argv[i].len()-1); + end + end + end + endfunction + function int get_arg_values (string match, ref string values[$]); + int chars = match.len(); + values.delete(); + foreach (m_argv[i]) begin + if(m_argv[i].len() >= chars) begin + if(m_argv[i].substr(0,chars-1) == match) + values.push_back(m_argv[i].substr(chars,m_argv[i].len()-1)); + end + end + return values.size(); + endfunction + function string get_tool_name (); + return uvm_dpi_get_tool_name(); + endfunction + function string get_tool_version (); + return uvm_dpi_get_tool_version(); + endfunction + function new(string name = ""); + string s; + string sub; + int doInit=1; + super.new(name); + do begin + s = uvm_dpi_get_next_arg(doInit); + doInit=0; + if(s!="") begin + m_argv.push_back(s); + if(s[0] == "+") begin + m_plus_argv.push_back(s); + end + if(s.len() >= 4 && (s[0]=="-" || s[0]=="+")) begin + sub = s.substr(1,3); + sub = sub.toupper(); + if(sub == "UVM") + m_uvm_argv.push_back(s); + end + end + end while(s!=""); + endfunction + function bit m_convert_verb(string verb_str, output uvm_verbosity verb_enum); + case (verb_str) + "NONE" : begin verb_enum = UVM_NONE; return 1; end + "UVM_NONE" : begin verb_enum = UVM_NONE; return 1; end + "LOW" : begin verb_enum = UVM_LOW; return 1; end + "UVM_LOW" : begin verb_enum = UVM_LOW; return 1; end + "MEDIUM" : begin verb_enum = UVM_MEDIUM; return 1; end + "UVM_MEDIUM" : begin verb_enum = UVM_MEDIUM; return 1; end + "HIGH" : begin verb_enum = UVM_HIGH; return 1; end + "UVM_HIGH" : begin verb_enum = UVM_HIGH; return 1; end + "FULL" : begin verb_enum = UVM_FULL; return 1; end + "UVM_FULL" : begin verb_enum = UVM_FULL; return 1; end + "DEBUG" : begin verb_enum = UVM_DEBUG; return 1; end + "UVM_DEBUG" : begin verb_enum = UVM_DEBUG; return 1; end + default : begin return 0; end + endcase + endfunction +endclass +virtual class uvm_visitor#(type NODE=uvm_component) extends uvm_object; + function new (string name = ""); + super.new(name); + endfunction + virtual function void begin_v(); endfunction + virtual function void end_v(); endfunction + pure virtual function void visit(NODE node); +endclass +virtual class uvm_structure_proxy#(type STRUCTURE=uvm_component) extends uvm_object; + function new (string name = ""); + super.new(name); + endfunction + pure virtual function void get_immediate_children(STRUCTURE s, ref STRUCTURE children[$]); +endclass +virtual class uvm_visitor_adapter#(type STRUCTURE=uvm_component,VISITOR=uvm_visitor#(STRUCTURE)) extends uvm_object; + pure virtual function void accept(STRUCTURE s, VISITOR v,uvm_structure_proxy#(STRUCTURE) p, bit invoke_begin_end=1); + function new (string name = ""); + super.new(name); + endfunction +endclass +class uvm_top_down_visitor_adapter#(type STRUCTURE=uvm_component,VISITOR=uvm_visitor#(STRUCTURE)) extends + uvm_visitor_adapter#(STRUCTURE,VISITOR); + function new (string name = ""); + super.new(name); + endfunction + virtual function void accept(STRUCTURE s, VISITOR v,uvm_structure_proxy#(STRUCTURE) p, bit invoke_begin_end=1); + STRUCTURE c[$]; + if(invoke_begin_end) + v.begin_v(); + v.visit(s); + p.get_immediate_children(s, c); + foreach(c[idx]) + accept(c[idx],v,p,0); + if(invoke_begin_end) + v.end_v(); + endfunction +endclass +class uvm_bottom_up_visitor_adapter#(type STRUCTURE=uvm_component,VISITOR=uvm_visitor#(STRUCTURE)) extends + uvm_visitor_adapter#(STRUCTURE,VISITOR); + function new (string name = ""); + super.new(name); + endfunction + virtual function void accept(STRUCTURE s, VISITOR v,uvm_structure_proxy#(STRUCTURE) p, bit invoke_begin_end=1); + STRUCTURE c[$]; + if(invoke_begin_end) + v.begin_v(); + p.get_immediate_children(s, c); + foreach(c[idx]) + accept(c[idx],v,p,0); + v.visit(s); + if(invoke_begin_end) + v.end_v(); + endfunction +endclass +class uvm_by_level_visitor_adapter#(type STRUCTURE=uvm_component,VISITOR=uvm_visitor#(STRUCTURE)) extends + uvm_visitor_adapter#(STRUCTURE,VISITOR); + function new (string name = ""); + super.new(name); + endfunction + virtual function void accept(STRUCTURE s, VISITOR v,uvm_structure_proxy#(STRUCTURE) p, bit invoke_begin_end=1); + STRUCTURE c[$]; + c.push_back(s); + if(invoke_begin_end) + v.begin_v(); + while(c.size() > 0) begin + STRUCTURE q[$]; + foreach(c[idx]) begin + STRUCTURE t[$]; + v.visit(c[idx]); + p.get_immediate_children(c[idx], t); + q = {q,t}; + end + c=q; + end + if(invoke_begin_end) + v.end_v(); + endfunction +endclass +class uvm_component_proxy extends uvm_structure_proxy#(uvm_component); + virtual function void get_immediate_children(STRUCTURE s, ref STRUCTURE children[$]); + s.get_children(children); + endfunction + function new (string name = ""); + super.new(name); + endfunction +endclass +class uvm_component_name_check_visitor extends uvm_visitor#(uvm_component); + local uvm_root _root; + virtual function string get_name_constraint(); + return "/^[][[:alnum:](){}_:-]([][[:alnum:](){} _:-]*[][[:alnum:](){}_:-])?$/"; + endfunction + virtual function void visit(NODE node); + if(_root != node) begin + if ( ! uvm_is_match( get_name_constraint(), node.get_name() ) ) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/COMP/NAME")) + uvm_report_warning ("UVM/COMP/NAME", $sformatf("the name \"%s\" of the component \"%s\" violates the uvm component name constraints",node.get_name(),node.get_full_name()), UVM_NONE, "t/uvm/src/base/uvm_traversal.svh", 274, "", 1); + end + end + end + endfunction + function new (string name = ""); + super.new(name); + endfunction + virtual function void begin_v(); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + _root = cs.get_root(); + endfunction +endclass +virtual class uvm_set_get_dap_base#(type T=int) extends uvm_object; + typedef uvm_set_get_dap_base#(T) this_type; + function new(string name="unnamed-uvm_set_get_dap_base#(T)"); + super.new(name); + endfunction : new + pure virtual function void set(T value); + pure virtual function bit try_set(T value); + pure virtual function T get(); + pure virtual function bit try_get(output T value); +endclass : uvm_set_get_dap_base +class uvm_simple_lock_dap#(type T=int) extends uvm_set_get_dap_base#(T); + typedef uvm_simple_lock_dap#(T) this_type; + typedef uvm_object_registry #(uvm_simple_lock_dap#(T)) type_id; + static function uvm_simple_lock_dap#(T) type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_simple_lock_dap#(T) tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + local T m_value; + local bit m_locked; + function new(string name="unnamed-uvm_simple_lock_dap#(T)"); + super.new(name); + m_locked = 0; + endfunction : new + virtual function void set(T value); + if (m_locked) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/SIMPLE_LOCK_DAP/SAG")) + uvm_report_error ("UVM/SIMPLE_LOCK_DAP/SAG", $sformatf("Attempt to set new value on '%s', but the data access policy forbids setting while locked!", get_full_name()), UVM_NONE, "t/uvm/src/dap/uvm_simple_lock_dap.svh", 68, "", 1); + end + else begin + m_value = value; + end + endfunction : set + virtual function bit try_set(T value); + if (m_locked) + return 0; + else begin + m_value = value; + return 1; + end + endfunction : try_set + virtual function T get(); + return m_value; + endfunction : get + virtual function bit try_get(output T value); + value = get(); + return 1; + endfunction : try_get + function void lock(); + m_locked = 1; + endfunction : lock + function void unlock(); + m_locked = 0; + endfunction : unlock + function bit is_locked(); + return m_locked; + endfunction : is_locked + virtual function void do_copy(uvm_object rhs); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/SIMPLE_LOCK_DAP/CPY")) + uvm_report_error ("UVM/SIMPLE_LOCK_DAP/CPY", "'copy()' is not supported for 'uvm_simple_lock_dap#(T)'", UVM_NONE, "t/uvm/src/dap/uvm_simple_lock_dap.svh", 144, "", 1); + end + endfunction : do_copy + virtual function void do_pack(uvm_packer packer); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/SIMPLE_LOCK_DAP/PCK")) + uvm_report_error ("UVM/SIMPLE_LOCK_DAP/PCK", "'pack()' is not supported for 'uvm_simple_lock_dap#(T)'", UVM_NONE, "t/uvm/src/dap/uvm_simple_lock_dap.svh", 149, "", 1); + end + endfunction : do_pack + virtual function void do_unpack(uvm_packer packer); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/SIMPLE_LOCK_DAP/UPK")) + uvm_report_error ("UVM/SIMPLE_LOCK_DAP/UPK", "'unpack()' is not supported for 'uvm_simple_lock_dap#(T)'", UVM_NONE, "t/uvm/src/dap/uvm_simple_lock_dap.svh", 154, "", 1); + end + endfunction : do_unpack + virtual function string convert2string(); + if (m_locked) + return $sformatf("(%s) %0p [LOCKED]", $typename(m_value), m_value); + else + return $sformatf("(%s) %0p [UNLOCKED]", $typename(m_value), m_value); + endfunction : convert2string + virtual function void do_print(uvm_printer printer); + super.do_print(printer); + printer.print_field("lock_state", m_locked, $bits(m_locked)); + printer.print_generic("value", + $typename(m_value), + 0, + $sformatf("%0p", m_value)); + endfunction : do_print +endclass +class uvm_get_to_lock_dap#(type T=int) extends uvm_set_get_dap_base#(T); + typedef uvm_get_to_lock_dap#(T) this_type; + typedef uvm_object_registry #(uvm_get_to_lock_dap#(T)) type_id; + static function uvm_get_to_lock_dap#(T) type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_get_to_lock_dap#(T) tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + local T m_value; + local bit m_locked; + function new(string name="unnamed-uvm_get_to_lock_dap#(T)"); + super.new(name); + m_locked = 0; + endfunction : new + virtual function void set(T value); + if (m_locked) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/GET_TO_LOCK_DAP/SAG")) + uvm_report_error ("UVM/GET_TO_LOCK_DAP/SAG", $sformatf("Attempt to set new value on '%s', but the data access policy forbids setting after a get!", get_full_name()), UVM_NONE, "t/uvm/src/dap/uvm_get_to_lock_dap.svh", 67, "", 1); + end + else begin + m_value = value; + end + endfunction : set + virtual function bit try_set(T value); + if (m_locked) + return 0; + else begin + m_value = value; + return 1; + end + endfunction : try_set + virtual function T get(); + m_locked = 1; + return m_value; + endfunction : get + virtual function bit try_get(output T value); + value = get(); + return 1; + endfunction : try_get + virtual function void do_copy(uvm_object rhs); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/GET_TO_LOCK_DAP/CPY")) + uvm_report_error ("UVM/GET_TO_LOCK_DAP/CPY", "'copy()' is not supported for 'uvm_get_to_lock_dap#(T)'", UVM_NONE, "t/uvm/src/dap/uvm_get_to_lock_dap.svh", 119, "", 1); + end + endfunction : do_copy + virtual function void do_pack(uvm_packer packer); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/GET_TO_LOCK_DAP/PCK")) + uvm_report_error ("UVM/GET_TO_LOCK_DAP/PCK", "'pack()' is not supported for 'uvm_get_to_lock_dap#(T)'", UVM_NONE, "t/uvm/src/dap/uvm_get_to_lock_dap.svh", 124, "", 1); + end + endfunction : do_pack + virtual function void do_unpack(uvm_packer packer); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/GET_TO_LOCK_DAP/UPK")) + uvm_report_error ("UVM/GET_TO_LOCK_DAP/UPK", "'unpack()' is not supported for 'uvm_get_to_lock_dap#(T)'", UVM_NONE, "t/uvm/src/dap/uvm_get_to_lock_dap.svh", 129, "", 1); + end + endfunction : do_unpack + virtual function string convert2string(); + if (m_locked) + return $sformatf("(%s) %0p [LOCKED]", $typename(m_value), m_value); + else + return $sformatf("(%s) %0p [UNLOCKED]", $typename(m_value), m_value); + endfunction : convert2string + virtual function void do_print(uvm_printer printer); + super.do_print(printer); + printer.print_field_int("lock_state", m_locked, $bits(m_locked)); + printer.print_generic("value", + $typename(m_value), + 0, + $sformatf("%0p", m_value)); + endfunction : do_print +endclass +class uvm_set_before_get_dap#(type T=int) extends uvm_set_get_dap_base#(T); + typedef uvm_set_before_get_dap#(T) this_type; + typedef uvm_object_registry #(uvm_set_before_get_dap#(T)) type_id; + static function uvm_set_before_get_dap#(T) type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_set_before_get_dap#(T) tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + local T m_value; + local bit m_set; + function new(string name="unnamed-uvm_set_before_get_dap#(T)"); + super.new(name); + m_set = 0; + endfunction : new + virtual function void set(T value); + m_set = 1; + m_value = value; + endfunction : set + virtual function bit try_set(T value); + set(value); + return 1; + endfunction : try_set + virtual function T get(); + if (!m_set) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/SET_BEFORE_GET_DAP/NO_SET")) + uvm_report_error ("UVM/SET_BEFORE_GET_DAP/NO_SET", $sformatf("Attempt to get value on '%s', but the data access policy forbits calling 'get' prior to calling 'set' or 'try_set'!", get_full_name()), UVM_NONE, "t/uvm/src/dap/uvm_set_before_get_dap.svh", 117, "", 1); + end + end + return m_value; + endfunction : get + virtual function bit try_get(output T value); + if (!m_set) begin + return 0; + end + else begin + value = m_value; + return 1; + end + endfunction : try_get + virtual function void do_copy(uvm_object rhs); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/SET_BEFORE_GET_DAP/CPY")) + uvm_report_error ("UVM/SET_BEFORE_GET_DAP/CPY", "'copy()' is not supported for 'uvm_set_before_get_dap#(T)'", UVM_NONE, "t/uvm/src/dap/uvm_set_before_get_dap.svh", 149, "", 1); + end + endfunction : do_copy + virtual function void do_pack(uvm_packer packer); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/SET_BEFORE_GET_DAP/PCK")) + uvm_report_error ("UVM/SET_BEFORE_GET_DAP/PCK", "'pack()' is not supported for 'uvm_set_before_get_dap#(T)'", UVM_NONE, "t/uvm/src/dap/uvm_set_before_get_dap.svh", 154, "", 1); + end + endfunction : do_pack + virtual function void do_unpack(uvm_packer packer); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/SET_BEFORE_GET_DAP/UPK")) + uvm_report_error ("UVM/SET_BEFORE_GET_DAP/UPK", "'unpack()' is not supported for 'uvm_set_before_get_dap#(T)'", UVM_NONE, "t/uvm/src/dap/uvm_set_before_get_dap.svh", 159, "", 1); + end + endfunction : do_unpack + virtual function string convert2string(); + if (m_set) + return $sformatf("(%s) %0p [SET]", $typename(m_value), m_value); + else + return $sformatf("(%s) %0p [UNSET]", $typename(m_value), m_value); + endfunction : convert2string + virtual function void do_print(uvm_printer printer); + super.do_print(printer); + printer.print_field_int("set_state", m_set, $bits(m_set)); + printer.print_generic("value", + $typename(m_value), + 0, + $sformatf("%0p", m_value)); + endfunction : do_print +endclass +virtual class uvm_tlm_if_base #(type T1=int, type T2=int); + virtual task put( input T1 t ); + uvm_report_error("put", "UVM TLM interface task not implemented", UVM_NONE); + endtask + virtual task get( output T2 t ); + uvm_report_error("get", "UVM TLM interface task not implemented", UVM_NONE); + endtask + virtual task peek( output T2 t ); + uvm_report_error("peek", "UVM TLM interface task not implemented", UVM_NONE); + endtask + virtual function bit try_put( input T1 t ); + uvm_report_error("try_put", "UVM TLM interface function not implemented", UVM_NONE); + return 0; + endfunction + virtual function bit can_put(); + uvm_report_error("can_put", "UVM TLM interface function not implemented", UVM_NONE); + return 0; + endfunction + virtual function bit try_get( output T2 t ); + uvm_report_error("try_get", "UVM TLM interface function not implemented", UVM_NONE); + return 0; + endfunction + virtual function bit can_get(); + uvm_report_error("can_get", "UVM TLM interface function not implemented", UVM_NONE); + return 0; + endfunction + virtual function bit try_peek( output T2 t ); + uvm_report_error("try_peek", "UVM TLM interface function not implemented", UVM_NONE); + return 0; + endfunction + virtual function bit can_peek(); + uvm_report_error("can_ppeek", "UVM TLM interface function not implemented", UVM_NONE); + return 0; + endfunction + virtual task transport( input T1 req , output T2 rsp ); + uvm_report_error("transport", "UVM TLM interface task not implemented", UVM_NONE); + endtask + virtual function bit nb_transport(input T1 req, output T2 rsp); + uvm_report_error("nb_transport", "UVM TLM interface function not implemented", UVM_NONE); + return 0; + endfunction + virtual function void write( input T1 t ); + uvm_report_error("write", "UVM TLM interface function not implemented", UVM_NONE); + endfunction +endclass +virtual class uvm_sqr_if_base #(type T1=uvm_object, T2=T1); + virtual task get_next_item(output T1 t); + uvm_report_error("get_next_item", "Sequencer interface task not implemented", UVM_NONE); + endtask + virtual task try_next_item(output T1 t); + uvm_report_error("try_next_item", "Sequencer interface task not implemented", UVM_NONE); + endtask + virtual function void item_done(input T2 t = null); + uvm_report_error("item_done", "Sequencer interface function not implemented", UVM_NONE); + endfunction + virtual task wait_for_sequences(); + uvm_report_error("wait_for_sequences", "Sequencer interface task not implemented", UVM_NONE); + endtask + virtual function bit has_do_available(); + uvm_report_error("has_do_available", "Sequencer interface function not implemented", UVM_NONE); + return 0; + endfunction + virtual task get(output T1 t); + uvm_report_error("get", "Sequencer interface task not implemented", UVM_NONE); + endtask + virtual task peek(output T1 t); + uvm_report_error("peek", "Sequencer interface task not implemented", UVM_NONE); + endtask + virtual task put(input T2 t); + uvm_report_error("put", "Sequencer interface task not implemented", UVM_NONE); + endtask + virtual function void put_response(input T2 t); + uvm_report_error("put_response", "Sequencer interface function not implemented", UVM_NONE); + endfunction + virtual function void disable_auto_item_recording(); + uvm_report_error("disable_auto_item_recording", "Sequencer interface function not implemented", UVM_NONE); + endfunction + virtual function bit is_auto_item_recording_enabled(); + uvm_report_error("is_auto_item_recording_enabled", "Sequencer interface function not implemented", UVM_NONE); + return 0; + endfunction +endclass +const int UVM_UNBOUNDED_CONNECTIONS = -1; +const string s_connection_error_id = "Connection Error"; +const string s_connection_warning_id = "Connection Warning"; +const string s_spaces = " "; +typedef class uvm_port_component_base; +typedef uvm_port_component_base uvm_port_list[string]; +virtual class uvm_port_component_base extends uvm_component; + function new (string name, uvm_component parent); + super.new(name,parent); + endfunction + pure virtual function void get_connected_to(ref uvm_port_list list); + pure virtual function bit is_port(); + pure virtual function bit is_export(); + pure virtual function bit is_imp(); + virtual function bit use_automatic_config(); + return 0; + endfunction : use_automatic_config + virtual task do_task_phase (uvm_phase phase); + endtask +endclass +class uvm_port_component #(type PORT=uvm_object) extends uvm_port_component_base; + PORT m_port; + function new (string name, uvm_component parent, PORT port); + super.new(name,parent); + if (port == null) + uvm_report_fatal("Bad usage", "Null handle to port", UVM_NONE); + m_port = port; + endfunction + virtual function string get_type_name(); + if(m_port == null) return "uvm_port_component"; + return m_port.get_type_name(); + endfunction + virtual function void resolve_bindings(); + m_port.resolve_bindings(); + endfunction + function PORT get_port(); + return m_port; + endfunction + virtual function void get_connected_to(ref uvm_port_list list); + PORT list1[string]; + m_port.get_connected_to(list1); + list.delete(); + foreach(list1[name]) begin + list[name] = list1[name].get_comp(); + end + endfunction + function bit is_port (); + return m_port.is_port(); + endfunction + function bit is_export (); + return m_port.is_export(); + endfunction + function bit is_imp (); + return m_port.is_imp(); + endfunction +endclass +virtual class uvm_port_base #(type IF=uvm_void) extends IF; + typedef uvm_port_base #(IF) this_type; + protected int unsigned m_if_mask; + protected this_type m_if; + protected int unsigned m_def_index; + uvm_port_component #(this_type) m_comp; + local this_type m_provided_by[string]; + local this_type m_provided_to[string]; + local uvm_port_type_e m_port_type; + local int m_min_size; + local int m_max_size; + local bit m_resolved; + local this_type m_imp_list[string]; + function new (string name, + uvm_component parent, + uvm_port_type_e port_type, + int min_size=0, + int max_size=1); + uvm_component comp; + int tmp; + m_port_type = port_type; + m_min_size = min_size; + m_max_size = max_size; + m_comp = new(name, parent, this); + if (!uvm_config_int::get(m_comp, "", "check_connection_relationships",tmp)) + m_comp.set_report_id_action(s_connection_warning_id, UVM_NO_ACTION); + endfunction + function string get_name(); + return m_comp.get_name(); + endfunction + virtual function string get_full_name(); + return m_comp.get_full_name(); + endfunction + virtual function uvm_component get_parent(); + return m_comp.get_parent(); + endfunction + virtual function uvm_port_component_base get_comp(); + return m_comp; + endfunction + virtual function string get_type_name(); + case( m_port_type ) + UVM_PORT : return "port"; + UVM_EXPORT : return "export"; + UVM_IMPLEMENTATION : return "implementation"; + endcase + endfunction + function int max_size (); + return m_max_size; + endfunction + function int min_size (); + return m_min_size; + endfunction + function bit is_unbounded (); + return (m_max_size == UVM_UNBOUNDED_CONNECTIONS); + endfunction + function bit is_port (); + return m_port_type == UVM_PORT; + endfunction + function bit is_export (); + return m_port_type == UVM_EXPORT; + endfunction + function bit is_imp (); + return m_port_type == UVM_IMPLEMENTATION; + endfunction + function int size (); + return m_imp_list.num(); + endfunction + function void set_if (int index=0); + m_if = get_if(index); + if (m_if != null) + m_def_index = index; + endfunction + function int m_get_if_mask(); + return m_if_mask; + endfunction + function void set_default_index (int index); + m_def_index = index; + endfunction + virtual function void connect (this_type provider); + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + if (end_of_elaboration_ph.get_state() == UVM_PHASE_EXECUTING || + end_of_elaboration_ph.get_state() == UVM_PHASE_DONE ) begin + m_comp.uvm_report_warning("Late Connection", + {"Attempt to connect ",this.get_full_name()," (of type ",this.get_type_name(), + ") at or after end_of_elaboration phase. Ignoring."}); + return; + end + if (provider == null) begin + m_comp.uvm_report_error(s_connection_error_id, + "Cannot connect to null port handle", UVM_NONE); + return; + end + if (provider == this) begin + m_comp.uvm_report_error(s_connection_error_id, + "Cannot connect a port instance to itself", UVM_NONE); + return; + end + if ((provider.m_if_mask & m_if_mask) != m_if_mask) begin + m_comp.uvm_report_error(s_connection_error_id, + {provider.get_full_name(), + " (of type ",provider.get_type_name(), + ") does not provide the complete interface required of this port (type ", + get_type_name(),")"}, UVM_NONE); + return; + end + if (is_imp()) begin + m_comp.uvm_report_error(s_connection_error_id, + $sformatf( +"Cannot call an imp port's connect method. An imp is connected only to the component passed in its constructor. (You attempted to bind this imp to %s)", provider.get_full_name()), UVM_NONE); + return; + end + if (is_export() && provider.is_port()) begin + m_comp.uvm_report_error(s_connection_error_id, + $sformatf( +"Cannot connect exports to ports Try calling port.connect(export) instead. (You attempted to bind this export to %s).", provider.get_full_name()), UVM_NONE); + return; + end + void'(m_check_relationship(provider)); + m_provided_by[provider.get_full_name()] = provider; + provider.m_provided_to[get_full_name()] = this; + endfunction + function void debug_connected_to (int level=0, int max_level=-1); + int sz, num, curr_num; + string s_sz; + static string indent, save; + this_type port; + if (level < 0) level = 0; + if (level == 0) begin save = ""; indent=" "; end + if (max_level != -1 && level >= max_level) + return; + num = m_provided_by.num(); + if (m_provided_by.num() != 0) begin + foreach (m_provided_by[nm]) begin + curr_num++; + port = m_provided_by[nm]; + save = {save, indent, " | \n"}; + save = {save, indent, " |_",nm," (",port.get_type_name(),")\n"}; + indent = (num > 1 && curr_num != num) ? {indent," | "}:{indent, " "}; + port.debug_connected_to(level+1, max_level); + indent = indent.substr(0,indent.len()-4-1); + end + end + if (level == 0) begin + if (save != "") + save = {"This port's fanout network:\n\n ", + get_full_name()," (",get_type_name(),")\n",save,"\n"}; + if (m_imp_list.num() == 0) begin + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + if (end_of_elaboration_ph.get_state() == UVM_PHASE_EXECUTING || + end_of_elaboration_ph.get_state() == UVM_PHASE_DONE ) + save = {save," Connected implementations: none\n"}; + else + save = {save, + " Connected implementations: not resolved until end-of-elab\n"}; + end + else begin + save = {save," Resolved implementation list:\n"}; + foreach (m_imp_list[nm]) begin + port = m_imp_list[nm]; + s_sz.itoa(sz); + save = {save, indent, s_sz, ": ",nm," (",port.get_type_name(),")\n"}; + sz++; + end + end + m_comp.uvm_report_info("debug_connected_to", save); + end + endfunction + function void debug_provided_to (int level=0, int max_level=-1); + string nm; + int num,curr_num; + this_type port; + static string indent, save; + if (level < 0) level = 0; + if (level == 0) begin save = ""; indent = " "; end + if (max_level != -1 && level > max_level) + return; + num = m_provided_to.num(); + if (num != 0) begin + foreach (m_provided_to[nm]) begin + curr_num++; + port = m_provided_to[nm]; + save = {save, indent, " | \n"}; + save = {save, indent, " |_",nm," (",port.get_type_name(),")\n"}; + indent = (num > 1 && curr_num != num) ? {indent," | "}:{indent, " "}; + port.debug_provided_to(level+1, max_level); + indent = indent.substr(0,indent.len()-4-1); + end + end + if (level == 0) begin + if (save != "") + save = {"This port's fanin network:\n\n ", + get_full_name()," (",get_type_name(),")\n",save,"\n"}; + if (m_provided_to.num() == 0) + save = {save,indent,"This port has not been bound\n"}; + m_comp.uvm_report_info("debug_provided_to", save); + end + endfunction + function void get_connected_to (ref uvm_port_base #(IF) list[string]); + this_type port; + list.delete(); + foreach (m_provided_by[name]) begin + port = m_provided_by[name]; + list[name] = port; + end + endfunction + function void get_provided_to (ref uvm_port_base #(IF) list[string]); + this_type port; + list.delete(); + foreach (m_provided_to[name]) begin + port = m_provided_to[name]; + list[name] = port; + end + endfunction + local function bit m_check_relationship (this_type provider); + string s; + this_type from; + uvm_component from_parent; + uvm_component to_parent; + uvm_component from_gparent; + uvm_component to_gparent; + if (get_type_name() == "uvm_analysis_port") + return 1; + from = this; + from_parent = get_parent(); + to_parent = provider.get_parent(); + if (from_parent == null || to_parent == null) + return 1; + from_gparent = from_parent.get_parent(); + to_gparent = to_parent.get_parent(); + if (from.is_port() && provider.is_port() && from_gparent != to_parent) begin + s = {provider.get_full_name(), + " (of type ",provider.get_type_name(), + ") is not up one level of hierarchy from this port. ", + "A port-to-port connection takes the form ", + "child_component.child_port.connect(parent_port)"}; + m_comp.uvm_report_warning(s_connection_warning_id, s, UVM_NONE); + return 0; + end + else if (from.is_port() && (provider.is_export() || provider.is_imp()) && + from_gparent != to_gparent) begin + s = {provider.get_full_name(), + " (of type ",provider.get_type_name(), + ") is not at the same level of hierarchy as this port. ", + "A port-to-export connection takes the form ", + "component1.port.connect(component2.export)"}; + m_comp.uvm_report_warning(s_connection_warning_id, s, UVM_NONE); + return 0; + end + else if (from.is_export() && (provider.is_export() || provider.is_imp()) && + from_parent != to_gparent) begin + s = {provider.get_full_name(), + " (of type ",provider.get_type_name(), + ") is not down one level of hierarchy from this export. ", + "An export-to-export or export-to-imp connection takes the form ", + "parent_export.connect(child_component.child_export)"}; + m_comp.uvm_report_warning(s_connection_warning_id, s, UVM_NONE); + return 0; + end + return 1; + endfunction + local function void m_add_list (this_type provider); + string sz; + this_type imp; + for (int i = 0; i < provider.size(); i++) begin + imp = provider.get_if(i); + if (!m_imp_list.exists(imp.get_full_name())) + m_imp_list[imp.get_full_name()] = imp; + end + endfunction + virtual function void resolve_bindings(); + if (m_resolved) + return; + if (is_imp()) begin + m_imp_list[get_full_name()] = this; + end + else begin + foreach (m_provided_by[nm]) begin + this_type port; + port = m_provided_by[nm]; + port.resolve_bindings(); + m_add_list(port); + end + end + m_resolved = 1; + if (size() < min_size() ) begin + m_comp.uvm_report_error(s_connection_error_id, + $sformatf("connection count of %0d does not meet required minimum of %0d", + size(), min_size()), UVM_NONE); + end + if (max_size() != UVM_UNBOUNDED_CONNECTIONS && size() > max_size() ) begin + m_comp.uvm_report_error(s_connection_error_id, + $sformatf("connection count of %0d exceeds maximum of %0d", + size(), max_size()), UVM_NONE); + end + if (size()) + set_if(0); + endfunction + function uvm_port_base #(IF) get_if(int index=0); + string s; + if (size()==0) begin + m_comp.uvm_report_warning("get_if", + "Port size is zero; cannot get interface at any index", UVM_NONE); + return null; + end + if (index < 0 || index >= size()) begin + $sformat(s, "Index %0d out of range [0,%0d]", index, size()-1); + m_comp.uvm_report_warning(s_connection_error_id, s, UVM_NONE); + return null; + end + foreach (m_imp_list[nm]) begin + if (index == 0) + return m_imp_list[nm]; + index--; + end + endfunction +endclass +class uvm_blocking_put_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = (1<<0); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_put_imp"; + endfunction + task put (T t); + m_imp.put(t); + endtask +endclass +class uvm_nonblocking_put_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = (1<<4); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_put_imp"; + endfunction + function bit try_put (T t); + return m_imp.try_put(t); + endfunction + function bit can_put(); + return m_imp.can_put(); + endfunction +endclass +class uvm_put_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = ((1<<0) | (1<<4)); + endfunction + virtual function string get_type_name(); + return "uvm_put_imp"; + endfunction + task put (T t); + m_imp.put(t); + endtask + function bit try_put (T t); + return m_imp.try_put(t); + endfunction + function bit can_put(); + return m_imp.can_put(); + endfunction +endclass +class uvm_blocking_get_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = (1<<1); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_get_imp"; + endfunction + task get (output T t); + m_imp.get(t); + endtask +endclass +class uvm_nonblocking_get_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = (1<<5); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_get_imp"; + endfunction + function bit try_get (output T t); + return m_imp.try_get(t); + endfunction + function bit can_get(); + return m_imp.can_get(); + endfunction +endclass +class uvm_get_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = ((1<<1) | (1<<5)); + endfunction + virtual function string get_type_name(); + return "uvm_get_imp"; + endfunction + task get (output T t); + m_imp.get(t); + endtask + function bit try_get (output T t); + return m_imp.try_get(t); + endfunction + function bit can_get(); + return m_imp.can_get(); + endfunction +endclass +class uvm_blocking_peek_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = (1<<2); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_peek_imp"; + endfunction + task peek (output T t); + m_imp.peek(t); + endtask +endclass +class uvm_nonblocking_peek_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = (1<<6); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_peek_imp"; + endfunction + function bit try_peek (output T t); + return m_imp.try_peek(t); + endfunction + function bit can_peek(); + return m_imp.can_peek(); + endfunction +endclass +class uvm_peek_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = ((1<<2) | (1<<6)); + endfunction + virtual function string get_type_name(); + return "uvm_peek_imp"; + endfunction + task peek (output T t); + m_imp.peek(t); + endtask + function bit try_peek (output T t); + return m_imp.try_peek(t); + endfunction + function bit can_peek(); + return m_imp.can_peek(); + endfunction +endclass +class uvm_blocking_get_peek_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = ((1<<1) | (1<<2)); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_get_peek_imp"; + endfunction + task get (output T t); + m_imp.get(t); + endtask + task peek (output T t); + m_imp.peek(t); + endtask +endclass +class uvm_nonblocking_get_peek_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = ((1<<5) | (1<<6)); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_get_peek_imp"; + endfunction + function bit try_get (output T t); + return m_imp.try_get(t); + endfunction + function bit can_get(); + return m_imp.can_get(); + endfunction + function bit try_peek (output T t); + return m_imp.try_peek(t); + endfunction + function bit can_peek(); + return m_imp.can_peek(); + endfunction +endclass +class uvm_get_peek_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = (((1<<1) | (1<<5)) | ((1<<2) | (1<<6))); + endfunction + virtual function string get_type_name(); + return "uvm_get_peek_imp"; + endfunction + task get (output T t); + m_imp.get(t); + endtask + task peek (output T t); + m_imp.peek(t); + endtask + function bit try_get (output T t); + return m_imp.try_get(t); + endfunction + function bit can_get(); + return m_imp.can_get(); + endfunction + function bit try_peek (output T t); + return m_imp.try_peek(t); + endfunction + function bit can_peek(); + return m_imp.can_peek(); + endfunction +endclass +class uvm_blocking_master_imp #(type REQ=int, type RSP=REQ, type IMP=int, + type REQ_IMP=IMP, type RSP_IMP=IMP) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + typedef IMP this_imp_type; + typedef REQ_IMP this_req_type; + typedef RSP_IMP this_rsp_type; + local this_req_type m_req_imp; + local this_rsp_type m_rsp_imp; + function new (string name, this_imp_type imp, + this_req_type req_imp = null, this_rsp_type rsp_imp = null); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + if(req_imp==null) $cast(req_imp, imp); + if(rsp_imp==null) $cast(rsp_imp, imp); + m_req_imp = req_imp; + m_rsp_imp = rsp_imp; + m_if_mask = ((1<<0) | (1<<1) | (1<<2) | (1<<9)); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_master_imp"; + endfunction + task put (REQ t); + m_req_imp.put(t); + endtask + task get (output RSP t); + m_rsp_imp.get(t); + endtask + task peek (output RSP t); + m_rsp_imp.peek(t); + endtask +endclass +class uvm_nonblocking_master_imp #(type REQ=int, type RSP=REQ, type IMP=int, + type REQ_IMP=IMP, type RSP_IMP=IMP) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + typedef IMP this_imp_type; + typedef REQ_IMP this_req_type; + typedef RSP_IMP this_rsp_type; + local this_req_type m_req_imp; + local this_rsp_type m_rsp_imp; + function new (string name, this_imp_type imp, + this_req_type req_imp = null, this_rsp_type rsp_imp = null); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + if(req_imp==null) $cast(req_imp, imp); + if(rsp_imp==null) $cast(rsp_imp, imp); + m_req_imp = req_imp; + m_rsp_imp = rsp_imp; + m_if_mask = ((1<<4) | (1<<5) | (1<<6) | (1<<9)); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_master_imp"; + endfunction + function bit try_put (REQ t); + return m_req_imp.try_put(t); + endfunction + function bit can_put(); + return m_req_imp.can_put(); + endfunction + function bit try_get (output RSP t); + return m_rsp_imp.try_get(t); + endfunction + function bit can_get(); + return m_rsp_imp.can_get(); + endfunction + function bit try_peek (output RSP t); + return m_rsp_imp.try_peek(t); + endfunction + function bit can_peek(); + return m_rsp_imp.can_peek(); + endfunction +endclass +class uvm_master_imp #(type REQ=int, type RSP=REQ, type IMP=int, + type REQ_IMP=IMP, type RSP_IMP=IMP) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + typedef IMP this_imp_type; + typedef REQ_IMP this_req_type; + typedef RSP_IMP this_rsp_type; + local this_req_type m_req_imp; + local this_rsp_type m_rsp_imp; + function new (string name, this_imp_type imp, + this_req_type req_imp = null, this_rsp_type rsp_imp = null); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + if(req_imp==null) $cast(req_imp, imp); + if(rsp_imp==null) $cast(rsp_imp, imp); + m_req_imp = req_imp; + m_rsp_imp = rsp_imp; + m_if_mask = (((1<<0) | (1<<1) | (1<<2) | (1<<9)) | ((1<<4) | (1<<5) | (1<<6) | (1<<9))); + endfunction + virtual function string get_type_name(); + return "uvm_master_imp"; + endfunction + task put (REQ t); + m_req_imp.put(t); + endtask + function bit try_put (REQ t); + return m_req_imp.try_put(t); + endfunction + function bit can_put(); + return m_req_imp.can_put(); + endfunction + task get (output RSP t); + m_rsp_imp.get(t); + endtask + task peek (output RSP t); + m_rsp_imp.peek(t); + endtask + function bit try_get (output RSP t); + return m_rsp_imp.try_get(t); + endfunction + function bit can_get(); + return m_rsp_imp.can_get(); + endfunction + function bit try_peek (output RSP t); + return m_rsp_imp.try_peek(t); + endfunction + function bit can_peek(); + return m_rsp_imp.can_peek(); + endfunction +endclass +class uvm_blocking_slave_imp #(type REQ=int, type RSP=REQ, type IMP=int, + type REQ_IMP=IMP, type RSP_IMP=IMP) + extends uvm_port_base #(uvm_tlm_if_base #(RSP, REQ)); + typedef IMP this_imp_type; + typedef REQ_IMP this_req_type; + typedef RSP_IMP this_rsp_type; + local this_req_type m_req_imp; + local this_rsp_type m_rsp_imp; + function new (string name, this_imp_type imp, + this_req_type req_imp = null, this_rsp_type rsp_imp = null); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + if(req_imp==null) $cast(req_imp, imp); + if(rsp_imp==null) $cast(rsp_imp, imp); + m_req_imp = req_imp; + m_rsp_imp = rsp_imp; + m_if_mask = ((1<<0) | (1<<1) | (1<<2) | (1<<10)); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_slave_imp"; + endfunction + task put (RSP t); + m_rsp_imp.put(t); + endtask + task get (output REQ t); + m_req_imp.get(t); + endtask + task peek (output REQ t); + m_req_imp.peek(t); + endtask +endclass +class uvm_nonblocking_slave_imp #(type REQ=int, type RSP=REQ, type IMP=int, + type REQ_IMP=IMP, type RSP_IMP=IMP) + extends uvm_port_base #(uvm_tlm_if_base #(RSP, REQ)); + typedef IMP this_imp_type; + typedef REQ_IMP this_req_type; + typedef RSP_IMP this_rsp_type; + local this_req_type m_req_imp; + local this_rsp_type m_rsp_imp; + function new (string name, this_imp_type imp, + this_req_type req_imp = null, this_rsp_type rsp_imp = null); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + if(req_imp==null) $cast(req_imp, imp); + if(rsp_imp==null) $cast(rsp_imp, imp); + m_req_imp = req_imp; + m_rsp_imp = rsp_imp; + m_if_mask = ((1<<4) | (1<<5) | (1<<6) | (1<<10)); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_slave_imp"; + endfunction + function bit try_put (RSP t); + return m_rsp_imp.try_put(t); + endfunction + function bit can_put(); + return m_rsp_imp.can_put(); + endfunction + function bit try_get (output REQ t); + return m_req_imp.try_get(t); + endfunction + function bit can_get(); + return m_req_imp.can_get(); + endfunction + function bit try_peek (output REQ t); + return m_req_imp.try_peek(t); + endfunction + function bit can_peek(); + return m_req_imp.can_peek(); + endfunction +endclass +class uvm_slave_imp #(type REQ=int, type RSP=REQ, type IMP=int, + type REQ_IMP=IMP, type RSP_IMP=IMP) + extends uvm_port_base #(uvm_tlm_if_base #(RSP, REQ)); + typedef IMP this_imp_type; + typedef REQ_IMP this_req_type; + typedef RSP_IMP this_rsp_type; + local this_req_type m_req_imp; + local this_rsp_type m_rsp_imp; + function new (string name, this_imp_type imp, + this_req_type req_imp = null, this_rsp_type rsp_imp = null); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + if(req_imp==null) $cast(req_imp, imp); + if(rsp_imp==null) $cast(rsp_imp, imp); + m_req_imp = req_imp; + m_rsp_imp = rsp_imp; + m_if_mask = (((1<<0) | (1<<1) | (1<<2) | (1<<10)) | ((1<<4) | (1<<5) | (1<<6) | (1<<10))); + endfunction + virtual function string get_type_name(); + return "uvm_slave_imp"; + endfunction + task put (RSP t); + m_rsp_imp.put(t); + endtask + function bit try_put (RSP t); + return m_rsp_imp.try_put(t); + endfunction + function bit can_put(); + return m_rsp_imp.can_put(); + endfunction + task get (output REQ t); + m_req_imp.get(t); + endtask + task peek (output REQ t); + m_req_imp.peek(t); + endtask + function bit try_get (output REQ t); + return m_req_imp.try_get(t); + endfunction + function bit can_get(); + return m_req_imp.can_get(); + endfunction + function bit try_peek (output REQ t); + return m_req_imp.try_peek(t); + endfunction + function bit can_peek(); + return m_req_imp.can_peek(); + endfunction +endclass +class uvm_blocking_transport_imp #(type REQ=int, type RSP=REQ, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = (1<<3); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_transport_imp"; + endfunction + task transport (REQ req, output RSP rsp); + m_imp.transport(req, rsp); + endtask +endclass +class uvm_nonblocking_transport_imp #(type REQ=int, type RSP=REQ, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = (1<<7); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_transport_imp"; + endfunction + function bit nb_transport (REQ req, output RSP rsp); + return m_imp.nb_transport(req, rsp); + endfunction +endclass +class uvm_transport_imp #(type REQ=int, type RSP=REQ, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = ((1<<3) | (1<<7)); + endfunction + virtual function string get_type_name(); + return "uvm_transport_imp"; + endfunction + task transport (REQ req, output RSP rsp); + m_imp.transport(req, rsp); + endtask + function bit nb_transport (REQ req, output RSP rsp); + return m_imp.nb_transport(req, rsp); + endfunction +endclass +class uvm_blocking_put_port #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = (1<<0); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_put_port"; + endfunction + task put (T t); + this.m_if.put(t); + endtask +endclass +class uvm_nonblocking_put_port #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = (1<<4); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_put_port"; + endfunction + function bit try_put (T t); + return this.m_if.try_put(t); + endfunction + function bit can_put(); + return this.m_if.can_put(); + endfunction +endclass +class uvm_put_port #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = ((1<<0) | (1<<4)); + endfunction + virtual function string get_type_name(); + return "uvm_put_port"; + endfunction + task put (T t); + this.m_if.put(t); + endtask + function bit try_put (T t); + return this.m_if.try_put(t); + endfunction + function bit can_put(); + return this.m_if.can_put(); + endfunction +endclass +class uvm_blocking_get_port #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = (1<<1); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_get_port"; + endfunction + task get (output T t); + this.m_if.get(t); + endtask +endclass +class uvm_nonblocking_get_port #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = (1<<5); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_get_port"; + endfunction + function bit try_get (output T t); + return this.m_if.try_get(t); + endfunction + function bit can_get(); + return this.m_if.can_get(); + endfunction +endclass +class uvm_get_port #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = ((1<<1) | (1<<5)); + endfunction + virtual function string get_type_name(); + return "uvm_get_port"; + endfunction + task get (output T t); + this.m_if.get(t); + endtask + function bit try_get (output T t); + return this.m_if.try_get(t); + endfunction + function bit can_get(); + return this.m_if.can_get(); + endfunction +endclass +class uvm_blocking_peek_port #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = (1<<2); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_peek_port"; + endfunction + task peek (output T t); + this.m_if.peek(t); + endtask +endclass +class uvm_nonblocking_peek_port #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = (1<<6); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_peek_port"; + endfunction + function bit try_peek (output T t); + return this.m_if.try_peek(t); + endfunction + function bit can_peek(); + return this.m_if.can_peek(); + endfunction +endclass +class uvm_peek_port #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = ((1<<2) | (1<<6)); + endfunction + virtual function string get_type_name(); + return "uvm_peek_port"; + endfunction + task peek (output T t); + this.m_if.peek(t); + endtask + function bit try_peek (output T t); + return this.m_if.try_peek(t); + endfunction + function bit can_peek(); + return this.m_if.can_peek(); + endfunction +endclass +class uvm_blocking_get_peek_port #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = ((1<<1) | (1<<2)); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_get_peek_port"; + endfunction + task get (output T t); + this.m_if.get(t); + endtask + task peek (output T t); + this.m_if.peek(t); + endtask +endclass +class uvm_nonblocking_get_peek_port #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = ((1<<5) | (1<<6)); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_get_peek_port"; + endfunction + function bit try_get (output T t); + return this.m_if.try_get(t); + endfunction + function bit can_get(); + return this.m_if.can_get(); + endfunction + function bit try_peek (output T t); + return this.m_if.try_peek(t); + endfunction + function bit can_peek(); + return this.m_if.can_peek(); + endfunction +endclass +class uvm_get_peek_port #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = (((1<<1) | (1<<5)) | ((1<<2) | (1<<6))); + endfunction + virtual function string get_type_name(); + return "uvm_get_peek_port"; + endfunction + task get (output T t); + this.m_if.get(t); + endtask + task peek (output T t); + this.m_if.peek(t); + endtask + function bit try_get (output T t); + return this.m_if.try_get(t); + endfunction + function bit can_get(); + return this.m_if.can_get(); + endfunction + function bit try_peek (output T t); + return this.m_if.try_peek(t); + endfunction + function bit can_peek(); + return this.m_if.can_peek(); + endfunction +endclass +class uvm_blocking_master_port #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = ((1<<0) | (1<<1) | (1<<2) | (1<<9)); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_master_port"; + endfunction + task put (REQ t); + this.m_if.put(t); + endtask + task get (output RSP t); + this.m_if.get(t); + endtask + task peek (output RSP t); + this.m_if.peek(t); + endtask +endclass +class uvm_nonblocking_master_port #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = ((1<<4) | (1<<5) | (1<<6) | (1<<9)); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_master_port"; + endfunction + function bit try_put (REQ t); + return this.m_if.try_put(t); + endfunction + function bit can_put(); + return this.m_if.can_put(); + endfunction + function bit try_get (output RSP t); + return this.m_if.try_get(t); + endfunction + function bit can_get(); + return this.m_if.can_get(); + endfunction + function bit try_peek (output RSP t); + return this.m_if.try_peek(t); + endfunction + function bit can_peek(); + return this.m_if.can_peek(); + endfunction +endclass +class uvm_master_port #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = (((1<<0) | (1<<1) | (1<<2) | (1<<9)) | ((1<<4) | (1<<5) | (1<<6) | (1<<9))); + endfunction + virtual function string get_type_name(); + return "uvm_master_port"; + endfunction + task put (REQ t); + this.m_if.put(t); + endtask + function bit try_put (REQ t); + return this.m_if.try_put(t); + endfunction + function bit can_put(); + return this.m_if.can_put(); + endfunction + task get (output RSP t); + this.m_if.get(t); + endtask + task peek (output RSP t); + this.m_if.peek(t); + endtask + function bit try_get (output RSP t); + return this.m_if.try_get(t); + endfunction + function bit can_get(); + return this.m_if.can_get(); + endfunction + function bit try_peek (output RSP t); + return this.m_if.try_peek(t); + endfunction + function bit can_peek(); + return this.m_if.can_peek(); + endfunction +endclass +class uvm_blocking_slave_port #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(RSP, REQ)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = ((1<<0) | (1<<1) | (1<<2) | (1<<10)); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_slave_port"; + endfunction + task put (RSP t); + this.m_if.put(t); + endtask + task get (output REQ t); + this.m_if.get(t); + endtask + task peek (output REQ t); + this.m_if.peek(t); + endtask +endclass +class uvm_nonblocking_slave_port #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(RSP, REQ)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = ((1<<4) | (1<<5) | (1<<6) | (1<<10)); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_slave_port"; + endfunction + function bit try_put (RSP t); + return this.m_if.try_put(t); + endfunction + function bit can_put(); + return this.m_if.can_put(); + endfunction + function bit try_get (output REQ t); + return this.m_if.try_get(t); + endfunction + function bit can_get(); + return this.m_if.can_get(); + endfunction + function bit try_peek (output REQ t); + return this.m_if.try_peek(t); + endfunction + function bit can_peek(); + return this.m_if.can_peek(); + endfunction +endclass +class uvm_slave_port #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(RSP, REQ)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = (((1<<0) | (1<<1) | (1<<2) | (1<<10)) | ((1<<4) | (1<<5) | (1<<6) | (1<<10))); + endfunction + virtual function string get_type_name(); + return "uvm_slave_port"; + endfunction + task put (RSP t); + this.m_if.put(t); + endtask + function bit try_put (RSP t); + return this.m_if.try_put(t); + endfunction + function bit can_put(); + return this.m_if.can_put(); + endfunction + task get (output REQ t); + this.m_if.get(t); + endtask + task peek (output REQ t); + this.m_if.peek(t); + endtask + function bit try_get (output REQ t); + return this.m_if.try_get(t); + endfunction + function bit can_get(); + return this.m_if.can_get(); + endfunction + function bit try_peek (output REQ t); + return this.m_if.try_peek(t); + endfunction + function bit can_peek(); + return this.m_if.can_peek(); + endfunction +endclass +class uvm_blocking_transport_port #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = (1<<3); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_transport_port"; + endfunction + task transport (REQ req, output RSP rsp); + this.m_if.transport(req, rsp); + endtask +endclass +class uvm_nonblocking_transport_port #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = (1<<7); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_transport_port"; + endfunction + function bit nb_transport (REQ req, output RSP rsp); + return this.m_if.nb_transport(req, rsp); + endfunction +endclass +class uvm_transport_port #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = ((1<<3) | (1<<7)); + endfunction + virtual function string get_type_name(); + return "uvm_transport_port"; + endfunction + task transport (REQ req, output RSP rsp); + this.m_if.transport(req, rsp); + endtask + function bit nb_transport (REQ req, output RSP rsp); + return this.m_if.nb_transport(req, rsp); + endfunction +endclass +class uvm_blocking_put_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = (1<<0); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_put_export"; + endfunction + task put (T t); + this.m_if.put(t); + endtask +endclass +class uvm_nonblocking_put_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = (1<<4); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_put_export"; + endfunction + function bit try_put (T t); + return this.m_if.try_put(t); + endfunction + function bit can_put(); + return this.m_if.can_put(); + endfunction +endclass +class uvm_put_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = ((1<<0) | (1<<4)); + endfunction + virtual function string get_type_name(); + return "uvm_put_export"; + endfunction + task put (T t); + this.m_if.put(t); + endtask + function bit try_put (T t); + return this.m_if.try_put(t); + endfunction + function bit can_put(); + return this.m_if.can_put(); + endfunction +endclass +class uvm_blocking_get_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = (1<<1); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_get_export"; + endfunction + task get (output T t); + this.m_if.get(t); + endtask +endclass +class uvm_nonblocking_get_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = (1<<5); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_get_export"; + endfunction + function bit try_get (output T t); + return this.m_if.try_get(t); + endfunction + function bit can_get(); + return this.m_if.can_get(); + endfunction +endclass +class uvm_get_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = ((1<<1) | (1<<5)); + endfunction + virtual function string get_type_name(); + return "uvm_get_export"; + endfunction + task get (output T t); + this.m_if.get(t); + endtask + function bit try_get (output T t); + return this.m_if.try_get(t); + endfunction + function bit can_get(); + return this.m_if.can_get(); + endfunction +endclass +class uvm_blocking_peek_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = (1<<2); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_peek_export"; + endfunction + task peek (output T t); + this.m_if.peek(t); + endtask +endclass +class uvm_nonblocking_peek_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = (1<<6); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_peek_export"; + endfunction + function bit try_peek (output T t); + return this.m_if.try_peek(t); + endfunction + function bit can_peek(); + return this.m_if.can_peek(); + endfunction +endclass +class uvm_peek_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = ((1<<2) | (1<<6)); + endfunction + virtual function string get_type_name(); + return "uvm_peek_export"; + endfunction + task peek (output T t); + this.m_if.peek(t); + endtask + function bit try_peek (output T t); + return this.m_if.try_peek(t); + endfunction + function bit can_peek(); + return this.m_if.can_peek(); + endfunction +endclass +class uvm_blocking_get_peek_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = ((1<<1) | (1<<2)); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_get_peek_export"; + endfunction + task get (output T t); + this.m_if.get(t); + endtask + task peek (output T t); + this.m_if.peek(t); + endtask +endclass +class uvm_nonblocking_get_peek_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = ((1<<5) | (1<<6)); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_get_peek_export"; + endfunction + function bit try_get (output T t); + return this.m_if.try_get(t); + endfunction + function bit can_get(); + return this.m_if.can_get(); + endfunction + function bit try_peek (output T t); + return this.m_if.try_peek(t); + endfunction + function bit can_peek(); + return this.m_if.can_peek(); + endfunction +endclass +class uvm_get_peek_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = (((1<<1) | (1<<5)) | ((1<<2) | (1<<6))); + endfunction + virtual function string get_type_name(); + return "uvm_get_peek_export"; + endfunction + task get (output T t); + this.m_if.get(t); + endtask + task peek (output T t); + this.m_if.peek(t); + endtask + function bit try_get (output T t); + return this.m_if.try_get(t); + endfunction + function bit can_get(); + return this.m_if.can_get(); + endfunction + function bit try_peek (output T t); + return this.m_if.try_peek(t); + endfunction + function bit can_peek(); + return this.m_if.can_peek(); + endfunction +endclass +class uvm_blocking_master_export #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = ((1<<0) | (1<<1) | (1<<2) | (1<<9)); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_master_export"; + endfunction + task put (REQ t); + this.m_if.put(t); + endtask + task get (output RSP t); + this.m_if.get(t); + endtask + task peek (output RSP t); + this.m_if.peek(t); + endtask +endclass +class uvm_nonblocking_master_export #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = ((1<<4) | (1<<5) | (1<<6) | (1<<9)); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_master_export"; + endfunction + function bit try_put (REQ t); + return this.m_if.try_put(t); + endfunction + function bit can_put(); + return this.m_if.can_put(); + endfunction + function bit try_get (output RSP t); + return this.m_if.try_get(t); + endfunction + function bit can_get(); + return this.m_if.can_get(); + endfunction + function bit try_peek (output RSP t); + return this.m_if.try_peek(t); + endfunction + function bit can_peek(); + return this.m_if.can_peek(); + endfunction +endclass +class uvm_master_export #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = (((1<<0) | (1<<1) | (1<<2) | (1<<9)) | ((1<<4) | (1<<5) | (1<<6) | (1<<9))); + endfunction + virtual function string get_type_name(); + return "uvm_master_export"; + endfunction + task put (REQ t); + this.m_if.put(t); + endtask + function bit try_put (REQ t); + return this.m_if.try_put(t); + endfunction + function bit can_put(); + return this.m_if.can_put(); + endfunction + task get (output RSP t); + this.m_if.get(t); + endtask + task peek (output RSP t); + this.m_if.peek(t); + endtask + function bit try_get (output RSP t); + return this.m_if.try_get(t); + endfunction + function bit can_get(); + return this.m_if.can_get(); + endfunction + function bit try_peek (output RSP t); + return this.m_if.try_peek(t); + endfunction + function bit can_peek(); + return this.m_if.can_peek(); + endfunction +endclass +class uvm_blocking_slave_export #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(RSP, REQ)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = ((1<<0) | (1<<1) | (1<<2) | (1<<10)); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_slave_export"; + endfunction + task put (RSP t); + this.m_if.put(t); + endtask + task get (output REQ t); + this.m_if.get(t); + endtask + task peek (output REQ t); + this.m_if.peek(t); + endtask +endclass +class uvm_nonblocking_slave_export #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(RSP, REQ)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = ((1<<4) | (1<<5) | (1<<6) | (1<<10)); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_slave_export"; + endfunction + function bit try_put (RSP t); + return this.m_if.try_put(t); + endfunction + function bit can_put(); + return this.m_if.can_put(); + endfunction + function bit try_get (output REQ t); + return this.m_if.try_get(t); + endfunction + function bit can_get(); + return this.m_if.can_get(); + endfunction + function bit try_peek (output REQ t); + return this.m_if.try_peek(t); + endfunction + function bit can_peek(); + return this.m_if.can_peek(); + endfunction +endclass +class uvm_slave_export #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(RSP, REQ)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = (((1<<0) | (1<<1) | (1<<2) | (1<<10)) | ((1<<4) | (1<<5) | (1<<6) | (1<<10))); + endfunction + virtual function string get_type_name(); + return "uvm_slave_export"; + endfunction + task put (RSP t); + this.m_if.put(t); + endtask + function bit try_put (RSP t); + return this.m_if.try_put(t); + endfunction + function bit can_put(); + return this.m_if.can_put(); + endfunction + task get (output REQ t); + this.m_if.get(t); + endtask + task peek (output REQ t); + this.m_if.peek(t); + endtask + function bit try_get (output REQ t); + return this.m_if.try_get(t); + endfunction + function bit can_get(); + return this.m_if.can_get(); + endfunction + function bit try_peek (output REQ t); + return this.m_if.try_peek(t); + endfunction + function bit can_peek(); + return this.m_if.can_peek(); + endfunction +endclass +class uvm_blocking_transport_export #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = (1<<3); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_transport_export"; + endfunction + task transport (REQ req, output RSP rsp); + this.m_if.transport(req, rsp); + endtask +endclass +class uvm_nonblocking_transport_export #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = (1<<7); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_transport_export"; + endfunction + function bit nb_transport (REQ req, output RSP rsp); + return this.m_if.nb_transport(req, rsp); + endfunction +endclass +class uvm_transport_export #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = ((1<<3) | (1<<7)); + endfunction + virtual function string get_type_name(); + return "uvm_transport_export"; + endfunction + task transport (REQ req, output RSP rsp); + this.m_if.transport(req, rsp); + endtask + function bit nb_transport (REQ req, output RSP rsp); + return this.m_if.nb_transport(req, rsp); + endfunction +endclass +class uvm_analysis_port # (type T = int) + extends uvm_port_base # (uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent); + super.new (name, parent, UVM_PORT, 0, UVM_UNBOUNDED_CONNECTIONS); + m_if_mask = (1<<8); + endfunction + virtual function string get_type_name(); + return "uvm_analysis_port"; + endfunction + function void write (input T t); + uvm_tlm_if_base # (T, T) tif; + for (int i = 0; i < this.size(); i++) begin + tif = this.get_if (i); + if ( tif == null ) + uvm_report_fatal ("NTCONN", {"No uvm_tlm interface is connected to ", get_full_name(), " for executing write()"}, UVM_NONE); + tif.write (t); + end + endfunction +endclass +class uvm_analysis_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = (1<<8); + endfunction + virtual function string get_type_name(); + return "uvm_analysis_imp"; + endfunction + function void write (input T t); + m_imp.write (t); + endfunction +endclass +class uvm_analysis_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent = null); + super.new (name, parent, UVM_EXPORT, 1, UVM_UNBOUNDED_CONNECTIONS); + m_if_mask = (1<<8); + endfunction + virtual function string get_type_name(); + return "uvm_analysis_export"; + endfunction + function void write (input T t); + uvm_tlm_if_base #(T, T) tif; + for (int i = 0; i < this.size(); i++) begin + tif = this.get_if (i); + if (tif == null) + uvm_report_fatal ("NTCONN", {"No uvm_tlm interface is connected to ", get_full_name(), " for executing write()"}, UVM_NONE); + tif.write (t); + end + endfunction +endclass +class uvm_tlm_event; + event trigger; +endclass +virtual class uvm_tlm_fifo_base #(type T=int) extends uvm_component; + typedef uvm_abstract_component_registry #(uvm_tlm_fifo_base #(T)) type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + typedef uvm_tlm_fifo_base #(T) this_type; + uvm_put_imp #(T, this_type) put_export; + uvm_get_peek_imp #(T, this_type) get_peek_export; + uvm_analysis_port #(T) put_ap; + uvm_analysis_port #(T) get_ap; + uvm_put_imp #(T, this_type) blocking_put_export; + uvm_put_imp #(T, this_type) nonblocking_put_export; + uvm_get_peek_imp #(T, this_type) blocking_get_export; + uvm_get_peek_imp #(T, this_type) nonblocking_get_export; + uvm_get_peek_imp #(T, this_type) get_export; + uvm_get_peek_imp #(T, this_type) blocking_peek_export; + uvm_get_peek_imp #(T, this_type) nonblocking_peek_export; + uvm_get_peek_imp #(T, this_type) peek_export; + uvm_get_peek_imp #(T, this_type) blocking_get_peek_export; + uvm_get_peek_imp #(T, this_type) nonblocking_get_peek_export; + function new(string name, uvm_component parent = null); + super.new(name, parent); + put_export = new("put_export", this); + blocking_put_export = put_export; + nonblocking_put_export = put_export; + get_peek_export = new("get_peek_export", this); + blocking_get_peek_export = get_peek_export; + nonblocking_get_peek_export = get_peek_export; + blocking_get_export = get_peek_export; + nonblocking_get_export = get_peek_export; + get_export = get_peek_export; + blocking_peek_export = get_peek_export; + nonblocking_peek_export = get_peek_export; + peek_export = get_peek_export; + put_ap = new("put_ap", this); + get_ap = new("get_ap", this); + endfunction + virtual function bit use_automatic_config(); + return 0; + endfunction : use_automatic_config + virtual function void flush(); + uvm_report_error("flush", "fifo channel function not implemented", UVM_NONE); + endfunction + virtual function int size(); + uvm_report_error("size", "fifo channel function not implemented", UVM_NONE); + return 0; + endfunction + virtual task put(T t); + uvm_report_error("put", "fifo channel task not implemented", UVM_NONE); + endtask + virtual task get(output T t); + uvm_report_error("get", "fifo channel task not implemented", UVM_NONE); + endtask + virtual task peek(output T t); + uvm_report_error("peek", "fifo channel task not implemented", UVM_NONE); + endtask + virtual function bit try_put(T t); + uvm_report_error("try_put", "fifo channel function not implemented", UVM_NONE); + return 0; + endfunction + virtual function bit try_get(output T t); + uvm_report_error("try_get", "fifo channel function not implemented", UVM_NONE); + return 0; + endfunction + virtual function bit try_peek(output T t); + uvm_report_error("try_peek", "fifo channel function not implemented", UVM_NONE); + return 0; + endfunction + virtual function bit can_put(); + uvm_report_error("can_put", "fifo channel function not implemented", UVM_NONE); + return 0; + endfunction + virtual function bit can_get(); + uvm_report_error("can_get", "fifo channel function not implemented", UVM_NONE); + return 0; + endfunction + virtual function bit can_peek(); + uvm_report_error("can_peek", "fifo channel function not implemented", UVM_NONE); + return 0; + endfunction + virtual function uvm_tlm_event ok_to_put(); + uvm_report_error("ok_to_put", "fifo channel function not implemented", UVM_NONE); + return null; + endfunction + virtual function uvm_tlm_event ok_to_get(); + uvm_report_error("ok_to_get", "fifo channel function not implemented", UVM_NONE); + return null; + endfunction + virtual function uvm_tlm_event ok_to_peek(); + uvm_report_error("ok_to_peek", "fifo channel function not implemented", UVM_NONE); + return null; + endfunction + virtual function bit is_empty(); + uvm_report_error("is_empty", "fifo channel function not implemented", UVM_NONE); + return 0; + endfunction + virtual function bit is_full(); + uvm_report_error("is_full", "fifo channel function not implemented"); + return 0; + endfunction + virtual function int used(); + uvm_report_error("used", "fifo channel function not implemented", UVM_NONE); + return 0; + endfunction +endclass +typedef class uvm_tlm_event; +class uvm_tlm_fifo #(type T=int) extends uvm_tlm_fifo_base #(T); + typedef uvm_component_registry #(uvm_tlm_fifo#(T)) type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_tlm_fifo #(T)"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_tlm_fifo #(T)"; + endfunction : get_type_name + local mailbox #( T ) m; + local int m_size; + protected int m_pending_blocked_gets; + function new(string name, uvm_component parent = null, int size = 1); + super.new(name, parent); + m = new( size ); + m_size = size; + endfunction + virtual function int size(); + return m_size; + endfunction + virtual function int used(); + return m.num(); + endfunction + virtual function bit is_empty(); + return (m.num() == 0); + endfunction + virtual function bit is_full(); + return (m_size != 0) && (m.num() == m_size); + endfunction + virtual task put( input T t ); + m.put( t ); + put_ap.write( t ); + endtask + virtual task get( output T t ); + m_pending_blocked_gets++; + m.get( t ); + m_pending_blocked_gets--; + get_ap.write( t ); + endtask + virtual task peek( output T t ); + m.peek( t ); + endtask + virtual function bit try_get( output T t ); + if( !m.try_get( t ) ) begin + return 0; + end + get_ap.write( t ); + return 1; + endfunction + virtual function bit try_peek( output T t ); + if( !m.try_peek( t ) ) begin + return 0; + end + return 1; + endfunction + virtual function bit try_put( input T t ); + if( !m.try_put( t ) ) begin + return 0; + end + put_ap.write( t ); + return 1; + endfunction + virtual function bit can_put(); + return m_size == 0 || m.num() < m_size; + endfunction + virtual function bit can_get(); + return m.num() > 0 && m_pending_blocked_gets == 0; + endfunction + virtual function bit can_peek(); + return m.num() > 0; + endfunction + virtual function void flush(); + T t; + bit r; + r = 1; + while( r ) r = try_get( t ) ; + if( m.num() > 0 && m_pending_blocked_gets != 0 ) begin + uvm_report_error("flush failed" , + "there are blocked gets preventing the flush", UVM_NONE); + end + endfunction +endclass +class uvm_tlm_analysis_fifo #(type T = int) extends uvm_tlm_fifo #(T); + typedef uvm_component_registry #(uvm_tlm_analysis_fifo#(T)) type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_tlm_analysis_fifo #(T)"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_tlm_analysis_fifo #(T)"; + endfunction : get_type_name + uvm_analysis_imp #(T, uvm_tlm_analysis_fifo #(T)) analysis_export; + function new(string name , uvm_component parent = null); + super.new(name, parent, 0); + analysis_export = new("analysis_export", this); + endfunction + function void write(input T t); + void'(this.try_put(t)); + endfunction +endclass +class uvm_tlm_req_rsp_channel #(type REQ=int, type RSP=REQ) extends uvm_component; + typedef uvm_tlm_req_rsp_channel #(REQ, RSP) this_type; + typedef uvm_component_registry #(uvm_tlm_req_rsp_channel#(REQ,RSP)) type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_tlm_req_rsp_channel #(REQ,RSP)"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_tlm_req_rsp_channel #(REQ,RSP)"; + endfunction : get_type_name + uvm_put_export #(REQ) put_request_export; + uvm_get_peek_export #(RSP) get_peek_response_export; + uvm_get_peek_export #(REQ) get_peek_request_export; + uvm_put_export #(RSP) put_response_export; + uvm_analysis_port #(REQ) request_ap; + uvm_analysis_port #(RSP) response_ap; + uvm_master_imp #(REQ, RSP, this_type, uvm_tlm_fifo #(REQ), uvm_tlm_fifo #(RSP)) master_export; + uvm_slave_imp #(REQ, RSP, this_type, uvm_tlm_fifo #(REQ), uvm_tlm_fifo #(RSP)) slave_export; + uvm_put_export #(REQ) blocking_put_request_export, + nonblocking_put_request_export; + uvm_get_peek_export #(REQ) get_request_export, + blocking_get_request_export, + nonblocking_get_request_export, + peek_request_export, + blocking_peek_request_export, + nonblocking_peek_request_export, + blocking_get_peek_request_export, + nonblocking_get_peek_request_export; + uvm_put_export #(RSP) blocking_put_response_export, + nonblocking_put_response_export; + uvm_get_peek_export #(RSP) get_response_export, + blocking_get_response_export, + nonblocking_get_response_export, + peek_response_export, + blocking_peek_response_export, + nonblocking_peek_response_export, + blocking_get_peek_response_export, + nonblocking_get_peek_response_export; + uvm_master_imp #(REQ, RSP, this_type, uvm_tlm_fifo #(REQ), uvm_tlm_fifo #(RSP)) + blocking_master_export, + nonblocking_master_export; + uvm_slave_imp #(REQ, RSP, this_type, uvm_tlm_fifo #(REQ), uvm_tlm_fifo #(RSP)) + blocking_slave_export, + nonblocking_slave_export; + protected uvm_tlm_fifo #(REQ) m_request_fifo; + protected uvm_tlm_fifo #(RSP) m_response_fifo; + function new (string name, uvm_component parent=null, + int request_fifo_size=1, + int response_fifo_size=1); + super.new (name, parent); + m_request_fifo = new ("request_fifo", this, request_fifo_size); + m_response_fifo = new ("response_fifo", this, response_fifo_size); + request_ap = new ("request_ap", this); + response_ap = new ("response_ap", this); + put_request_export = new ("put_request_export", this); + get_peek_request_export = new ("get_peek_request_export", this); + put_response_export = new ("put_response_export", this); + get_peek_response_export = new ("get_peek_response_export", this); + master_export = new ("master_export", this, m_request_fifo, m_response_fifo); + slave_export = new ("slave_export", this, m_request_fifo, m_response_fifo); + create_aliased_exports(); + set_report_id_action_hier(s_connection_error_id, UVM_NO_ACTION); + endfunction + virtual function void connect_phase(uvm_phase phase); + put_request_export.connect (m_request_fifo.put_export); + get_peek_request_export.connect (m_request_fifo.get_peek_export); + m_request_fifo.put_ap.connect (request_ap); + put_response_export.connect (m_response_fifo.put_export); + get_peek_response_export.connect (m_response_fifo.get_peek_export); + m_response_fifo.put_ap.connect (response_ap); + endfunction + function void create_aliased_exports(); + blocking_put_request_export = put_request_export; + nonblocking_put_request_export = put_request_export; + get_request_export = get_peek_request_export; + blocking_get_request_export = get_peek_request_export; + nonblocking_get_request_export = get_peek_request_export; + peek_request_export = get_peek_request_export; + blocking_peek_request_export = get_peek_request_export; + nonblocking_peek_request_export = get_peek_request_export; + blocking_get_peek_request_export = get_peek_request_export; + nonblocking_get_peek_request_export = get_peek_request_export; + blocking_put_response_export = put_response_export; + nonblocking_put_response_export = put_response_export; + get_response_export = get_peek_response_export; + blocking_get_response_export = get_peek_response_export; + nonblocking_get_response_export = get_peek_response_export; + peek_response_export = get_peek_response_export; + blocking_peek_response_export = get_peek_response_export; + nonblocking_peek_response_export = get_peek_response_export; + blocking_get_peek_response_export = get_peek_response_export; + nonblocking_get_peek_response_export = get_peek_response_export; + blocking_master_export = master_export; + nonblocking_master_export = master_export; + blocking_slave_export = slave_export; + nonblocking_slave_export = slave_export; + endfunction +endclass +class uvm_tlm_transport_channel #(type REQ=int, type RSP=REQ) + extends uvm_tlm_req_rsp_channel #(REQ, RSP); + typedef uvm_component_registry #(uvm_tlm_transport_channel#(REQ,RSP)) type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_tlm_transport_channel #(REQ,RSP)"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_tlm_transport_channel #(REQ,RSP)"; + endfunction : get_type_name + typedef uvm_tlm_transport_channel #(REQ, RSP) this_type; + uvm_transport_imp #(REQ, RSP, this_type) transport_export; + function new (string name, uvm_component parent=null); + super.new(name, parent, 1, 1); + transport_export = new("transport_export", this); + endfunction + task transport (REQ request, output RSP response ); + this.m_request_fifo.put( request ); + this.m_response_fifo.get( response ); + endtask + function bit nb_transport (REQ req, output RSP rsp ); + if(this.m_request_fifo.try_put(req)) + return this.m_response_fifo.try_get(rsp); + else + return 0; + endfunction +endclass +class uvm_seq_item_pull_port #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_sqr_if_base #(REQ, RSP)); + function new (string name, uvm_component parent, + int min_size=0, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = ((1<<0) | (1<<1) | + (1<<2) | (1<<3) | + (1<<4) | (1<<5) | + (1<<6) | (1<<7) | (1<<8)); + endfunction + virtual function string get_type_name(); + return "uvm_seq_item_pull_port"; + endfunction + function void disable_auto_item_recording(); this.m_if.disable_auto_item_recording(); endfunction + function bit is_auto_item_recording_enabled(); return this.m_if.is_auto_item_recording_enabled(); endfunction + task get_next_item(output REQ t); this.m_if.get_next_item(t); endtask + task try_next_item(output REQ t); this.m_if.try_next_item(t); endtask + function void item_done(input RSP t = null); this.m_if.item_done(t); endfunction + task wait_for_sequences(); this.m_if.wait_for_sequences(); endtask + function bit has_do_available(); return this.m_if.has_do_available(); endfunction + function void put_response(input RSP t); this.m_if.put_response(t); endfunction + task get(output REQ t); this.m_if.get(t); endtask + task peek(output REQ t); this.m_if.peek(t); endtask + task put(input RSP t); this.m_if.put(t); endtask + bit print_enabled; +endclass +class uvm_seq_item_pull_export #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_sqr_if_base #(REQ, RSP)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = ((1<<0) | (1<<1) | + (1<<2) | (1<<3) | + (1<<4) | (1<<5) | + (1<<6) | (1<<7) | (1<<8)); + endfunction + virtual function string get_type_name(); + return "uvm_seq_item_pull_export"; + endfunction + function void disable_auto_item_recording(); this.m_if.disable_auto_item_recording(); endfunction + function bit is_auto_item_recording_enabled(); return this.m_if.is_auto_item_recording_enabled(); endfunction + task get_next_item(output REQ t); this.m_if.get_next_item(t); endtask + task try_next_item(output REQ t); this.m_if.try_next_item(t); endtask + function void item_done(input RSP t = null); this.m_if.item_done(t); endfunction + task wait_for_sequences(); this.m_if.wait_for_sequences(); endtask + function bit has_do_available(); return this.m_if.has_do_available(); endfunction + function void put_response(input RSP t); this.m_if.put_response(t); endfunction + task get(output REQ t); this.m_if.get(t); endtask + task peek(output REQ t); this.m_if.peek(t); endtask + task put(input RSP t); this.m_if.put(t); endtask +endclass +class uvm_seq_item_pull_imp #(type REQ=int, type RSP=REQ, type IMP=int) + extends uvm_port_base #(uvm_sqr_if_base #(REQ, RSP)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = ((1<<0) | (1<<1) | + (1<<2) | (1<<3) | + (1<<4) | (1<<5) | + (1<<6) | (1<<7) | (1<<8)); + endfunction + virtual function string get_type_name(); + return "uvm_seq_item_pull_imp"; + endfunction + function void disable_auto_item_recording(); m_imp.disable_auto_item_recording(); endfunction + function bit is_auto_item_recording_enabled(); return m_imp.is_auto_item_recording_enabled(); endfunction + task get_next_item(output REQ t); m_imp.get_next_item(t); endtask + task try_next_item(output REQ t); m_imp.try_next_item(t); endtask + function void item_done(input RSP t = null); m_imp.item_done(t); endfunction + task wait_for_sequences(); m_imp.wait_for_sequences(); endtask + function bit has_do_available(); return m_imp.has_do_available(); endfunction + function void put_response(input RSP t); m_imp.put_response(t); endfunction + task get(output REQ t); m_imp.get(t); endtask + task peek(output REQ t); m_imp.peek(t); endtask + task put(input RSP t); m_imp.put(t); endtask +endclass +class uvm_class_pair #(type T1=int, T2=T1) extends uvm_object; + typedef uvm_class_pair #(T1, T2 ) this_type; + typedef uvm_object_registry #(this_type) type_id; + static function this_type type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + this_type tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_class_pair #(T1,T2)"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_class_pair #(T1,T2)"; + endfunction : get_type_name + T1 first; + T2 second; + function new (string name="", T1 f=null, T2 s=null); + super.new(name); + if (f == null) + first = new; + else + first = f; + if (s == null) + second = new; + else + second = s; + endfunction + virtual function string convert2string; + string s; + $sformat(s, "pair : %s, %s", + first.convert2string(), second.convert2string()); + return s; + endfunction + virtual function bit do_compare(uvm_object rhs, uvm_comparer comparer); + this_type rhs_; + if(!$cast(rhs_,rhs)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"WRONG_TYPE")) + uvm_report_error ("WRONG_TYPE", {"do_compare: rhs argument is not of type '",get_type_name(),"'"}, UVM_NONE, "t/uvm/src/comps/uvm_pair.svh", 88, "", 1); + end + return 0; + end + return first.compare(rhs_.first) && second.compare(rhs_.second); + endfunction + virtual function void do_copy (uvm_object rhs); + this_type rhs_; + if(!$cast(rhs_,rhs)) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"WRONG_TYPE")) + uvm_report_fatal ("WRONG_TYPE", {"do_copy: rhs argument is not of type '",get_type_name(),"'"}, UVM_NONE, "t/uvm/src/comps/uvm_pair.svh", 97, "", 1); + end + first.copy(rhs_.first); + second.copy(rhs_.second); + endfunction +endclass +class uvm_built_in_pair #(type T1=int, T2=T1) extends uvm_object; + typedef uvm_built_in_pair #(T1,T2) this_type; + typedef uvm_object_registry #(this_type) type_id; + static function this_type type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + this_type tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_built_in_pair #(T1,T2)"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_built_in_pair #(T1,T2)"; + endfunction : get_type_name + T1 first; + T2 second; + function new (string name=""); + super.new(name); + endfunction + virtual function string convert2string; + return $sformatf("built-in pair : %p, %p", first, second); + endfunction + virtual function bit do_compare(uvm_object rhs, uvm_comparer comparer); + this_type rhs_; + if(!$cast(rhs_,rhs)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"WRONG_TYPE")) + uvm_report_error ("WRONG_TYPE", {"do_compare: rhs argument is not of type '",get_type_name(),"'"}, UVM_NONE, "t/uvm/src/comps/uvm_pair.svh", 146, "", 1); + end + return 0; + end + return first == rhs_.first && second == rhs_.second; + endfunction + function void do_copy (uvm_object rhs); + this_type rhs_; + if(!$cast(rhs_,rhs)) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"WRONG_TYPE")) + uvm_report_fatal ("WRONG_TYPE", {"do_copy: rhs argument is not of type '",get_type_name(),"'"}, UVM_NONE, "t/uvm/src/comps/uvm_pair.svh", 155, "", 1); + end + first = rhs_.first; + second = rhs_.second; + endfunction +endclass +class uvm_built_in_comp #(type T=int); + static function bit comp(T a, T b); + return a == b; + endfunction +endclass +class uvm_built_in_converter #(type T=int); + static function string convert2string(input T t); + return $sformatf("%p" , t ); + endfunction +endclass +class uvm_built_in_clone #(type T=int); + static function T clone(input T from); + return from; + endfunction +endclass +class uvm_class_comp #(type T=int); + static function bit comp(input T a, input T b); + return a.compare(b); + endfunction +endclass +class uvm_class_converter #(type T=int); + static function string convert2string(input T t); + return t.convert2string(); + endfunction +endclass +class uvm_class_clone #(type T=int); + static function uvm_object clone(input T from); + return from.clone(); + endfunction +endclass +class uvm_in_order_comparator + #( type T = int , + type comp_type = uvm_built_in_comp #( T ) , + type convert = uvm_built_in_converter #( T ) , + type pair_type = uvm_built_in_pair #( T ) ) + extends uvm_component; + typedef uvm_in_order_comparator #(T,comp_type,convert,pair_type) this_type; + typedef uvm_component_registry #(this_type) type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_in_order_comparator #(T,comp_type,convert,pair_type)"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_in_order_comparator #(T,comp_type,convert,pair_type)"; + endfunction : get_type_name + uvm_analysis_export #(T) before_export; + uvm_analysis_export #(T) after_export; + uvm_analysis_port #(pair_type) pair_ap; + local uvm_tlm_analysis_fifo #(T) m_before_fifo; + local uvm_tlm_analysis_fifo #(T) m_after_fifo; + int m_matches, m_mismatches; + function new(string name, uvm_component parent); + super.new(name, parent); + before_export = new("before_export", this); + after_export = new("after_export", this); + pair_ap = new("pair_ap", this); + m_before_fifo = new("before", this); + m_after_fifo = new("after", this); + m_matches = 0; + m_mismatches = 0; + endfunction + virtual function void connect_phase(uvm_phase phase); + before_export.connect(m_before_fifo.analysis_export); + after_export.connect(m_after_fifo.analysis_export); + endfunction + virtual task run_phase(uvm_phase phase); + pair_type pair; + T b; + T a; + string s; + super.run_phase(phase); + forever begin + m_before_fifo.get(b); + m_after_fifo.get(a); + if(!comp_type::comp(b, a)) begin + $sformat(s, "%s differs from %s", convert::convert2string(a), + convert::convert2string(b)); + uvm_report_warning("Comparator Mismatch", s); + m_mismatches++; + end + else begin + s = convert::convert2string(b); + uvm_report_info("Comparator Match", s); + m_matches++; + end + pair = new("after/before"); + pair.first = a; + pair.second = b; + pair_ap.write(pair); + end + endtask + virtual function void flush(); + m_matches = 0; + m_mismatches = 0; + endfunction +endclass +class uvm_in_order_built_in_comparator #(type T=int) + extends uvm_in_order_comparator #(T); + typedef uvm_in_order_built_in_comparator #(T) this_type; + typedef uvm_component_registry #(this_type) type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_in_order_built_in_comparator #(T)"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_in_order_built_in_comparator #(T)"; + endfunction : get_type_name + function new(string name, uvm_component parent); + super.new(name, parent); + endfunction +endclass +class uvm_in_order_class_comparator #( type T = int ) + extends uvm_in_order_comparator #( T , + uvm_class_comp #( T ) , + uvm_class_converter #( T ) , + uvm_class_pair #( T, T ) ); + typedef uvm_in_order_class_comparator #(T) this_type; + typedef uvm_component_registry #(this_type) type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_in_order_class_comparator #(T)"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_in_order_class_comparator #(T)"; + endfunction : get_type_name + function new( string name , uvm_component parent); + super.new( name, parent ); + endfunction +endclass +class uvm_algorithmic_comparator #( type BEFORE=int, + type AFTER=int, + type TRANSFORMER=int) extends uvm_component; + typedef uvm_algorithmic_comparator #( BEFORE , + AFTER , + TRANSFORMER ) this_type; + typedef uvm_component_registry #(this_type) type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_algorithmic_comparator #(BEFORE,AFTER,TRANSFORMER)"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_algorithmic_comparator #(BEFORE,AFTER,TRANSFORMER)"; + endfunction : get_type_name + uvm_analysis_imp #(BEFORE, this_type) before_export; + uvm_analysis_export #(AFTER) after_export; + local uvm_in_order_class_comparator #(AFTER) comp; + local TRANSFORMER m_transformer; + function new(string name, uvm_component parent=null, TRANSFORMER transformer=null); + super.new( name , parent ); + m_transformer = transformer; + comp = new("comp", this ); + before_export = new("before_analysis_export" , this ); + after_export = new("after_analysis_export" , this ); + endfunction + virtual function void connect_phase(uvm_phase phase); + after_export.connect( comp.after_export ); + endfunction + function void write( input BEFORE b ); + comp.before_export.write( m_transformer.transform( b ) ); + endfunction +endclass +virtual class uvm_subscriber #(type T=int) extends uvm_component; + typedef uvm_subscriber #(T) this_type; + uvm_analysis_imp #(T, this_type) analysis_export; + function new (string name, uvm_component parent); + super.new(name, parent); + analysis_export = new("analysis_imp", this); + endfunction + pure virtual function void write(T t); +endclass +virtual class uvm_monitor extends uvm_component; + typedef uvm_abstract_component_registry #(uvm_monitor,"uvm_monitor") type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_monitor"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_monitor"; + endfunction : get_type_name + function new (string name, uvm_component parent); + super.new(name, parent); + endfunction +endclass +typedef class uvm_sequence_item; +class uvm_driver #(type REQ=uvm_sequence_item, + type RSP=REQ) extends uvm_component; + typedef uvm_component_registry #(uvm_driver#(REQ,RSP)) type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_driver #(REQ,RSP)"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_driver #(REQ,RSP)"; + endfunction : get_type_name + uvm_seq_item_pull_port #(REQ, RSP) seq_item_port; + uvm_seq_item_pull_port #(REQ, RSP) seq_item_prod_if; + uvm_analysis_port #(RSP) rsp_port; + REQ req; + RSP rsp; + function new (string name, uvm_component parent); + super.new(name, parent); + seq_item_port = new("seq_item_port", this); + rsp_port = new("rsp_port", this); + seq_item_prod_if = seq_item_port; + endfunction + virtual function void end_of_elaboration_phase(uvm_phase phase); + if(seq_item_port.size<1) + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"DRVCONNECT")) + uvm_report_warning ("DRVCONNECT", "the driver is not connected to a sequencer via the standard mechanisms enabled by connect()", UVM_NONE, "t/uvm/src/comps/uvm_driver.svh", 90, "", 1); + end + endfunction +endclass +class uvm_push_driver #(type REQ=uvm_sequence_item, + type RSP=REQ) extends uvm_component; + typedef uvm_component_registry #(uvm_push_driver#(REQ,RSP)) type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_push_driver #(REQ,RSP)"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_push_driver #(REQ,RSP)"; + endfunction : get_type_name + uvm_blocking_put_imp #(REQ, uvm_push_driver #(REQ,RSP)) req_export; + uvm_analysis_port #(RSP) rsp_port; + REQ req; + RSP rsp; + function new (string name, uvm_component parent); + super.new(name, parent); + req_export = new("req_export", this); + rsp_port = new("rsp_port", this); + endfunction + function void check_port_connections(); + if (req_export.size() != 1) + uvm_report_fatal("Connection Error", + $sformatf("Must connect to seq_item_port(%0d)", + req_export.size()), UVM_NONE); + endfunction + virtual function void end_of_elaboration_phase(uvm_phase phase); + super.end_of_elaboration_phase(phase); + check_port_connections(); + endfunction + virtual task put(REQ item); + uvm_report_fatal("UVM_PUSH_DRIVER", "Put task for push driver is not implemented", UVM_NONE); + endtask +endclass +virtual class uvm_scoreboard extends uvm_component; + typedef uvm_abstract_component_registry #(uvm_scoreboard,"uvm_scoreboard") type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_scoreboard"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_scoreboard"; + endfunction : get_type_name + function new (string name, uvm_component parent); + super.new(name, parent); + endfunction +endclass +virtual class uvm_agent extends uvm_component; + uvm_active_passive_enum is_active = UVM_ACTIVE; + typedef uvm_abstract_component_registry #(uvm_agent,"uvm_agent") type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_agent"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_agent"; + endfunction : get_type_name + function new (string name, uvm_component parent); + super.new(name, parent); + endfunction + function void build_phase(uvm_phase phase); + int active; + uvm_resource_pool rp; + uvm_resource_types::rsrc_q_t rq; + bit found; + super.build_phase(phase); + rp = uvm_resource_pool::get(); + rq = rp.lookup_name(get_full_name(), "is_active", null, 0); + uvm_resource_pool::sort_by_precedence(rq); + for (int i = 0; i < rq.size() && !found; i++) begin + uvm_resource_base rsrc = rq.get(i); +begin +begin + uvm_resource#(uvm_active_passive_enum) __tmp_rsrc__; + found = $cast(__tmp_rsrc__, rsrc); + if (found) begin + is_active = __tmp_rsrc__.read(this); + end +end + if (!found) begin + uvm_active_passive_enum __tmp_val__; + string __tmp_string_val__; + bit __tmp_success_val__; +begin + uvm_resource#(string) __tmp_rsrc__; + __tmp_success_val__ = $cast(__tmp_rsrc__, rsrc); + if (__tmp_success_val__) begin + __tmp_string_val__ = __tmp_rsrc__.read(this); + end +end + if (__tmp_success_val__ && + uvm_enum_wrapper#(uvm_active_passive_enum)::from_name(__tmp_string_val__, + __tmp_val__)) begin + is_active = __tmp_val__; + found = __tmp_success_val__; + end + end + if (!found) begin + typedef bit [$bits(uvm_active_passive_enum)-1:0] __tmp_int_t__; + __tmp_int_t__ __tmp_int_val__; + bit __tmp_success_val__; +begin +begin + uvm_resource#(__tmp_int_t__) __tmp_rsrc__; + __tmp_success_val__ = $cast(__tmp_rsrc__, rsrc); + if (__tmp_success_val__) begin + __tmp_int_val__ = __tmp_rsrc__.read(this); + end +end + if (!__tmp_success_val__) +begin +begin + uvm_resource#(uvm_integral_t) __tmp_rsrc__; + __tmp_success_val__ = $cast(__tmp_rsrc__, rsrc); + if (__tmp_success_val__) begin + __tmp_int_val__ = __tmp_rsrc__.read(this); + end +end + if (!__tmp_success_val__) +begin + uvm_resource#(uvm_bitstream_t) __tmp_rsrc__; + __tmp_success_val__ = $cast(__tmp_rsrc__, rsrc); + if (__tmp_success_val__) begin + __tmp_int_val__ = __tmp_rsrc__.read(this); + end +end + if (!__tmp_success_val__) +begin + uvm_resource#(int) __tmp_rsrc__; + __tmp_success_val__ = $cast(__tmp_rsrc__, rsrc); + if (__tmp_success_val__) begin + __tmp_int_val__ = __tmp_rsrc__.read(this); + end +end + if (!__tmp_success_val__) +begin + uvm_resource#(int unsigned) __tmp_rsrc__; + __tmp_success_val__ = $cast(__tmp_rsrc__, rsrc); + if (__tmp_success_val__) begin + __tmp_int_val__ = __tmp_rsrc__.read(this); + end +end +end +end + if (__tmp_success_val__) begin + is_active = uvm_active_passive_enum'(__tmp_int_val__); + found = __tmp_success_val__; + end + end +end + end + endfunction + virtual function uvm_active_passive_enum get_is_active(); + return is_active; + endfunction +endclass +virtual class uvm_env extends uvm_component; + typedef uvm_abstract_component_registry #(uvm_env,"uvm_env") type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_env"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_env"; + endfunction : get_type_name + function new (string name="env", uvm_component parent=null); + super.new(name,parent); + endfunction +endclass +virtual class uvm_test extends uvm_component; + typedef uvm_abstract_component_registry #(uvm_test,"uvm_test") type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_test"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_test"; + endfunction : get_type_name + function new (string name, uvm_component parent); + super.new(name,parent); + endfunction +endclass +typedef class uvm_sequence_base; +typedef class uvm_sequencer_base; +class uvm_sequence_item extends uvm_transaction; + local int m_sequence_id = -1; + protected bit m_use_sequence_info; + protected int m_depth = -1; + protected uvm_sequencer_base m_sequencer; + protected uvm_sequence_base m_parent_sequence; + static bit issued1,issued2; + bit print_sequence_info; + function new (string name = "uvm_sequence_item"); + super.new(name); + endfunction + function string get_type_name(); + return "uvm_sequence_item"; + endfunction + typedef uvm_object_registry#(uvm_sequence_item,"uvm_sequence_item") type_id; + static function uvm_sequence_item type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function void set_sequence_id(int id); + m_sequence_id = id; + endfunction + function int get_sequence_id(); + return (m_sequence_id); + endfunction + function void set_item_context(uvm_sequence_base parent_seq, + uvm_sequencer_base sequencer = null); + set_use_sequence_info(1); + if (parent_seq != null) set_parent_sequence(parent_seq); + if (sequencer == null && m_parent_sequence != null) sequencer = m_parent_sequence.get_sequencer(); + set_sequencer(sequencer); + if (m_parent_sequence != null) set_depth(m_parent_sequence.get_depth() + 1); + reseed(); + endfunction + function void set_use_sequence_info(bit value); + m_use_sequence_info = value; + endfunction + function bit get_use_sequence_info(); + return (m_use_sequence_info); + endfunction + function void set_id_info(uvm_sequence_item item); + if (item == null) begin + uvm_report_fatal(get_full_name(), "set_id_info called with null parameter", UVM_NONE); + end + this.set_transaction_id(item.get_transaction_id()); + this.set_sequence_id(item.get_sequence_id()); + endfunction + virtual function void set_sequencer(uvm_sequencer_base sequencer); + m_sequencer = sequencer; + m_set_p_sequencer(); + endfunction + function uvm_sequencer_base get_sequencer(); + return m_sequencer; + endfunction + function void set_parent_sequence(uvm_sequence_base parent); + m_parent_sequence = parent; + endfunction + function uvm_sequence_base get_parent_sequence(); + return (m_parent_sequence); + endfunction + function void set_depth(int value); + m_depth = value; + endfunction + function int get_depth(); + if (m_depth != -1) begin + return (m_depth); + end + if (m_parent_sequence == null) begin + m_depth = 1; + end else begin + m_depth = m_parent_sequence.get_depth() + 1; + end + return (m_depth); + endfunction + virtual function bit is_item(); + return(1); + endfunction + function string get_full_name(); + if(m_parent_sequence != null) + get_full_name = {m_parent_sequence.get_full_name(), "."}; + else if(m_sequencer!=null) + get_full_name = {m_sequencer.get_full_name(), "."}; + if(get_name() != "") + get_full_name = {get_full_name, get_name()}; + else begin + get_full_name = {get_full_name, "_item"}; + end + endfunction + function string get_root_sequence_name(); + uvm_sequence_base root_seq; + root_seq = get_root_sequence(); + if (root_seq == null) + return ""; + else + return root_seq.get_name(); + endfunction + virtual function void m_set_p_sequencer(); + return; + endfunction + function uvm_sequence_base get_root_sequence(); + uvm_sequence_item root_seq_base; + uvm_sequence_base root_seq; + root_seq_base = this; + while(1) begin + if(root_seq_base.get_parent_sequence()!=null) begin + root_seq_base = root_seq_base.get_parent_sequence(); + $cast(root_seq, root_seq_base); + end + else + return root_seq; + end + endfunction + function string get_sequence_path(); + uvm_sequence_item this_item; + string seq_path; + this_item = this; + seq_path = this.get_name(); + while(1) begin + if(this_item.get_parent_sequence()!=null) begin + this_item = this_item.get_parent_sequence(); + seq_path = {this_item.get_name(), ".", seq_path}; + end + else + return seq_path; + end + endfunction + virtual function uvm_report_object uvm_get_report_object(); + if(m_sequencer == null) begin + uvm_coreservice_t cs = uvm_coreservice_t::get(); + return cs.get_root(); + end else + return m_sequencer; + endfunction + function int uvm_report_enabled(int verbosity, + uvm_severity severity=UVM_INFO, string id=""); + uvm_report_object l_report_object = uvm_get_report_object(); + if (l_report_object.get_report_verbosity_level(severity, id) < verbosity) + return 0; + return 1; + endfunction + virtual function void uvm_report( uvm_severity severity, + string id, + string message, + 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 = "", + bit report_enabled_checked = 0); + uvm_report_message l_report_message; + if (report_enabled_checked == 0) begin + if (!uvm_report_enabled(verbosity, severity, id)) + return; + end + l_report_message = uvm_report_message::new_report_message(); + l_report_message.set_report_message(severity, id, message, + verbosity, filename, line, context_name); + uvm_process_report_message(l_report_message); + endfunction + virtual function void uvm_report_info( string id, + string message, + int verbosity = UVM_MEDIUM, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + this.uvm_report(UVM_INFO, id, message, verbosity, filename, line, + context_name, report_enabled_checked); + endfunction + virtual function void uvm_report_warning( string id, + string message, + int verbosity = UVM_MEDIUM, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + this.uvm_report(UVM_WARNING, id, message, verbosity, filename, line, + context_name, report_enabled_checked); + endfunction + virtual function void uvm_report_error( string id, + string message, + int verbosity = UVM_NONE, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + this.uvm_report(UVM_ERROR, id, message, verbosity, filename, line, + context_name, report_enabled_checked); + endfunction + virtual function void uvm_report_fatal( string id, + string message, + int verbosity = UVM_NONE, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + this.uvm_report(UVM_FATAL, id, message, verbosity, filename, line, + context_name, report_enabled_checked); + endfunction + virtual function void uvm_process_report_message (uvm_report_message report_message); + uvm_report_object l_report_object = uvm_get_report_object(); + report_message.set_report_object(l_report_object); + if (report_message.get_context() == "") + report_message.set_context(get_sequence_path()); + l_report_object.m_rh.process_report_message(report_message); + endfunction + function void do_print (uvm_printer printer); + string temp_str0, temp_str1; + int depth = get_depth(); + super.do_print(printer); + if(print_sequence_info || m_use_sequence_info) begin + printer.print_field_int("depth", depth, $bits(depth), UVM_DEC, ".", "int"); + if(m_parent_sequence != null) begin + temp_str0 = m_parent_sequence.get_name(); + temp_str1 = m_parent_sequence.get_full_name(); + end + printer.print_string("parent sequence (name)", temp_str0); + printer.print_string("parent sequence (full name)", temp_str1); + temp_str1 = ""; + if(m_sequencer != null) begin + temp_str1 = m_sequencer.get_full_name(); + end + printer.print_string("sequencer", temp_str1); + end + endfunction +endclass +typedef uvm_config_db#(uvm_sequence_base) uvm_config_seq; +typedef class uvm_sequence_request; +class uvm_sequence_process_wrapper; + process pid; + uvm_sequence_base seq; +endclass : uvm_sequence_process_wrapper +virtual +class uvm_sequencer_base extends uvm_component; + typedef enum {SEQ_TYPE_REQ, + SEQ_TYPE_LOCK} seq_req_t; + protected uvm_sequence_request arb_sequence_q[$]; + protected bit arb_completed[int]; + protected uvm_sequence_base lock_list[$]; + protected uvm_sequence_base reg_sequences[int]; + protected int m_sequencer_id; + protected int m_lock_arb_size; + protected int m_arb_size; + protected int m_wait_for_item_sequence_id, + m_wait_for_item_transaction_id; + protected int m_wait_relevant_count = 0 ; + protected int m_max_zero_time_wait_relevant_count = 10; + protected time m_last_wait_relevant_time = 0 ; + local uvm_sequencer_arb_mode m_arbitration = UVM_SEQ_ARB_FIFO; + local static int g_request_id; + local static int g_sequence_id = 1; + local static int g_sequencer_id = 1; + extern function new (string name, uvm_component parent); + extern function bit is_child (uvm_sequence_base parent, uvm_sequence_base child); + extern virtual function int user_priority_arbitration(int avail_sequences[$]); + extern virtual task execute_item(uvm_sequence_item item); + protected uvm_sequence_process_wrapper m_default_sequences[uvm_phase]; + extern virtual function void start_phase_sequence(uvm_phase phase); + extern virtual function void stop_phase_sequence(uvm_phase phase); + extern virtual task wait_for_grant(uvm_sequence_base sequence_ptr, + int item_priority = -1, + bit lock_request = 0); + extern virtual task wait_for_item_done(uvm_sequence_base sequence_ptr, + int transaction_id); + extern function bit is_blocked(uvm_sequence_base sequence_ptr); + extern function bit has_lock(uvm_sequence_base sequence_ptr); + extern virtual task lock(uvm_sequence_base sequence_ptr); + extern virtual task grab(uvm_sequence_base sequence_ptr); + extern virtual function void unlock(uvm_sequence_base sequence_ptr); + extern virtual function void ungrab(uvm_sequence_base sequence_ptr); + extern virtual function void stop_sequences(); + extern virtual function bit is_grabbed(); + extern virtual function uvm_sequence_base current_grabber(); + extern virtual function bit has_do_available(); + extern function void set_arbitration(UVM_SEQ_ARB_TYPE val); + extern function UVM_SEQ_ARB_TYPE get_arbitration(); + extern virtual task wait_for_sequences(); + extern virtual function void send_request(uvm_sequence_base sequence_ptr, + uvm_sequence_item t, + bit rerandomize = 0); + extern virtual function void set_max_zero_time_wait_relevant_count(int new_val) ; + extern virtual function uvm_sequence_base get_arbitration_sequence( int index ); + extern protected function void grant_queued_locks(); + extern protected task m_select_sequence(); + extern protected function int m_choose_next_request(); + extern task m_wait_for_arbitration_completed(int request_id); + extern function void m_set_arbitration_completed(int request_id); + extern local task m_lock_req(uvm_sequence_base sequence_ptr, bit lock); + extern function void m_unlock_req(uvm_sequence_base sequence_ptr); + extern local function void remove_sequence_from_queues(uvm_sequence_base sequence_ptr); + extern function void m_sequence_exiting(uvm_sequence_base sequence_ptr); + extern function void kill_sequence(uvm_sequence_base sequence_ptr); + extern virtual function void analysis_write(uvm_sequence_item t); + extern function void do_print (uvm_printer printer); + extern virtual function int m_register_sequence(uvm_sequence_base sequence_ptr); + extern protected + virtual function void m_unregister_sequence(int sequence_id); + extern protected function + uvm_sequence_base m_find_sequence(int sequence_id); + extern protected function void m_update_lists(); + extern function string convert2string(); + extern protected + virtual function int m_find_number_driver_connections(); + extern protected task m_wait_arb_not_equal(); + extern protected task m_wait_for_available_sequence(); + extern protected function int m_get_seq_item_priority(uvm_sequence_request seq_q_entry); + int m_is_relevant_completed; + local bit m_auto_item_recording = 1; + virtual function void disable_auto_item_recording(); + m_auto_item_recording = 0; + endfunction + virtual function bit is_auto_item_recording_enabled(); + return m_auto_item_recording; + endfunction + static uvm_sequencer_base all_sequencer_insts[int unsigned]; +endclass +function uvm_sequencer_base::new (string name, uvm_component parent); + super.new(name, parent); + m_sequencer_id = g_sequencer_id++; + m_lock_arb_size = -1; + all_sequencer_insts[m_sequencer_id]=this; +endfunction +function void uvm_sequencer_base::do_print (uvm_printer printer); + super.do_print(printer); + printer.print_array_header("arbitration_queue", arb_sequence_q.size()); + foreach (arb_sequence_q[i]) + printer.print_string($sformatf("[%0d]", i), + $sformatf("%s@seqid%0d",arb_sequence_q[i].request.name(),arb_sequence_q[i].sequence_id), "["); + printer.print_array_footer(arb_sequence_q.size()); + printer.print_array_header("lock_queue", lock_list.size()); + foreach(lock_list[i]) + printer.print_string($sformatf("[%0d]", i), + $sformatf("%s@seqid%0d",lock_list[i].get_full_name(),lock_list[i].get_sequence_id()), "["); + printer.print_array_footer(lock_list.size()); +endfunction +function void uvm_sequencer_base::m_update_lists(); + m_lock_arb_size++; +endfunction +function string uvm_sequencer_base::convert2string(); + string s; + $sformat(s, " -- arb i/id/type: "); + foreach (arb_sequence_q[i]) begin + $sformat(s, "%s %0d/%0d/%s ", s, i, arb_sequence_q[i].sequence_id, arb_sequence_q[i].request.name()); + end + $sformat(s, "%s\n -- lock_list i/id: ", s); + foreach (lock_list[i]) begin + $sformat(s, "%s %0d/%0d",s, i, lock_list[i].get_sequence_id()); + end + return(s); +endfunction +function int uvm_sequencer_base::m_find_number_driver_connections(); + return 0; +endfunction +function int uvm_sequencer_base::m_register_sequence(uvm_sequence_base sequence_ptr); + if (sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 1) > 0) + return sequence_ptr.get_sequence_id(); + sequence_ptr.m_set_sqr_sequence_id(m_sequencer_id, g_sequence_id++); + reg_sequences[sequence_ptr.get_sequence_id()] = sequence_ptr; + return sequence_ptr.get_sequence_id(); +endfunction +function uvm_sequence_base uvm_sequencer_base::m_find_sequence(int sequence_id); + uvm_sequence_base seq_ptr; + int i; + if (sequence_id == -1) begin + if (reg_sequences.first(i)) begin + return(reg_sequences[i]); + end + return(null); + end + if (!reg_sequences.exists(sequence_id)) + return null; + return reg_sequences[sequence_id]; +endfunction +function void uvm_sequencer_base::m_unregister_sequence(int sequence_id); + if (!reg_sequences.exists(sequence_id)) + return; + reg_sequences.delete(sequence_id); +endfunction +function int uvm_sequencer_base::user_priority_arbitration(int avail_sequences[$]); + return avail_sequences[0]; +endfunction +function void uvm_sequencer_base::grant_queued_locks(); + begin + uvm_sequence_request zombies[$]; + zombies = arb_sequence_q.find(item) with (item.request==SEQ_TYPE_LOCK && item.process_id.status inside {process::KILLED,process::FINISHED}); + foreach(zombies[idx]) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"SEQLCKZMB")) + uvm_report_error ("SEQLCKZMB", $sformatf("The task responsible for requesting a lock on sequencer '%s' for sequence '%s' has been killed, to avoid a deadlock the sequence will be removed from the arbitration queues", this.get_full_name(), zombies[idx].sequence_ptr.get_full_name()), UVM_NONE, "t/uvm/src/seq/uvm_sequencer_base.svh", 557, "", 1); + end + remove_sequence_from_queues(zombies[idx].sequence_ptr); + end + end + begin + int lock_req_indices[$]; + lock_req_indices = arb_sequence_q.find_first_index(item) with (item.request==SEQ_TYPE_LOCK && is_blocked(item.sequence_ptr) == 0); + if(lock_req_indices.size()) begin + uvm_sequence_request lock_req = arb_sequence_q[lock_req_indices[0]]; + lock_list.push_back(lock_req.sequence_ptr); + m_set_arbitration_completed(lock_req.request_id); + arb_sequence_q.delete(lock_req_indices[0]); + m_update_lists(); + end + end +endfunction +task uvm_sequencer_base::m_select_sequence(); + int selected_sequence; + do begin + wait_for_sequences(); + selected_sequence = m_choose_next_request(); + if (selected_sequence == -1) begin + m_wait_for_available_sequence(); + end + end while (selected_sequence == -1); + if (selected_sequence >= 0) begin + m_set_arbitration_completed(arb_sequence_q[selected_sequence].request_id); + arb_sequence_q.delete(selected_sequence); + m_update_lists(); + end +endtask +function int uvm_sequencer_base::m_choose_next_request(); + int i, temp; + int avail_sequence_count; + int sum_priority_val; + int avail_sequences[$]; + int highest_sequences[$]; + int highest_pri; + string s; + avail_sequence_count = 0; + grant_queued_locks(); + i = 0; + while (i < arb_sequence_q.size()) begin + if ((arb_sequence_q[i].process_id.status == process::KILLED) || + (arb_sequence_q[i].process_id.status == process::FINISHED)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"SEQREQZMB")) + uvm_report_error ("SEQREQZMB", $sformatf("The task responsible for requesting a wait_for_grant on sequencer '%s' for sequence '%s' has been killed, to avoid a deadlock the sequence will be removed from the arbitration queues", this.get_full_name(), arb_sequence_q[i].sequence_ptr.get_full_name()), UVM_NONE, "t/uvm/src/seq/uvm_sequencer_base.svh", 625, "", 1); + end + remove_sequence_from_queues(arb_sequence_q[i].sequence_ptr); + continue; + end + if (i < arb_sequence_q.size()) + if (arb_sequence_q[i].request == SEQ_TYPE_REQ) + if (is_blocked(arb_sequence_q[i].sequence_ptr) == 0) + if (arb_sequence_q[i].sequence_ptr.is_relevant() == 1) begin + if (m_arbitration == UVM_SEQ_ARB_FIFO) begin + return i; + end + else avail_sequences.push_back(i); + end + i++; + end + if (m_arbitration == UVM_SEQ_ARB_FIFO) begin + return -1; + end + if (avail_sequences.size() < 1) begin + return -1; + end + if (avail_sequences.size() == 1) begin + return avail_sequences[0]; + end + if (lock_list.size() > 0) begin + for (i = 0; i < avail_sequences.size(); i++) begin + if (is_blocked(arb_sequence_q[avail_sequences[i]].sequence_ptr) != 0) begin + avail_sequences.delete(i); + i--; + end + end + if (avail_sequences.size() < 1) + return -1; + if (avail_sequences.size() == 1) + return avail_sequences[0]; + end + if (m_arbitration == UVM_SEQ_ARB_WEIGHTED) begin + sum_priority_val = 0; + for (i = 0; i < avail_sequences.size(); i++) begin + sum_priority_val += m_get_seq_item_priority(arb_sequence_q[avail_sequences[i]]); + end + temp = $urandom_range(sum_priority_val-1, 0); + sum_priority_val = 0; + for (i = 0; i < avail_sequences.size(); i++) begin + if ((m_get_seq_item_priority(arb_sequence_q[avail_sequences[i]]) + + sum_priority_val) > temp) begin + return avail_sequences[i]; + end + sum_priority_val += m_get_seq_item_priority(arb_sequence_q[avail_sequences[i]]); + end + uvm_report_fatal("Sequencer", "UVM Internal error in weighted arbitration code", UVM_NONE); + end + if (m_arbitration == UVM_SEQ_ARB_RANDOM) begin + i = $urandom_range(avail_sequences.size()-1, 0); + return avail_sequences[i]; + end + if ((m_arbitration == UVM_SEQ_ARB_STRICT_FIFO) || m_arbitration == UVM_SEQ_ARB_STRICT_RANDOM) begin + highest_pri = 0; + for (i = 0; i < avail_sequences.size(); i++) begin + if (m_get_seq_item_priority(arb_sequence_q[avail_sequences[i]]) > highest_pri) begin + highest_sequences.delete(); + highest_sequences.push_back(avail_sequences[i]); + highest_pri = m_get_seq_item_priority(arb_sequence_q[avail_sequences[i]]); + end + else if (m_get_seq_item_priority(arb_sequence_q[avail_sequences[i]]) == highest_pri) begin + highest_sequences.push_back(avail_sequences[i]); + end + end + if (m_arbitration == UVM_SEQ_ARB_STRICT_FIFO) begin + return(highest_sequences[0]); + end + i = $urandom_range(highest_sequences.size()-1, 0); + return highest_sequences[i]; + end + if (m_arbitration == UVM_SEQ_ARB_USER) begin + i = user_priority_arbitration( avail_sequences); + highest_sequences = avail_sequences.find with (item == i); + if (highest_sequences.size() == 0) begin + uvm_report_fatal("Sequencer", + $sformatf("Error in User arbitration, sequence %0d not available\n%s", + i, convert2string()), UVM_NONE); + end + return(i); + end + uvm_report_fatal("Sequencer", "Internal error: Failed to choose sequence", UVM_NONE); +endfunction +task uvm_sequencer_base::m_wait_arb_not_equal(); + wait (m_arb_size != m_lock_arb_size); +endtask +task uvm_sequencer_base::m_wait_for_available_sequence(); + int i; + int is_relevant_entries[$]; + m_arb_size = m_lock_arb_size; + for (i = 0; i < arb_sequence_q.size(); i++) begin + if (arb_sequence_q[i].request == SEQ_TYPE_REQ) begin + if (is_blocked(arb_sequence_q[i].sequence_ptr) == 0) begin + if (arb_sequence_q[i].sequence_ptr.is_relevant() == 0) begin + is_relevant_entries.push_back(i); + end + end + end + end + if (is_relevant_entries.size() == 0) begin + m_wait_arb_not_equal(); + return; + end + fork + begin + fork + begin + fork + begin + m_is_relevant_completed = 0; + for(i = 0; i < is_relevant_entries.size(); i++) begin + fork + automatic int k = i; + begin + arb_sequence_q[is_relevant_entries[k]].sequence_ptr.wait_for_relevant(); + if ($realtime != m_last_wait_relevant_time) begin + m_last_wait_relevant_time = $realtime ; + m_wait_relevant_count = 0 ; + end + else begin + m_wait_relevant_count++ ; + if (m_wait_relevant_count > m_max_zero_time_wait_relevant_count) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"SEQRELEVANTLOOP")) + uvm_report_fatal ("SEQRELEVANTLOOP", $sformatf("Zero time loop detected, passed wait_for_relevant %0d times without time advancing",m_wait_relevant_count), UVM_NONE, "t/uvm/src/seq/uvm_sequencer_base.svh", 798, "", 1); + end + end + end + m_is_relevant_completed = 1; + end + join_none + end + wait (m_is_relevant_completed > 0); + end + begin + m_wait_arb_not_equal(); + end + join_any + end + join_any + disable fork; + end + join +endtask +function int uvm_sequencer_base::m_get_seq_item_priority(uvm_sequence_request seq_q_entry); + if (seq_q_entry.item_priority != -1) begin + if (seq_q_entry.item_priority <= 0) begin + uvm_report_fatal("SEQITEMPRI", + $sformatf("Sequence item from %s has illegal priority: %0d", + seq_q_entry.sequence_ptr.get_full_name(), + seq_q_entry.item_priority), UVM_NONE); + end + return seq_q_entry.item_priority; + end + if (seq_q_entry.sequence_ptr.get_priority() < 0) begin + uvm_report_fatal("SEQDEFPRI", + $sformatf("Sequence %s has illegal priority: %0d", + seq_q_entry.sequence_ptr.get_full_name(), + seq_q_entry.sequence_ptr.get_priority()), UVM_NONE); + end + return seq_q_entry.sequence_ptr.get_priority(); +endfunction +task uvm_sequencer_base::m_wait_for_arbitration_completed(int request_id); + int lock_arb_size; + forever + begin + lock_arb_size = m_lock_arb_size; + if (arb_completed.exists(request_id)) begin + arb_completed.delete(request_id); + return; + end + wait (lock_arb_size != m_lock_arb_size); + end +endtask +function void uvm_sequencer_base::m_set_arbitration_completed(int request_id); + arb_completed[request_id] = 1; +endfunction +function bit uvm_sequencer_base::is_child (uvm_sequence_base parent, + uvm_sequence_base child); + uvm_sequence_base child_parent; + if (child == null) begin + uvm_report_fatal("uvm_sequencer", "is_child passed null child", UVM_NONE); + end + if (parent == null) begin + uvm_report_fatal("uvm_sequencer", "is_child passed null parent", UVM_NONE); + end + child_parent = child.get_parent_sequence(); + while (child_parent != null) begin + if (child_parent.get_inst_id() == parent.get_inst_id()) begin + return 1; + end + child_parent = child_parent.get_parent_sequence(); + end + return 0; +endfunction +class m_uvm_sqr_seq_base extends uvm_sequence_base; + function new(string name="unnamed-m_uvm_sqr_seq_base"); + super.new(name); + endfunction : new +endclass : m_uvm_sqr_seq_base +task uvm_sequencer_base::execute_item(uvm_sequence_item item); + m_uvm_sqr_seq_base seq; + seq = new("execute_item_seq"); + item.set_sequencer(this); + item.set_parent_sequence(seq); + seq.set_sequencer(this); + seq.start_item(item); + seq.finish_item(item); +endtask +task uvm_sequencer_base::wait_for_grant(uvm_sequence_base sequence_ptr, + int item_priority = -1, + bit lock_request = 0); + uvm_sequence_request req_s; + int my_seq_id; + if (sequence_ptr == null) + uvm_report_fatal("uvm_sequencer", + "wait_for_grant passed null sequence_ptr", UVM_NONE); + my_seq_id = m_register_sequence(sequence_ptr); + if (lock_request == 1) begin + req_s = new(); + req_s.grant = 0; + req_s.sequence_id = my_seq_id; + req_s.request = SEQ_TYPE_LOCK; + req_s.sequence_ptr = sequence_ptr; + req_s.request_id = g_request_id++; + req_s.process_id = process::self(); + arb_sequence_q.push_back(req_s); + end + req_s = new(); + req_s.grant = 0; + req_s.request = SEQ_TYPE_REQ; + req_s.sequence_id = my_seq_id; + req_s.item_priority = item_priority; + req_s.sequence_ptr = sequence_ptr; + req_s.request_id = g_request_id++; + req_s.process_id = process::self(); + arb_sequence_q.push_back(req_s); + m_update_lists(); + m_wait_for_arbitration_completed(req_s.request_id); + req_s.sequence_ptr.m_wait_for_grant_semaphore++; +endtask +task uvm_sequencer_base::wait_for_item_done(uvm_sequence_base sequence_ptr, + int transaction_id); + int sequence_id; + sequence_id = sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 1); + m_wait_for_item_sequence_id = -1; + m_wait_for_item_transaction_id = -1; + if (transaction_id == -1) + wait (m_wait_for_item_sequence_id == sequence_id); + else + wait ((m_wait_for_item_sequence_id == sequence_id && + m_wait_for_item_transaction_id == transaction_id)); +endtask +function bit uvm_sequencer_base::is_blocked(uvm_sequence_base sequence_ptr); + if (sequence_ptr == null) + uvm_report_fatal("uvm_sequence_controller", + "is_blocked passed null sequence_ptr", UVM_NONE); + foreach (lock_list[i]) begin + if ((lock_list[i].get_inst_id() != + sequence_ptr.get_inst_id()) && + (is_child(lock_list[i], sequence_ptr) == 0)) begin + return 1; + end + end + return 0; +endfunction +function bit uvm_sequencer_base::has_lock(uvm_sequence_base sequence_ptr); + int my_seq_id; + if (sequence_ptr == null) + uvm_report_fatal("uvm_sequence_controller", + "has_lock passed null sequence_ptr", UVM_NONE); + my_seq_id = m_register_sequence(sequence_ptr); + foreach (lock_list[i]) begin + if (lock_list[i].get_inst_id() == sequence_ptr.get_inst_id()) begin + return 1; + end + end + return 0; +endfunction +task uvm_sequencer_base::m_lock_req(uvm_sequence_base sequence_ptr, bit lock); + int my_seq_id; + uvm_sequence_request new_req; + if (sequence_ptr == null) + uvm_report_fatal("uvm_sequence_controller", + "lock_req passed null sequence_ptr", UVM_NONE); + my_seq_id = m_register_sequence(sequence_ptr); + new_req = new(); + new_req.grant = 0; + new_req.sequence_id = sequence_ptr.get_sequence_id(); + new_req.request = SEQ_TYPE_LOCK; + new_req.sequence_ptr = sequence_ptr; + new_req.request_id = g_request_id++; + new_req.process_id = process::self(); + if (lock == 1) begin + arb_sequence_q.push_back(new_req); + end else begin + arb_sequence_q.push_front(new_req); + m_update_lists(); + end + grant_queued_locks(); + m_wait_for_arbitration_completed(new_req.request_id); +endtask +function void uvm_sequencer_base::m_unlock_req(uvm_sequence_base sequence_ptr); + if (sequence_ptr == null) begin + uvm_report_fatal("uvm_sequencer", + "m_unlock_req passed null sequence_ptr", UVM_NONE); + end + begin + int q[$]; + int seqid=sequence_ptr.get_inst_id(); + q=lock_list.find_first_index(item) with (item.get_inst_id() == seqid); + if(q.size()==1) begin + lock_list.delete(q[0]); + grant_queued_locks(); + m_update_lists(); + end + else + uvm_report_warning("SQRUNL", + {"Sequence '", sequence_ptr.get_full_name(), + "' called ungrab / unlock, but didn't have lock"}, UVM_NONE); + end +endfunction +task uvm_sequencer_base::lock(uvm_sequence_base sequence_ptr); + m_lock_req(sequence_ptr, 1); +endtask +task uvm_sequencer_base::grab(uvm_sequence_base sequence_ptr); + m_lock_req(sequence_ptr, 0); +endtask +function void uvm_sequencer_base::unlock(uvm_sequence_base sequence_ptr); + m_unlock_req(sequence_ptr); +endfunction +function void uvm_sequencer_base::ungrab(uvm_sequence_base sequence_ptr); + m_unlock_req(sequence_ptr); +endfunction +function void uvm_sequencer_base::remove_sequence_from_queues( + uvm_sequence_base sequence_ptr); + int i; + int seq_id; + seq_id = sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 0); + i = 0; + do + begin + if (arb_sequence_q.size() > i) begin + if ((arb_sequence_q[i].sequence_id == seq_id) || + (is_child(sequence_ptr, arb_sequence_q[i].sequence_ptr))) begin + if (sequence_ptr.get_sequence_state() == UVM_FINISHED) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"SEQFINERR")) + uvm_report_error ("SEQFINERR", $sformatf("Parent sequence '%s' should not finish before all items from itself and items from descendent sequences are processed. The item request from the sequence '%s' is being removed.", sequence_ptr.get_full_name(), arb_sequence_q[i].sequence_ptr.get_full_name()), UVM_NONE, "t/uvm/src/seq/uvm_sequencer_base.svh", 1153, "", 1); + end + arb_sequence_q.delete(i); + m_update_lists(); + end + else begin + i++; + end + end + end + while (i < arb_sequence_q.size()); + i = 0; + do + begin + if (lock_list.size() > i) begin + if ((lock_list[i].get_inst_id() == sequence_ptr.get_inst_id()) || + (is_child(sequence_ptr, lock_list[i]))) begin + if (sequence_ptr.get_sequence_state() == UVM_FINISHED) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"SEQFINERR")) + uvm_report_error ("SEQFINERR", $sformatf("Parent sequence '%s' should not finish before locks from itself and descedent sequences are removed. The lock held by the child sequence '%s' is being removed.",sequence_ptr.get_full_name(), lock_list[i].get_full_name()), UVM_NONE, "t/uvm/src/seq/uvm_sequencer_base.svh", 1172, "", 1); + end + lock_list.delete(i); + m_update_lists(); + end + else begin + i++; + end + end + end + while (i < lock_list.size()); + m_unregister_sequence(sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 1)); +endfunction +function void uvm_sequencer_base::stop_sequences(); + uvm_sequence_base seq_ptr; + seq_ptr = m_find_sequence(-1); + while (seq_ptr != null) + begin + kill_sequence(seq_ptr); + seq_ptr = m_find_sequence(-1); + end +endfunction +function void uvm_sequencer_base::m_sequence_exiting(uvm_sequence_base sequence_ptr); + remove_sequence_from_queues(sequence_ptr); +endfunction +function void uvm_sequencer_base::kill_sequence(uvm_sequence_base sequence_ptr); + remove_sequence_from_queues(sequence_ptr); + sequence_ptr.m_kill(); +endfunction +function bit uvm_sequencer_base::is_grabbed(); + return (lock_list.size() != 0); +endfunction +function uvm_sequence_base uvm_sequencer_base::current_grabber(); + if (lock_list.size() == 0) begin + return null; + end + return lock_list[lock_list.size()-1]; +endfunction +function bit uvm_sequencer_base::has_do_available(); + foreach (arb_sequence_q[i]) begin + if ((arb_sequence_q[i].sequence_ptr.is_relevant() == 1) && + (is_blocked(arb_sequence_q[i].sequence_ptr) == 0)) begin + return 1; + end + end + return 0; +endfunction +function void uvm_sequencer_base::set_arbitration(UVM_SEQ_ARB_TYPE val); + m_arbitration = val; +endfunction +function UVM_SEQ_ARB_TYPE uvm_sequencer_base::get_arbitration(); + return m_arbitration; +endfunction +function uvm_sequence_base uvm_sequencer_base::get_arbitration_sequence( int index); + return arb_sequence_q[index].sequence_ptr; +endfunction +function void uvm_sequencer_base::analysis_write(uvm_sequence_item t); + return; +endfunction +task uvm_sequencer_base::wait_for_sequences(); + uvm_wait_for_nba_region(); +endtask +function void uvm_sequencer_base::send_request(uvm_sequence_base sequence_ptr, + uvm_sequence_item t, + bit rerandomize = 0); + return; +endfunction +function void uvm_sequencer_base::set_max_zero_time_wait_relevant_count(int new_val) ; + m_max_zero_time_wait_relevant_count = new_val ; +endfunction +function void uvm_sequencer_base::start_phase_sequence(uvm_phase phase); + uvm_resource_pool rp = uvm_resource_pool::get(); + uvm_resource_types::rsrc_q_t rq; + uvm_sequence_base seq; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory f = cs.get_factory(); + rq = rp.lookup_name({get_full_name(), ".", phase.get_name(), "_phase"}, + "default_sequence", null, 0); + uvm_resource_pool::sort_by_precedence(rq); + for (int i = 0; seq == null && i < rq.size(); i++) begin + uvm_resource_base rsrc = rq.get(i); + uvm_resource#(uvm_sequence_base) sbr; + uvm_resource#(uvm_object_wrapper) owr; + if ($cast(sbr, rsrc) && sbr != null) begin + seq = sbr.read(this); + if (seq == null) begin + begin + if (uvm_report_enabled(UVM_FULL,UVM_INFO,"UVM/SQR/PH/DEF/SB/NULL")) + uvm_report_info ("UVM/SQR/PH/DEF/SB/NULL", {"Default phase sequence for phase '", phase.get_name(),"' explicitly disabled"}, UVM_FULL, "t/uvm/src/seq/uvm_sequencer_base.svh", 1341, "", 1); + end + return; + end + end + else if ($cast(owr, rsrc) && owr != null) begin + uvm_object_wrapper wrapper; + wrapper = owr.read(this); + if (wrapper == null) begin + begin + if (uvm_report_enabled(UVM_FULL,UVM_INFO,"UVM/SQR/PH/DEF/OW/NULL")) + uvm_report_info ("UVM/SQR/PH/DEF/OW/NULL", {"Default phase sequence for phase '", phase.get_name(),"' explicitly disabled"}, UVM_FULL, "t/uvm/src/seq/uvm_sequencer_base.svh", 1353, "", 1); + end + return; + end + if (!$cast(seq, f.create_object_by_type(wrapper, get_full_name(), + wrapper.get_type_name())) + || seq == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"PHASESEQ")) + uvm_report_warning ("PHASESEQ", {"Default sequence for phase '", phase.get_name(),"' %s is not a sequence type"}, UVM_NONE, "t/uvm/src/seq/uvm_sequencer_base.svh", 1361, "", 1); + end + return; + end + end + end + if (seq == null) begin + begin + if (uvm_report_enabled(UVM_FULL,UVM_INFO,"PHASESEQ")) + uvm_report_info ("PHASESEQ", {"No default phase sequence for phase '", phase.get_name(),"'"}, UVM_FULL, "t/uvm/src/seq/uvm_sequencer_base.svh", 1369, "", 1); + end + return; + end + begin + if (uvm_report_enabled(UVM_FULL,UVM_INFO,"PHASESEQ")) + uvm_report_info ("PHASESEQ", {"Starting default sequence '", seq.get_type_name(),"' for phase '", phase.get_name(),"'"}, UVM_FULL, "t/uvm/src/seq/uvm_sequencer_base.svh", 1374, "", 1); + end + seq.print_sequence_info = 1; + seq.set_sequencer(this); + seq.reseed(); + seq.set_starting_phase(phase); + if (seq.get_randomize_enabled() && !seq.randomize()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"STRDEFSEQ")) + uvm_report_warning ("STRDEFSEQ", {"Randomization failed for default sequence '", seq.get_type_name(),"' for phase '", phase.get_name(),"'"}, UVM_NONE, "t/uvm/src/seq/uvm_sequencer_base.svh", 1383, "", 1); + end + return; + end + fork begin + uvm_sequence_process_wrapper w = new(); + w.pid = process::self(); + w.seq = seq; + w.pid.srandom(uvm_create_random_seed(seq.get_type_name(), this.get_full_name())); + m_default_sequences[phase] = w; + seq.start(this); + m_default_sequences.delete(phase); + end + join_none +endfunction +function void uvm_sequencer_base::stop_phase_sequence(uvm_phase phase); + if (m_default_sequences.exists(phase)) begin + begin + if (uvm_report_enabled(UVM_FULL,UVM_INFO,"PHASESEQ")) + uvm_report_info ("PHASESEQ", {"Killing default sequence '", m_default_sequences[phase].seq.get_type_name(), "' for phase '", phase.get_name(), "'"}, UVM_FULL, "t/uvm/src/seq/uvm_sequencer_base.svh", 1409, "", 1); + end + m_default_sequences[phase].seq.kill(); + end + else begin + begin + if (uvm_report_enabled(UVM_FULL,UVM_INFO,"PHASESEQ")) + uvm_report_info ("PHASESEQ", {"No default sequence to kill for phase '", phase.get_name(), "'"}, UVM_FULL, "t/uvm/src/seq/uvm_sequencer_base.svh", 1415, "", 1); + end + end +endfunction : stop_phase_sequence +class uvm_sequence_request; + bit grant; + int sequence_id; + int request_id; + int item_priority; + process process_id; + uvm_sequencer_base::seq_req_t request; + uvm_sequence_base sequence_ptr; +endclass +class uvm_sequencer_analysis_fifo #(type RSP = uvm_sequence_item) extends uvm_tlm_fifo #(RSP); + uvm_analysis_imp #(RSP, uvm_sequencer_analysis_fifo #(RSP)) analysis_export; + uvm_sequencer_base sequencer_ptr; + function new (string name, uvm_component parent = null); + super.new(name, parent, 0); + analysis_export = new ("analysis_export", this); + endfunction + function void write(input RSP t); + if (sequencer_ptr == null) + uvm_report_fatal ("SEQRNULL", "The sequencer pointer is null when attempting a write", UVM_NONE); + sequencer_ptr.analysis_write(t); + endfunction +endclass +virtual + class uvm_sequencer_param_base #(type REQ = uvm_sequence_item, + type RSP = REQ) extends uvm_sequencer_base; + typedef uvm_sequencer_param_base #( REQ , RSP) this_type; + typedef REQ req_type; + typedef RSP rsp_type; + REQ m_last_req_buffer[$]; + RSP m_last_rsp_buffer[$]; + protected int m_num_last_reqs = 1; + protected int num_last_items = m_num_last_reqs; + protected int m_num_last_rsps = 1; + protected int m_num_reqs_sent; + protected int m_num_rsps_received; + uvm_sequencer_analysis_fifo #(RSP) sqr_rsp_analysis_fifo; + extern function new (string name, uvm_component parent); + extern virtual function void send_request(uvm_sequence_base sequence_ptr, + uvm_sequence_item t, + bit rerandomize = 0); + function REQ get_current_item(); + REQ t; + if (m_req_fifo.try_peek(t) == 0) + return null; + return t; + endfunction + extern function int get_num_reqs_sent(); + extern function void set_num_last_reqs(int unsigned max); + extern function int unsigned get_num_last_reqs(); + function REQ last_req(int unsigned n = 0); + if(n > m_num_last_reqs) begin + uvm_report_warning("HSTOB", + $sformatf("Invalid last access (%0d), the max history is %0d", n, + m_num_last_reqs)); + return null; + end + if(n == m_last_req_buffer.size()) + return null; + return m_last_req_buffer[n]; + endfunction + uvm_analysis_export #(RSP) rsp_export; + extern function int get_num_rsps_received(); + extern function void set_num_last_rsps(int unsigned max); + extern function int unsigned get_num_last_rsps(); + function RSP last_rsp(int unsigned n = 0); + if(n > m_num_last_rsps) begin + uvm_report_warning("HSTOB", + $sformatf("Invalid last access (%0d), the max history is %0d", n, + m_num_last_rsps)); + return null; + end + if(n == m_last_rsp_buffer.size()) + return null; + return m_last_rsp_buffer[n]; + endfunction + extern function void m_last_rsp_push_front(RSP item); + extern function void put_response (RSP t); + extern virtual function void build_phase(uvm_phase phase); + extern virtual function void connect_phase(uvm_phase phase); + extern virtual function void do_print (uvm_printer printer); + extern virtual function void analysis_write(uvm_sequence_item t); + extern function void m_last_req_push_front(REQ item); + uvm_tlm_fifo #(REQ) m_req_fifo; +endclass +function uvm_sequencer_param_base::new (string name, uvm_component parent); + super.new(name, parent); + rsp_export = new("rsp_export", this); + sqr_rsp_analysis_fifo = new("sqr_rsp_analysis_fifo", this); + sqr_rsp_analysis_fifo.print_enabled = 0; + m_req_fifo = new("req_fifo", this); + m_req_fifo.print_enabled = 0; +endfunction +function void uvm_sequencer_param_base::do_print (uvm_printer printer); + super.do_print(printer); + printer.print_field_int("num_last_reqs", m_num_last_reqs, $bits(m_num_last_reqs), UVM_DEC); + printer.print_field_int("num_last_rsps", m_num_last_rsps, $bits(m_num_last_rsps), UVM_DEC); +endfunction +function void uvm_sequencer_param_base::connect_phase(uvm_phase phase); + super.connect_phase(phase); + rsp_export.connect(sqr_rsp_analysis_fifo.analysis_export); +endfunction +function void uvm_sequencer_param_base::build_phase(uvm_phase phase); + super.build_phase(phase); + sqr_rsp_analysis_fifo.sequencer_ptr = this; +endfunction +function void uvm_sequencer_param_base::send_request(uvm_sequence_base sequence_ptr, + uvm_sequence_item t, + bit rerandomize = 0); + REQ param_t; + if (sequence_ptr == null) begin + uvm_report_fatal("SNDREQ", "Send request sequence_ptr is null", UVM_NONE); + end + if (sequence_ptr.m_wait_for_grant_semaphore < 1) begin + uvm_report_fatal("SNDREQ", "Send request called without wait_for_grant", UVM_NONE); + end + sequence_ptr.m_wait_for_grant_semaphore--; + if ($cast(param_t, t)) begin + if (rerandomize == 1) begin + if (!param_t.randomize()) begin + uvm_report_warning("SQRSNDREQ", "Failed to rerandomize sequence item in send_request"); + end + end + if (param_t.get_transaction_id() == -1) begin + param_t.set_transaction_id(sequence_ptr.m_next_transaction_id++); + end + m_last_req_push_front(param_t); + end else begin + uvm_report_fatal("SQRSNDREQCAST",$sformatf("send_request failed to cast sequence item"), UVM_NONE); + end + param_t.set_sequence_id(sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 1)); + t.set_sequencer(this); + if (m_req_fifo.try_put(param_t) != 1) begin + uvm_report_fatal("SQRSNDREQGNI", "Concurrent calls to get_next_item() not supported. Consider using a semaphore to ensure that concurrent processes take turns in the driver", UVM_NONE); + end + m_num_reqs_sent++; + grant_queued_locks(); +endfunction +function void uvm_sequencer_param_base::put_response (RSP t); + uvm_sequence_base sequence_ptr; + if (t == null) begin + uvm_report_fatal("SQRPUT", "Driver put a null response", UVM_NONE); + end + m_last_rsp_push_front(t); + m_num_rsps_received++; + if (t.get_sequence_id() == -1) begin + uvm_report_fatal("SQRPUT", "Driver put a response with null sequence_id", UVM_NONE); + return; + end + sequence_ptr = m_find_sequence(t.get_sequence_id()); + if (sequence_ptr != null) begin + if (sequence_ptr.get_use_response_handler() == 1) begin + sequence_ptr.response_handler(t); + return; + end + sequence_ptr.put_response(t); + end + else begin + uvm_report_warning("Sequencer", + $sformatf("Dropping response for sequence %0d, sequence not found. Probable cause: sequence exited or has been killed", + t.get_sequence_id())); + end +endfunction +function void uvm_sequencer_param_base::analysis_write(uvm_sequence_item t); + RSP response; + if (!$cast(response, t)) begin + uvm_report_fatal("ANALWRT", "Failure to cast analysis port write item", UVM_NONE); + end + put_response(response); +endfunction +function int uvm_sequencer_param_base::get_num_reqs_sent(); + return m_num_reqs_sent; +endfunction +function int uvm_sequencer_param_base::get_num_rsps_received(); + return m_num_rsps_received; +endfunction +function void uvm_sequencer_param_base::set_num_last_reqs(int unsigned max); + if(max > 1024) begin + uvm_report_warning("HSTOB", + $sformatf("Invalid last size; 1024 is the maximum and will be used")); + max = 1024; + end + while((m_last_req_buffer.size() != 0) && (m_last_req_buffer.size() > max)) + void'(m_last_req_buffer.pop_back()); + m_num_last_reqs = max; + num_last_items = max; +endfunction +function int unsigned uvm_sequencer_param_base::get_num_last_reqs(); + return m_num_last_reqs; +endfunction +function void uvm_sequencer_param_base::m_last_req_push_front(REQ item); + if(!m_num_last_reqs) + return; + if(m_last_req_buffer.size() == m_num_last_reqs) + void'(m_last_req_buffer.pop_back()); + this.m_last_req_buffer.push_front(item); +endfunction +function void uvm_sequencer_param_base::set_num_last_rsps(int unsigned max); + if(max > 1024) begin + uvm_report_warning("HSTOB", + $sformatf("Invalid last size; 1024 is the maximum and will be used")); + max = 1024; + end + while((m_last_rsp_buffer.size() != 0) && (m_last_rsp_buffer.size() > max)) begin + void'(m_last_rsp_buffer.pop_back()); + end + m_num_last_rsps = max; +endfunction +function int unsigned uvm_sequencer_param_base::get_num_last_rsps(); + return m_num_last_rsps; +endfunction +function void uvm_sequencer_param_base::m_last_rsp_push_front(RSP item); + if(!m_num_last_rsps) + return; + if(m_last_rsp_buffer.size() == m_num_last_rsps) + void'(m_last_rsp_buffer.pop_back()); + this.m_last_rsp_buffer.push_front(item); +endfunction +class uvm_sequencer #(type REQ=uvm_sequence_item, RSP=REQ) + extends uvm_sequencer_param_base #(REQ, RSP); + typedef uvm_sequencer #( REQ , RSP) this_type; + bit sequence_item_requested; + bit get_next_item_called; + typedef uvm_component_registry #(this_type) type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + extern function new (string name, uvm_component parent=null); + extern virtual function void stop_sequences(); + extern virtual function string get_type_name(); + uvm_seq_item_pull_imp #(REQ, RSP, this_type) seq_item_export; + extern virtual task get_next_item (output REQ t); + extern virtual task try_next_item (output REQ t); + extern virtual function void item_done (RSP item = null); + extern virtual task put (RSP t); + extern task get (output REQ t); + extern task peek (output REQ t); + extern function void item_done_trigger(RSP item = null); + function RSP item_done_get_trigger_data(); + return last_rsp(0); + endfunction + extern protected virtual function int m_find_number_driver_connections(); +endclass +typedef uvm_sequencer #(uvm_sequence_item) uvm_virtual_sequencer; +function uvm_sequencer::new (string name, uvm_component parent=null); + super.new(name, parent); + seq_item_export = new ("seq_item_export", this); +endfunction +function void uvm_sequencer::stop_sequences(); + REQ t; + super.stop_sequences(); + sequence_item_requested = 0; + get_next_item_called = 0; + if (m_req_fifo.used()) begin + uvm_report_info(get_full_name(), "Sequences stopped. Removing request from sequencer fifo"); + m_req_fifo.flush(); + end +endfunction +function string uvm_sequencer::get_type_name(); + return "uvm_sequencer"; +endfunction +function int uvm_sequencer::m_find_number_driver_connections(); + uvm_port_base #(uvm_sqr_if_base #(REQ, RSP)) provided_to_port_list[string]; + seq_item_export.get_provided_to(provided_to_port_list); + return provided_to_port_list.num(); +endfunction +task uvm_sequencer::get_next_item(output REQ t); + REQ req_item; + if (get_next_item_called == 1) + uvm_report_error(get_full_name(), + "Get_next_item called twice without item_done or get in between", UVM_NONE); + if (!sequence_item_requested) + m_select_sequence(); + sequence_item_requested = 1; + get_next_item_called = 1; + m_req_fifo.peek(t); +endtask +task uvm_sequencer::try_next_item(output REQ t); + int selected_sequence; + time arb_time; + uvm_sequence_base seq; + if (get_next_item_called == 1) begin + uvm_report_error(get_full_name(), "get_next_item/try_next_item called twice without item_done or get in between", UVM_NONE); + return; + end + wait_for_sequences(); + selected_sequence = m_choose_next_request(); + if (selected_sequence == -1) begin + t = null; + return; + end + m_set_arbitration_completed(arb_sequence_q[selected_sequence].request_id); + seq = arb_sequence_q[selected_sequence].sequence_ptr; + arb_sequence_q.delete(selected_sequence); + m_update_lists(); + sequence_item_requested = 1; + get_next_item_called = 1; + wait_for_sequences(); + if (!m_req_fifo.try_peek(t)) + uvm_report_error("TRY_NEXT_BLOCKED", {"try_next_item: the selected sequence '", + seq.get_full_name(), "' did not produce an item within an NBA delay. ", + "Sequences should not consume time between calls to start_item and finish_item. ", + "Returning null item."}, UVM_NONE); +endtask +function void uvm_sequencer::item_done(RSP item = null); + REQ t; + sequence_item_requested = 0; + get_next_item_called = 0; + if (m_req_fifo.try_get(t) == 0) begin + uvm_report_fatal("SQRBADITMDN", {"Item_done() called with no outstanding requests.", + " Each call to item_done() must be paired with a previous call to get_next_item()."}); + end else begin + m_wait_for_item_sequence_id = t.get_sequence_id(); + m_wait_for_item_transaction_id = t.get_transaction_id(); + end + if (item != null) begin + seq_item_export.put_response(item); + end + grant_queued_locks(); +endfunction +task uvm_sequencer::put (RSP t); + put_response(t); +endtask +task uvm_sequencer::get(output REQ t); + if (sequence_item_requested == 0) begin + m_select_sequence(); + end + sequence_item_requested = 1; + m_req_fifo.peek(t); + item_done(); +endtask +task uvm_sequencer::peek(output REQ t); + if (sequence_item_requested == 0) begin + m_select_sequence(); + end + sequence_item_requested = 1; + m_req_fifo.peek(t); +endtask +function void uvm_sequencer::item_done_trigger(RSP item = null); + item_done(item); +endfunction +class uvm_push_sequencer #(type REQ=uvm_sequence_item, RSP=REQ) + extends uvm_sequencer_param_base #(REQ, RSP); + typedef uvm_push_sequencer #( REQ , RSP) this_type; + uvm_blocking_put_port #(REQ) req_port; + function new (string name, uvm_component parent=null); + super.new(name, parent); + req_port = new ("req_port", this); + endfunction + task run_phase(uvm_phase phase); + REQ t; + int selected_sequence; + fork + super.run_phase(phase); + forever + begin + m_select_sequence(); + m_req_fifo.get(t); + req_port.put(t); + m_wait_for_item_sequence_id = t.get_sequence_id(); + m_wait_for_item_transaction_id = t.get_transaction_id(); + end + join + endtask + protected virtual function int m_find_number_driver_connections(); + return req_port.size(); + endfunction +endclass +virtual class uvm_sequence_base extends uvm_sequence_item; + typedef uvm_abstract_object_registry#(uvm_sequence_base,"uvm_sequence_base") type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_sequence_base"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_sequence_base"; + endfunction : get_type_name + protected uvm_sequence_state m_sequence_state; + int m_next_transaction_id = 1; + local int m_priority = -1; + uvm_recorder m_tr_recorder; + int m_wait_for_grant_semaphore; + protected int m_sqr_seq_ids[int]; + protected bit children_array[uvm_sequence_base]; + protected uvm_sequence_item response_queue[$]; + protected int response_queue_depth = 8; + protected bit response_queue_error_report_enabled; + local bit do_not_randomize; + protected process m_sequence_process; + local bit m_use_response_handler; + local bit is_rel_default; + local bit wait_rel_default; + function new (string name = "uvm_sequence"); + super.new(name); + m_sequence_state = UVM_CREATED; + m_wait_for_grant_semaphore = 0; + m_init_phase_daps(1); + endfunction + virtual function bit get_randomize_enabled(); + return (do_not_randomize == 0); + endfunction : get_randomize_enabled + virtual function void set_randomize_enabled(bit enable); + do_not_randomize = !enable; + endfunction : set_randomize_enabled + virtual function bit is_item(); + return 0; + endfunction + function uvm_sequence_state_enum get_sequence_state(); + return m_sequence_state; + endfunction + task wait_for_sequence_state(int unsigned state_mask); + wait (m_sequence_state & state_mask); + endtask + function int get_tr_handle(); + if (m_tr_recorder != null) + return m_tr_recorder.get_handle(); + else + return 0; + endfunction + virtual task start (uvm_sequencer_base sequencer, + uvm_sequence_base parent_sequence = null, + int this_priority = -1, + bit call_pre_post = 1); + bit old_automatic_phase_objection; + set_item_context(parent_sequence, sequencer); + if (!(m_sequence_state inside {UVM_CREATED,UVM_STOPPED,UVM_FINISHED})) begin + uvm_report_fatal("SEQ_NOT_DONE", + {"Sequence ", get_full_name(), " already started"},UVM_NONE); + end + if (m_parent_sequence != null) begin + m_parent_sequence.children_array[this] = 1; + end + if (this_priority < -1) begin + uvm_report_fatal("SEQPRI", $sformatf("Sequence %s start has illegal priority: %0d", + get_full_name(), + this_priority), UVM_NONE); + end + if (this_priority < 0) begin + if (parent_sequence == null) this_priority = 100; + else this_priority = parent_sequence.get_priority(); + end + clear_response_queue(); + m_priority = this_priority; + if (m_sequencer != null) begin + int handle; + if (m_parent_sequence == null) begin + handle = m_sequencer.begin_tr(this, get_name()); + m_tr_recorder = uvm_recorder::get_recorder_from_handle(handle); + end else begin + handle = m_sequencer.begin_tr(.tr(this), .stream_name(get_root_sequence_name()), + .parent_handle((m_parent_sequence.m_tr_recorder == null) ? 0 : m_parent_sequence.m_tr_recorder.get_handle())); + m_tr_recorder = uvm_recorder::get_recorder_from_handle(handle); + end + end + set_sequence_id(-1); + if (m_sequencer != null) begin + void'(m_sequencer.m_register_sequence(this)); + end + m_sequence_state = UVM_PRE_START; + fork + begin + m_sequence_process = process::self(); + #0; + if (get_automatic_phase_objection()) begin + m_safe_raise_starting_phase("automatic phase objection"); + end + pre_start(); + if (call_pre_post == 1) begin + m_sequence_state = UVM_PRE_BODY; + #0; + pre_body(); + end + if (parent_sequence != null) begin + parent_sequence.pre_do(0); + parent_sequence.mid_do(this); + end + m_sequence_state = UVM_BODY; + #0; + body(); + m_sequence_state = UVM_ENDED; + #0; + if (parent_sequence != null) begin + parent_sequence.post_do(this); + end + if (call_pre_post == 1) begin + m_sequence_state = UVM_POST_BODY; + #0; + post_body(); + end + m_sequence_state = UVM_POST_START; + #0; + post_start(); + if (get_automatic_phase_objection()) begin + m_safe_drop_starting_phase("automatic phase objection"); + end + m_sequence_state = UVM_FINISHED; + #0; + end + join + if (m_sequencer != null) begin + m_sequencer.end_tr(this); + end + if (m_sequence_state != UVM_STOPPED) begin + clean_exit_sequence(); + end + #0; + if ((m_parent_sequence != null) && (m_parent_sequence.children_array.exists(this))) begin + m_parent_sequence.children_array.delete(this); + end + old_automatic_phase_objection = get_automatic_phase_objection(); + m_init_phase_daps(1); + set_automatic_phase_objection(old_automatic_phase_objection); + endtask + function void clean_exit_sequence(); + if (m_sequencer != null) + m_sequencer.m_sequence_exiting(this); + else + foreach(m_sqr_seq_ids[seqrID]) begin + uvm_sequencer_base s = uvm_sequencer_base::all_sequencer_insts[seqrID]; + s.m_sequence_exiting(this); + end + m_sqr_seq_ids.delete(); + endfunction + virtual task pre_start(); + return; + endtask + virtual task pre_body(); + return; + endtask + virtual task pre_do(bit is_item); + return; + endtask + virtual function void mid_do(uvm_sequence_item this_item); + return; + endfunction + virtual task body(); + uvm_report_warning("uvm_sequence_base", "Body definition undefined"); + return; + endtask + virtual function void post_do(uvm_sequence_item this_item); + return; + endfunction + virtual task post_body(); + return; + endtask + virtual task post_start(); + return; + endtask + local uvm_get_to_lock_dap#(bit) m_automatic_phase_objection_dap; + local uvm_get_to_lock_dap#(uvm_phase) m_starting_phase_dap; + function void m_init_phase_daps(bit create); + string apo_name = $sformatf("%s.automatic_phase_objection", get_full_name()); + string sp_name = $sformatf("%s.starting_phase", get_full_name()); + if (create) begin + m_automatic_phase_objection_dap = uvm_get_to_lock_dap#(bit)::type_id_create(apo_name, get_sequencer()); + m_starting_phase_dap = uvm_get_to_lock_dap#(uvm_phase)::type_id_create(sp_name, get_sequencer()); + end + else begin + m_automatic_phase_objection_dap.set_name(apo_name); + m_starting_phase_dap.set_name(sp_name); + end + endfunction : m_init_phase_daps + function uvm_phase get_starting_phase(); + return m_starting_phase_dap.get(); + endfunction : get_starting_phase + function void set_starting_phase(uvm_phase phase); + m_starting_phase_dap.set(phase); + endfunction : set_starting_phase + function void set_automatic_phase_objection(bit value); + m_automatic_phase_objection_dap.set(value); + endfunction : set_automatic_phase_objection + function bit get_automatic_phase_objection(); + return m_automatic_phase_objection_dap.get(); + endfunction : get_automatic_phase_objection + function void m_safe_raise_starting_phase(string description = "", + int count = 1); + uvm_phase starting_phase = get_starting_phase(); + if (starting_phase != null) + starting_phase.raise_objection(this, description, count); + endfunction : m_safe_raise_starting_phase + function void m_safe_drop_starting_phase(string description = "", + int count = 1); + uvm_phase starting_phase = get_starting_phase(); + if (starting_phase != null) + starting_phase.drop_objection(this, description, count); + endfunction : m_safe_drop_starting_phase + function void set_priority (int value); + m_priority = value; + endfunction + function int get_priority(); + return m_priority; + endfunction + virtual function bit is_relevant(); + is_rel_default = 1; + return 1; + endfunction + virtual task wait_for_relevant(); + event e; + wait_rel_default = 1; + if (is_rel_default != wait_rel_default) + uvm_report_fatal("RELMSM", + "is_relevant() was implemented without defining wait_for_relevant()", UVM_NONE); + @e; + endtask + task lock(uvm_sequencer_base sequencer = null); + if (sequencer == null) + sequencer = m_sequencer; + if (sequencer == null) + uvm_report_fatal("LOCKSEQR", "Null m_sequencer reference", UVM_NONE); + sequencer.lock(this); + endtask + task grab(uvm_sequencer_base sequencer = null); + if (sequencer == null) begin + if (m_sequencer == null) begin + uvm_report_fatal("GRAB", "Null m_sequencer reference", UVM_NONE); + end + m_sequencer.grab(this); + end + else begin + sequencer.grab(this); + end + endtask + function void unlock(uvm_sequencer_base sequencer = null); + if (sequencer == null) begin + if (m_sequencer == null) begin + uvm_report_fatal("UNLOCK", "Null m_sequencer reference", UVM_NONE); + end + m_sequencer.unlock(this); + end else begin + sequencer.unlock(this); + end + endfunction + function void ungrab(uvm_sequencer_base sequencer = null); + unlock(sequencer); + endfunction + function bit is_blocked(); + return m_sequencer.is_blocked(this); + endfunction + function bit has_lock(); + return m_sequencer.has_lock(this); + endfunction + function void kill(); + if (m_sequence_process != null) begin + if (m_sequencer == null) begin + m_kill(); + if (get_automatic_phase_objection()) begin + m_safe_drop_starting_phase("automatic phase objection"); + end + return; + end + m_sequencer.kill_sequence(this); + if (get_automatic_phase_objection()) begin + m_safe_drop_starting_phase("automatic phase objection"); + end + return; + end + endfunction + virtual function void do_kill(); + return; + endfunction + function void m_kill(); + do_kill(); + foreach(children_array[i]) begin + i.kill(); + end + if (m_sequence_process != null) begin + m_sequence_process.kill; + m_sequence_process = null; + end + m_sequence_state = UVM_STOPPED; + if ((m_parent_sequence != null) && (m_parent_sequence.children_array.exists(this))) + m_parent_sequence.children_array.delete(this); + clean_exit_sequence(); + endfunction + protected function uvm_sequence_item create_item(uvm_object_wrapper type_var, + uvm_sequencer_base l_sequencer, string name); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory=cs.get_factory(); + $cast(create_item, factory.create_object_by_type( type_var, this.get_full_name(), name )); + create_item.set_item_context(this, l_sequencer); + endfunction + virtual task start_item (uvm_sequence_item item, + int set_priority = -1, + uvm_sequencer_base sequencer=null); + if(item == null) begin + uvm_report_fatal("NULLITM", + {"attempting to start a null item from sequence '", + get_full_name(), "'"}, UVM_NONE); + return; + end + if ( ! item.is_item() ) begin + uvm_report_fatal("SEQNOTITM", + {"attempting to start a sequence using start_item() from sequence '", + get_full_name(), "'. Use seq.start() instead."}, UVM_NONE); + return; + end + if (sequencer == null) + sequencer = item.get_sequencer(); + if(sequencer == null) + sequencer = get_sequencer(); + if(sequencer == null) begin + uvm_report_fatal("SEQ",{"neither the item's sequencer nor dedicated sequencer has been supplied to start item in ",get_full_name()},UVM_NONE); + return; + end + item.set_item_context(this, sequencer); + if (set_priority < 0) + set_priority = get_priority(); + sequencer.wait_for_grant(this, set_priority); + if (sequencer.is_auto_item_recording_enabled()) begin + void'(sequencer.begin_tr(.tr(item), .stream_name(item.get_root_sequence_name()), .label("Transactions"), + .parent_handle((m_tr_recorder == null) ? 0 : m_tr_recorder.get_handle()))); + end + pre_do(1); + endtask + virtual task finish_item (uvm_sequence_item item, + int set_priority = -1); + uvm_sequencer_base sequencer; + sequencer = item.get_sequencer(); + if (sequencer == null) begin + uvm_report_fatal("STRITM", "sequence_item has null sequencer", UVM_NONE); + end + mid_do(item); + sequencer.send_request(this, item); + sequencer.wait_for_item_done(this, -1); + if (sequencer.is_auto_item_recording_enabled()) begin + sequencer.end_tr(item); + end + post_do(item); + endtask + virtual task wait_for_grant(int item_priority = -1, bit lock_request = 0); + if (m_sequencer == null) begin + uvm_report_fatal("WAITGRANT", "Null m_sequencer reference", UVM_NONE); + end + m_sequencer.wait_for_grant(this, item_priority, lock_request); + endtask + virtual function void send_request(uvm_sequence_item request, bit rerandomize = 0); + if (m_sequencer == null) begin + uvm_report_fatal("SENDREQ", "Null m_sequencer reference", UVM_NONE); + end + m_sequencer.send_request(this, request, rerandomize); + endfunction + virtual task wait_for_item_done(int transaction_id = -1); + if (m_sequencer == null) begin + uvm_report_fatal("WAITITEMDONE", "Null m_sequencer reference", UVM_NONE); + end + m_sequencer.wait_for_item_done(this, transaction_id); + endtask + function void use_response_handler(bit enable); + m_use_response_handler = enable; + endfunction + function bit get_use_response_handler(); + return m_use_response_handler; + endfunction + virtual function void response_handler(uvm_sequence_item response); + return; + endfunction + function void set_response_queue_error_report_enabled(bit value); + response_queue_error_report_enabled = value; + endfunction : set_response_queue_error_report_enabled + function bit get_response_queue_error_report_enabled(); + return response_queue_error_report_enabled; + endfunction : get_response_queue_error_report_enabled + function void set_response_queue_depth(int value); + response_queue_depth = value; + endfunction + function int get_response_queue_depth(); + return response_queue_depth; + endfunction + virtual function void clear_response_queue(); + response_queue.delete(); + endfunction + virtual function void put_base_response(input uvm_sequence_item response); + if ((response_queue_depth == -1) || + (response_queue.size() < response_queue_depth)) begin + response_queue.push_back(response); + return; + end + if (response_queue_error_report_enabled) begin + uvm_report_error(get_full_name(), "Response queue overflow, response was dropped", UVM_NONE); + end + endfunction + virtual function void put_response (uvm_sequence_item response_item); + put_base_response(response_item); + endfunction + virtual task get_base_response(output uvm_sequence_item response, input int transaction_id = -1); + int queue_size, i; + if (response_queue.size() == 0) + wait (response_queue.size() != 0); + if (transaction_id == -1) begin + response = response_queue.pop_front(); + return; + end + forever begin + queue_size = response_queue.size(); + for (i = 0; i < queue_size; i++) begin + if (response_queue[i].get_transaction_id() == transaction_id) + begin + $cast(response,response_queue[i]); + response_queue.delete(i); + return; + end + end + wait (response_queue.size() != queue_size); + end + endtask + function int m_get_sqr_sequence_id(int sequencer_id, bit update_sequence_id); + if (m_sqr_seq_ids.exists(sequencer_id)) begin + if (update_sequence_id == 1) begin + set_sequence_id(m_sqr_seq_ids[sequencer_id]); + end + return m_sqr_seq_ids[sequencer_id]; + end + if (update_sequence_id == 1) + set_sequence_id(-1); + return -1; + endfunction + function void m_set_sqr_sequence_id(int sequencer_id, int sequence_id); + m_sqr_seq_ids[sequencer_id] = sequence_id; + set_sequence_id(sequence_id); + endfunction +endclass +virtual class uvm_sequence #(type REQ = uvm_sequence_item, + type RSP = REQ) extends uvm_sequence_base; + typedef uvm_sequencer_param_base #(REQ, RSP) sequencer_t; + sequencer_t param_sequencer; + REQ req; + RSP rsp; + function new (string name = "uvm_sequence"); + super.new(name); + endfunction + function void send_request(uvm_sequence_item request, bit rerandomize = 0); + REQ m_request; + if (m_sequencer == null) begin + uvm_report_fatal("SSENDREQ", "Null m_sequencer reference", UVM_NONE); + end + if (!$cast(m_request, request)) begin + uvm_report_fatal("SSENDREQ", "Failure to cast uvm_sequence_item to request", UVM_NONE); + end + m_sequencer.send_request(this, m_request, rerandomize); + endfunction + function REQ get_current_item(); + if (!$cast(param_sequencer, m_sequencer)) + uvm_report_fatal("SGTCURR", "Failure to cast m_sequencer to the parameterized sequencer", UVM_NONE); + return (param_sequencer.get_current_item()); + endfunction + virtual task get_response(output RSP response, input int transaction_id = -1); + uvm_sequence_item rsp; + get_base_response( rsp, transaction_id); + $cast(response,rsp); + endtask + virtual function void put_response(uvm_sequence_item response_item); + RSP response; + if (!$cast(response, response_item)) begin + uvm_report_fatal("PUTRSP", "Failure to cast response in put_response", UVM_NONE); + end + put_base_response(response_item); + endfunction + function void do_print (uvm_printer printer); + super.do_print(printer); + printer.print_object("req", req); + printer.print_object("rsp", rsp); + endfunction +endclass +typedef class uvm_sequence_library_cfg; +class uvm_sequence_library #(type REQ=uvm_sequence_item,RSP=REQ) extends uvm_sequence #(REQ,RSP); + typedef uvm_object_registry #(uvm_sequence_library#(REQ,RSP)) type_id; + static function uvm_sequence_library#(REQ,RSP) type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_sequence_library#(REQ,RSP) tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_sequence_library #(REQ,RSP)"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_sequence_library #(REQ,RSP)"; + endfunction : get_type_name + extern function new(string name=""); + uvm_sequence_lib_mode selection_mode; + int unsigned min_random_count=10; + int unsigned max_random_count=10; + protected int unsigned sequences_executed; + rand int unsigned sequence_count = 10; + rand int unsigned select_rand; + randc bit [15:0] select_randc; + protected int seqs_distrib[string] = '{default:0}; + protected uvm_object_wrapper sequences[$]; + constraint valid_rand_selection { + select_rand inside {[0:sequences.size()-1]}; + } + constraint valid_randc_selection { + select_randc inside {[0:sequences.size()-1]}; + } + constraint valid_sequence_count { + sequence_count inside {[min_random_count:max_random_count]}; + } + extern virtual function int unsigned select_sequence(int unsigned max); + extern static function void add_typewide_sequence(uvm_object_wrapper seq_type); + extern static function void add_typewide_sequences(uvm_object_wrapper seq_types[$]); + extern function void add_sequence(uvm_object_wrapper seq_type); + extern virtual function void add_sequences(uvm_object_wrapper seq_types[$]); + extern virtual function void remove_sequence(uvm_object_wrapper seq_type); + extern virtual function void get_sequences(ref uvm_object_wrapper seq_types[$]); + extern virtual function uvm_object_wrapper get_sequence(int unsigned idx); + extern function void init_sequence_library(); + typedef uvm_sequence_library #(REQ,RSP) this_type; + static protected uvm_object_wrapper m_typewide_sequences[$]; + bit m_abort; + extern static function bit m_static_check(uvm_object_wrapper seq_type); + extern static function bit m_check(uvm_object_wrapper seq_type, this_type lib); + extern function bit m_dyn_check(uvm_object_wrapper seq_type); + extern function void m_get_config(); + extern static function bit m_add_typewide_sequence(uvm_object_wrapper seq_type); + extern virtual task execute(uvm_object_wrapper wrap); + extern virtual task body(); + extern virtual function void do_print(uvm_printer printer); + extern function void pre_randomize(); +endclass +class uvm_sequence_library_cfg extends uvm_object; + typedef uvm_object_registry#(uvm_sequence_library_cfg,"uvm_sequence_library_cfg") type_id; + static function uvm_sequence_library_cfg type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_sequence_library_cfg tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_sequence_library_cfg"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_sequence_library_cfg"; + endfunction : get_type_name + uvm_sequence_lib_mode selection_mode; + int unsigned min_random_count; + int unsigned max_random_count; + function new(string name="", + uvm_sequence_lib_mode mode=UVM_SEQ_LIB_RAND, + int unsigned min=1, + int unsigned max=10); + super.new(name); + selection_mode = mode; + min_random_count = min; + max_random_count = max; + endfunction +endclass +function uvm_sequence_library::new(string name=""); + super.new(name); + init_sequence_library(); + valid_rand_selection.constraint_mode(0); + valid_randc_selection.constraint_mode(0); +endfunction +function bit uvm_sequence_library::m_add_typewide_sequence(uvm_object_wrapper seq_type); + this_type::add_typewide_sequence(seq_type); + return 1; +endfunction +function void uvm_sequence_library::add_typewide_sequence(uvm_object_wrapper seq_type); + if (m_static_check(seq_type)) + m_typewide_sequences.push_back(seq_type); +endfunction +function void uvm_sequence_library::add_typewide_sequences(uvm_object_wrapper seq_types[$]); + foreach (seq_types[i]) + add_typewide_sequence(seq_types[i]); +endfunction +function void uvm_sequence_library::add_sequence(uvm_object_wrapper seq_type); + if (m_dyn_check(seq_type)) + sequences.push_back(seq_type); +endfunction +function void uvm_sequence_library::add_sequences(uvm_object_wrapper seq_types[$]); + foreach (seq_types[i]) + add_sequence(seq_types[i]); +endfunction +function void uvm_sequence_library::remove_sequence(uvm_object_wrapper seq_type); + foreach (sequences[i]) + if (sequences[i] == seq_type) begin + sequences.delete(i); + return; + end +endfunction +function void uvm_sequence_library::get_sequences(ref uvm_object_wrapper seq_types[$]); + foreach (sequences[i]) + seq_types.push_back(sequences[i]); +endfunction +function uvm_object_wrapper uvm_sequence_library::get_sequence(int unsigned idx); + if(idx < sequences.size()) + return sequences[idx]; + else begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"SEQ_LIB/GET_SEQ")) + uvm_report_error ("SEQ_LIB/GET_SEQ", $sformatf("idx %0d > number of sequences in library", idx), UVM_NONE, "t/uvm/src/seq/uvm_sequence_library.svh", 453, "", 1); + end + return null; + end +endfunction +function int unsigned uvm_sequence_library::select_sequence(int unsigned max); + static int unsigned counter; + select_sequence = counter; + counter++; + if (counter >= max) + counter = 0; +endfunction +function void uvm_sequence_library::init_sequence_library(); + foreach (this_type::m_typewide_sequences[i]) + sequences.push_back(this_type::m_typewide_sequences[i]); +endfunction +function bit uvm_sequence_library::m_static_check(uvm_object_wrapper seq_type); + if (!m_check(seq_type,null)) + return 0; + foreach (m_typewide_sequences[i]) + if (m_typewide_sequences[i] == seq_type) + return 0; + return 1; +endfunction +function bit uvm_sequence_library::m_dyn_check(uvm_object_wrapper seq_type); + if (!m_check(seq_type,this)) + return 0; + foreach (sequences[i]) + if (sequences[i] == seq_type) + return 0; + return 1; +endfunction +function bit uvm_sequence_library::m_check(uvm_object_wrapper seq_type, this_type lib); + uvm_object obj; + uvm_sequence_base seq; + uvm_root top; + uvm_coreservice_t cs; + string name; + string typ; + obj = seq_type.create_object(); + name = (lib == null) ? type_name() : lib.get_full_name(); + typ = (lib == null) ? type_name() : lib.get_type_name(); + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + if (!$cast(seq, obj)) begin + begin + if (top.uvm_report_enabled(UVM_NONE,UVM_ERROR,"SEQLIB/BAD_SEQ_TYPE")) + top.uvm_report_error ("SEQLIB/BAD_SEQ_TYPE", {"Object '",obj.get_type_name(), "' is not a sequence. Cannot add to sequence library '",name, "'"}, UVM_NONE, "t/uvm/src/seq/uvm_sequence_library.svh", 538, "", 1); + end + return 0; + end + return 1; +endfunction +function void uvm_sequence_library::pre_randomize(); + m_get_config(); +endfunction +function void uvm_sequence_library::m_get_config(); + uvm_sequence_library_cfg cfg; + string phase_name; + uvm_phase starting_phase = get_starting_phase(); + if (starting_phase != null) begin + phase_name = {starting_phase.get_name(),"_phase"}; + end + if (uvm_config_db #(uvm_sequence_library_cfg)::get(m_sequencer, + phase_name, + "default_sequence.config", + cfg) ) begin + selection_mode = cfg.selection_mode; + min_random_count = cfg.min_random_count; + max_random_count = cfg.max_random_count; + end + else begin + void'(uvm_config_db #(int unsigned)::get(m_sequencer, + phase_name, + "default_sequence.min_random_count", + min_random_count) ); + void'(uvm_config_db #(int unsigned)::get(m_sequencer, + phase_name, + "default_sequence.max_random_count", + max_random_count) ); + void'(uvm_config_db #(uvm_sequence_lib_mode)::get(m_sequencer, + phase_name, + "default_sequence.selection_mode", + selection_mode) ); + end + if (max_random_count == 0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"SEQLIB/MAX_ZERO")) + uvm_report_warning ("SEQLIB/MAX_ZERO", $sformatf("max_random_count (%0d) zero. Nothing will be done.", max_random_count), UVM_NONE, "t/uvm/src/seq/uvm_sequence_library.svh", 593, "", 1); + end + if (min_random_count > max_random_count) + min_random_count = max_random_count; + end + else if (min_random_count > max_random_count) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"SEQLIB/MIN_GT_MAX")) + uvm_report_error ("SEQLIB/MIN_GT_MAX", $sformatf("min_random_count (%0d) greater than max_random_count (%0d). Setting min to max.", min_random_count,max_random_count), UVM_NONE, "t/uvm/src/seq/uvm_sequence_library.svh", 600, "", 1); + end + min_random_count = max_random_count; + end + else begin + if (selection_mode == UVM_SEQ_LIB_ITEM) begin + uvm_sequencer #(REQ,RSP) seqr; + uvm_object_wrapper lhs = REQ::get_type(); + uvm_object_wrapper rhs = uvm_sequence_item::get_type(); + if (lhs == rhs) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"SEQLIB/BASE_ITEM")) + uvm_report_error ("SEQLIB/BASE_ITEM", {"selection_mode cannot be UVM_SEQ_LIB_ITEM when ", "the REQ type is the base uvm_sequence_item. Using UVM_SEQ_LIB_RAND mode"}, UVM_NONE, "t/uvm/src/seq/uvm_sequence_library.svh", 610, "", 1); + end + selection_mode = UVM_SEQ_LIB_RAND; + end + if (m_sequencer == null || !$cast(seqr,m_sequencer)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"SEQLIB/VIRT_SEQ")) + uvm_report_error ("SEQLIB/VIRT_SEQ", {"selection_mode cannot be UVM_SEQ_LIB_ITEM when ", "running as a virtual sequence. Using UVM_SEQ_LIB_RAND mode"}, UVM_NONE, "t/uvm/src/seq/uvm_sequence_library.svh", 615, "", 1); + end + selection_mode = UVM_SEQ_LIB_RAND; + end + end + end +endfunction +task uvm_sequence_library::body(); + uvm_object_wrapper wrap; + uvm_phase starting_phase = get_starting_phase(); + if (m_sequencer == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"SEQLIB/VIRT_SEQ")) + uvm_report_fatal ("SEQLIB/VIRT_SEQ", {"Sequence library 'm_sequencer' handle is null ", " no current support for running as a virtual sequence."}, UVM_NONE, "t/uvm/src/seq/uvm_sequence_library.svh", 634, "", 1); + end + return; + end + if (sequences.size() == 0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"SEQLIB/NOSEQS")) + uvm_report_error ("SEQLIB/NOSEQS", "Sequence library does not contain any sequences. Did you forget to call init_sequence_library() in the constructor?", UVM_NONE, "t/uvm/src/seq/uvm_sequence_library.svh", 639, "", 1); + end + return; + end + if (!get_randomize_enabled()) + m_get_config(); + m_safe_raise_starting_phase({"starting sequence library ",get_full_name()," (", get_type_name(),")"}); + begin + if (uvm_report_enabled(UVM_LOW,UVM_INFO,"SEQLIB/START")) + uvm_report_info ("SEQLIB/START", $sformatf("Starting sequence library %s in %s phase: %0d iterations in mode %s", get_type_name(), (starting_phase != null ? starting_phase.get_name() : "unknown"), sequence_count, selection_mode.name()), UVM_LOW, "t/uvm/src/seq/uvm_sequence_library.svh", 652, "", 1); + end + begin + if (uvm_report_enabled(UVM_FULL,UVM_INFO,"SEQLIB/SPRINT")) + uvm_report_info ("SEQLIB/SPRINT", {"\n",sprint(uvm_table_printer::get_default())}, UVM_FULL, "t/uvm/src/seq/uvm_sequence_library.svh", 654, "", 1); + end + case (selection_mode) + UVM_SEQ_LIB_RAND: begin + valid_rand_selection.constraint_mode(1); + valid_sequence_count.constraint_mode(0); + for (int i=1; i<=sequence_count; i++) begin + if (!randomize(select_rand)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"SEQLIB/RAND_FAIL")) + uvm_report_error ("SEQLIB/RAND_FAIL", "Random sequence selection failed", UVM_NONE, "t/uvm/src/seq/uvm_sequence_library.svh", 663, "", 1); + end + break; + end + else begin + wrap = sequences[select_rand]; + end + execute(wrap); + end + valid_rand_selection.constraint_mode(0); + valid_sequence_count.constraint_mode(1); + end + UVM_SEQ_LIB_RANDC: begin + uvm_object_wrapper q[$]; + valid_randc_selection.constraint_mode(1); + valid_sequence_count.constraint_mode(0); + for (int i=1; i<=sequence_count; i++) begin + if (!randomize(select_randc)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"SEQLIB/RANDC_FAIL")) + uvm_report_error ("SEQLIB/RANDC_FAIL", "Random sequence selection failed", UVM_NONE, "t/uvm/src/seq/uvm_sequence_library.svh", 681, "", 1); + end + break; + end + else begin + wrap = sequences[select_randc]; + end + q.push_back(wrap); + end + valid_randc_selection.constraint_mode(0); + valid_sequence_count.constraint_mode(1); + foreach(q[i]) + execute(q[i]); + valid_randc_selection.constraint_mode(0); + valid_sequence_count.constraint_mode(1); + end + UVM_SEQ_LIB_ITEM: begin + for (int i=1; i<=sequence_count; i++) begin + wrap = REQ::get_type(); + execute(wrap); + end + end + UVM_SEQ_LIB_USER: begin + for (int i=1; i<=sequence_count; i++) begin + int user_selection; + user_selection = select_sequence(sequences.size()-1); + if (user_selection >= sequences.size()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"SEQLIB/USER_FAIL")) + uvm_report_error ("SEQLIB/USER_FAIL", "User sequence selection out of range", UVM_NONE, "t/uvm/src/seq/uvm_sequence_library.svh", 709, "", 1); + end + wrap = REQ::get_type(); + end + else begin + wrap = sequences[user_selection]; + end + execute(wrap); + end + end + default: begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"SEQLIB/RAND_MODE")) + uvm_report_fatal ("SEQLIB/RAND_MODE", $sformatf("Unknown random sequence selection mode: %0d",selection_mode), UVM_NONE, "t/uvm/src/seq/uvm_sequence_library.svh", 721, "", 1); + end + end + endcase + begin + if (uvm_report_enabled(UVM_LOW,UVM_INFO,"SEQLIB/END")) + uvm_report_info ("SEQLIB/END", {"Ending sequence library in phase ", (starting_phase != null ? starting_phase.get_name() : "unknown")}, UVM_LOW, "t/uvm/src/seq/uvm_sequence_library.svh", 726, "", 1); + end + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"SEQLIB/DSTRB")) + uvm_report_info ("SEQLIB/DSTRB", $sformatf("%p",seqs_distrib), UVM_HIGH, "t/uvm/src/seq/uvm_sequence_library.svh", 728, "", 1); + end + m_safe_drop_starting_phase({"starting sequence library ",get_full_name()," (", get_type_name(),")"}); +endtask +task uvm_sequence_library::execute(uvm_object_wrapper wrap); + uvm_object obj; + uvm_sequence_item seq_or_item; + uvm_sequence_base seq_base; + REQ req_item; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory=cs.get_factory(); + obj = factory.create_object_by_type(wrap,get_full_name(), + $sformatf("%s:%0d",wrap.get_type_name(),sequences_executed+1)); + if (!$cast(seq_base, obj)) begin + if (!$cast(req_item, obj)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"SEQLIB/WRONG_ITEM_TYPE")) + uvm_report_error ("SEQLIB/WRONG_ITEM_TYPE", {"The item created by '", get_full_name(), "' when in 'UVM_SEQ_LIB_ITEM' mode doesn't match the REQ type which was passed in to the uvm_sequence_library#(REQ[,RSP]), this can happen if the REQ type which was passed in was a pure-virtual type. Either configure the factory overrides to properly generate items for this sequence library, or do not execute this sequence library in UVM_SEQ_LIB_ITEM mode."}, UVM_NONE, "t/uvm/src/seq/uvm_sequence_library.svh", 756, "", 1); + end + return; + end + end + void'($cast(seq_or_item,obj)); + begin + if (uvm_report_enabled(UVM_FULL,UVM_INFO,"SEQLIB/EXEC")) + uvm_report_info ("SEQLIB/EXEC", {"Executing ",(seq_or_item.is_item() ? "item " : "sequence "),seq_or_item.get_name(), " (",seq_or_item.get_type_name(),")"}, UVM_FULL, "t/uvm/src/seq/uvm_sequence_library.svh", 764, "", 1); + end + seq_or_item.print_sequence_info = 1; + begin + uvm_sequence_base __seq; + if ( seq_or_item.is_item() ) begin + start_item(seq_or_item, -1); + if ( ! seq_or_item.randomize() with {} ) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RNDFLD")) + uvm_report_warning ("RNDFLD", "Randomization failed in uvm_rand_send action", UVM_NONE, "t/uvm/src/seq/uvm_sequence_library.svh", 766, "", 1); + end + end + finish_item(seq_or_item, -1); + end + else if ( $cast( __seq, seq_or_item ) ) begin + __seq.set_item_context(this,seq_or_item.get_sequencer()); + if ( __seq.get_randomize_enabled() ) begin + if ( ! seq_or_item.randomize() with {} ) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RNDFLD")) + uvm_report_warning ("RNDFLD", "Randomization failed in uvm_rand_send action", UVM_NONE, "t/uvm/src/seq/uvm_sequence_library.svh", 766, "", 1); + end + end + end + __seq.start(__seq.get_sequencer(), this, -1, 0); + end + else begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"NOT_SEQ_OR_ITEM")) + uvm_report_warning ("NOT_SEQ_OR_ITEM", "Object passed uvm_rand_send appears to be neither a sequence or item.", UVM_NONE, "t/uvm/src/seq/uvm_sequence_library.svh", 766, "", 1); + end + end + end + seqs_distrib[seq_or_item.get_type_name()] = seqs_distrib[seq_or_item.get_type_name()]+1; + sequences_executed++; +endtask +function void uvm_sequence_library::do_print(uvm_printer printer); + printer.print_field_int("min_random_count",min_random_count,32,UVM_DEC,,"int unsigned"); + printer.print_field_int("max_random_count",max_random_count,32,UVM_DEC,,"int unsigned"); + printer.print_generic("selection_mode","uvm_sequence_lib_mode",32,selection_mode.name()); + printer.print_field_int("sequence_count",sequence_count,32,UVM_DEC,,"int unsigned"); + printer.print_array_header("typewide_sequences",m_typewide_sequences.size(),"queue_object_types"); + foreach (m_typewide_sequences[i]) + printer.print_generic($sformatf("[%0d]",i),"uvm_object_wrapper","-",m_typewide_sequences[i].get_type_name()); + printer.print_array_footer(); + printer.print_array_header("sequences",sequences.size(),"queue_object_types"); + foreach (sequences[i]) + printer.print_generic($sformatf("[%0d]",i),"uvm_object_wrapper","-",sequences[i].get_type_name()); + printer.print_array_footer(); + printer.print_array_header("seqs_distrib",seqs_distrib.num(),"as_int_string"); + foreach (seqs_distrib[typ]) begin + printer.print_field_int({"[",typ,"]"},seqs_distrib[typ],32,,UVM_DEC,"int unsigned"); + end + printer.print_array_footer(); +endfunction +typedef uvm_sequence #(uvm_sequence_item, uvm_sequence_item) uvm_default_sequence_type; +typedef uvm_sequencer #(uvm_sequence_item, uvm_sequence_item) uvm_default_sequencer_type; +typedef uvm_driver #(uvm_sequence_item, uvm_sequence_item) uvm_default_driver_type; +typedef uvm_sequencer_param_base #(uvm_sequence_item, uvm_sequence_item) uvm_default_sequencer_param_type; +class uvm_time; + static local real m_resolution = 1.0e-12; + local real m_res; + local time m_time; + local string m_name; + static function void set_time_resolution(real res); + m_resolution = res; + endfunction + function new(string name = "uvm_tlm_time", real res = 0); + m_name = name; + m_res = (res == 0) ? m_resolution : res; + reset(); + endfunction + function string get_name(); + return m_name; + endfunction + function void reset(); + m_time = 0; + endfunction + local function real to_m_res(real t, time scaled, real secs); + return t/real'(scaled) * (secs/m_res); + endfunction + function real get_realtime(time scaled, real secs = 1.0e-9); + return m_time*real'(scaled) * m_res/secs; + endfunction + function void incr(real t, time scaled, real secs = 1.0e-9); + if (t < 0.0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/TIMENEG")) + uvm_report_error ("UVM/TLM/TIMENEG", {"Cannot increment uvm_tlm_time variable ", m_name, " by a negative value"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm_time.svh", 134, "", 1); + end + return; + end + if (scaled == 0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"UVM/TLM/BADSCALE")) + uvm_report_fatal ("UVM/TLM/BADSCALE", "uvm_tlm_time::incr() called with a scaled time literal that is smaller than the current timescale", UVM_NONE, "t/uvm/src/tlm2/uvm_tlm_time.svh", 139, "", 1); + end + end + m_time += to_m_res(t, scaled, secs); + endfunction + function void decr(real t, time scaled, real secs); + if (t < 0.0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/TIMENEG")) + uvm_report_error ("UVM/TLM/TIMENEG", {"Cannot decrement uvm_tlm_time variable ", m_name, " by a negative value"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm_time.svh", 161, "", 1); + end + return; + end + if (scaled == 0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"UVM/TLM/BADSCALE")) + uvm_report_fatal ("UVM/TLM/BADSCALE", "uvm_tlm_time::decr() called with a scaled time literal that is smaller than the current timescale", UVM_NONE, "t/uvm/src/tlm2/uvm_tlm_time.svh", 166, "", 1); + end + end + m_time -= to_m_res(t, scaled, secs); + if (m_time < 0.0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/TOODECR")) + uvm_report_error ("UVM/TLM/TOODECR", {"Cannot decrement uvm_tlm_time variable ", m_name, " to a negative value"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm_time.svh", 172, "", 1); + end + reset(); + end + endfunction + function real get_abstime(real secs); + return m_time*m_res/secs; + endfunction + function void set_abstime(real t, real secs); + m_time = t*secs/m_res; + endfunction +endclass +typedef uvm_time uvm_tlm_time; +typedef enum +{ + UVM_TLM_READ_COMMAND, + UVM_TLM_WRITE_COMMAND, + UVM_TLM_IGNORE_COMMAND +} uvm_tlm_command_e; +typedef enum +{ + UVM_TLM_OK_RESPONSE = 1, + UVM_TLM_INCOMPLETE_RESPONSE = 0, + UVM_TLM_GENERIC_ERROR_RESPONSE = -1, + UVM_TLM_ADDRESS_ERROR_RESPONSE = -2, + UVM_TLM_COMMAND_ERROR_RESPONSE = -3, + UVM_TLM_BURST_ERROR_RESPONSE = -4, + UVM_TLM_BYTE_ENABLE_ERROR_RESPONSE = -5 +} uvm_tlm_response_status_e; +typedef class uvm_tlm_extension_base; +class uvm_tlm_generic_payload extends uvm_sequence_item; + rand bit [63:0] m_address; + rand uvm_tlm_command_e m_command; + rand byte unsigned m_data[]; + rand int unsigned m_length; + rand uvm_tlm_response_status_e m_response_status; + bit m_dmi; + rand byte unsigned m_byte_enable[]; + rand int unsigned m_byte_enable_length; + rand int unsigned m_streaming_width; + protected uvm_tlm_extension_base m_extensions [uvm_tlm_extension_base]; + local rand uvm_tlm_extension_base m_rand_exts[]; + typedef uvm_object_registry#(uvm_tlm_generic_payload,"uvm_tlm_generic_payload") type_id; + static function uvm_tlm_generic_payload type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_tlm_generic_payload tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_tlm_generic_payload"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_tlm_generic_payload"; + endfunction : get_type_name + function new(string name=""); + super.new(name); + m_address = 0; + m_command = UVM_TLM_IGNORE_COMMAND; + m_length = 0; + m_response_status = UVM_TLM_INCOMPLETE_RESPONSE; + m_dmi = 0; + m_byte_enable_length = 0; + m_streaming_width = 0; + endfunction + function void do_print(uvm_printer printer); + byte unsigned be; + super.do_print(printer); + printer.print_field_int ("address", m_address, 64, UVM_HEX); + printer.print_generic ("command", "uvm_tlm_command_e", 32, m_command.name()); + printer.print_generic ("response_status", "uvm_tlm_response_status_e", + 32, m_response_status.name()); + printer.print_field_int ("streaming_width", m_streaming_width, 32, UVM_HEX); + printer.print_array_header("data", m_length, "darray(byte)"); + for (int i=0; i < m_length && i < m_data.size(); i++) begin + if (m_byte_enable_length) begin + be = m_byte_enable[i % m_byte_enable_length]; + printer.print_generic ($sformatf("[%0d]",i), "byte", 8, + $sformatf("'h%h%s",m_data[i],((be=='hFF) ? "" : " x"))); + end + else + printer.print_generic ($sformatf("[%0d]",i), "byte", 8, + $sformatf("'h%h",m_data[i])); + end + printer.print_array_footer(); + begin + string name; + printer.print_array_header("extensions", m_extensions.num(), "aa(obj,obj)"); + foreach (m_extensions[ext_]) begin + uvm_tlm_extension_base ext = m_extensions[ext_]; + name = {"[",ext.get_name(),"]"}; + printer.print_object(name, ext, "["); + end + printer.print_array_footer(); + end + endfunction + function void do_copy(uvm_object rhs); + uvm_tlm_generic_payload gp; + super.do_copy(rhs); + $cast(gp, rhs); + m_address = gp.m_address; + m_command = gp.m_command; + m_data = gp.m_data; + m_dmi = gp.m_dmi; + m_length = gp.m_length; + m_response_status = gp.m_response_status; + m_byte_enable = gp.m_byte_enable; + m_streaming_width = gp.m_streaming_width; + m_byte_enable_length = gp.m_byte_enable_length; + m_extensions.delete(); + foreach (gp.m_extensions[ext]) + $cast(m_extensions[ext], gp.m_extensions[ext].clone()); + endfunction + function bit do_compare(uvm_object rhs, uvm_comparer comparer); + uvm_tlm_generic_payload gp; + do_compare = super.do_compare(rhs, comparer); + $cast(gp, rhs); + if ( (!comparer.get_threshold() || (comparer.get_result() < comparer.get_threshold())) && + ((m_address) != (gp.m_address)) ) begin + string name = ("" == "") ? "m_address" : ""; + void'(comparer.compare_field_int(name , m_address, gp.m_address, $bits(m_address), UVM_HEX)); + end + if ( (!comparer.get_threshold() || (comparer.get_result() < comparer.get_threshold())) && + ((m_command) != (gp.m_command)) ) begin + string name = ("" == "") ? "m_command" : ""; + void'( comparer.compare_string(name, + $sformatf("%s'(%s)", "uvm_tlm_command_e", m_command.name()), + $sformatf("%s'(%s)", "uvm_tlm_command_e", gp.m_command.name())) ); + end + if ( (!comparer.get_threshold() || (comparer.get_result() < comparer.get_threshold())) && + ((m_length) != (gp.m_length)) ) begin + string name = ("" == "") ? "m_length" : ""; + void'(comparer.compare_field_int(name , m_length, gp.m_length, $bits(m_length), UVM_UNSIGNED)); + end + if ( (!comparer.get_threshold() || (comparer.get_result() < comparer.get_threshold())) && + ((m_dmi) != (gp.m_dmi)) ) begin + string name = ("" == "") ? "m_dmi" : ""; + void'(comparer.compare_field_int(name , m_dmi, gp.m_dmi, $bits(m_dmi), UVM_BIN)); + end + if ( (!comparer.get_threshold() || (comparer.get_result() < comparer.get_threshold())) && + ((m_byte_enable_length) != (gp.m_byte_enable_length)) ) begin + string name = ("" == "") ? "m_byte_enable_length" : ""; + void'(comparer.compare_field_int(name , m_byte_enable_length, gp.m_byte_enable_length, $bits(m_byte_enable_length), UVM_UNSIGNED)); + end + if ( (!comparer.get_threshold() || (comparer.get_result() < comparer.get_threshold())) && + ((m_response_status) != (gp.m_response_status)) ) begin + string name = ("" == "") ? "m_response_status" : ""; + void'( comparer.compare_string(name, + $sformatf("%s'(%s)", "uvm_tlm_response_status_e", m_response_status.name()), + $sformatf("%s'(%s)", "uvm_tlm_response_status_e", gp.m_response_status.name())) ); + end + if ( (!comparer.get_threshold() || (comparer.get_result() < comparer.get_threshold())) && + ((m_streaming_width) != (gp.m_streaming_width)) ) begin + string name = ("" == "") ? "m_streaming_width" : ""; + void'(comparer.compare_field_int(name , m_streaming_width, gp.m_streaming_width, $bits(m_streaming_width), UVM_UNSIGNED)); + end + if ( (!comparer.get_threshold() || (comparer.get_result() < comparer.get_threshold())) && + m_byte_enable_length == gp.m_byte_enable_length ) begin + for (int i=0; i < m_byte_enable_length && i < m_byte_enable.size(); i++) begin + if ( (!comparer.get_threshold() || (comparer.get_result() < comparer.get_threshold())) && + ((m_byte_enable[i]) != (gp.m_byte_enable[i])) ) begin + string name = ($sformatf("m_byte_enable[%0d]", i) == "") ? "m_byte_enable[i]" : $sformatf("m_byte_enable[%0d]", i); + void'(comparer.compare_field_int(name , m_byte_enable[i], gp.m_byte_enable[i], $bits(m_byte_enable[i]), UVM_HEX)); + end + end + end + if ( (!comparer.get_threshold() || (comparer.get_result() < comparer.get_threshold())) && + m_length == gp.m_length ) begin + byte unsigned be; + for (int i=0; i < m_length && i < m_data.size(); i++) begin + if (m_byte_enable_length) begin + be = m_byte_enable[i % m_byte_enable_length]; + end + else begin + be = 8'hFF; + end + if ( (!comparer.get_threshold() || (comparer.get_result() < comparer.get_threshold())) && + ((m_data[i] & be) != (gp.m_data[i] & be)) ) begin + string name = ($sformatf("m_data[%0d] & %0x", i, be) == "") ? "m_data[i] & be" : $sformatf("m_data[%0d] & %0x", i, be); + void'(comparer.compare_field_int(name , m_data[i] & be, gp.m_data[i] & be, $bits(m_data[i] & be), UVM_HEX)); + end + end + end + if ( !comparer.get_threshold() || (comparer.get_result() < comparer.get_threshold()) ) + foreach (m_extensions[ext_]) begin + uvm_tlm_extension_base ext = ext_; + uvm_tlm_extension_base rhs_ext = gp.m_extensions.exists(ext) ? + gp.m_extensions[ext] : null; + void'(comparer.compare_object(ext.get_name(), + m_extensions[ext], rhs_ext)); + if ( !comparer.get_threshold() || (comparer.get_result() < comparer.get_threshold()) ) + break; + end + if (comparer.get_result()) begin + string msg = $sformatf("GP miscompare between '%s' and '%s':\nlhs = %s\nrhs = %s", + get_full_name(), gp.get_full_name(), + this.convert2string(), gp.convert2string()); + comparer.print_msg(msg); + end + return (comparer.get_result() == 0); + endfunction + function void do_pack(uvm_packer packer); + super.do_pack(packer); + if (m_length > m_data.size()) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PACK_DATA_ARR")) + uvm_report_fatal ("PACK_DATA_ARR", $sformatf("Data array m_length property (%0d) greater than m_data.size (%0d)", m_length,m_data.size()), UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_generic_payload.svh", 562, "", 1); + end + if (m_byte_enable_length > m_byte_enable.size()) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PACK_DATA_ARR")) + uvm_report_fatal ("PACK_DATA_ARR", $sformatf("Data array m_byte_enable_length property (%0d) greater than m_byte_enable.size (%0d)", m_byte_enable_length,m_byte_enable.size()), UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_generic_payload.svh", 566, "", 1); + end + begin + bit __array[]; + { << bit { __array}} = m_address; + __array = new [64] (__array); + packer.pack_bits(__array, 64); + end + begin + bit __array[]; + { << bit { __array}} = m_command; + __array = new [32] (__array); + packer.pack_bits(__array, 32); + end + begin + bit __array[]; + { << bit { __array}} = m_length; + __array = new [32] (__array); + packer.pack_bits(__array, 32); + end + begin + bit __array[]; + { << bit { __array}} = m_dmi; + __array = new [1] (__array); + packer.pack_bits(__array, 1); + end + for (int i=0; i 64) + recorder.record_field("address", m_address, $bits(m_address), UVM_NORADIX); + else + recorder.record_field_int("address", m_address, $bits(m_address), UVM_NORADIX); + end + if (recorder != null && recorder.is_open()) begin + if (recorder.use_record_attribute()) + recorder.record_generic("command", $sformatf("%p", m_command.name())); + else + recorder.record_string("command",m_command.name()); + end + if (recorder != null && recorder.is_open()) begin + if (recorder.use_record_attribute()) + recorder.record_generic("data_length", $sformatf("%p", m_length)); + else + if ($bits(m_length) > 64) + recorder.record_field("data_length", m_length, $bits(m_length), UVM_NORADIX); + else + recorder.record_field_int("data_length", m_length, $bits(m_length), UVM_NORADIX); + end + if (recorder != null && recorder.is_open()) begin + if (recorder.use_record_attribute()) + recorder.record_generic("byte_enable_length", $sformatf("%p", m_byte_enable_length)); + else + if ($bits(m_byte_enable_length) > 64) + recorder.record_field("byte_enable_length", m_byte_enable_length, $bits(m_byte_enable_length), UVM_NORADIX); + else + recorder.record_field_int("byte_enable_length", m_byte_enable_length, $bits(m_byte_enable_length), UVM_NORADIX); + end + if (recorder != null && recorder.is_open()) begin + if (recorder.use_record_attribute()) + recorder.record_generic("response_status", $sformatf("%p", m_response_status.name())); + else + recorder.record_string("response_status",m_response_status.name()); + end + if (recorder != null && recorder.is_open()) begin + if (recorder.use_record_attribute()) + recorder.record_generic("streaming_width", $sformatf("%p", m_streaming_width)); + else + if ($bits(m_streaming_width) > 64) + recorder.record_field("streaming_width", m_streaming_width, $bits(m_streaming_width), UVM_NORADIX); + else + recorder.record_field_int("streaming_width", m_streaming_width, $bits(m_streaming_width), UVM_NORADIX); + end + for (int i=0; i < m_length; i++) + if (recorder != null && recorder.is_open()) begin + if (recorder.use_record_attribute()) + recorder.record_generic($sformatf("\\data[%0d] ", i), $sformatf("%p", m_data[i])); + else + if ($bits(m_data[i]) > 64) + recorder.record_field($sformatf("\\data[%0d] ", i), m_data[i], $bits(m_data[i]), UVM_NORADIX); + else + recorder.record_field_int($sformatf("\\data[%0d] ", i), m_data[i], $bits(m_data[i]), UVM_NORADIX); + end + for (int i=0; i < m_byte_enable_length; i++) + if (recorder != null && recorder.is_open()) begin + if (recorder.use_record_attribute()) + recorder.record_generic($sformatf("\\byte_en[%0d] ", i), $sformatf("%p", m_byte_enable[i])); + else + if ($bits(m_byte_enable[i]) > 64) + recorder.record_field($sformatf("\\byte_en[%0d] ", i), m_byte_enable[i], $bits(m_byte_enable[i]), UVM_NORADIX); + else + recorder.record_field_int($sformatf("\\byte_en[%0d] ", i), m_byte_enable[i], $bits(m_byte_enable[i]), UVM_NORADIX); + end + foreach (m_extensions[ext]) + recorder.record_object(ext.get_name(),m_extensions[ext]); + endfunction + function string convert2string(); + string msg; + string s; + $sformat(msg, "%s %s [0x%16x] =", super.convert2string(), + m_command.name(), m_address); + for(int unsigned i = 0; i < m_length; i++) begin + if (!m_byte_enable_length || (m_byte_enable[i % m_byte_enable_length] == 'hFF)) + $sformat(s, " %02x", m_data[i]); + else + $sformat(s, " --"); + msg = { msg , s }; + end + msg = { msg, " (status=", get_response_string(), ")" }; + return msg; + endfunction + virtual function uvm_tlm_command_e get_command(); + return m_command; + endfunction + virtual function void set_command(uvm_tlm_command_e command); + m_command = command; + endfunction + virtual function bit is_read(); + return (m_command == UVM_TLM_READ_COMMAND); + endfunction + virtual function void set_read(); + set_command(UVM_TLM_READ_COMMAND); + endfunction + virtual function bit is_write(); + return (m_command == UVM_TLM_WRITE_COMMAND); + endfunction + virtual function void set_write(); + set_command(UVM_TLM_WRITE_COMMAND); + endfunction + virtual function void set_address(bit [63:0] addr); + m_address = addr; + endfunction + virtual function bit [63:0] get_address(); + return m_address; + endfunction + virtual function void get_data (output byte unsigned p []); + p = m_data; + endfunction + virtual function void set_data(ref byte unsigned p []); + m_data = p; + endfunction + virtual function int unsigned get_data_length(); + return m_length; + endfunction + virtual function void set_data_length(int unsigned length); + m_length = length; + endfunction + virtual function int unsigned get_streaming_width(); + return m_streaming_width; + endfunction + virtual function void set_streaming_width(int unsigned width); + m_streaming_width = width; + endfunction + virtual function void get_byte_enable(output byte unsigned p[]); + p = m_byte_enable; + endfunction + virtual function void set_byte_enable(ref byte unsigned p[]); + m_byte_enable = p; + endfunction + virtual function int unsigned get_byte_enable_length(); + return m_byte_enable_length; + endfunction + virtual function void set_byte_enable_length(int unsigned length); + m_byte_enable_length = length; + endfunction + virtual function void set_dmi_allowed(bit dmi); + m_dmi = dmi; + endfunction + virtual function bit is_dmi_allowed(); + return m_dmi; + endfunction + virtual function uvm_tlm_response_status_e get_response_status(); + return m_response_status; + endfunction + virtual function void set_response_status(uvm_tlm_response_status_e status); + m_response_status = status; + endfunction + virtual function bit is_response_ok(); + return (int'(m_response_status) > 0); + endfunction + virtual function bit is_response_error(); + return !is_response_ok(); + endfunction + virtual function string get_response_string(); + case(m_response_status) + UVM_TLM_OK_RESPONSE : return "OK"; + UVM_TLM_INCOMPLETE_RESPONSE : return "INCOMPLETE"; + UVM_TLM_GENERIC_ERROR_RESPONSE : return "GENERIC_ERROR"; + UVM_TLM_ADDRESS_ERROR_RESPONSE : return "ADDRESS_ERROR"; + UVM_TLM_COMMAND_ERROR_RESPONSE : return "COMMAND_ERROR"; + UVM_TLM_BURST_ERROR_RESPONSE : return "BURST_ERROR"; + UVM_TLM_BYTE_ENABLE_ERROR_RESPONSE : return "BYTE_ENABLE_ERROR"; + endcase + return "UNKNOWN_RESPONSE"; + endfunction + function uvm_tlm_extension_base set_extension(uvm_tlm_extension_base ext); + uvm_tlm_extension_base ext_handle = ext.get_type_handle(); + if(!m_extensions.exists(ext_handle)) + set_extension = null; + else + set_extension = m_extensions[ext_handle]; + m_extensions[ext_handle] = ext; + endfunction + function int get_num_extensions(); + return m_extensions.num(); + endfunction: get_num_extensions + function uvm_tlm_extension_base get_extension(uvm_tlm_extension_base ext_handle); + if(!m_extensions.exists(ext_handle)) + return null; + return m_extensions[ext_handle]; + endfunction + function void clear_extension(uvm_tlm_extension_base ext_handle); + if(m_extensions.exists(ext_handle)) + m_extensions.delete(ext_handle); + else + begin + if (uvm_report_enabled(UVM_MEDIUM,UVM_INFO,"GP_EXT")) + uvm_report_info ("GP_EXT", $sformatf("Unable to find extension to clear"), UVM_MEDIUM, "t/uvm/src/tlm2/uvm_tlm2_generic_payload.svh", 965, "", 1); + end + endfunction + function void clear_extensions(); + m_extensions.delete(); + endfunction + function void pre_randomize(); + int i; + m_rand_exts = new [m_extensions.num()]; + foreach (m_extensions[ext_]) begin + uvm_tlm_extension_base ext = ext_; + m_rand_exts[i++] = m_extensions[ext]; + end + endfunction + function void post_randomize(); + m_rand_exts.delete(); + endfunction +endclass +typedef uvm_tlm_generic_payload uvm_tlm_gp; +virtual class uvm_tlm_extension_base extends uvm_object; + function new(string name = ""); + super.new(name); + endfunction + pure virtual function uvm_tlm_extension_base get_type_handle(); + pure virtual function string get_type_handle_name(); + virtual function void do_copy(uvm_object rhs); + super.do_copy(rhs); + endfunction + virtual function uvm_object create (string name=""); + return null; + endfunction +endclass +class uvm_tlm_extension #(type T=int) extends uvm_tlm_extension_base; + typedef uvm_tlm_extension#(T) this_type; + local static this_type m_my_tlm_ext_type = ID(); + function new(string name=""); + super.new(name); + endfunction + static function this_type ID(); + if (m_my_tlm_ext_type == null) + m_my_tlm_ext_type = new(); + return m_my_tlm_ext_type; + endfunction + virtual function uvm_tlm_extension_base get_type_handle(); + return ID(); + endfunction + virtual function string get_type_handle_name(); + return $typename(T); + endfunction + virtual function uvm_object create (string name=""); + return null; + endfunction +endclass +typedef class uvm_time; +typedef enum + { + UNINITIALIZED_PHASE, + BEGIN_REQ, + END_REQ, + BEGIN_RESP, + END_RESP + } uvm_tlm_phase_e; +typedef enum + { + UVM_TLM_ACCEPTED, + UVM_TLM_UPDATED, + UVM_TLM_COMPLETED + } uvm_tlm_sync_e; +class uvm_tlm_if #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e); + virtual function uvm_tlm_sync_e nb_transport_fw(T t, ref P p, input uvm_tlm_time delay); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"nb_transport_fw")) + uvm_report_error ("nb_transport_fw", "UVM TLM 2 interface function not implemented", UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_ifs.svh", 115, "", 1); + end + return UVM_TLM_ACCEPTED; + endfunction + virtual function uvm_tlm_sync_e nb_transport_bw(T t, ref P p, input uvm_tlm_time delay); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"nb_transport_bw")) + uvm_report_error ("nb_transport_bw", "UVM TLM 2 interface function not implemented", UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_ifs.svh", 158, "", 1); + end + return UVM_TLM_ACCEPTED; + endfunction + virtual task b_transport(T t, uvm_tlm_time delay); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"b_transport")) + uvm_report_error ("b_transport", "TLM-2 interface task not implemented", UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_ifs.svh", 182, "", 1); + end + endtask +endclass +class uvm_tlm_b_transport_imp #(type T=uvm_tlm_generic_payload, + type IMP=int) + extends uvm_port_base #(uvm_tlm_if #(T)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = (1<<2); + endfunction + virtual function string get_type_name(); + return "uvm_tlm_b_transport_imp"; + endfunction + task b_transport(T t, uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".b_transport() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_imps.svh", 173, "", 1); + end + return; + end + m_imp.b_transport(t, delay); + endtask +endclass +class uvm_tlm_nb_transport_fw_imp #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e, + type IMP=int) + extends uvm_port_base #(uvm_tlm_if #(T,P)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = (1<<0); + endfunction + virtual function string get_type_name(); + return "uvm_tlm_nb_transport_fw_imp"; + endfunction + function uvm_tlm_sync_e nb_transport_fw(T t, ref P p, input uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".nb_transport_fw() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_imps.svh", 190, "", 1); + end + return UVM_TLM_COMPLETED; + end + return m_imp.nb_transport_fw(t, p, delay); + endfunction +endclass +class uvm_tlm_nb_transport_bw_imp #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e, + type IMP=int) + extends uvm_port_base #(uvm_tlm_if #(T,P)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = (1<<1); + endfunction + virtual function string get_type_name(); + return "uvm_tlm_nb_transport_bw_imp"; + endfunction + function uvm_tlm_sync_e nb_transport_bw(T t, ref P p, input uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".nb_transport_bw() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_imps.svh", 207, "", 1); + end + return UVM_TLM_COMPLETED; + end + return m_imp.nb_transport_bw(t, p, delay); + endfunction +endclass +class uvm_tlm_b_transport_port #(type T=uvm_tlm_generic_payload) + extends uvm_port_base #(uvm_tlm_if #(T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = (1<<2); + endfunction + virtual function string get_type_name(); + return "uvm_tlm_b_transport_port"; + endfunction + task b_transport(T t, uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".b_transport() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_ports.svh", 41, "", 1); + end + return; + end + this.m_if.b_transport(t, delay); + endtask +endclass +class uvm_tlm_nb_transport_fw_port #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e) + extends uvm_port_base #(uvm_tlm_if #(T,P)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = (1<<0); + endfunction + virtual function string get_type_name(); + return "uvm_tlm_nb_transport_fw_port"; + endfunction + function uvm_tlm_sync_e nb_transport_fw(T t, ref P p, input uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".nb_transport_fw() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_ports.svh", 59, "", 1); + end + return UVM_TLM_COMPLETED; + end + return this.m_if.nb_transport_fw(t, p, delay); + endfunction +endclass +class uvm_tlm_nb_transport_bw_port #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e) + extends uvm_port_base #(uvm_tlm_if #(T,P)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = (1<<1); + endfunction + virtual function string get_type_name(); + return "uvm_tlm_nb_transport_bw_port"; + endfunction + function uvm_tlm_sync_e nb_transport_bw(T t, ref P p, input uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".nb_transport_bw() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_ports.svh", 78, "", 1); + end + return UVM_TLM_COMPLETED; + end + return this.m_if.nb_transport_bw(t, p, delay); + endfunction +endclass +class uvm_tlm_b_transport_export #(type T=uvm_tlm_generic_payload) + extends uvm_port_base #(uvm_tlm_if #(T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = (1<<2); + endfunction + virtual function string get_type_name(); + return "uvm_tlm_b_transport_export"; + endfunction + task b_transport(T t, uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".b_transport() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_exports.svh", 39, "", 1); + end + return; + end + this.m_if.b_transport(t, delay); + endtask +endclass +class uvm_tlm_nb_transport_fw_export #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e) + extends uvm_port_base #(uvm_tlm_if #(T,P)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = (1<<0); + endfunction + virtual function string get_type_name(); + return "uvm_tlm_nb_transport_fw_export"; + endfunction + function uvm_tlm_sync_e nb_transport_fw(T t, ref P p, input uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".nb_transport_fw() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_exports.svh", 53, "", 1); + end + return UVM_TLM_COMPLETED; + end + return this.m_if.nb_transport_fw(t, p, delay); + endfunction +endclass +class uvm_tlm_nb_transport_bw_export #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e) + extends uvm_port_base #(uvm_tlm_if #(T,P)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = (1<<1); + endfunction + virtual function string get_type_name(); + return "uvm_tlm_nb_transport_bw_export"; + endfunction + function uvm_tlm_sync_e nb_transport_bw(T t, ref P p, input uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".nb_transport_bw() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_exports.svh", 68, "", 1); + end + return UVM_TLM_COMPLETED; + end + return this.m_if.nb_transport_bw(t, p, delay); + endfunction +endclass +virtual +class uvm_tlm_b_target_socket_base #(type T=uvm_tlm_generic_payload) + extends uvm_port_base #(uvm_tlm_if #(T)); + function new (string name, uvm_component parent); + super.new (name, parent, UVM_IMPLEMENTATION, 1, 1); + m_if_mask = (1<<2); + endfunction + virtual function string get_type_name(); + return "uvm_tlm_b_target_socket"; + endfunction +endclass +virtual +class uvm_tlm_b_initiator_socket_base #(type T=uvm_tlm_generic_payload) + extends uvm_port_base #(uvm_tlm_if #(T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = (1<<2); + endfunction + virtual function string get_type_name(); + return "uvm_tlm_b_initiator_socket"; + endfunction + task b_transport(T t, uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".b_transport() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets_base.svh", 77, "", 1); + end + return; + end + this.m_if.b_transport(t, delay); + endtask +endclass +virtual +class uvm_tlm_nb_target_socket_base #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e) + extends uvm_port_base #(uvm_tlm_if #(T,P)); + uvm_tlm_nb_transport_bw_port #(T,P) bw_port; + function new (string name, uvm_component parent); + super.new (name, parent, UVM_IMPLEMENTATION, 1, 1); + m_if_mask = (1<<0); + endfunction + virtual function string get_type_name(); + return "uvm_tlm_nb_target_socket"; + endfunction + function uvm_tlm_sync_e nb_transport_bw(T t, ref P p, input uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".nb_transport_bw() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets_base.svh", 102, "", 1); + end + return UVM_TLM_COMPLETED; + end + return bw_port.nb_transport_bw(t, p, delay); + endfunction +endclass +virtual +class uvm_tlm_nb_initiator_socket_base #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e) + extends uvm_port_base #(uvm_tlm_if #(T,P)); + function new (string name, uvm_component parent); + super.new (name, parent, UVM_PORT, 1, 1); + m_if_mask = (1<<0); + endfunction + virtual function string get_type_name(); + return "uvm_tlm_nb_initiator_socket"; + endfunction + function uvm_tlm_sync_e nb_transport_fw(T t, ref P p, input uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".nb_transport_fw() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets_base.svh", 125, "", 1); + end + return UVM_TLM_COMPLETED; + end + return this.m_if.nb_transport_fw(t, p, delay); + endfunction +endclass +virtual +class uvm_tlm_nb_passthrough_initiator_socket_base #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e) + extends uvm_port_base #(uvm_tlm_if #(T,P)); + uvm_tlm_nb_transport_bw_export #(T,P) bw_export; + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = (1<<0); + bw_export = new("bw_export", get_comp()); + endfunction + virtual function string get_type_name(); + return "uvm_tlm_nb_passthrough_initiator_socket"; + endfunction + function uvm_tlm_sync_e nb_transport_fw(T t, ref P p, input uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".nb_transport_fw() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets_base.svh", 155, "", 1); + end + return UVM_TLM_COMPLETED; + end + return this.m_if.nb_transport_fw(t, p, delay); + endfunction + function uvm_tlm_sync_e nb_transport_bw(T t, ref P p, input uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".nb_transport_bw() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets_base.svh", 156, "", 1); + end + return UVM_TLM_COMPLETED; + end + return bw_export.nb_transport_bw(t, p, delay); + endfunction +endclass +virtual +class uvm_tlm_nb_passthrough_target_socket_base #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e) + extends uvm_port_base #(uvm_tlm_if #(T,P)); + uvm_tlm_nb_transport_bw_port #(T,P) bw_port; + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = (1<<0); + bw_port = new("bw_port", get_comp()); + endfunction + virtual function string get_type_name(); + return "uvm_tlm_nb_passthrough_target_socket"; + endfunction + function uvm_tlm_sync_e nb_transport_fw(T t, ref P p, input uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".nb_transport_fw() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets_base.svh", 183, "", 1); + end + return UVM_TLM_COMPLETED; + end + return this.m_if.nb_transport_fw(t, p, delay); + endfunction + function uvm_tlm_sync_e nb_transport_bw(T t, ref P p, input uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".nb_transport_bw() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets_base.svh", 184, "", 1); + end + return UVM_TLM_COMPLETED; + end + return bw_port.nb_transport_bw(t, p, delay); + endfunction +endclass +virtual +class uvm_tlm_b_passthrough_initiator_socket_base #(type T=uvm_tlm_generic_payload) + extends uvm_port_base #(uvm_tlm_if #(T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = (1<<2); + endfunction + virtual function string get_type_name(); + return "uvm_tlm_b_passthrough_initiator_socket"; + endfunction + task b_transport(T t, uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".b_transport() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets_base.svh", 200, "", 1); + end + return; + end + this.m_if.b_transport(t, delay); + endtask +endclass +virtual +class uvm_tlm_b_passthrough_target_socket_base #(type T=uvm_tlm_generic_payload) + extends uvm_port_base #(uvm_tlm_if #(T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = (1<<2); + endfunction + virtual function string get_type_name(); + return "uvm_tlm_b_passthrough_target_socket"; + endfunction + task b_transport(T t, uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".b_transport() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets_base.svh", 217, "", 1); + end + return; + end + this.m_if.b_transport(t, delay); + endtask + endclass +class uvm_tlm_b_initiator_socket #(type T=uvm_tlm_generic_payload) + extends uvm_tlm_b_initiator_socket_base #(T); + function new(string name, uvm_component parent); + super.new(name, parent); + endfunction + function void connect(this_type provider); + uvm_tlm_b_passthrough_initiator_socket_base #(T) initiator_pt_socket; + uvm_tlm_b_passthrough_target_socket_base #(T) target_pt_socket; + uvm_tlm_b_target_socket_base #(T) target_socket; + uvm_component c; + super.connect(provider); + if($cast(initiator_pt_socket, provider) || + $cast(target_pt_socket, provider) || + $cast(target_socket, provider)) + return; + c = get_comp(); + begin + if (c.uvm_report_enabled(UVM_NONE,UVM_ERROR,get_type_name())) + c.uvm_report_error (get_type_name(), "type mismatch in connect -- connection cannot be completed", UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets.svh", 87, "", 1); + end + endfunction +endclass +class uvm_tlm_b_target_socket #(type IMP=int, + type T=uvm_tlm_generic_payload) + extends uvm_tlm_b_target_socket_base #(T); + local IMP m_imp; + function new (string name, uvm_component parent, IMP imp = null); + super.new (name, parent); + if (imp == null) $cast(m_imp, parent); + else m_imp = imp; + if (m_imp == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM2/NOIMP")) + uvm_report_error ("UVM/TLM2/NOIMP", {"b_target socket ", name, " has no implementation"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets.svh", 121, "", 1); + end + endfunction + function void connect(this_type provider); + uvm_component c; + super.connect(provider); + c = get_comp(); + begin + if (c.uvm_report_enabled(UVM_NONE,UVM_ERROR,get_type_name())) + c.uvm_report_error (get_type_name(), "You cannot call connect() on a target termination socket", UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets.svh", 134, "", 1); + end + endfunction + task b_transport(T t, uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".b_transport() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets.svh", 137, "", 1); + end + return; + end + m_imp.b_transport(t, delay); + endtask +endclass +class uvm_tlm_nb_initiator_socket #(type IMP=int, + type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e) + extends uvm_tlm_nb_initiator_socket_base #(T,P); + uvm_tlm_nb_transport_bw_imp #(T,P,IMP) bw_imp; + function new(string name, uvm_component parent, IMP imp = null); + super.new (name, parent); + if (imp == null) $cast(imp, parent); + if (imp == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM2/NOIMP")) + uvm_report_error ("UVM/TLM2/NOIMP", {"nb_initiator socket ", name, " has no implementation"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets.svh", 168, "", 1); + end + bw_imp = new("bw_imp", imp); + endfunction + function void connect(this_type provider); + uvm_tlm_nb_passthrough_initiator_socket_base #(T,P) initiator_pt_socket; + uvm_tlm_nb_passthrough_target_socket_base #(T,P) target_pt_socket; + uvm_tlm_nb_target_socket_base #(T,P) target_socket; + uvm_component c; + super.connect(provider); + if($cast(initiator_pt_socket, provider)) begin + initiator_pt_socket.bw_export.connect(bw_imp); + return; + end + if($cast(target_pt_socket, provider)) begin + target_pt_socket.bw_port.connect(bw_imp); + return; + end + if($cast(target_socket, provider)) begin + target_socket.bw_port.connect(bw_imp); + return; + end + c = get_comp(); + begin + if (c.uvm_report_enabled(UVM_NONE,UVM_ERROR,get_type_name())) + c.uvm_report_error (get_type_name(), "type mismatch in connect -- connection cannot be completed", UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets.svh", 200, "", 1); + end + endfunction +endclass +class uvm_tlm_nb_target_socket #(type IMP=int, + type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e) + extends uvm_tlm_nb_target_socket_base #(T,P); + local IMP m_imp; + function new (string name, uvm_component parent, IMP imp = null); + super.new (name, parent); + if (imp == null) $cast(m_imp, parent); + else m_imp = imp; + bw_port = new("bw_port", get_comp()); + if (m_imp == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM2/NOIMP")) + uvm_report_error ("UVM/TLM2/NOIMP", {"nb_target socket ", name, " has no implementation"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets.svh", 236, "", 1); + end + endfunction + function void connect(this_type provider); + uvm_component c; + super.connect(provider); + c = get_comp(); + begin + if (c.uvm_report_enabled(UVM_NONE,UVM_ERROR,get_type_name())) + c.uvm_report_error (get_type_name(), "You cannot call connect() on a target termination socket", UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets.svh", 249, "", 1); + end + endfunction + function uvm_tlm_sync_e nb_transport_fw(T t, ref P p, input uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".nb_transport_fw() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets.svh", 252, "", 1); + end + return UVM_TLM_COMPLETED; + end + return m_imp.nb_transport_fw(t, p, delay); + endfunction +endclass +class uvm_tlm_b_passthrough_initiator_socket #(type T=uvm_tlm_generic_payload) + extends uvm_tlm_b_passthrough_initiator_socket_base #(T); + function new(string name, uvm_component parent); + super.new(name, parent); + endfunction + function void connect(this_type provider); + uvm_tlm_b_passthrough_initiator_socket_base #(T) initiator_pt_socket; + uvm_tlm_b_passthrough_target_socket_base #(T) target_pt_socket; + uvm_tlm_b_target_socket_base #(T) target_socket; + uvm_component c; + super.connect(provider); + if($cast(initiator_pt_socket, provider) || + $cast(target_pt_socket, provider) || + $cast(target_socket, provider)) + return; + c = get_comp(); + begin + if (c.uvm_report_enabled(UVM_NONE,UVM_ERROR,get_type_name())) + c.uvm_report_error (get_type_name(), "type mismatch in connect -- connection cannot be completed", UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets.svh", 290, "", 1); + end + endfunction +endclass +class uvm_tlm_b_passthrough_target_socket #(type T=uvm_tlm_generic_payload) + extends uvm_tlm_b_passthrough_target_socket_base #(T); + function new(string name, uvm_component parent); + super.new(name, parent); + endfunction + function void connect(this_type provider); + uvm_tlm_b_passthrough_target_socket_base #(T) target_pt_socket; + uvm_tlm_b_target_socket_base #(T) target_socket; + uvm_component c; + super.connect(provider); + if($cast(target_pt_socket, provider) || + $cast(target_socket, provider)) + return; + c = get_comp(); + begin + if (c.uvm_report_enabled(UVM_NONE,UVM_ERROR,get_type_name())) + c.uvm_report_error (get_type_name(), "type mismatch in connect -- connection cannot be completed", UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets.svh", 323, "", 1); + end + endfunction +endclass +class uvm_tlm_nb_passthrough_initiator_socket #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e) + extends uvm_tlm_nb_passthrough_initiator_socket_base #(T,P); + function new(string name, uvm_component parent); + super.new(name, parent); + endfunction + function void connect(this_type provider); + uvm_tlm_nb_passthrough_initiator_socket_base #(T,P) initiator_pt_socket; + uvm_tlm_nb_passthrough_target_socket_base #(T,P) target_pt_socket; + uvm_tlm_nb_target_socket_base #(T,P) target_socket; + uvm_component c; + super.connect(provider); + if($cast(initiator_pt_socket, provider)) begin + bw_export.connect(initiator_pt_socket.bw_export); + return; + end + if($cast(target_pt_socket, provider)) begin + target_pt_socket.bw_port.connect(bw_export); + return; + end + if($cast(target_socket, provider)) begin + target_socket.bw_port.connect(bw_export); + return; + end + c = get_comp(); + begin + if (c.uvm_report_enabled(UVM_NONE,UVM_ERROR,get_type_name())) + c.uvm_report_error (get_type_name(), "type mismatch in connect -- connection cannot be completed", UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets.svh", 375, "", 1); + end + endfunction +endclass +class uvm_tlm_nb_passthrough_target_socket #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e) + extends uvm_tlm_nb_passthrough_target_socket_base #(T,P); + function new(string name, uvm_component parent); + super.new(name, parent); + endfunction + function void connect(this_type provider); + uvm_tlm_nb_passthrough_target_socket_base #(T,P) target_pt_socket; + uvm_tlm_nb_target_socket_base #(T,P) target_socket; + uvm_component c; + super.connect(provider); + if($cast(target_pt_socket, provider)) begin + target_pt_socket.bw_port.connect(bw_port); + return; + end + if($cast(target_socket, provider)) begin + target_socket.bw_port.connect(bw_port); + return; + end + c = get_comp(); + begin + if (c.uvm_report_enabled(UVM_NONE,UVM_ERROR,get_type_name())) + c.uvm_report_error (get_type_name(), "type mismatch in connect -- connection cannot be completed", UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets.svh", 419, "", 1); + end + endfunction +endclass +typedef class uvm_reg_field; +typedef class uvm_vreg_field; +typedef class uvm_reg; +typedef class uvm_reg_file; +typedef class uvm_vreg; +typedef class uvm_reg_block; +typedef class uvm_mem; +typedef class uvm_reg_item; +typedef class uvm_reg_map; +typedef class uvm_reg_map_info; +typedef class uvm_reg_sequence; +typedef class uvm_reg_adapter; +typedef class uvm_reg_indirect_data; +typedef bit unsigned [64-1:0] uvm_reg_data_t ; +typedef logic unsigned [64-1:0] uvm_reg_data_logic_t ; +typedef bit unsigned [64-1:0] uvm_reg_addr_t ; +typedef logic unsigned [64-1:0] uvm_reg_addr_logic_t ; +typedef bit unsigned [((64-1)/8+1)-1:0] uvm_reg_byte_en_t ; +typedef bit [32-1:0] uvm_reg_cvr_t ; +typedef struct { + string path; + int offset; + int size; +} uvm_hdl_path_slice; +typedef uvm_resource_db#(uvm_reg_cvr_t) uvm_reg_cvr_rsrc_db; + typedef enum { + UVM_IS_OK, + UVM_NOT_OK, + UVM_HAS_X + } uvm_status_e; + typedef enum { + UVM_FRONTDOOR, + UVM_BACKDOOR, + UVM_PREDICT, + UVM_DEFAULT_DOOR + } uvm_door_e; + typedef enum { + UVM_NO_CHECK, + UVM_CHECK + } uvm_check_e; + typedef enum { + UVM_NO_ENDIAN, + UVM_LITTLE_ENDIAN, + UVM_BIG_ENDIAN, + UVM_LITTLE_FIFO, + UVM_BIG_FIFO + } uvm_endianness_e; + typedef enum { + UVM_REG, + UVM_FIELD, + UVM_MEM + } uvm_elem_kind_e; + typedef enum { + UVM_READ, + UVM_WRITE, + UVM_BURST_READ, + UVM_BURST_WRITE + } uvm_access_e; + typedef enum { + UVM_NO_HIER, + UVM_HIER + } uvm_hier_e; + typedef enum { + UVM_PREDICT_DIRECT, + UVM_PREDICT_READ, + UVM_PREDICT_WRITE + } uvm_predict_e; + typedef enum uvm_reg_cvr_t { + UVM_NO_COVERAGE = 'h0000, + UVM_CVR_REG_BITS = 'h0001, + UVM_CVR_ADDR_MAP = 'h0002, + UVM_CVR_FIELD_VALS = 'h0004, + UVM_CVR_ALL = -1 + } uvm_coverage_model_e; +typedef enum bit [63:0] { + UVM_DO_REG_HW_RESET = 64'h0000_0000_0000_0001, + UVM_DO_REG_BIT_BASH = 64'h0000_0000_0000_0002, + UVM_DO_REG_ACCESS = 64'h0000_0000_0000_0004, + UVM_DO_MEM_ACCESS = 64'h0000_0000_0000_0008, + UVM_DO_SHARED_ACCESS = 64'h0000_0000_0000_0010, + UVM_DO_MEM_WALK = 64'h0000_0000_0000_0020, + UVM_DO_ALL_REG_MEM_TESTS = 64'hffff_ffff_ffff_ffff +} uvm_reg_mem_tests_e; +class uvm_hdl_path_concat; + uvm_hdl_path_slice slices[]; + function void set(uvm_hdl_path_slice t[]); + slices = t; + endfunction + function void add_slice(uvm_hdl_path_slice slice); + slices = new [slices.size()+1] (slices); + slices[slices.size()-1] = slice; + endfunction + function void add_path(string path, + int unsigned offset = -1, + int unsigned size = -1); + uvm_hdl_path_slice t; + t.offset = offset; + t.path = path; + t.size = size; + add_slice(t); + endfunction +endclass +function automatic string uvm_hdl_concat2string(uvm_hdl_path_concat concat); + string image = "{"; + if (concat.slices.size() == 1 && + concat.slices[0].offset == -1 && + concat.slices[0].size == -1) + return concat.slices[0].path; + foreach (concat.slices[i]) begin + uvm_hdl_path_slice slice=concat.slices[i]; + image = { image, (i == 0) ? "" : ", ", slice.path }; + if (slice.offset >= 0) + image = { image, "@", $sformatf("[%0d +: %0d]", slice.offset, slice.size) }; + end + image = { image, "}" }; + return image; +endfunction +typedef struct packed { + uvm_reg_addr_t min; + uvm_reg_addr_t max; + int unsigned stride; + } uvm_reg_map_addr_range; +class uvm_reg_item extends uvm_sequence_item; + typedef uvm_object_registry#(uvm_reg_item,"uvm_reg_item") type_id; + static function uvm_reg_item type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_reg_item tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_reg_item"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_reg_item"; + endfunction : get_type_name + uvm_elem_kind_e element_kind; + uvm_object element; + rand uvm_access_e kind; + rand uvm_reg_data_t value[]; + constraint max_values { value.size() > 0 && value.size() < 1000; } + rand uvm_reg_addr_t offset; + uvm_status_e status; + uvm_reg_map local_map; + uvm_reg_map map; + uvm_door_e path; + rand uvm_sequence_base parent; + int prior = -1; + rand uvm_object extension; + string bd_kind; + string fname; + int lineno; + function new(string name=""); + super.new(name); + value = new[1]; + endfunction + virtual function string convert2string(); + string s,value_s; + s = {"kind=",kind.name(), + " ele_kind=",element_kind.name(), + " ele_name=",element==null?"null":element.get_full_name() }; + if (value.size() > 1 && uvm_report_enabled(UVM_HIGH, UVM_INFO, "RegModel")) begin + value_s = "'{"; + foreach (value[i]) + value_s = {value_s,$sformatf("%0h,",value[i])}; + value_s[value_s.len()-1]="}"; + end + else + value_s = $sformatf("%0h",value[0]); + s = {s, " value=",value_s}; + if (element_kind == UVM_MEM) + s = {s, $sformatf(" offset=%0h",offset)}; + s = {s," map=",(map==null?"null":map.get_full_name())," path=",path.name()}; + s = {s," status=",status.name()}; + return s; + endfunction + virtual function void do_copy(uvm_object rhs); + uvm_reg_item rhs_; + if (rhs == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"REG/NULL")) + uvm_report_fatal ("REG/NULL", "do_copy: rhs argument is null", UVM_NONE, "t/uvm/src/reg/uvm_reg_item.svh", 215, "", 1); + end + if (!$cast(rhs_,rhs)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"WRONG_TYPE")) + uvm_report_error ("WRONG_TYPE", "Provided rhs is not of type uvm_reg_item", UVM_NONE, "t/uvm/src/reg/uvm_reg_item.svh", 218, "", 1); + end + return; + end + super.do_copy(rhs); + element_kind = rhs_.element_kind; + element = rhs_.element; + kind = rhs_.kind; + value = rhs_.value; + offset = rhs_.offset; + status = rhs_.status; + local_map = rhs_.local_map; + map = rhs_.map; + path = rhs_.path; + extension = rhs_.extension; + bd_kind = rhs_.bd_kind; + parent = rhs_.parent; + prior = rhs_.prior; + fname = rhs_.fname; + lineno = rhs_.lineno; + endfunction +endclass +typedef struct { + uvm_access_e kind; + uvm_reg_addr_t addr; + uvm_reg_data_t data; + int n_bits; + uvm_reg_byte_en_t byte_en; + uvm_status_e status; +} uvm_reg_bus_op; +virtual class uvm_reg_adapter extends uvm_object; + typedef uvm_abstract_object_registry#(uvm_reg_adapter,"uvm_reg_adapter") type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_reg_adapter"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_reg_adapter"; + endfunction : get_type_name + function new(string name=""); + super.new(name); + endfunction + bit supports_byte_enable; + bit provides_responses; + uvm_sequence_base parent_sequence; + pure virtual function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw); + pure virtual function void bus2reg(uvm_sequence_item bus_item, + ref uvm_reg_bus_op rw); + local uvm_reg_item m_item; + virtual function uvm_reg_item get_item(); + return m_item; + endfunction + virtual function void m_set_item(uvm_reg_item item); + m_item = item; + endfunction +endclass +class uvm_reg_tlm_adapter extends uvm_reg_adapter; + typedef uvm_object_registry#(uvm_reg_tlm_adapter,"uvm_reg_tlm_adapter") type_id; + static function uvm_reg_tlm_adapter type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_reg_tlm_adapter tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_reg_tlm_adapter"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_reg_tlm_adapter"; + endfunction : get_type_name + function new(string name = "uvm_reg_tlm_adapter"); + super.new(name); + endfunction + virtual function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw); + uvm_tlm_gp gp = uvm_tlm_gp::type_id_create("tlm_gp",, this.get_full_name()); + int nbytes = (rw.n_bits-1)/8+1; + uvm_reg_addr_t addr=rw.addr; + if (rw.kind == UVM_WRITE) + gp.set_command(UVM_TLM_WRITE_COMMAND); + else + gp.set_command(UVM_TLM_READ_COMMAND); + gp.set_address(addr); + gp.m_byte_enable = new [nbytes]; + gp.m_byte_enable_length = nbytes; + gp.set_streaming_width (nbytes); + gp.m_data = new [gp.get_streaming_width()]; + gp.m_length = nbytes; + for (int i = 0; i < nbytes; i++) begin + gp.m_data[i] = rw.data[i*8+:8]; + gp.m_byte_enable[i] = (i > nbytes) ? 8'h00 : (rw.byte_en[i] ? 8'hFF : 8'h00); + end + return gp; + endfunction + virtual function void bus2reg(uvm_sequence_item bus_item, + ref uvm_reg_bus_op rw); + uvm_tlm_gp gp; + int nbytes; + if (bus_item == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"REG/NULL_ITEM")) + uvm_report_fatal ("REG/NULL_ITEM", "bus2reg: bus_item argument is null", UVM_NONE, "t/uvm/src/reg/uvm_reg_adapter.svh", 232, "", 1); + end + if (!$cast(gp,bus_item)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"WRONG_TYPE")) + uvm_report_error ("WRONG_TYPE", "Provided bus_item is not of type uvm_tlm_gp", UVM_NONE, "t/uvm/src/reg/uvm_reg_adapter.svh", 235, "", 1); + end + return; + end + if (gp.get_command() == UVM_TLM_WRITE_COMMAND) + rw.kind = UVM_WRITE; + else + rw.kind = UVM_READ; + rw.addr = gp.get_address(); + rw.byte_en = 0; + foreach (gp.m_byte_enable[i]) + rw.byte_en[i] = gp.m_byte_enable[i]; + rw.data = 0; + foreach (gp.m_data[i]) + rw.data[i*8+:8] = gp.m_data[i]; + rw.status = (gp.is_response_ok()) ? UVM_IS_OK : UVM_NOT_OK; + endfunction +endclass +class uvm_predict_s; + bit addr[uvm_reg_addr_t]; + uvm_reg_item reg_item; +endclass +class uvm_reg_predictor #(type BUSTYPE=int) extends uvm_component; + typedef uvm_component_registry #(uvm_reg_predictor#(BUSTYPE)) type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + uvm_analysis_imp #(BUSTYPE, uvm_reg_predictor #(BUSTYPE)) bus_in; + uvm_analysis_port #(uvm_reg_item) reg_ap; + uvm_reg_map map; + uvm_reg_adapter adapter; + function new (string name, uvm_component parent); + super.new(name, parent); + bus_in = new("bus_in", this); + reg_ap = new("reg_ap", this); + endfunction + static function string type_name(); + static string m_type_name; + if (m_type_name == "") begin + BUSTYPE t; + t = BUSTYPE::type_id_create("t"); + m_type_name = {"uvm_reg_predictor #(", t.get_type_name(), ")"}; + end + return m_type_name; + endfunction + virtual function string get_type_name(); + return type_name(); + endfunction : get_type_name + virtual function void pre_predict(uvm_reg_item rw); + endfunction + local uvm_predict_s m_pending[uvm_reg]; + virtual function void write(BUSTYPE tr); + uvm_reg rg; + uvm_reg_bus_op rw; + if (adapter == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"REG/WRITE/NULL")) + uvm_report_fatal ("REG/WRITE/NULL", "write: adapter handle is null", UVM_NONE, "t/uvm/src/reg/uvm_reg_predictor.svh", 168, "", 1); + end + rw.byte_en = -1; + adapter.bus2reg(tr,rw); + rg = map.get_reg_by_offset(rw.addr, (rw.kind == UVM_READ)); + if (rg != null) begin + bit found; + uvm_reg_item reg_item; + uvm_reg_map local_map; + uvm_reg_map_info map_info; + uvm_predict_s predict_info; + uvm_reg_indirect_data ireg; + uvm_reg ir; + if (!m_pending.exists(rg)) begin + uvm_reg_item item = new; + predict_info =new; + item.element_kind = UVM_REG; + item.element = rg; + item.path = UVM_PREDICT; + item.map = map; + item.kind = rw.kind; + predict_info.reg_item = item; + m_pending[rg] = predict_info; + end + predict_info = m_pending[rg]; + reg_item = predict_info.reg_item; + if (predict_info.addr.exists(rw.addr)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"REG_PREDICT_COLLISION")) + uvm_report_error ("REG_PREDICT_COLLISION", {"Collision detected for register '", rg.get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_predictor.svh", 202, "", 1); + end + m_pending.delete(rg); + end + local_map = rg.get_local_map(map); + map_info = local_map.get_reg_map_info(rg); + ir=($cast(ireg, rg))?ireg.get_indirect_reg():rg; + foreach (map_info.addr[i]) begin + if (rw.addr == map_info.addr[i]) begin + found = 1; + reg_item.value[0] |= rw.data << (i * map.get_n_bytes()*8); + predict_info.addr[rw.addr] = 1; + if (predict_info.addr.num() == map_info.addr.size()) begin + uvm_predict_e predict_kind = + (reg_item.kind == UVM_WRITE) ? UVM_PREDICT_WRITE : UVM_PREDICT_READ; + if (reg_item.kind == UVM_READ && + local_map.get_check_on_read() && + reg_item.status != UVM_NOT_OK) begin + void'(rg.do_check(ir.get_mirrored_value(), reg_item.value[0], local_map)); + end + pre_predict(reg_item); + ir.XsampleX(reg_item.value[0], rw.byte_en, + reg_item.kind == UVM_READ, local_map); + begin + uvm_reg_block blk = rg.get_parent(); + blk.XsampleX(map_info.offset, + reg_item.kind == UVM_READ, + local_map); + end + rg.do_predict(reg_item, predict_kind, rw.byte_en); + if(reg_item.kind == UVM_WRITE) + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"REG_PREDICT")) + uvm_report_info ("REG_PREDICT", {"Observed WRITE transaction to register ", ir.get_full_name(), ": value='h", $sformatf("%0h",reg_item.value[0]), " : updated value = 'h", $sformatf("%0h",ir.get())}, UVM_HIGH, "t/uvm/src/reg/uvm_reg_predictor.svh", 243, "", 1); + end + else + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"REG_PREDICT")) + uvm_report_info ("REG_PREDICT", {"Observed READ transaction to register ", ir.get_full_name(), ": value='h", $sformatf("%0h",reg_item.value[0])}, UVM_HIGH, "t/uvm/src/reg/uvm_reg_predictor.svh", 247, "", 1); + end + reg_ap.write(reg_item); + m_pending.delete(rg); + end + break; + end + end + if (!found) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"REG_PREDICT_INTERNAL")) + uvm_report_error ("REG_PREDICT_INTERNAL", {"Unexpected failed address lookup for register '", rg.get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_predictor.svh", 256, "", 1); + end + end + else begin + begin + if (uvm_report_enabled(UVM_FULL,UVM_INFO,"REG_PREDICT_NOT_FOR_ME")) + uvm_report_info ("REG_PREDICT_NOT_FOR_ME", {"Observed transaction does not target a register: ", $sformatf("%p",tr)}, UVM_FULL, "t/uvm/src/reg/uvm_reg_predictor.svh", 261, "", 1); + end + end + endfunction + virtual function void check_phase(uvm_phase phase); + string q[$]; + super.check_phase(phase); + foreach (m_pending[l]) begin + uvm_reg rg=l; + q.push_back($sformatf("\n%s",rg.get_full_name())); + end + if (m_pending.num() > 0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"PENDING REG ITEMS")) + uvm_report_error ("PENDING REG ITEMS", $sformatf("There are %0d incomplete register transactions still pending completion:%s",m_pending.num(),uvm_pkg::m_uvm_string_queue_join(q)), UVM_NONE, "t/uvm/src/reg/uvm_reg_predictor.svh", 282, "", 1); + end + end + endfunction +endclass +class uvm_reg_sequence #(type BASE=uvm_sequence #(uvm_reg_item)) extends BASE; + typedef uvm_object_registry #(uvm_reg_sequence #(BASE)) type_id; + static function uvm_reg_sequence #(BASE) type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_reg_sequence #(BASE) tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + uvm_reg_block model; + uvm_reg_adapter adapter; + uvm_sequencer #(uvm_reg_item) reg_seqr; + function new (string name="uvm_reg_sequence_inst"); + super.new(name); + endfunction + virtual task body(); + if (m_sequencer == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"NO_SEQR")) + uvm_report_fatal ("NO_SEQR", {"Sequence executing as translation sequence, ", "but is not associated with a sequencer (m_sequencer == null)"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_sequence.svh", 127, "", 1); + end + end + if (reg_seqr == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"REG_XLATE_NO_SEQR")) + uvm_report_warning ("REG_XLATE_NO_SEQR", {"Executing RegModel translation sequence on sequencer ", m_sequencer.get_full_name(),"' does not have an upstream sequencer defined. ", "Execution of register items available only via direct calls to 'do_reg_item'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_sequence.svh", 133, "", 1); + end + wait(0); + end + begin + if (uvm_report_enabled(UVM_LOW,UVM_INFO,"REG_XLATE_SEQ_START")) + uvm_report_info ("REG_XLATE_SEQ_START", {"Starting RegModel translation sequence on sequencer ", m_sequencer.get_full_name(),"'"}, UVM_LOW, "t/uvm/src/reg/uvm_reg_sequence.svh", 138, "", 1); + end + forever begin + uvm_reg_item reg_item; + reg_seqr.peek(reg_item); + do_reg_item(reg_item); + reg_seqr.get(reg_item); + #0; + end + endtask + typedef enum { LOCAL, UPSTREAM } seq_parent_e; + seq_parent_e parent_select = LOCAL; + uvm_sequence_base upstream_parent; + virtual task do_reg_item(uvm_reg_item rw); + string rws=rw.convert2string(); + if (m_sequencer == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"REG/DO_ITEM/NULL")) + uvm_report_fatal ("REG/DO_ITEM/NULL", "do_reg_item: m_sequencer is null", UVM_NONE, "t/uvm/src/reg/uvm_reg_sequence.svh", 161, "", 1); + end + if (adapter == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"REG/DO_ITEM/NULL")) + uvm_report_fatal ("REG/DO_ITEM/NULL", "do_reg_item: adapter handle is null", UVM_NONE, "t/uvm/src/reg/uvm_reg_sequence.svh", 163, "", 1); + end + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"DO_RW_ACCESS")) + uvm_report_info ("DO_RW_ACCESS", {"Doing transaction: ",rws}, UVM_HIGH, "t/uvm/src/reg/uvm_reg_sequence.svh", 165, "", 1); + end + if (parent_select == LOCAL) begin + upstream_parent = rw.parent; + rw.parent = this; + end + if (rw.kind == UVM_WRITE) + rw.local_map.do_bus_write(rw, m_sequencer, adapter); + else + rw.local_map.do_bus_read(rw, m_sequencer, adapter); + if (parent_select == LOCAL) + rw.parent = upstream_parent; + endtask + virtual task write_reg(input uvm_reg rg, + output uvm_status_e status, + input uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + if (rg == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"NO_REG")) + uvm_report_error ("NO_REG", "Register argument is null", UVM_NONE, "t/uvm/src/reg/uvm_reg_sequence.svh", 211, "", 1); + end + else + rg.write(status,value,path,map,this,prior,extension,fname,lineno); + endtask + virtual task read_reg(input uvm_reg rg, + output uvm_status_e status, + output uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + if (rg == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"NO_REG")) + uvm_report_error ("NO_REG", "Register argument is null", UVM_NONE, "t/uvm/src/reg/uvm_reg_sequence.svh", 229, "", 1); + end + else + rg.read(status,value,path,map,this,prior,extension,fname,lineno); + endtask + virtual task poke_reg(input uvm_reg rg, + output uvm_status_e status, + input uvm_reg_data_t value, + input string kind = "", + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + if (rg == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"NO_REG")) + uvm_report_error ("NO_REG", "Register argument is null", UVM_NONE, "t/uvm/src/reg/uvm_reg_sequence.svh", 246, "", 1); + end + else + rg.poke(status,value,kind,this,extension,fname,lineno); + endtask + virtual task peek_reg(input uvm_reg rg, + output uvm_status_e status, + output uvm_reg_data_t value, + input string kind = "", + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + if (rg == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"NO_REG")) + uvm_report_error ("NO_REG", "Register argument is null", UVM_NONE, "t/uvm/src/reg/uvm_reg_sequence.svh", 263, "", 1); + end + else + rg.peek(status,value,kind,this,extension,fname,lineno); + endtask + virtual task update_reg(input uvm_reg rg, + output uvm_status_e status, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + if (rg == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"NO_REG")) + uvm_report_error ("NO_REG", "Register argument is null", UVM_NONE, "t/uvm/src/reg/uvm_reg_sequence.svh", 281, "", 1); + end + else + rg.update(status,path,map,this,prior,extension,fname,lineno); + endtask + virtual task mirror_reg(input uvm_reg rg, + output uvm_status_e status, + input uvm_check_e check = UVM_NO_CHECK, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + if (rg == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"NO_REG")) + uvm_report_error ("NO_REG", "Register argument is null", UVM_NONE, "t/uvm/src/reg/uvm_reg_sequence.svh", 300, "", 1); + end + else + rg.mirror(status,check,path,map,this,prior,extension,fname,lineno); + endtask + virtual task write_mem(input uvm_mem mem, + output uvm_status_e status, + input uvm_reg_addr_t offset, + input uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + if (mem == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"NO_MEM")) + uvm_report_error ("NO_MEM", "Memory argument is null", UVM_NONE, "t/uvm/src/reg/uvm_reg_sequence.svh", 320, "", 1); + end + else + mem.write(status,offset,value,path,map,this,prior,extension,fname,lineno); + endtask + virtual task read_mem(input uvm_mem mem, + output uvm_status_e status, + input uvm_reg_addr_t offset, + output uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + if (mem == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"NO_MEM")) + uvm_report_error ("NO_MEM", "Memory argument is null", UVM_NONE, "t/uvm/src/reg/uvm_reg_sequence.svh", 339, "", 1); + end + else + mem.read(status,offset,value,path,map,this,prior,extension,fname,lineno); + endtask + virtual task poke_mem(input uvm_mem mem, + output uvm_status_e status, + input uvm_reg_addr_t offset, + input uvm_reg_data_t value, + input string kind = "", + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + if (mem == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"NO_MEM")) + uvm_report_error ("NO_MEM", "Memory argument is null", UVM_NONE, "t/uvm/src/reg/uvm_reg_sequence.svh", 357, "", 1); + end + else + mem.poke(status,offset,value,kind,this,extension,fname,lineno); + endtask + virtual task peek_mem(input uvm_mem mem, + output uvm_status_e status, + input uvm_reg_addr_t offset, + output uvm_reg_data_t value, + input string kind = "", + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + if (mem == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"NO_MEM")) + uvm_report_error ("NO_MEM", "Memory argument is null", UVM_NONE, "t/uvm/src/reg/uvm_reg_sequence.svh", 375, "", 1); + end + else + mem.peek(status,offset,value,kind,this,extension,fname,lineno); + endtask + virtual function void put_response(uvm_sequence_item response_item); + put_base_response(response_item); + endfunction +endclass +virtual class uvm_reg_frontdoor extends uvm_reg_sequence #(uvm_sequence #(uvm_sequence_item)); + typedef uvm_abstract_object_registry#(uvm_reg_frontdoor,"uvm_reg_frontdoor") type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_reg_frontdoor"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_reg_frontdoor"; + endfunction : get_type_name + uvm_reg_item rw_info; + uvm_sequencer_base sequencer; + function new(string name=""); + super.new(name); + endfunction + string fname; + int lineno; +endclass: uvm_reg_frontdoor +typedef class uvm_reg; +typedef class uvm_mem; +typedef class uvm_reg_backdoor; +class uvm_reg_cbs extends uvm_callback; + typedef uvm_object_registry#(uvm_reg_cbs,"uvm_reg_cbs") type_id; + static function uvm_reg_cbs type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_reg_cbs tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_reg_cbs"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_reg_cbs"; + endfunction : get_type_name + function new(string name = "uvm_reg_cbs"); + super.new(name); + endfunction + virtual task pre_write(uvm_reg_item rw); endtask + virtual task post_write(uvm_reg_item rw); endtask + virtual task pre_read(uvm_reg_item rw); endtask + virtual task post_read(uvm_reg_item rw); endtask + virtual function void post_predict(input uvm_reg_field fld, + input uvm_reg_data_t previous, + inout uvm_reg_data_t value, + input uvm_predict_e kind, + input uvm_door_e path, + input uvm_reg_map map); + endfunction + virtual function void encode(ref uvm_reg_data_t data[]); + endfunction + virtual function void decode(ref uvm_reg_data_t data[]); + endfunction +endclass +typedef uvm_callbacks#(uvm_reg, uvm_reg_cbs) uvm_reg_cb ; +typedef uvm_callback_iter#(uvm_reg, uvm_reg_cbs) uvm_reg_cb_iter ; +typedef uvm_callbacks#(uvm_reg_backdoor, uvm_reg_cbs) uvm_reg_bd_cb ; +typedef uvm_callback_iter#(uvm_reg_backdoor, uvm_reg_cbs) uvm_reg_bd_cb_iter ; +typedef uvm_callbacks#(uvm_mem, uvm_reg_cbs) uvm_mem_cb ; +typedef uvm_callback_iter#(uvm_mem, uvm_reg_cbs) uvm_mem_cb_iter ; +typedef uvm_callbacks#(uvm_reg_field, uvm_reg_cbs) uvm_reg_field_cb ; +typedef uvm_callback_iter#(uvm_reg_field, uvm_reg_cbs) uvm_reg_field_cb_iter ; +class uvm_reg_read_only_cbs extends uvm_reg_cbs; + function new(string name = "uvm_reg_read_only_cbs"); + super.new(name); + endfunction + typedef uvm_object_registry#(uvm_reg_read_only_cbs,"uvm_reg_read_only_cbs") type_id; + static function uvm_reg_read_only_cbs type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_reg_read_only_cbs tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_reg_read_only_cbs"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_reg_read_only_cbs"; + endfunction : get_type_name + virtual task pre_write(uvm_reg_item rw); + string name = rw.element.get_full_name(); + if (rw.status != UVM_IS_OK) + return; + if (rw.element_kind == UVM_FIELD) begin + uvm_reg_field fld; + uvm_reg rg; + $cast(fld, rw.element); + rg = fld.get_parent(); + name = rg.get_full_name(); + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/REG/READONLY")) + uvm_report_error ("UVM/REG/READONLY", {name, " is read-only. Cannot call write() method."}, UVM_NONE, "t/uvm/src/reg/uvm_reg_cbs.svh", 232, "", 1); + end + rw.status = UVM_NOT_OK; + endtask + local static uvm_reg_read_only_cbs m_me; + local static function uvm_reg_read_only_cbs get(); + if (m_me == null) m_me = new; + return m_me; + endfunction + static function void add(uvm_reg rg); + uvm_reg_field flds[$]; + uvm_reg_cb::add(rg, get()); + rg.get_fields(flds); + foreach (flds[i]) begin + uvm_reg_field_cb::add(flds[i], get()); + end + endfunction + static function void remove(uvm_reg rg); + uvm_reg_cb_iter cbs = new(rg); + uvm_reg_field flds[$]; + void'(cbs.first()); + while (cbs.get_cb() != get()) begin + if (cbs.get_cb() == null) + return; + void'(cbs.next()); + end + uvm_reg_cb::delete(rg, get()); + rg.get_fields(flds); + foreach (flds[i]) begin + uvm_reg_field_cb::delete(flds[i], get()); + end + endfunction +endclass +class uvm_reg_write_only_cbs extends uvm_reg_cbs; + function new(string name = "uvm_reg_write_only_cbs"); + super.new(name); + endfunction + typedef uvm_object_registry#(uvm_reg_write_only_cbs,"uvm_reg_write_only_cbs") type_id; + static function uvm_reg_write_only_cbs type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_reg_write_only_cbs tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_reg_write_only_cbs"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_reg_write_only_cbs"; + endfunction : get_type_name + virtual task pre_read(uvm_reg_item rw); + string name = rw.element.get_full_name(); + if (rw.status != UVM_IS_OK) + return; + if (rw.element_kind == UVM_FIELD) begin + uvm_reg_field fld; + uvm_reg rg; + $cast(fld, rw.element); + rg = fld.get_parent(); + name = rg.get_full_name(); + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/REG/WRTEONLY")) + uvm_report_error ("UVM/REG/WRTEONLY", {name, " is write-only. Cannot call read() method."}, UVM_NONE, "t/uvm/src/reg/uvm_reg_cbs.svh", 316, "", 1); + end + rw.status = UVM_NOT_OK; + endtask + local static uvm_reg_write_only_cbs m_me; + local static function uvm_reg_write_only_cbs get(); + if (m_me == null) m_me = new; + return m_me; + endfunction + static function void add(uvm_reg rg); + uvm_reg_field flds[$]; + uvm_reg_cb::add(rg, get()); + rg.get_fields(flds); + foreach (flds[i]) begin + uvm_reg_field_cb::add(flds[i], get()); + end + endfunction + static function void remove(uvm_reg rg); + uvm_reg_cb_iter cbs = new(rg); + uvm_reg_field flds[$]; + void'(cbs.first()); + while (cbs.get_cb() != get()) begin + if (cbs.get_cb() == null) + return; + void'(cbs.next()); + end + uvm_reg_cb::delete(rg, get()); + rg.get_fields(flds); + foreach (flds[i]) begin + uvm_reg_field_cb::delete(flds[i], get()); + end + endfunction +endclass +typedef class uvm_reg_cbs; +virtual class uvm_reg_backdoor extends uvm_object; + typedef uvm_abstract_object_registry#(uvm_reg_backdoor,"uvm_reg_backdoor") type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_reg_backdoor"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_reg_backdoor"; + endfunction : get_type_name + function new(string name = ""); + super.new(name); + endfunction: new + protected task do_pre_read(uvm_reg_item rw); + pre_read(rw); + begin + uvm_callback_iter#(uvm_reg_backdoor,uvm_reg_cbs) iter = new(this); + uvm_reg_cbs cb = iter.first(); + while(cb != null) begin + cb.pre_read(rw); + cb = iter.next(); + end + end + endtask + protected task do_post_read(uvm_reg_item rw); + uvm_callback_iter#(uvm_reg_backdoor, uvm_reg_cbs) iter = new(this); + for(uvm_reg_cbs cb = iter.last(); cb != null; cb=iter.prev()) + cb.decode(rw.value); + begin + uvm_callback_iter#(uvm_reg_backdoor,uvm_reg_cbs) iter = new(this); + uvm_reg_cbs cb = iter.first(); + while(cb != null) begin + cb.post_read(rw); + cb = iter.next(); + end + end + post_read(rw); + endtask + protected task do_pre_write(uvm_reg_item rw); + uvm_callback_iter#(uvm_reg_backdoor, uvm_reg_cbs) iter = new(this); + pre_write(rw); + begin + uvm_callback_iter#(uvm_reg_backdoor,uvm_reg_cbs) iter = new(this); + uvm_reg_cbs cb = iter.first(); + while(cb != null) begin + cb.pre_write(rw); + cb = iter.next(); + end + end + for(uvm_reg_cbs cb = iter.first(); cb != null; cb = iter.next()) + cb.encode(rw.value); + endtask + protected task do_post_write(uvm_reg_item rw); + begin + uvm_callback_iter#(uvm_reg_backdoor,uvm_reg_cbs) iter = new(this); + uvm_reg_cbs cb = iter.first(); + while(cb != null) begin + cb.post_write(rw); + cb = iter.next(); + end + end + post_write(rw); + endtask + extern virtual task write(uvm_reg_item rw); + extern virtual task read(uvm_reg_item rw); + extern virtual function void read_func(uvm_reg_item rw); + extern virtual function bit is_auto_updated(uvm_reg_field field); + extern virtual local task wait_for_change(uvm_object element); + extern function void start_update_thread(uvm_object element); + extern function void kill_update_thread(uvm_object element); + extern function bit has_update_threads(); + virtual task pre_read(uvm_reg_item rw); endtask + virtual task post_read(uvm_reg_item rw); endtask + virtual task pre_write(uvm_reg_item rw); endtask + virtual task post_write(uvm_reg_item rw); endtask + string fname; + int lineno; + local process m_update_thread[uvm_object]; + static local bit m_register_cb_uvm_reg_cbs = uvm_callbacks#(uvm_reg_backdoor,uvm_reg_cbs)::m_register_pair("uvm_reg_backdoor","uvm_reg_cbs"); +endclass: uvm_reg_backdoor +function bit uvm_reg_backdoor::is_auto_updated(uvm_reg_field field); + return 0; +endfunction +task uvm_reg_backdoor::wait_for_change(uvm_object element); + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"RegModel")) + uvm_report_fatal ("RegModel", "uvm_reg_backdoor::wait_for_change() method has not been overloaded", UVM_NONE, "t/uvm/src/reg/uvm_reg_backdoor.svh", 171, "", 1); + end +endtask +function void uvm_reg_backdoor::start_update_thread(uvm_object element); + uvm_reg rg; + if (this.m_update_thread.exists(element)) begin + this.kill_update_thread(element); + end + if (!$cast(rg,element)) + return; + fork + begin + uvm_reg_field fields[$]; + this.m_update_thread[element] = process::self(); + rg.get_fields(fields); + forever begin + uvm_status_e status; + uvm_reg_data_t val; + uvm_reg_item r_item = new("bd_r_item"); + r_item.element = rg; + r_item.element_kind = UVM_REG; + this.read(r_item); + val = r_item.value[0]; + if (r_item.status != UVM_IS_OK) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Backdoor read of register '%s' failed.", rg.get_name()), UVM_NONE, "t/uvm/src/reg/uvm_reg_backdoor.svh", 206, "", 1); + end + end + foreach (fields[i]) begin + if (this.is_auto_updated(fields[i])) begin + r_item.value[0] = (val >> fields[i].get_lsb_pos()) & + ((1 << fields[i].get_n_bits())-1); + fields[i].do_predict(r_item); + end + end + this.wait_for_change(element); + end + end + join_none +endfunction +function void uvm_reg_backdoor::kill_update_thread(uvm_object element); + if (this.m_update_thread.exists(element)) begin + this.m_update_thread[element].kill(); + this.m_update_thread.delete(element); + end +endfunction +function bit uvm_reg_backdoor::has_update_threads(); + return this.m_update_thread.num() > 0; +endfunction +task uvm_reg_backdoor::write(uvm_reg_item rw); + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"RegModel")) + uvm_report_fatal ("RegModel", "uvm_reg_backdoor::write() method has not been overloaded", UVM_NONE, "t/uvm/src/reg/uvm_reg_backdoor.svh", 248, "", 1); + end +endtask +task uvm_reg_backdoor::read(uvm_reg_item rw); + do_pre_read(rw); + read_func(rw); + do_post_read(rw); +endtask +function void uvm_reg_backdoor::read_func(uvm_reg_item rw); + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"RegModel")) + uvm_report_fatal ("RegModel", "uvm_reg_backdoor::read_func() method has not been overloaded", UVM_NONE, "t/uvm/src/reg/uvm_reg_backdoor.svh", 264, "", 1); + end + rw.status = UVM_NOT_OK; +endfunction +typedef class uvm_reg_cbs; +class uvm_reg_field extends uvm_object; + rand uvm_reg_data_t value; + local uvm_reg_data_t m_mirrored; + local uvm_reg_data_t m_desired; + local string m_access; + local uvm_reg m_parent; + local int unsigned m_lsb; + local int unsigned m_size; + local bit m_volatile; + local uvm_reg_data_t m_reset[string]; + local bit m_written; + local bit m_read_in_progress; + local bit m_write_in_progress; + local string m_fname; + local int m_lineno; + local int m_cover_on; + local bit m_individually_accessible; + local uvm_check_e m_check; + local static int m_max_size; + local static bit m_policy_names[string]; + constraint uvm_reg_field_valid { + if (64 > m_size) { + value < (64'h1 << m_size); + } + } + typedef uvm_object_registry#(uvm_reg_field,"uvm_reg_field") type_id; + static function uvm_reg_field type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_reg_field tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_reg_field"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_reg_field"; + endfunction : get_type_name + extern function new(string name = "uvm_reg_field"); + extern function void configure(uvm_reg parent, + int unsigned size, + int unsigned lsb_pos, + string access, + bit volatile, + uvm_reg_data_t reset, + bit has_reset, + bit is_rand, + bit individually_accessible); + extern virtual function string get_full_name(); + extern virtual function uvm_reg get_parent(); + extern virtual function uvm_reg get_register(); + extern virtual function int unsigned get_lsb_pos(); + extern virtual function int unsigned get_n_bits(); + extern static function int unsigned get_max_size(); + extern virtual function string set_access(string mode); + extern static function bit define_access(string name); + local static bit m_predefined = m_predefine_policies(); + extern local static function bit m_predefine_policies(); + extern virtual function string get_access(uvm_reg_map map = null); + extern virtual function bit is_known_access(uvm_reg_map map = null); + extern virtual function void set_volatility(bit volatile); + extern virtual function bit is_volatile(); + extern virtual function void set(uvm_reg_data_t value, + string fname = "", + int lineno = 0); + extern virtual function uvm_reg_data_t get(string fname = "", + int lineno = 0); + extern virtual function uvm_reg_data_t get_mirrored_value(string fname = "", + int lineno = 0); + extern virtual function void reset(string kind = "HARD"); + extern virtual function uvm_reg_data_t get_reset(string kind = "HARD"); + extern virtual function bit has_reset(string kind = "HARD", + bit delete = 0); + extern virtual function void set_reset(uvm_reg_data_t value, + string kind = "HARD"); + extern virtual function bit needs_update(); + extern virtual task write (output uvm_status_e status, + input uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + extern virtual task read (output uvm_status_e status, + output uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + extern virtual task poke (output uvm_status_e status, + input uvm_reg_data_t value, + input string kind = "", + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + extern virtual task peek (output uvm_status_e status, + output uvm_reg_data_t value, + input string kind = "", + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + extern virtual task mirror(output uvm_status_e status, + input uvm_check_e check = UVM_NO_CHECK, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + extern function void set_compare(uvm_check_e check=UVM_CHECK); + extern function uvm_check_e get_compare(); + extern function bit is_indv_accessible (uvm_door_e path, + uvm_reg_map local_map); + extern function bit predict (uvm_reg_data_t value, + uvm_reg_byte_en_t be = -1, + uvm_predict_e kind = UVM_PREDICT_DIRECT, + uvm_door_e path = UVM_FRONTDOOR, + uvm_reg_map map = null, + string fname = "", + int lineno = 0); + extern virtual function uvm_reg_data_t XpredictX (uvm_reg_data_t cur_val, + uvm_reg_data_t wr_val, + uvm_reg_map map); + extern virtual function uvm_reg_data_t XupdateX(); + extern function bit Xcheck_accessX (input uvm_reg_item rw, + output uvm_reg_map_info map_info); + extern virtual task do_write(uvm_reg_item rw); + extern virtual task do_read(uvm_reg_item rw); + extern virtual function void do_predict + (uvm_reg_item rw, + uvm_predict_e kind=UVM_PREDICT_DIRECT, + uvm_reg_byte_en_t be = -1); + extern function void pre_randomize(); + extern function void post_randomize(); + static local bit m_register_cb_uvm_reg_cbs = uvm_callbacks#(uvm_reg_field,uvm_reg_cbs)::m_register_pair("uvm_reg_field","uvm_reg_cbs"); + virtual task pre_write (uvm_reg_item rw); endtask + virtual task post_write (uvm_reg_item rw); endtask + virtual task pre_read (uvm_reg_item rw); endtask + virtual task post_read (uvm_reg_item rw); endtask + extern virtual function void do_print (uvm_printer printer); + extern virtual function string convert2string; + extern virtual function uvm_object clone(); + extern virtual function void do_copy (uvm_object rhs); + extern virtual function bit do_compare (uvm_object rhs, + uvm_comparer comparer); + extern virtual function void do_pack (uvm_packer packer); + extern virtual function void do_unpack (uvm_packer packer); +endclass: uvm_reg_field +function uvm_reg_field::new(string name = "uvm_reg_field"); + super.new(name); +endfunction: new +function void uvm_reg_field::configure(uvm_reg parent, + int unsigned size, + int unsigned lsb_pos, + string access, + bit volatile, + uvm_reg_data_t reset, + bit has_reset, + bit is_rand, + bit individually_accessible); + m_parent = parent; + if (size == 0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Field \"%s\" cannot have 0 bits", get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_reg_field.svh", 416, "", 1); + end + size = 1; + end + m_size = size; + m_volatile = volatile; + m_access = access.toupper(); + m_lsb = lsb_pos; + m_cover_on = UVM_NO_COVERAGE; + m_written = 0; + m_check = volatile ? UVM_NO_CHECK : UVM_CHECK; + m_individually_accessible = individually_accessible; + if (has_reset) + set_reset(reset); + m_parent.add_field(this); + if (!m_policy_names.exists(m_access)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Access policy '",access, "' for field '",get_full_name(),"' is not defined. Setting to RW"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_field.svh", 436, "", 1); + end + m_access = "RW"; + end + if (size > m_max_size) + m_max_size = size; + case (access) + "RO", "RC", "RS", "WC", "WS", + "W1C", "W1S", "W1T", "W0C", "W0S", "W0T", + "W1SRC", "W1CRS", "W0SRC", "W0CRS", "WSRC", "WCRS", + "WOC", "WOS": is_rand = 0; + endcase + if (!is_rand) + value.rand_mode(0); +endfunction: configure +function uvm_reg uvm_reg_field::get_parent(); + return m_parent; +endfunction: get_parent +function string uvm_reg_field::get_full_name(); + return {m_parent.get_full_name(), ".", get_name()}; +endfunction: get_full_name +function uvm_reg uvm_reg_field::get_register(); + return m_parent; +endfunction: get_register +function int unsigned uvm_reg_field::get_lsb_pos(); + return m_lsb; +endfunction: get_lsb_pos +function int unsigned uvm_reg_field::get_n_bits(); + return m_size; +endfunction: get_n_bits +function int unsigned uvm_reg_field::get_max_size(); + return m_max_size; +endfunction: get_max_size +function bit uvm_reg_field::is_known_access(uvm_reg_map map = null); + string acc = get_access(map); + case (acc) + "RO", "RW", "RC", "RS", "WC", "WS", + "W1C", "W1S", "W1T", "W0C", "W0S", "W0T", + "WRC", "WRS", "W1SRC", "W1CRS", "W0SRC", "W0CRS", "WSRC", "WCRS", + "WO", "WOC", "WOS", "W1", "WO1" : return 1; + endcase + return 0; +endfunction +function string uvm_reg_field::get_access(uvm_reg_map map = null); + string field_access = m_access; + if (map == uvm_reg_map::backdoor()) + return field_access; + case (m_parent.get_rights(map)) + "RW": + return field_access; + "RO": + case (field_access) + "RW", "RO", "WC", "WS", + "W1C", "W1S", "W1T", "W0C", "W0S", "W0T", + "W1" + : field_access = "RO"; + "RC", "WRC", "W1SRC", "W0SRC", "WSRC" + : field_access = "RC"; + "RS", "WRS", "W1CRS", "W0CRS", "WCRS" + : field_access = "RS"; + "WO", "WOC", "WOS", "WO1": begin + field_access = "NOACCESS"; + end + endcase + "WO": + case (field_access) + "RW","WRC","WRS" : field_access = "WO"; + "W1SRC" : field_access = "W1S"; + "W0SRC": field_access = "W0S"; + "W1CRS": field_access = "W1C"; + "W0CRS": field_access = "W0C"; + "WCRS": field_access = "WC"; + "W1" : field_access = "W1"; + "WO1" : field_access = "WO1"; + "WSRC" : field_access = "WS"; + "RO","RC","RS": field_access = "NOACCESS"; + endcase + default: + begin + field_access = "NOACCESS"; + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Register '",m_parent.get_full_name(), "' containing field '",get_name(),"' is mapped in map '", map.get_full_name(),"' with unknown access right '", m_parent.get_rights(map), "'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_field.svh", 570, "", 1); + end + end + endcase + return field_access; +endfunction: get_access +function string uvm_reg_field::set_access(string mode); + set_access = m_access; + m_access = mode.toupper(); + if (!m_policy_names.exists(m_access)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Access policy '",m_access, "' is not a defined field access policy"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_field.svh", 584, "", 1); + end + m_access = set_access; + end +endfunction: set_access +function bit uvm_reg_field::define_access(string name); + if (!m_predefined) m_predefined = m_predefine_policies(); + name = name.toupper(); + if (m_policy_names.exists(name)) return 0; + m_policy_names[name] = 1; + return 1; +endfunction +function bit uvm_reg_field::m_predefine_policies(); + if (m_predefined) return 1; + m_predefined = 1; + void'(define_access("RO")); + void'(define_access("RW")); + void'(define_access("RC")); + void'(define_access("RS")); + void'(define_access("WRC")); + void'(define_access("WRS")); + void'(define_access("WC")); + void'(define_access("WS")); + void'(define_access("WSRC")); + void'(define_access("WCRS")); + void'(define_access("W1C")); + void'(define_access("W1S")); + void'(define_access("W1T")); + void'(define_access("W0C")); + void'(define_access("W0S")); + void'(define_access("W0T")); + void'(define_access("W1SRC")); + void'(define_access("W1CRS")); + void'(define_access("W0SRC")); + void'(define_access("W0CRS")); + void'(define_access("WO")); + void'(define_access("WOC")); + void'(define_access("WOS")); + void'(define_access("W1")); + void'(define_access("WO1")); + return 1; +endfunction +function void uvm_reg_field::set_volatility(bit volatile); + m_volatile = volatile; +endfunction +function bit uvm_reg_field::is_volatile(); + return m_volatile; +endfunction +function uvm_reg_data_t uvm_reg_field::XpredictX (uvm_reg_data_t cur_val, + uvm_reg_data_t wr_val, + uvm_reg_map map); + uvm_reg_data_t mask = ('b1 << m_size)-1; + case (get_access(map)) + "RO": return cur_val; + "RW": return wr_val; + "RC": return cur_val; + "RS": return cur_val; + "WC": return '0; + "WS": return mask; + "WRC": return wr_val; + "WRS": return wr_val; + "WSRC": return mask; + "WCRS": return '0; + "W1C": return cur_val & (~wr_val); + "W1S": return cur_val | wr_val; + "W1T": return cur_val ^ wr_val; + "W0C": return cur_val & wr_val; + "W0S": return cur_val | (~wr_val & mask); + "W0T": return cur_val ^ (~wr_val & mask); + "W1SRC": return cur_val | wr_val; + "W1CRS": return cur_val & (~wr_val); + "W0SRC": return cur_val | (~wr_val & mask); + "W0CRS": return cur_val & wr_val; + "WO": return wr_val; + "WOC": return '0; + "WOS": return mask; + "W1": return (m_written) ? cur_val : wr_val; + "WO1": return (m_written) ? cur_val : wr_val; + "NOACCESS": return cur_val; + default: return wr_val; + endcase + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"RegModel")) + uvm_report_fatal ("RegModel", "uvm_reg_field::XpredictX(): Internal error", UVM_NONE, "t/uvm/src/reg/uvm_reg_field.svh", 691, "", 1); + end + return 0; +endfunction: XpredictX +function bit uvm_reg_field::predict (uvm_reg_data_t value, + uvm_reg_byte_en_t be = -1, + uvm_predict_e kind = UVM_PREDICT_DIRECT, + uvm_door_e path = UVM_FRONTDOOR, + uvm_reg_map map = null, + string fname = "", + int lineno = 0); + uvm_reg_item rw = new; + rw.value[0] = value; + rw.path = path; + rw.map = map; + rw.fname = fname; + rw.lineno = lineno; + do_predict(rw, kind, be); + predict = (rw.status == UVM_NOT_OK) ? 0 : 1; +endfunction: predict +function void uvm_reg_field::do_predict(uvm_reg_item rw, + uvm_predict_e kind = UVM_PREDICT_DIRECT, + uvm_reg_byte_en_t be = -1); + uvm_reg_data_t field_val = rw.value[0] & ((1 << m_size)-1); + if (rw.status != UVM_NOT_OK) + rw.status = UVM_IS_OK; + if (!be[0]) + return; + m_fname = rw.fname; + m_lineno = rw.lineno; + case (kind) + UVM_PREDICT_WRITE: + begin + uvm_reg_field_cb_iter cbs = new(this); + if (rw.path == UVM_FRONTDOOR || rw.path == UVM_PREDICT) + field_val = XpredictX(m_mirrored, field_val, rw.map); + m_written = 1; + for (uvm_reg_cbs cb = cbs.first(); cb != null; cb = cbs.next()) + cb.post_predict(this, m_mirrored, field_val, + UVM_PREDICT_WRITE, rw.path, rw.map); + field_val &= ('b1 << m_size)-1; + end + UVM_PREDICT_READ: + begin + uvm_reg_field_cb_iter cbs = new(this); + if (rw.path == UVM_FRONTDOOR || rw.path == UVM_PREDICT) begin + string acc = get_access(rw.map); + if (acc == "RC" || + acc == "WRC" || + acc == "WSRC" || + acc == "W1SRC" || + acc == "W0SRC") + field_val = 0; + else if (acc == "RS" || + acc == "WRS" || + acc == "WCRS" || + acc == "W1CRS" || + acc == "W0CRS") + field_val = ('b1 << m_size)-1; + else if (acc == "WO" || + acc == "WOC" || + acc == "WOS" || + acc == "WO1" || + acc == "NOACCESS") + return; + end + for (uvm_reg_cbs cb = cbs.first(); cb != null; cb = cbs.next()) + cb.post_predict(this, m_mirrored, field_val, + UVM_PREDICT_READ, rw.path, rw.map); + field_val &= ('b1 << m_size)-1; + end + UVM_PREDICT_DIRECT: + begin + if (m_parent.is_busy()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Trying to predict value of field '", get_name(),"' while register '",m_parent.get_full_name(), "' is being accessed"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_field.svh", 797, "", 1); + end + rw.status = UVM_NOT_OK; + end + end + endcase + m_mirrored = field_val; + m_desired = field_val; + this.value = field_val; +endfunction: do_predict +function uvm_reg_data_t uvm_reg_field::XupdateX(); + XupdateX = 0; + case (m_access) + "RO": XupdateX = m_desired; + "RW": XupdateX = m_desired; + "RC": XupdateX = m_desired; + "RS": XupdateX = m_desired; + "WRC": XupdateX = m_desired; + "WRS": XupdateX = m_desired; + "WC": XupdateX = m_desired; + "WS": XupdateX = m_desired; + "WSRC": XupdateX = m_desired; + "WCRS": XupdateX = m_desired; + "W1C": XupdateX = ~m_desired; + "W1S": XupdateX = m_desired; + "W1T": XupdateX = m_desired ^ m_mirrored; + "W0C": XupdateX = m_desired; + "W0S": XupdateX = ~m_desired; + "W0T": XupdateX = ~(m_desired ^ m_mirrored); + "W1SRC": XupdateX = m_desired; + "W1CRS": XupdateX = ~m_desired; + "W0SRC": XupdateX = ~m_desired; + "W0CRS": XupdateX = m_desired; + "WO": XupdateX = m_desired; + "WOC": XupdateX = m_desired; + "WOS": XupdateX = m_desired; + "W1": XupdateX = m_desired; + "WO1": XupdateX = m_desired; + default: XupdateX = m_desired; + endcase + XupdateX &= (1 << m_size) - 1; +endfunction: XupdateX +function void uvm_reg_field::set(uvm_reg_data_t value, + string fname = "", + int lineno = 0); + uvm_reg_data_t mask = ('b1 << m_size)-1; + m_fname = fname; + m_lineno = lineno; + if (value >> m_size) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", $sformatf("Specified value (0x%h) greater than field \"%s\" size (%0d bits)", value, get_name(), m_size), UVM_NONE, "t/uvm/src/reg/uvm_reg_field.svh", 863, "", 1); + end + value &= mask; + end + if (m_parent.is_busy()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/FLD/SET/BSY")) + uvm_report_warning ("UVM/FLD/SET/BSY", $sformatf("Setting the value of field \"%s\" while containing register \"%s\" is being accessed may result in loss of desired field value. A race condition between threads concurrently accessing the register model is the likely cause of the problem.", get_name(), m_parent.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_reg_field.svh", 870, "", 1); + end + end + case (m_access) + "RO": m_desired = m_desired; + "RW": m_desired = value; + "RC": m_desired = m_desired; + "RS": m_desired = m_desired; + "WC": m_desired = '0; + "WS": m_desired = mask; + "WRC": m_desired = value; + "WRS": m_desired = value; + "WSRC": m_desired = mask; + "WCRS": m_desired = '0; + "W1C": m_desired = m_desired & (~value); + "W1S": m_desired = m_desired | value; + "W1T": m_desired = m_desired ^ value; + "W0C": m_desired = m_desired & value; + "W0S": m_desired = m_desired | (~value & mask); + "W0T": m_desired = m_desired ^ (~value & mask); + "W1SRC": m_desired = m_desired | value; + "W1CRS": m_desired = m_desired & (~value); + "W0SRC": m_desired = m_desired | (~value & mask); + "W0CRS": m_desired = m_desired & value; + "WO": m_desired = value; + "WOC": m_desired = '0; + "WOS": m_desired = mask; + "W1": m_desired = (m_written) ? m_desired : value; + "WO1": m_desired = (m_written) ? m_desired : value; + default: m_desired = value; + endcase + this.value = m_desired; +endfunction: set +function uvm_reg_data_t uvm_reg_field::get(string fname = "", + int lineno = 0); + m_fname = fname; + m_lineno = lineno; + get = m_desired; +endfunction: get +function uvm_reg_data_t uvm_reg_field::get_mirrored_value(string fname = "", + int lineno = 0); + m_fname = fname; + m_lineno = lineno; + get_mirrored_value = m_mirrored; +endfunction: get_mirrored_value +function void uvm_reg_field::reset(string kind = "HARD"); + if (!m_reset.exists(kind)) + return; + m_mirrored = m_reset[kind]; + m_desired = m_mirrored; + value = m_mirrored; + if (kind == "HARD") + m_written = 0; +endfunction: reset +function bit uvm_reg_field::has_reset(string kind = "HARD", + bit delete = 0); + if (!m_reset.exists(kind)) return 0; + if (delete) m_reset.delete(kind); + return 1; +endfunction: has_reset +function uvm_reg_data_t + uvm_reg_field::get_reset(string kind = "HARD"); + if (!m_reset.exists(kind)) + return m_desired; + return m_reset[kind]; +endfunction: get_reset +function void uvm_reg_field::set_reset(uvm_reg_data_t value, + string kind = "HARD"); + m_reset[kind] = value & ((1<> m_size) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"uvm_reg_field::write(): Value greater than field '", get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_field.svh", 1096, "", 1); + end + rw.value[0] &= ((1<> m_lsb) & ((1<0) begin + prev_lsb = fields[fld_idx-1].get_lsb_pos(); + prev_sz = fields[fld_idx-1].get_n_bits(); + end + if (fld_idx < fields.size()-1) begin + next_lsb = fields[fld_idx+1].get_lsb_pos(); + next_sz = fields[fld_idx+1].get_n_bits(); + end + if (fld_idx == 0 && + ((next_lsb % bus_sz) == 0 || + (next_lsb - this_sz) > (next_lsb % bus_sz))) + return 1; + else if (fld_idx == (fields.size()-1) && + ((this_lsb % bus_sz) == 0 || + (this_lsb - (prev_lsb + prev_sz)) >= (this_lsb % bus_sz))) + return 1; + else begin + if ((this_lsb % bus_sz) == 0) begin + if ((next_lsb % bus_sz) == 0 || + (next_lsb - (this_lsb + this_sz)) >= (next_lsb % bus_sz)) + return 1; + end + else begin + if ( (next_lsb - (this_lsb + this_sz)) >= (next_lsb % bus_sz) && + ((this_lsb - (prev_lsb + prev_sz)) >= (this_lsb % bus_sz)) ) + return 1; + end + end + end + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Target bus does not support byte enabling, and the field '", get_full_name(),"' is not the only field within the entire bus width. ", "Individual field access will not be available. ", "Accessing complete register instead."}, UVM_NONE, "t/uvm/src/reg/uvm_reg_field.svh", 1430, "", 1); + end + return 0; +endfunction +task uvm_reg_field::poke(output uvm_status_e status, + input uvm_reg_data_t value, + input string kind = "", + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_data_t tmp; + m_fname = fname; + m_lineno = lineno; + if (value >> m_size) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"uvm_reg_field::poke(): Value exceeds size of field '", get_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_field.svh", 1454, "", 1); + end + value &= value & ((1<> m_lsb) & ((1< 64) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Virtual field \"%s\" cannot have more than %0d bits", this.get_full_name(), 64), UVM_NONE, "t/uvm/src/reg/uvm_vreg_field.svh", 327, "", 1); + end + size = 64; + end + this.size = size; + this.lsb = lsb_pos; + this.parent.add_field(this); +endfunction: configure +function string uvm_vreg_field::get_full_name(); + get_full_name = {this.parent.get_full_name(), ".", this.get_name()}; +endfunction: get_full_name +function uvm_vreg uvm_vreg_field::get_register(); + get_register = this.parent; +endfunction: get_register +function uvm_vreg uvm_vreg_field::get_parent(); + get_parent = this.parent; +endfunction: get_parent +function int unsigned uvm_vreg_field::get_lsb_pos_in_register(); + get_lsb_pos_in_register = this.lsb; +endfunction: get_lsb_pos_in_register +function int unsigned uvm_vreg_field::get_n_bits(); + get_n_bits = this.size; +endfunction: get_n_bits +function string uvm_vreg_field::get_access(uvm_reg_map map = null); + if (this.parent.get_memory() == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot call uvm_vreg_field::get_rights() on unimplemented virtual field \"%s\"", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg_field.svh", 368, "", 1); + end + return "RW"; + end + return this.parent.get_access(map); +endfunction: get_access +task uvm_vreg_field::write(input longint unsigned idx, + output uvm_status_e status, + input uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_data_t tmp; + uvm_reg_data_t segval; + uvm_reg_addr_t segoff; + uvm_status_e st; + int flsb, fmsb, rmwbits; + int segsiz, segn; + uvm_mem mem; + uvm_door_e rm_path; + uvm_vreg_field_cb_iter cbs = new(this); + this.fname = fname; + this.lineno = lineno; + write_in_progress = 1'b1; + mem = this.parent.get_memory(); + if (mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot call uvm_vreg_field::write() on unimplemented virtual register \"%s\"", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg_field.svh", 404, "", 1); + end + status = UVM_NOT_OK; + return; + end + if (path == UVM_DEFAULT_DOOR) begin + uvm_reg_block blk = this.parent.get_block(); + path = blk.get_default_door(); + end + status = UVM_IS_OK; + this.parent.XatomicX(1); + if (value >> this.size) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", $sformatf("Writing value 'h%h that is greater than field \"%s\" size (%0d bits)", value, this.get_full_name(), this.get_n_bits()), UVM_NONE, "t/uvm/src/reg/uvm_vreg_field.svh", 419, "", 1); + end + value &= value & ((1< 0) begin + uvm_reg_addr_t segn; + mem.read(st, segoff, tmp, rm_path, map, parent, , extension, fname, lineno); + if (st != UVM_IS_OK && st != UVM_HAS_X) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Unable to read LSB bits in %s[%0d] to for RMW cycle on virtual field %s.", mem.get_full_name(), segoff, this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg_field.svh", 453, "", 1); + end + status = UVM_NOT_OK; + this.parent.XatomicX(0); + return; + end + value = (value << rmwbits) | (tmp & ((1< 0) begin + if (segn > 0) begin + mem.read(st, segoff + segn - 1, tmp, rm_path, map, parent,, extension, fname, lineno); + if (st != UVM_IS_OK && st != UVM_HAS_X) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Unable to read MSB bits in %s[%0d] to for RMW cycle on virtual field %s.", mem.get_full_name(), segoff+segn-1, this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg_field.svh", 472, "", 1); + end + status = UVM_NOT_OK; + this.parent.XatomicX(0); + return; + end + end + value |= (tmp & ~((1<> segsiz; + end + this.post_write(idx, value, path, map, status); + for (uvm_vreg_field_cbs cb = cbs.first(); cb != null; + cb = cbs.next()) begin + cb.fname = this.fname; + cb.lineno = this.lineno; + cb.post_write(this, idx, value, path, map, status); + end + this.parent.XatomicX(0); + begin + if (uvm_report_enabled(UVM_MEDIUM,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", $sformatf("Wrote virtual field \"%s\"[%0d] via %s with: 'h%h", this.get_full_name(), idx, (path == UVM_FRONTDOOR) ? "frontdoor" : "backdoor", value), UVM_MEDIUM, "t/uvm/src/reg/uvm_vreg_field.svh", 505, "", 1); + end + write_in_progress = 1'b0; + this.fname = ""; + this.lineno = 0; +endtask: write +task uvm_vreg_field::read(input longint unsigned idx, + output uvm_status_e status, + output uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_data_t tmp; + uvm_reg_data_t segval; + uvm_reg_addr_t segoff; + uvm_status_e st; + int flsb, lsb; + int segsiz, segn; + uvm_mem mem; + uvm_vreg_field_cb_iter cbs = new(this); + this.fname = fname; + this.lineno = lineno; + read_in_progress = 1'b1; + mem = this.parent.get_memory(); + if (mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot call uvm_vreg_field::read() on unimplemented virtual register \"%s\"", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg_field.svh", 540, "", 1); + end + status = UVM_NOT_OK; + return; + end + if (path == UVM_DEFAULT_DOOR) begin + uvm_reg_block blk = this.parent.get_block(); + path = blk.get_default_door(); + end + status = UVM_IS_OK; + this.parent.XatomicX(1); + value = 0; + this.pre_read(idx, path, map); + for (uvm_vreg_field_cbs cb = cbs.first(); cb != null; + cb = cbs.next()) begin + cb.fname = this.fname; + cb.lineno = this.lineno; + cb.pre_read(this, idx, path, map); + end + segsiz = mem.get_n_bytes() * 8; + flsb = this.get_lsb_pos_in_register(); + segoff = this.parent.get_offset_in_memory(idx) + (flsb / segsiz); + lsb = flsb % segsiz; + segn = (lsb + this.get_n_bits() - 1) / segsiz + 1; + segoff += segn - 1; + repeat (segn) begin + value = value << segsiz; + mem.read(st, segoff, tmp, path, map, parent, , extension, fname, lineno); + if (st != UVM_IS_OK && st != UVM_HAS_X) status = UVM_NOT_OK; + segoff--; + value |= tmp; + end + value = value >> lsb; + value &= (1<> this.size) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", $sformatf("Writing value 'h%h that is greater than field \"%s\" size (%0d bits)", value, this.get_full_name(), this.get_n_bits()), UVM_NONE, "t/uvm/src/reg/uvm_vreg_field.svh", 644, "", 1); + end + value &= value & ((1< 0) begin + uvm_reg_addr_t segn; + mem.peek(st, segoff, tmp, "", parent, extension, fname, lineno); + if (st != UVM_IS_OK && st != UVM_HAS_X) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Unable to read LSB bits in %s[%0d] to for RMW cycle on virtual field %s.", mem.get_full_name(), segoff, this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg_field.svh", 666, "", 1); + end + status = UVM_NOT_OK; + this.parent.XatomicX(0); + return; + end + value = (value << rmwbits) | (tmp & ((1< 0) begin + if (segn > 0) begin + mem.peek(st, segoff + segn - 1, tmp, "", parent, extension, fname, lineno); + if (st != UVM_IS_OK && st != UVM_HAS_X) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Unable to read MSB bits in %s[%0d] to for RMW cycle on virtual field %s.", mem.get_full_name(), segoff+segn-1, this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg_field.svh", 685, "", 1); + end + status = UVM_NOT_OK; + this.parent.XatomicX(0); + return; + end + end + value |= (tmp & ~((1<> segsiz; + end + this.parent.XatomicX(0); + begin + if (uvm_report_enabled(UVM_MEDIUM,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", $sformatf("Wrote virtual field \"%s\"[%0d] with: 'h%h", this.get_full_name(), idx, value), UVM_MEDIUM, "t/uvm/src/reg/uvm_vreg_field.svh", 707, "", 1); + end + this.fname = ""; + this.lineno = 0; +endtask: poke +task uvm_vreg_field::peek(input longint unsigned idx, + output uvm_status_e status, + output uvm_reg_data_t value, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_data_t tmp; + uvm_reg_data_t segval; + uvm_reg_addr_t segoff; + uvm_status_e st; + int flsb, lsb; + int segsiz, segn; + uvm_mem mem; + this.fname = fname; + this.lineno = lineno; + mem = this.parent.get_memory(); + if (mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot call uvm_vreg_field::peek() on unimplemented virtual register \"%s\"", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg_field.svh", 735, "", 1); + end + status = UVM_NOT_OK; + return; + end + status = UVM_IS_OK; + this.parent.XatomicX(1); + value = 0; + segsiz = mem.get_n_bytes() * 8; + flsb = this.get_lsb_pos_in_register(); + segoff = this.parent.get_offset_in_memory(idx) + (flsb / segsiz); + lsb = flsb % segsiz; + segn = (lsb + this.get_n_bits() - 1) / segsiz + 1; + segoff += segn - 1; + repeat (segn) begin + value = value << segsiz; + mem.peek(st, segoff, tmp, "", parent, extension, fname, lineno); + if (st != UVM_IS_OK && st != UVM_HAS_X) status = UVM_NOT_OK; + segoff--; + value |= tmp; + end + value = value >> lsb; + value &= (1< m_max_size) + m_max_size = n_bits; +endfunction: new +function void uvm_reg::configure (uvm_reg_block blk_parent, + uvm_reg_file regfile_parent=null, + string hdl_path = ""); + if (blk_parent == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/REG/CFG/NOBLK")) + uvm_report_error ("UVM/REG/CFG/NOBLK", {"uvm_reg::configure() called without a parent block for instance \"", get_name(), "\" of register type \"", get_type_name(), "\"."}, UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 623, "", 1); + end + return; + end + m_parent = blk_parent; + m_parent.add_reg(this); + m_regfile_parent = regfile_parent; + if (hdl_path != "") + add_hdl_path_slice(hdl_path, -1, -1); +endfunction: configure +function void uvm_reg::add_field(uvm_reg_field field); + int offset; + int idx; + if (m_locked) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", "Cannot add field to locked register model", UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 642, "", 1); + end + return; + end + if (field == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"RegModel")) + uvm_report_fatal ("RegModel", "Attempting to register NULL field", UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 646, "", 1); + end + offset = field.get_lsb_pos(); + idx = -1; + foreach (m_fields[i]) begin + if (offset < m_fields[i].get_lsb_pos()) begin + int j = i; + m_fields.insert(j, field); + idx = i; + break; + end + end + if (idx < 0) begin + m_fields.push_back(field); + idx = m_fields.size()-1; + end + m_n_used_bits += field.get_n_bits(); + if (m_n_used_bits > m_n_bits) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Fields use more bits (%0d) than available in register \"%s\" (%0d)", m_n_used_bits, get_name(), m_n_bits), UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 671, "", 1); + end + end + if (idx > 0) begin + if (m_fields[idx-1].get_lsb_pos() + + m_fields[idx-1].get_n_bits() > offset) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Field %s overlaps field %s in register \"%s\"", m_fields[idx-1].get_name(), field.get_name(), get_name()), UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 680, "", 1); + end + end + end + if (idx < m_fields.size()-1) begin + if (offset + field.get_n_bits() > + m_fields[idx+1].get_lsb_pos()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Field %s overlaps field %s in register \"%s\"", field.get_name(), m_fields[idx+1].get_name(), get_name()), UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 689, "", 1); + end + end + end +endfunction: add_field +function void uvm_reg::Xlock_modelX(); + if (m_locked) + return; + m_locked = 1; +endfunction +function void uvm_reg::set_frontdoor(uvm_reg_frontdoor ftdr, + uvm_reg_map map = null, + string fname = "", + int lineno = 0); + uvm_reg_map_info map_info; + ftdr.fname = m_fname; + ftdr.lineno = m_lineno; + map = get_local_map(map); + if (map == null) + return; + map_info = map.get_reg_map_info(this); + if (map_info == null) + map.add_reg(this, -1, "RW", 1, ftdr); + else begin + map_info.frontdoor = ftdr; + end +endfunction: set_frontdoor +function uvm_reg_frontdoor uvm_reg::get_frontdoor(uvm_reg_map map = null); + uvm_reg_map_info map_info; + map = get_local_map(map); + if (map == null) + return null; + map_info = map.get_reg_map_info(this); + return map_info.frontdoor; +endfunction: get_frontdoor +function void uvm_reg::set_backdoor(uvm_reg_backdoor bkdr, + string fname = "", + int lineno = 0); + bkdr.fname = fname; + bkdr.lineno = lineno; + if (m_backdoor != null && + m_backdoor.has_update_threads()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", "Previous register backdoor still has update threads running. Backdoors with active mirroring should only be set before simulation starts.", UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 750, "", 1); + end + end + m_backdoor = bkdr; +endfunction: set_backdoor +function uvm_reg_backdoor uvm_reg::get_backdoor(bit inherited = 1); + if (m_backdoor == null && inherited) begin + uvm_reg_block blk = get_parent(); + uvm_reg_backdoor bkdr; + while (blk != null) begin + bkdr = blk.get_backdoor(); + if (bkdr != null) begin + m_backdoor = bkdr; + break; + end + blk = blk.get_parent(); + end + end + return m_backdoor; +endfunction: get_backdoor +function void uvm_reg::clear_hdl_path(string kind = "RTL"); + if (kind == "ALL") begin + m_hdl_paths_pool = new("hdl_paths"); + return; + end + if (kind == "") begin + if (m_regfile_parent != null) + kind = m_regfile_parent.get_default_hdl_path(); + else + kind = m_parent.get_default_hdl_path(); + end + if (!m_hdl_paths_pool.exists(kind)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Unknown HDL Abstraction '",kind,"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 793, "", 1); + end + return; + end + m_hdl_paths_pool.delete(kind); +endfunction +function void uvm_reg::add_hdl_path(uvm_hdl_path_slice slices[], + string kind = "RTL"); + uvm_queue #(uvm_hdl_path_concat) paths = m_hdl_paths_pool.get(kind); + uvm_hdl_path_concat concat = new(); + concat.set(slices); + paths.push_back(concat); +endfunction +function void uvm_reg::add_hdl_path_slice(string name, + int offset, + int size, + bit first = 0, + string kind = "RTL"); + uvm_queue #(uvm_hdl_path_concat) paths = m_hdl_paths_pool.get(kind); + uvm_hdl_path_concat concat; + if (first || paths.size() == 0) begin + concat = new(); + paths.push_back(concat); + end + else + concat = paths.get(paths.size()-1); + concat.add_path(name, offset, size); +endfunction +function bit uvm_reg::has_hdl_path(string kind = ""); + if (kind == "") begin + if (m_regfile_parent != null) + kind = m_regfile_parent.get_default_hdl_path(); + else + kind = m_parent.get_default_hdl_path(); + end + return m_hdl_paths_pool.exists(kind); +endfunction +function void uvm_reg::get_hdl_path_kinds (ref string kinds[$]); + string kind; + kinds.delete(); + if (!m_hdl_paths_pool.first(kind)) + return; + do + kinds.push_back(kind); + while (m_hdl_paths_pool.next(kind)); +endfunction +function void uvm_reg::get_hdl_path(ref uvm_hdl_path_concat paths[$], + input string kind = ""); + uvm_queue #(uvm_hdl_path_concat) hdl_paths; + if (kind == "") begin + if (m_regfile_parent != null) + kind = m_regfile_parent.get_default_hdl_path(); + else + kind = m_parent.get_default_hdl_path(); + end + if (!has_hdl_path(kind)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Register does not have hdl path defined for abstraction '",kind,"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 877, "", 1); + end + return; + end + hdl_paths = m_hdl_paths_pool.get(kind); + for (int i=0; i 1 && map == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"set_offset requires a non-null map when register '", get_full_name(),"' belongs to more than one map."}, UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 949, "", 1); + end + return; + end + map = get_local_map(map); + if (map == null) + return; + map.m_set_reg_offset(this, offset, unmapped); +endfunction +function void uvm_reg::set_parent(uvm_reg_block blk_parent, + uvm_reg_file regfile_parent); + if (m_parent != null) begin + end + m_parent = blk_parent; + m_regfile_parent = regfile_parent; +endfunction +function uvm_reg_block uvm_reg::get_parent(); + return get_block(); +endfunction +function uvm_reg_file uvm_reg::get_regfile(); + return m_regfile_parent; +endfunction +function string uvm_reg::get_full_name(); + if (m_regfile_parent != null) + return {m_regfile_parent.get_full_name(), ".", get_name()}; + if (m_parent != null) + return {m_parent.get_full_name(), ".", get_name()}; + return get_name(); +endfunction: get_full_name +function void uvm_reg::add_map(uvm_reg_map map); + m_maps[map] = 1; +endfunction +function void uvm_reg::get_maps(ref uvm_reg_map maps[$]); + foreach (m_maps[map]) + maps.push_back(map); +endfunction +function int uvm_reg::get_n_maps(); + return m_maps.num(); +endfunction +function bit uvm_reg::is_in_map(uvm_reg_map map); + if (m_maps.exists(map)) + return 1; + foreach (m_maps[l]) begin + uvm_reg_map local_map = l; + uvm_reg_map parent_map = local_map.get_parent_map(); + while (parent_map != null) begin + if (parent_map == map) + return 1; + parent_map = parent_map.get_parent_map(); + end + end + return 0; +endfunction +function uvm_reg_map uvm_reg::get_local_map(uvm_reg_map map); + if (map == null) + return get_default_map(); + if (m_maps.exists(map)) + return map; + foreach (m_maps[l]) begin + uvm_reg_map local_map=l; + uvm_reg_map parent_map = local_map.get_parent_map(); + while (parent_map != null) begin + if (parent_map == map) + return local_map; + parent_map = parent_map.get_parent_map(); + end + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Register '",get_full_name(),"' is not contained within map '",map.get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 1062, "", 1); + end + return null; +endfunction +function uvm_reg_map uvm_reg::get_default_map(); + if (m_maps.num() == 0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Register '",get_full_name(),"' is not registered with any map"}, UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 1075, "", 1); + end + return null; + end + if (m_maps.num() == 1) begin + uvm_reg_map map; + void'(m_maps.first(map)); + return map; + end + foreach (m_maps[l]) begin + uvm_reg_map map = l; + uvm_reg_block blk = map.get_parent(); + uvm_reg_map default_map = blk.get_default_map(); + if (default_map != null) begin + uvm_reg_map local_map = get_local_map(default_map); + if (local_map != null) + return local_map; + end + end + begin + uvm_reg_map map; + void'(m_maps.first(map)); + return map; + end +endfunction +function string uvm_reg::get_rights(uvm_reg_map map = null); + uvm_reg_map_info info; + map = get_local_map(map); + if (map == null) + return "RW"; + info = map.get_reg_map_info(this); + return info.rights; +endfunction +function uvm_reg_block uvm_reg::get_block(); + get_block = m_parent; +endfunction +function uvm_reg_addr_t uvm_reg::get_offset(uvm_reg_map map = null); + uvm_reg_map_info map_info; + uvm_reg_map orig_map = map; + map = get_local_map(map); + if (map == null) + return -1; + map_info = map.get_reg_map_info(this); + if (map_info.unmapped) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Register '",get_name(), "' is unmapped in map '", ((orig_map == null) ? map.get_full_name() : orig_map.get_full_name()),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 1151, "", 1); + end + return -1; + end + return map_info.offset; +endfunction +function int uvm_reg::get_addresses(uvm_reg_map map=null, ref uvm_reg_addr_t addr[]); + uvm_reg_map_info map_info; + uvm_reg_map orig_map = map; + map = get_local_map(map); + if (map == null) + return -1; + map_info = map.get_reg_map_info(this); + if (map_info.unmapped) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Register '",get_name(), "' is unmapped in map '", ((orig_map == null) ? map.get_full_name() : orig_map.get_full_name()),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 1177, "", 1); + end + return -1; + end + addr = map_info.addr; + return map.get_n_bytes(); +endfunction +function uvm_reg_addr_t uvm_reg::get_address(uvm_reg_map map = null); + uvm_reg_addr_t addr[]; + void'(get_addresses(map,addr)); + return addr[0]; +endfunction +function int unsigned uvm_reg::get_n_bits(); + return m_n_bits; +endfunction +function int unsigned uvm_reg::get_n_bytes(); + return ((m_n_bits-1) / 8) + 1; +endfunction +function int unsigned uvm_reg::get_max_size(); + return m_max_size; +endfunction: get_max_size +function void uvm_reg::get_fields(ref uvm_reg_field fields[$]); + foreach(m_fields[i]) + fields.push_back(m_fields[i]); +endfunction +function uvm_reg_field uvm_reg::get_field_by_name(string name); + foreach (m_fields[i]) + if (m_fields[i].get_name() == name) + return m_fields[i]; + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Unable to locate field '",name, "' in register '",get_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 1232, "", 1); + end + return null; +endfunction +function string uvm_reg::Xget_fields_accessX(uvm_reg_map map); + bit is_R; + bit is_W; + foreach(m_fields[i]) begin + case (m_fields[i].get_access(map)) + "RO", + "RC", + "RS": + is_R = 1; + "WO", + "WOC", + "WOS", + "WO1": + is_W = 1; + default: + return "RW"; + endcase + if (is_R && is_W) return "RW"; + end + case ({is_R, is_W}) + 2'b01: return "WO"; + 2'b10: return "RO"; + endcase + return "RW"; +endfunction +function void uvm_reg::include_coverage(string scope, + uvm_reg_cvr_t models, + uvm_object accessor = null); + uvm_reg_cvr_rsrc_db::set({"uvm_reg::", scope}, + "include_coverage", + models, accessor); +endfunction +function uvm_reg_cvr_t uvm_reg::build_coverage(uvm_reg_cvr_t models); + build_coverage = UVM_NO_COVERAGE; + void'(uvm_reg_cvr_rsrc_db::read_by_name({"uvm_reg::", get_full_name()}, + "include_coverage", + build_coverage, this)); + return build_coverage & models; +endfunction: build_coverage +function void uvm_reg::add_coverage(uvm_reg_cvr_t models); + m_has_cover |= models; +endfunction: add_coverage +function bit uvm_reg::has_coverage(uvm_reg_cvr_t models); + return ((m_has_cover & models) == models); +endfunction: has_coverage +function uvm_reg_cvr_t uvm_reg::set_coverage(uvm_reg_cvr_t is_on); + if (is_on == uvm_reg_cvr_t'(UVM_NO_COVERAGE)) begin + m_cover_on = is_on; + return m_cover_on; + end + m_cover_on = m_has_cover & is_on; + return m_cover_on; +endfunction: set_coverage +function bit uvm_reg::get_coverage(uvm_reg_cvr_t is_on); + if (has_coverage(is_on) == 0) + return 0; + return ((m_cover_on & is_on) == is_on); +endfunction: get_coverage +function void uvm_reg::set(uvm_reg_data_t value, + string fname = "", + int lineno = 0); + m_fname = fname; + m_lineno = lineno; + foreach (m_fields[i]) + m_fields[i].set((value >> m_fields[i].get_lsb_pos()) & + ((1 << m_fields[i].get_n_bits()) - 1)); +endfunction: set +function bit uvm_reg::predict (uvm_reg_data_t value, + uvm_reg_byte_en_t be = -1, + uvm_predict_e kind = UVM_PREDICT_DIRECT, + uvm_door_e path = UVM_FRONTDOOR, + uvm_reg_map map = null, + string fname = "", + int lineno = 0); + uvm_reg_item rw = new; + rw.value[0] = value; + rw.path = path; + rw.map = map; + rw.fname = fname; + rw.lineno = lineno; + do_predict(rw, kind, be); + predict = (rw.status == UVM_NOT_OK) ? 0 : 1; +endfunction: predict +function void uvm_reg::do_predict(uvm_reg_item rw, + uvm_predict_e kind = UVM_PREDICT_DIRECT, + uvm_reg_byte_en_t be = -1); + uvm_reg_data_t reg_value = rw.value[0]; + m_fname = rw.fname; + m_lineno = rw.lineno; +if (rw.status ==UVM_IS_OK ) + rw.status = UVM_IS_OK; + if (m_is_busy && kind == UVM_PREDICT_DIRECT) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Trying to predict value of register '", get_full_name(),"' while it is being accessed"}, UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 1395, "", 1); + end + rw.status = UVM_NOT_OK; + return; + end + foreach (m_fields[i]) begin + rw.value[0] = (reg_value >> m_fields[i].get_lsb_pos()) & + ((1 << m_fields[i].get_n_bits())-1); + m_fields[i].do_predict(rw, kind, be>>(m_fields[i].get_lsb_pos()/8)); + end + rw.value[0] = reg_value; +endfunction: do_predict +function uvm_reg_data_t uvm_reg::get(string fname = "", + int lineno = 0); + m_fname = fname; + m_lineno = lineno; + get = 0; + foreach (m_fields[i]) + get |= m_fields[i].get() << m_fields[i].get_lsb_pos(); +endfunction: get +function uvm_reg_data_t uvm_reg::get_mirrored_value(string fname = "", + int lineno = 0); + m_fname = fname; + m_lineno = lineno; + get_mirrored_value = 0; + foreach (m_fields[i]) + get_mirrored_value |= m_fields[i].get_mirrored_value() << m_fields[i].get_lsb_pos(); +endfunction: get_mirrored_value +function void uvm_reg::reset(string kind = "HARD"); + foreach (m_fields[i]) + m_fields[i].reset(kind); + void'(m_atomic.try_get(1)); + m_atomic.put(1); + m_process = null; + Xset_busyX(0); +endfunction: reset +function uvm_reg_data_t uvm_reg::get_reset(string kind = "HARD"); + get_reset = 0; + foreach (m_fields[i]) + get_reset |= m_fields[i].get_reset(kind) << m_fields[i].get_lsb_pos(); +endfunction: get_reset +function bit uvm_reg::has_reset(string kind = "HARD", + bit delete = 0); + has_reset = 0; + foreach (m_fields[i]) begin + has_reset |= m_fields[i].has_reset(kind, delete); + if (!delete && has_reset) + return 1; + end +endfunction: has_reset +function void uvm_reg::set_reset(uvm_reg_data_t value, + string kind = "HARD"); + foreach (m_fields[i]) begin + m_fields[i].set_reset(value >> m_fields[i].get_lsb_pos(), kind); + end +endfunction: set_reset +function bit uvm_reg::needs_update(); + needs_update = 0; + foreach (m_fields[i]) begin + if (m_fields[i].needs_update()) begin + return 1; + end + end +endfunction: needs_update +task uvm_reg::update(output uvm_status_e status, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_data_t upd; + status = UVM_IS_OK; + if (!needs_update()) return; + upd = 0; + foreach (m_fields[i]) + upd |= m_fields[i].XupdateX() << m_fields[i].get_lsb_pos(); + write(status, upd, path, map, parent, prior, extension, fname, lineno); +endtask: update +task uvm_reg::write(output uvm_status_e status, + input uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_item rw; + XatomicX(1); + set(value); + rw = uvm_reg_item::type_id_create("write_item",,get_full_name()); + rw.element = this; + rw.element_kind = UVM_REG; + rw.kind = UVM_WRITE; + rw.value[0] = value; + rw.path = path; + rw.map = map; + rw.parent = parent; + rw.prior = prior; + rw.extension = extension; + rw.fname = fname; + rw.lineno = lineno; + do_write(rw); + status = rw.status; + XatomicX(0); +endtask +task uvm_reg::do_write (uvm_reg_item rw); + uvm_reg_cb_iter cbs = new(this); + uvm_reg_map_info map_info; + uvm_reg_data_t value; + m_fname = rw.fname; + m_lineno = rw.lineno; + if (!Xcheck_accessX(rw,map_info)) + return; + XatomicX(1); + m_write_in_progress = 1'b1; + rw.value[0] &= ((1 << m_n_bits)-1); + value = rw.value[0]; + rw.status = UVM_IS_OK; + begin : pre_write_callbacks + uvm_reg_data_t msk; + int lsb; + foreach (m_fields[i]) begin + uvm_reg_field_cb_iter cbs = new(m_fields[i]); + uvm_reg_field f = m_fields[i]; + lsb = f.get_lsb_pos(); + msk = ((1<> lsb; + f.pre_write(rw); + for (uvm_reg_cbs cb=cbs.first(); cb!=null; cb=cbs.next()) begin + rw.element = f; + rw.element_kind = UVM_FIELD; + cb.pre_write(rw); + end + value = (value & ~msk) | (rw.value[0] << lsb); + end + end + rw.element = this; + rw.element_kind = UVM_REG; + rw.value[0] = value; + pre_write(rw); + for (uvm_reg_cbs cb=cbs.first(); cb!=null; cb=cbs.next()) + cb.pre_write(rw); + if (rw.status != UVM_IS_OK) begin + m_write_in_progress = 1'b0; + XatomicX(0); + return; + end + case (rw.path) + UVM_BACKDOOR: begin + uvm_reg_data_t final_val; + uvm_reg_backdoor bkdr = get_backdoor(); + if (rw.map != null) + rw.local_map = rw.map; + else + rw.local_map = get_default_map(); + value = rw.value[0]; + rw.kind = UVM_READ; + if (bkdr != null) + bkdr.read(rw); + else + backdoor_read(rw); + if (rw.status == UVM_NOT_OK) begin + m_write_in_progress = 1'b0; + return; + end + begin + foreach (m_fields[i]) begin + uvm_reg_data_t field_val; + int lsb = m_fields[i].get_lsb_pos(); + int sz = m_fields[i].get_n_bits(); + field_val = m_fields[i].XpredictX((rw.value[0] >> lsb) & ((1<> lsb) & ((1<> f.get_lsb_pos()) & ((1<> f.get_lsb_pos()) & ((1<> hdl_concat.slices[j].offset; + slice &= (1 << hdl_concat.slices[j].size)-1; + ok &= uvm_hdl_deposit(hdl_concat.slices[j].path, slice); + end + end + end + rw.status = (ok ? UVM_IS_OK : UVM_NOT_OK); +endtask +task uvm_reg::backdoor_read (uvm_reg_item rw); + rw.status = backdoor_read_func(rw); +endtask +function uvm_status_e uvm_reg::backdoor_read_func(uvm_reg_item rw); + uvm_hdl_path_concat paths[$]; + uvm_reg_data_t val; + bit ok=1; + get_full_hdl_path(paths,rw.bd_kind); + foreach (paths[i]) begin + uvm_hdl_path_concat hdl_concat = paths[i]; + val = 0; + foreach (hdl_concat.slices[j]) begin + begin + if (uvm_report_enabled(UVM_DEBUG,UVM_INFO,"RegMem")) + uvm_report_info ("RegMem", $sformatf("backdoor_read from %s ", hdl_concat.slices[j].path), UVM_DEBUG, "t/uvm/src/reg/uvm_reg.svh", 2192, "", 1); + end + if (hdl_concat.slices[j].offset < 0) begin + ok &= uvm_hdl_read(hdl_concat.slices[j].path,val); + continue; + end + begin + uvm_reg_data_t slice; + int k = hdl_concat.slices[j].offset; + ok &= uvm_hdl_read(hdl_concat.slices[j].path, slice); + repeat (hdl_concat.slices[j].size) begin + val[k++] = slice[0]; + slice >>= 1; + end + end + end + val &= (1 << m_n_bits)-1; + if (i == 0) + rw.value[0] = val; + if (val != rw.value[0]) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Backdoor read of register %s with multiple HDL copies: values are not the same: %0h at path '%s', and %0h at path '%s'. Returning first value.", get_full_name(), rw.value[0], uvm_hdl_concat2string(paths[0]), val, uvm_hdl_concat2string(paths[i])), UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 2220, "", 1); + end + return UVM_NOT_OK; + end + begin + if (uvm_report_enabled(UVM_DEBUG,UVM_INFO,"RegMem")) + uvm_report_info ("RegMem", $sformatf("returned backdoor value 0x%0x",rw.value[0]), UVM_DEBUG, "t/uvm/src/reg/uvm_reg.svh", 2224, "", 1); + end + end + rw.status = (ok) ? UVM_IS_OK : UVM_NOT_OK; + return rw.status; +endfunction +task uvm_reg::poke(output uvm_status_e status, + input uvm_reg_data_t value, + input string kind = "", + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_backdoor bkdr = get_backdoor(); + uvm_reg_item rw; + m_fname = fname; + m_lineno = lineno; + if (bkdr == null && !has_hdl_path(kind)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"No backdoor access available to poke register '",get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 2252, "", 1); + end + status = UVM_NOT_OK; + return; + end + if (!m_is_locked_by_field) + XatomicX(1); + rw = uvm_reg_item::type_id_create("reg_poke_item",,get_full_name()); + rw.element = this; + rw.path = UVM_BACKDOOR; + rw.element_kind = UVM_REG; + rw.kind = UVM_WRITE; + rw.bd_kind = kind; + rw.value[0] = value & ((1 << m_n_bits)-1); + rw.parent = parent; + rw.extension = extension; + rw.fname = fname; + rw.lineno = lineno; + if (bkdr != null) + bkdr.write(rw); + else + backdoor_write(rw); + status = rw.status; + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", $sformatf("Poked register \"%s\": 'h%h", get_full_name(), value), UVM_HIGH, "t/uvm/src/reg/uvm_reg.svh", 2285, "", 1); + end + do_predict(rw, UVM_PREDICT_WRITE); + if (!m_is_locked_by_field) + XatomicX(0); +endtask: poke +task uvm_reg::peek(output uvm_status_e status, + output uvm_reg_data_t value, + input string kind = "", + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_backdoor bkdr = get_backdoor(); + uvm_reg_item rw; + m_fname = fname; + m_lineno = lineno; + if (bkdr == null && !has_hdl_path(kind)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("No backdoor access available to peek register \"%s\"", get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 2313, "", 1); + end + status = UVM_NOT_OK; + return; + end + if(!m_is_locked_by_field) + XatomicX(1); + rw = uvm_reg_item::type_id_create("mem_peek_item",,get_full_name()); + rw.element = this; + rw.path = UVM_BACKDOOR; + rw.element_kind = UVM_REG; + rw.kind = UVM_READ; + rw.bd_kind = kind; + rw.parent = parent; + rw.extension = extension; + rw.fname = fname; + rw.lineno = lineno; + if (bkdr != null) + bkdr.read(rw); + else + backdoor_read(rw); + status = rw.status; + value = rw.value[0]; + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", $sformatf("Peeked register \"%s\": 'h%h", get_full_name(), value), UVM_HIGH, "t/uvm/src/reg/uvm_reg.svh", 2346, "", 1); + end + do_predict(rw, UVM_PREDICT_READ); + if (!m_is_locked_by_field) + XatomicX(0); +endtask: peek +function bit uvm_reg::do_check(input uvm_reg_data_t expected, + input uvm_reg_data_t actual, + uvm_reg_map map); + uvm_reg_data_t valid_bits_mask = 0; + foreach(m_fields[i]) begin + string acc = m_fields[i].get_access(map); + acc = acc.substr(0, 1); + if (!(m_fields[i].get_compare() == UVM_NO_CHECK ||acc == "WO")) begin + valid_bits_mask |= ((1 << m_fields[i].get_n_bits())-1)<< m_fields[i].get_lsb_pos(); + end + end + if ((actual&valid_bits_mask) === (expected&valid_bits_mask)) return 1; + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Register \"%s\" value read from DUT (0x%h) does not match mirrored value (0x%h) (valid bit mask = 0x%h)", get_full_name(), actual, expected,valid_bits_mask), UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 2373, "", 1); + end + foreach(m_fields[i]) begin + string acc = m_fields[i].get_access(map); + acc = acc.substr(0, 1); + if (!(m_fields[i].get_compare() == UVM_NO_CHECK || + acc == "WO")) begin + uvm_reg_data_t mask = ((1 << m_fields[i].get_n_bits())-1); + uvm_reg_data_t val = actual >> m_fields[i].get_lsb_pos() & mask; + uvm_reg_data_t exp = expected >> m_fields[i].get_lsb_pos() & mask; + if (val !== exp) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", $sformatf("Field %s (%s[%0d:%0d]) mismatch read=%0d'h%0h mirrored=%0d'h%0h ", m_fields[i].get_name(), get_full_name(), m_fields[i].get_lsb_pos() + m_fields[i].get_n_bits() - 1, m_fields[i].get_lsb_pos(), m_fields[i].get_n_bits(), val, m_fields[i].get_n_bits(), exp), UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 2392, "", 1); + end + end + end + end + return 0; +endfunction +task uvm_reg::mirror(output uvm_status_e status, + input uvm_check_e check = UVM_NO_CHECK, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_data_t v; + uvm_reg_data_t exp; + uvm_reg_backdoor bkdr = get_backdoor(); + XatomicX(1); + m_fname = fname; + m_lineno = lineno; + if (path == UVM_DEFAULT_DOOR) + path = m_parent.get_default_door(); + if (path == UVM_BACKDOOR && (bkdr != null || has_hdl_path())) + map = uvm_reg_map::backdoor(); + else + map = get_local_map(map); + if (map == null) + return; + if (check == UVM_CHECK) + exp = get_mirrored_value(); + XreadX(status, v, path, map, parent, prior, extension, fname, lineno); + if (status == UVM_NOT_OK) begin + XatomicX(0); + return; + end + if (check == UVM_CHECK) void'(do_check(exp, v, map)); + XatomicX(0); +endtask: mirror +task uvm_reg::XatomicX(bit on); + process m_reg_process; + m_reg_process=process::self(); + if (on) begin + if (m_reg_process == m_process) + return; + m_atomic.get(1); + m_process = m_reg_process; + end + else begin + void'(m_atomic.try_get(1)); + m_atomic.put(1); + m_process = null; + end +endtask: XatomicX +function string uvm_reg::convert2string(); + string res_str; + string t_str; + bit with_debug_info; + string prefix; + $sformat(convert2string, "Register %s -- %0d bytes, mirror value:'h%h", + get_full_name(), get_n_bytes(),get()); + if (m_maps.num()==0) + convert2string = {convert2string, " (unmapped)\n"}; + else + convert2string = {convert2string, "\n"}; + foreach (m_maps[map]) begin + uvm_reg_map parent_map = map; + int unsigned offset; + while (parent_map != null) begin + uvm_reg_map this_map = parent_map; + parent_map = this_map.get_parent_map(); + offset = parent_map == null ? this_map.get_base_addr(UVM_NO_HIER) : + parent_map.get_submap_offset(this_map); + prefix = {prefix, " "}; + begin + uvm_endianness_e e = this_map.get_endian(); + $sformat(convert2string, + "%sMapped in '%s' -- %d bytes, %s, offset 'h%0h\n", + prefix, this_map.get_full_name(), this_map.get_n_bytes(), + e.name(), offset); + end + end + end + prefix = " "; + foreach(m_fields[i]) begin + $sformat(convert2string, "%s\n%s", convert2string, + m_fields[i].convert2string()); + end + if (m_read_in_progress == 1'b1) begin + if (m_fname != "" && m_lineno != 0) + $sformat(res_str, "%s:%0d ",m_fname, m_lineno); + convert2string = {convert2string, "\n", res_str, + "currently executing read method"}; + end + if ( m_write_in_progress == 1'b1) begin + if (m_fname != "" && m_lineno != 0) + $sformat(res_str, "%s:%0d ",m_fname, m_lineno); + convert2string = {convert2string, "\n", res_str, + "currently executing write method"}; + end +endfunction: convert2string +function void uvm_reg::do_print (uvm_printer printer); + uvm_reg_field f[$]; + super.do_print(printer); + get_fields(f); + foreach(f[i]) printer.print_generic(f[i].get_name(),f[i].get_type_name(),-2,f[i].convert2string()); +endfunction +function uvm_object uvm_reg::clone(); + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"RegModel")) + uvm_report_fatal ("RegModel", "RegModel registers cannot be cloned", UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 2544, "", 1); + end + return null; +endfunction +function void uvm_reg::do_copy(uvm_object rhs); + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"RegModel")) + uvm_report_fatal ("RegModel", "RegModel registers cannot be copied", UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 2551, "", 1); + end +endfunction +function bit uvm_reg::do_compare (uvm_object rhs, + uvm_comparer comparer); + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", "RegModel registers cannot be compared", UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 2559, "", 1); + end + return 0; +endfunction +function void uvm_reg::do_pack (uvm_packer packer); + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", "RegModel registers cannot be packed", UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 2567, "", 1); + end +endfunction +function void uvm_reg::do_unpack (uvm_packer packer); + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", "RegModel registers cannot be unpacked", UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 2574, "", 1); + end +endfunction +typedef class uvm_reg_indirect_ftdr_seq; +class uvm_reg_indirect_data extends uvm_reg; + protected uvm_reg m_idx; + protected uvm_reg m_tbl[]; + function new(string name = "uvm_reg_indirect", + int unsigned n_bits, + int has_cover); + super.new(name,n_bits,has_cover); + endfunction: new + virtual function void build(); + endfunction: build + function void configure (uvm_reg idx, + uvm_reg reg_a[], + uvm_reg_block blk_parent, + uvm_reg_file regfile_parent = null); + super.configure(blk_parent, regfile_parent, ""); + m_idx = idx; + m_tbl = reg_a; + uvm_resource_db#(bit)::set({"REG::", get_full_name()}, + "NO_REG_TESTS", 1); + foreach (m_maps[map]) begin + add_frontdoors(map); + end + endfunction + virtual function void add_map(uvm_reg_map map); + super.add_map(map); + add_frontdoors(map); + endfunction + local function void add_frontdoors(uvm_reg_map map); + foreach (m_tbl[i]) begin + uvm_reg_indirect_ftdr_seq fd; + if (m_tbl[i] == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,get_full_name())) + uvm_report_error (get_full_name(), $sformatf("Indirect register #%0d is NULL", i), UVM_NONE, "t/uvm/src/reg/uvm_reg_indirect.svh", 90, "", 1); + end + continue; + end + fd = new(m_idx, i, this); + if (m_tbl[i].is_in_map(map)) + m_tbl[i].set_frontdoor(fd, map); + else + map.add_reg(m_tbl[i], -1, "RW", 1, fd); + end + endfunction + virtual function void do_predict (uvm_reg_item rw, + uvm_predict_e kind = UVM_PREDICT_DIRECT, + uvm_reg_byte_en_t be = -1); + if (m_idx.get() >= m_tbl.size()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,get_full_name())) + uvm_report_error (get_full_name(), $sformatf("Address register %s has a value (%0d) greater than the maximum indirect register array size (%0d)", m_idx.get_full_name(), m_idx.get(), m_tbl.size()), UVM_NONE, "t/uvm/src/reg/uvm_reg_indirect.svh", 105, "", 1); + end + rw.status = UVM_NOT_OK; + return; + end + begin + int unsigned idx = m_idx.get(); + m_tbl[idx].do_predict(rw, kind, be); + end + endfunction + virtual function uvm_reg_map get_local_map(uvm_reg_map map); + return m_idx.get_local_map(map); + endfunction + virtual function void add_field (uvm_reg_field field); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,get_full_name())) + uvm_report_error (get_full_name(), "Cannot add field to an indirect data access register", UVM_NONE, "t/uvm/src/reg/uvm_reg_indirect.svh", 126, "", 1); + end + endfunction + virtual function void set (uvm_reg_data_t value, + string fname = "", + int lineno = 0); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,get_full_name())) + uvm_report_error (get_full_name(), "Cannot set() an indirect data access register", UVM_NONE, "t/uvm/src/reg/uvm_reg_indirect.svh", 132, "", 1); + end + endfunction + virtual function uvm_reg_data_t get(string fname = "", + int lineno = 0); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,get_full_name())) + uvm_report_error (get_full_name(), "Cannot get() an indirect data access register", UVM_NONE, "t/uvm/src/reg/uvm_reg_indirect.svh", 137, "", 1); + end + return 0; + endfunction + virtual function uvm_reg get_indirect_reg(string fname = "", + int lineno = 0); + int unsigned idx = m_idx.get_mirrored_value(); + return(m_tbl[idx]); + endfunction + virtual function bit needs_update(); + return 0; + endfunction + virtual task write(output uvm_status_e status, + input uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + if (path == UVM_DEFAULT_DOOR) begin + uvm_reg_block blk = get_parent(); + path = blk.get_default_door(); + end + if (path == UVM_BACKDOOR) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,get_full_name())) + uvm_report_warning (get_full_name(), "Cannot backdoor-write an indirect data access register. Switching to frontdoor.", UVM_NONE, "t/uvm/src/reg/uvm_reg_indirect.svh", 167, "", 1); + end + path = UVM_FRONTDOOR; + end + begin + uvm_reg_item rw; + XatomicX(1); + rw = uvm_reg_item::type_id_create("write_item",,get_full_name()); + rw.element = this; + rw.element_kind = UVM_REG; + rw.kind = UVM_WRITE; + rw.value[0] = value; + rw.path = path; + rw.map = map; + rw.parent = parent; + rw.prior = prior; + rw.extension = extension; + rw.fname = fname; + rw.lineno = lineno; + do_write(rw); + status = rw.status; + XatomicX(0); + end + endtask + virtual task read(output uvm_status_e status, + output uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + if (path == UVM_DEFAULT_DOOR) begin + uvm_reg_block blk = get_parent(); + path = blk.get_default_door(); + end + if (path == UVM_BACKDOOR) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,get_full_name())) + uvm_report_warning (get_full_name(), "Cannot backdoor-read an indirect data access register. Switching to frontdoor.", UVM_NONE, "t/uvm/src/reg/uvm_reg_indirect.svh", 218, "", 1); + end + path = UVM_FRONTDOOR; + end + super.read(status, value, path, map, parent, prior, extension, fname, lineno); + endtask + virtual task poke(output uvm_status_e status, + input uvm_reg_data_t value, + input string kind = "", + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,get_full_name())) + uvm_report_error (get_full_name(), "Cannot poke() an indirect data access register", UVM_NONE, "t/uvm/src/reg/uvm_reg_indirect.svh", 232, "", 1); + end + status = UVM_NOT_OK; + endtask + virtual task peek(output uvm_status_e status, + output uvm_reg_data_t value, + input string kind = "", + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,get_full_name())) + uvm_report_error (get_full_name(), "Cannot peek() an indirect data access register", UVM_NONE, "t/uvm/src/reg/uvm_reg_indirect.svh", 243, "", 1); + end + status = UVM_NOT_OK; + endtask + virtual task update(output uvm_status_e status, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + status = UVM_IS_OK; + endtask + virtual task mirror(output uvm_status_e status, + input uvm_check_e check = UVM_NO_CHECK, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + status = UVM_IS_OK; + endtask +endclass : uvm_reg_indirect_data +class uvm_reg_indirect_ftdr_seq extends uvm_reg_frontdoor; + local uvm_reg m_addr_reg; + local uvm_reg m_data_reg; + local int m_idx; + function new(uvm_reg addr_reg, + int idx, + uvm_reg data_reg); + super.new("uvm_reg_indirect_ftdr_seq"); + m_addr_reg = addr_reg; + m_idx = idx; + m_data_reg = data_reg; + endfunction: new + virtual task body(); + uvm_reg_item rw; + $cast(rw,rw_info.clone()); + rw.element = m_addr_reg; + rw.kind = UVM_WRITE; + rw.value[0]= m_idx; + m_addr_reg.XatomicX(1); + m_data_reg.XatomicX(1); + m_addr_reg.do_write(rw); + if (rw.status == UVM_NOT_OK) + return; + $cast(rw,rw_info.clone()); + rw.element = m_data_reg; + if (rw_info.kind == UVM_WRITE) + m_data_reg.do_write(rw); + else begin + m_data_reg.do_read(rw); + rw_info.value[0] = rw.value[0]; + end + m_addr_reg.XatomicX(0); + m_data_reg.XatomicX(0); + rw_info.status = rw.status; + endtask +endclass +class uvm_reg_fifo extends uvm_reg; + local uvm_reg_field value; + local int m_set_cnt; + local int unsigned m_size; + rand uvm_reg_data_t fifo[$]; + constraint valid_fifo_size { + fifo.size() <= m_size; + } + function new(string name = "reg_fifo", + int unsigned size, + int unsigned n_bits, + int has_cover); + super.new(name,n_bits,has_cover); + m_size = size; + endfunction + virtual function void build(); + value = uvm_reg_field::type_id_create("value"); + value.configure(this, get_n_bits(), 0, "RW", 0, 32'h0, 1, 0, 1); + endfunction + function void set_compare(uvm_check_e check=UVM_CHECK); + value.set_compare(check); + endfunction + function int unsigned size(); + return fifo.size(); + endfunction + function int unsigned capacity(); + return m_size; + endfunction + virtual function void set(uvm_reg_data_t value, + string fname = "", + int lineno = 0); + value &= ((1 << get_n_bits())-1); + if (fifo.size() == m_size) begin + return; + end + super.set(value,fname,lineno); + m_set_cnt++; + fifo.push_back(this.value.value); + endfunction + virtual task update(output uvm_status_e status, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_data_t upd; + if (!m_set_cnt || fifo.size() == 0) + return; + m_update_in_progress = 1; + for (int i=fifo.size()-m_set_cnt; m_set_cnt > 0; i++, m_set_cnt--) begin + if (i >= 0) begin + write(status,fifo[i],path,map,parent,prior,extension,fname,lineno); + end + end + m_update_in_progress = 0; + endtask + virtual function uvm_reg_data_t get(string fname="", int lineno=0); + return fifo[0]; + endfunction + virtual function void do_predict(uvm_reg_item rw, + uvm_predict_e kind = UVM_PREDICT_DIRECT, + uvm_reg_byte_en_t be = -1); + super.do_predict(rw,kind,be); + if (rw.status == UVM_NOT_OK) + return; + case (kind) + UVM_PREDICT_WRITE, + UVM_PREDICT_DIRECT: + begin + if (fifo.size() != m_size && !m_update_in_progress) + fifo.push_back(this.value.value); + end + UVM_PREDICT_READ: + begin + uvm_reg_data_t value = rw.value[0] & ((1 << get_n_bits())-1); + uvm_reg_data_t mirror_val; + if (fifo.size() == 0) begin + return; + end + mirror_val = fifo.pop_front(); + if (this.value.get_compare() == UVM_CHECK && mirror_val != value) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"MIRROR_MISMATCH")) + uvm_report_warning ("MIRROR_MISMATCH", $sformatf("Observed DUT read value 'h%0h != mirror value 'h%0h",value,mirror_val), UVM_NONE, "t/uvm/src/reg/uvm_reg_fifo.svh", 241, "", 1); + end + end + end + endcase + endfunction + virtual task pre_write(uvm_reg_item rw); + if (m_set_cnt && !m_update_in_progress) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"Needs Update")) + uvm_report_error ("Needs Update", "Must call update() after set() and before write()", UVM_NONE, "t/uvm/src/reg/uvm_reg_fifo.svh", 263, "", 1); + end + rw.status = UVM_NOT_OK; + return; + end + if (fifo.size() >= m_size && !m_update_in_progress) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"FIFO Full")) + uvm_report_error ("FIFO Full", "Write to full FIFO ignored", UVM_NONE, "t/uvm/src/reg/uvm_reg_fifo.svh", 268, "", 1); + end + rw.status = UVM_NOT_OK; + return; + end + endtask + virtual task pre_read(uvm_reg_item rw); + if (fifo.size() == 0) begin + rw.status = UVM_NOT_OK; + return; + end + endtask + function void post_randomize(); + m_set_cnt = 0; + endfunction +endclass +class uvm_reg_file extends uvm_object; + local uvm_reg_block parent; + local uvm_reg_file m_rf; + local string default_hdl_path = "RTL"; + local uvm_object_string_pool #(uvm_queue #(string)) hdl_paths_pool; + typedef uvm_object_registry#(uvm_reg_file,"uvm_reg_file") type_id; + static function uvm_reg_file type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_reg_file tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_reg_file"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_reg_file"; + endfunction : get_type_name + extern function new (string name=""); + extern function void configure (uvm_reg_block blk_parent, + uvm_reg_file regfile_parent, + string hdl_path = ""); + extern virtual function string get_full_name(); + extern virtual function uvm_reg_block get_parent (); + extern virtual function uvm_reg_block get_block (); + extern virtual function uvm_reg_file get_regfile (); + extern function void clear_hdl_path (string kind = "RTL"); + extern function void add_hdl_path (string path, string kind = "RTL"); + extern function bit has_hdl_path (string kind = ""); + extern function void get_hdl_path (ref string paths[$], input string kind = ""); + extern function void get_full_hdl_path (ref string paths[$], + input string kind = "", + input string separator = "."); + extern function void set_default_hdl_path (string kind); + extern function string get_default_hdl_path (); + extern virtual function void do_print (uvm_printer printer); + extern virtual function string convert2string(); + extern virtual function uvm_object clone (); + extern virtual function void do_copy (uvm_object rhs); + extern virtual function bit do_compare (uvm_object rhs, + uvm_comparer comparer); + extern virtual function void do_pack (uvm_packer packer); + extern virtual function void do_unpack (uvm_packer packer); +endclass: uvm_reg_file +function uvm_reg_file::new(string name=""); + super.new(name); + hdl_paths_pool = new("hdl_paths"); +endfunction: new +function void uvm_reg_file::configure(uvm_reg_block blk_parent, uvm_reg_file regfile_parent, string hdl_path = ""); + if (blk_parent == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/RFILE/CFG/NOBLK")) + uvm_report_error ("UVM/RFILE/CFG/NOBLK", {"uvm_reg_file::configure() called without a parent block for instance \"", get_name(), "\" of register file type \"", get_type_name(), "\"."}, UVM_NONE, "t/uvm/src/reg/uvm_reg_file.svh", 148, "", 1); + end + return; + end + this.parent = blk_parent; + this.m_rf = regfile_parent; + this.add_hdl_path(hdl_path); +endfunction: configure +function uvm_reg_block uvm_reg_file::get_block(); + get_block = this.parent; +endfunction: get_block +function uvm_reg_file uvm_reg_file::get_regfile(); + return m_rf; +endfunction +function void uvm_reg_file::clear_hdl_path(string kind = "RTL"); + if (kind == "ALL") begin + hdl_paths_pool = new("hdl_paths"); + return; + end + if (kind == "") begin + if (m_rf != null) + kind = m_rf.get_default_hdl_path(); + else + kind = parent.get_default_hdl_path(); + end + if (!hdl_paths_pool.exists(kind)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Unknown HDL Abstraction '",kind,"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_file.svh", 188, "", 1); + end + return; + end + hdl_paths_pool.delete(kind); +endfunction +function void uvm_reg_file::add_hdl_path(string path, string kind = "RTL"); + uvm_queue #(string) paths; + paths = hdl_paths_pool.get(kind); + paths.push_back(path); +endfunction +function bit uvm_reg_file::has_hdl_path(string kind = ""); + if (kind == "") begin + if (m_rf != null) + kind = m_rf.get_default_hdl_path(); + else + kind = parent.get_default_hdl_path(); + end + return hdl_paths_pool.exists(kind); +endfunction +function void uvm_reg_file::get_hdl_path(ref string paths[$], input string kind = ""); + uvm_queue #(string) hdl_paths; + if (kind == "") begin + if (m_rf != null) + kind = m_rf.get_default_hdl_path(); + else + kind = parent.get_default_hdl_path(); + end + if (!has_hdl_path(kind)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Register does not have hdl path defined for abstraction '",kind,"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_file.svh", 237, "", 1); + end + return; + end + hdl_paths = hdl_paths_pool.get(kind); + for (int i=0; i= min_offset; + start_offset <= max_offset - len + 1; + } + constraint uvm_mem_mam_policy_no_overlap { + foreach (in_use[i]) { + !(start_offset <= in_use[i].Xend_offsetX && + start_offset + len - 1 >= in_use[i].Xstart_offsetX); + } + } +endclass +class uvm_mem_mam_cfg; + rand int unsigned n_bytes; + rand bit [63:0] start_offset; + rand bit [63:0] end_offset; + rand uvm_mem_mam::alloc_mode_e mode; + rand uvm_mem_mam::locality_e locality; + constraint uvm_mem_mam_cfg_valid { + end_offset > start_offset; + n_bytes < 64; + } +endclass +function uvm_mem_region::new(bit [63:0] start_offset, + bit [63:0] end_offset, + int unsigned len, + int unsigned n_bytes, + uvm_mem_mam parent); + this.Xstart_offsetX = start_offset; + this.Xend_offsetX = end_offset; + this.len = len; + this.n_bytes = n_bytes; + this.parent = parent; + this.XvregX = null; +endfunction: new +function bit [63:0] uvm_mem_region::get_start_offset(); + return this.Xstart_offsetX; +endfunction: get_start_offset +function bit [63:0] uvm_mem_region::get_end_offset(); + return this.Xend_offsetX; +endfunction: get_end_offset +function int unsigned uvm_mem_region::get_len(); + return this.len; +endfunction: get_len +function int unsigned uvm_mem_region::get_n_bytes(); + return this.n_bytes; +endfunction: get_n_bytes +function string uvm_mem_region::convert2string(); + $sformat(convert2string, "['h%h:'h%h]", + this.Xstart_offsetX, this.Xend_offsetX); +endfunction: convert2string +function void uvm_mem_region::release_region(); + this.parent.release_region(this); +endfunction +function uvm_mem uvm_mem_region::get_memory(); + return this.parent.get_memory(); +endfunction: get_memory +function uvm_vreg uvm_mem_region::get_virtual_registers(); + return this.XvregX; +endfunction: get_virtual_registers +function uvm_mem_mam::new(string name, + uvm_mem_mam_cfg cfg, + uvm_mem mem = null); + this.cfg = cfg; + this.memory = mem; + this.default_alloc = new; +endfunction: new +function uvm_mem_mam_cfg uvm_mem_mam::reconfigure(uvm_mem_mam_cfg cfg = null); + uvm_root top; + uvm_coreservice_t cs; + if (cfg == null) + return this.cfg; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + if (cfg.n_bytes !== this.cfg.n_bytes) begin + top.uvm_report_error("uvm_mem_mam", + $sformatf("Cannot reconfigure Memory Allocation Manager with a different number of bytes (%0d !== %0d)", + cfg.n_bytes, this.cfg.n_bytes), UVM_LOW); + return this.cfg; + end + foreach (this.in_use[i]) begin + if (this.in_use[i].get_start_offset() < cfg.start_offset || + this.in_use[i].get_end_offset() > cfg.end_offset) begin + top.uvm_report_error("uvm_mem_mam", + $sformatf("Cannot reconfigure Memory Allocation Manager with a currently allocated region outside of the managed address range ([%0d:%0d] outside of [%0d:%0d])", + this.in_use[i].get_start_offset(), + this.in_use[i].get_end_offset(), + cfg.start_offset, cfg.end_offset), UVM_LOW); + return this.cfg; + end + end + reconfigure = this.cfg; + this.cfg = cfg; +endfunction: reconfigure +function uvm_mem_region uvm_mem_mam::reserve_region(bit [63:0] start_offset, + int unsigned n_bytes, + string fname = "", + int lineno = 0); + bit [63:0] end_offset; + this.fname = fname; + this.lineno = lineno; + if (n_bytes == 0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", "Cannot reserve 0 bytes", UVM_NONE, "t/uvm/src/reg/uvm_mem_mam.svh", 638, "", 1); + end + return null; + end + if (start_offset < this.cfg.start_offset) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot reserve before start of memory space: 'h%h < 'h%h", start_offset, this.cfg.start_offset), UVM_NONE, "t/uvm/src/reg/uvm_mem_mam.svh", 644, "", 1); + end + return null; + end + end_offset = start_offset + ((n_bytes-1) / this.cfg.n_bytes); + n_bytes = (end_offset - start_offset + 1) * this.cfg.n_bytes; + if (end_offset > this.cfg.end_offset) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot reserve past end of memory space: 'h%h > 'h%h", end_offset, this.cfg.end_offset), UVM_NONE, "t/uvm/src/reg/uvm_mem_mam.svh", 653, "", 1); + end + return null; + end + begin + if (uvm_report_enabled(UVM_MEDIUM,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", $sformatf("Attempting to reserve ['h%h:'h%h]...", start_offset, end_offset), UVM_MEDIUM, "t/uvm/src/reg/uvm_mem_mam.svh", 658, "", 1); + end + foreach (this.in_use[i]) begin + if (start_offset <= this.in_use[i].get_end_offset() && + end_offset >= this.in_use[i].get_start_offset()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot reserve ['h%h:'h%h] because it overlaps with %s", start_offset, end_offset, this.in_use[i].convert2string()), UVM_NONE, "t/uvm/src/reg/uvm_mem_mam.svh", 669, "", 1); + end + return null; + end + if (start_offset > this.in_use[i].get_start_offset()) begin + reserve_region = new(start_offset, end_offset, + end_offset - start_offset + 1, n_bytes, this); + this.in_use.insert(i, reserve_region); + return reserve_region; + end + end + reserve_region = new(start_offset, end_offset, + end_offset - start_offset + 1, n_bytes, this); + this.in_use.push_back(reserve_region); +endfunction: reserve_region +function uvm_mem_region uvm_mem_mam::request_region(int unsigned n_bytes, + uvm_mem_mam_policy alloc = null, + string fname = "", + int lineno = 0); + this.fname = fname; + this.lineno = lineno; + if (alloc == null) alloc = this.default_alloc; + alloc.len = (n_bytes-1) / this.cfg.n_bytes + 1; + alloc.min_offset = this.cfg.start_offset; + alloc.max_offset = this.cfg.end_offset; + alloc.in_use = this.in_use; + if (!alloc.randomize()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", "Unable to randomize policy", UVM_NONE, "t/uvm/src/reg/uvm_mem_mam.svh", 702, "", 1); + end + return null; + end + return reserve_region(alloc.start_offset, n_bytes); +endfunction: request_region +function void uvm_mem_mam::release_region(uvm_mem_region region); + if (region == null) return; + foreach (this.in_use[i]) begin + if (this.in_use[i] == region) begin + this.in_use.delete(i); + return; + end + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Attempting to release unallocated region\n", region.convert2string()}, UVM_NONE, "t/uvm/src/reg/uvm_mem_mam.svh", 721, "", 1); + end +endfunction: release_region +function void uvm_mem_mam::release_all_regions(); + in_use.delete(); +endfunction: release_all_regions +function string uvm_mem_mam::convert2string(); + convert2string = "Allocated memory regions:\n"; + foreach (this.in_use[i]) begin + $sformat(convert2string, "%s %s\n", convert2string, + this.in_use[i].convert2string()); + end +endfunction: convert2string +function uvm_mem_region uvm_mem_mam::for_each(bit reset = 0); + if (reset) this.for_each_idx = -1; + this.for_each_idx++; + if (this.for_each_idx >= this.in_use.size()) begin + return null; + end + return this.in_use[this.for_each_idx]; +endfunction: for_each +function uvm_mem uvm_mem_mam::get_memory(); + return this.memory; +endfunction: get_memory +task uvm_mem_region::write(output uvm_status_e status, + input uvm_reg_addr_t offset, + input uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_mem mem = this.parent.get_memory(); + this.fname = fname; + this.lineno = lineno; + if (mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", "Cannot use uvm_mem_region::write() on a region that was allocated by a Memory Allocation Manager that was not associated with a uvm_mem instance", UVM_NONE, "t/uvm/src/reg/uvm_mem_mam.svh", 773, "", 1); + end + status = UVM_NOT_OK; + return; + end + if (offset > this.len) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Attempting to write to an offset outside of the allocated region (%0d > %0d)", offset, this.len), UVM_NONE, "t/uvm/src/reg/uvm_mem_mam.svh", 781, "", 1); + end + status = UVM_NOT_OK; + return; + end + mem.write(status, offset + this.get_start_offset(), value, + path, map, parent, prior, extension); +endtask: write +task uvm_mem_region::read(output uvm_status_e status, + input uvm_reg_addr_t offset, + output uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_mem mem = this.parent.get_memory(); + this.fname = fname; + this.lineno = lineno; + if (mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", "Cannot use uvm_mem_region::read() on a region that was allocated by a Memory Allocation Manager that was not associated with a uvm_mem instance", UVM_NONE, "t/uvm/src/reg/uvm_mem_mam.svh", 806, "", 1); + end + status = UVM_NOT_OK; + return; + end + if (offset > this.len) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Attempting to read from an offset outside of the allocated region (%0d > %0d)", offset, this.len), UVM_NONE, "t/uvm/src/reg/uvm_mem_mam.svh", 814, "", 1); + end + status = UVM_NOT_OK; + return; + end + mem.read(status, offset + this.get_start_offset(), value, + path, map, parent, prior, extension); +endtask: read +task uvm_mem_region::burst_write(output uvm_status_e status, + input uvm_reg_addr_t offset, + input uvm_reg_data_t value[], + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_mem mem = this.parent.get_memory(); + this.fname = fname; + this.lineno = lineno; + if (mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", "Cannot use uvm_mem_region::burst_write() on a region that was allocated by a Memory Allocation Manager that was not associated with a uvm_mem instance", UVM_NONE, "t/uvm/src/reg/uvm_mem_mam.svh", 839, "", 1); + end + status = UVM_NOT_OK; + return; + end + if (offset + value.size() > this.len) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Attempting to burst-write to an offset outside of the allocated region (burst to [%0d:%0d] > mem_size %0d)", offset,offset+value.size(),this.len), UVM_NONE, "t/uvm/src/reg/uvm_mem_mam.svh", 847, "", 1); + end + status = UVM_NOT_OK; + return; + end + mem.burst_write(status, offset + get_start_offset(), value, + path, map, parent, prior, extension); +endtask: burst_write +task uvm_mem_region::burst_read(output uvm_status_e status, + input uvm_reg_addr_t offset, + output uvm_reg_data_t value[], + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_mem mem = this.parent.get_memory(); + this.fname = fname; + this.lineno = lineno; + if (mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", "Cannot use uvm_mem_region::burst_read() on a region that was allocated by a Memory Allocation Manager that was not associated with a uvm_mem instance", UVM_NONE, "t/uvm/src/reg/uvm_mem_mam.svh", 873, "", 1); + end + status = UVM_NOT_OK; + return; + end + if (offset + value.size() > this.len) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Attempting to burst-read to an offset outside of the allocated region (burst to [%0d:%0d] > mem_size %0d)", offset,offset+value.size(),this.len), UVM_NONE, "t/uvm/src/reg/uvm_mem_mam.svh", 881, "", 1); + end + status = UVM_NOT_OK; + return; + end + mem.burst_read(status, offset + get_start_offset(), value, + path, map, parent, prior, extension); +endtask: burst_read +task uvm_mem_region::poke(output uvm_status_e status, + input uvm_reg_addr_t offset, + input uvm_reg_data_t value, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_mem mem = this.parent.get_memory(); + this.fname = fname; + this.lineno = lineno; + if (mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", "Cannot use uvm_mem_region::poke() on a region that was allocated by a Memory Allocation Manager that was not associated with a uvm_mem instance", UVM_NONE, "t/uvm/src/reg/uvm_mem_mam.svh", 904, "", 1); + end + status = UVM_NOT_OK; + return; + end + if (offset > this.len) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Attempting to poke to an offset outside of the allocated region (%0d > %0d)", offset, this.len), UVM_NONE, "t/uvm/src/reg/uvm_mem_mam.svh", 912, "", 1); + end + status = UVM_NOT_OK; + return; + end + mem.poke(status, offset + this.get_start_offset(), value, "", parent, extension); +endtask: poke +task uvm_mem_region::peek(output uvm_status_e status, + input uvm_reg_addr_t offset, + output uvm_reg_data_t value, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_mem mem = this.parent.get_memory(); + this.fname = fname; + this.lineno = lineno; + if (mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", "Cannot use uvm_mem_region::peek() on a region that was allocated by a Memory Allocation Manager that was not associated with a uvm_mem instance", UVM_NONE, "t/uvm/src/reg/uvm_mem_mam.svh", 933, "", 1); + end + status = UVM_NOT_OK; + return; + end + if (offset > this.len) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Attempting to peek from an offset outside of the allocated region (%0d > %0d)", offset, this.len), UVM_NONE, "t/uvm/src/reg/uvm_mem_mam.svh", 941, "", 1); + end + status = UVM_NOT_OK; + return; + end + mem.peek(status, offset + this.get_start_offset(), value, "", parent, extension); +endtask: peek +typedef class uvm_mem_region; +typedef class uvm_mem_mam; +typedef class uvm_vreg_cbs; +class uvm_vreg extends uvm_object; + static local bit m_register_cb_uvm_vreg_cbs = uvm_callbacks#(uvm_vreg,uvm_vreg_cbs)::m_register_pair("uvm_vreg","uvm_vreg_cbs"); + local bit locked; + local uvm_reg_block parent; + local int unsigned n_bits; + local int unsigned n_used_bits; + local uvm_vreg_field fields[$]; + local uvm_mem mem; + local uvm_reg_addr_t offset; + local int unsigned incr; + local longint unsigned size; + local bit is_static; + local uvm_mem_region region; + local semaphore atomic; + local string fname; + local int lineno; + local bit read_in_progress; + local bit write_in_progress; + extern function new(string name, + int unsigned n_bits); + extern function void configure(uvm_reg_block parent, + uvm_mem mem = null, + longint unsigned size = 0, + uvm_reg_addr_t offset = 0, + int unsigned incr = 0); + extern virtual function bit implement(longint unsigned n, + uvm_mem mem = null, + uvm_reg_addr_t offset = 0, + int unsigned incr = 0); + extern virtual function uvm_mem_region allocate(longint unsigned n, + uvm_mem_mam mam, + uvm_mem_mam_policy alloc = null); + extern virtual function uvm_mem_region get_region(); + extern virtual function void release_region(); + extern virtual function void set_parent(uvm_reg_block parent); + extern function void Xlock_modelX(); + extern function void add_field(uvm_vreg_field field); + extern task XatomicX(bit on); + extern virtual function string get_full_name(); + extern virtual function uvm_reg_block get_parent(); + extern virtual function uvm_reg_block get_block(); + extern virtual function uvm_mem get_memory(); + extern virtual function int get_n_maps (); + extern function bit is_in_map (uvm_reg_map map); + extern virtual function void get_maps (ref uvm_reg_map maps[$]); + extern virtual function string get_rights(uvm_reg_map map = null); + extern virtual function string get_access(uvm_reg_map map = null); + extern virtual function int unsigned get_size(); + extern virtual function int unsigned get_n_bytes(); + extern virtual function int unsigned get_n_memlocs(); + extern virtual function int unsigned get_incr(); + extern virtual function void get_fields(ref uvm_vreg_field fields[$]); + extern virtual function uvm_vreg_field get_field_by_name(string name); + extern virtual function uvm_reg_addr_t get_offset_in_memory(longint unsigned idx); + extern virtual function uvm_reg_addr_t get_address(longint unsigned idx, + uvm_reg_map map = null); + extern virtual task write(input longint unsigned idx, + output uvm_status_e status, + input uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + extern virtual task read(input longint unsigned idx, + output uvm_status_e status, + output uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + extern virtual task poke(input longint unsigned idx, + output uvm_status_e status, + input uvm_reg_data_t value, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + extern virtual task peek(input longint unsigned idx, + output uvm_status_e status, + output uvm_reg_data_t value, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + extern function void reset(string kind = "HARD"); + virtual task pre_write(longint unsigned idx, + ref uvm_reg_data_t wdat, + ref uvm_door_e path, + ref uvm_reg_map map); + endtask: pre_write + virtual task post_write(longint unsigned idx, + uvm_reg_data_t wdat, + uvm_door_e path, + uvm_reg_map map, + ref uvm_status_e status); + endtask: post_write + virtual task pre_read(longint unsigned idx, + ref uvm_door_e path, + ref uvm_reg_map map); + endtask: pre_read + virtual task post_read(longint unsigned idx, + ref uvm_reg_data_t rdat, + input uvm_door_e path, + input uvm_reg_map map, + ref uvm_status_e status); + endtask: post_read + extern virtual function void do_print (uvm_printer printer); + extern virtual function string convert2string; + extern virtual function uvm_object clone(); + extern virtual function void do_copy (uvm_object rhs); + extern virtual function bit do_compare (uvm_object rhs, + uvm_comparer comparer); + extern virtual function void do_pack (uvm_packer packer); + extern virtual function void do_unpack (uvm_packer packer); +endclass: uvm_vreg +virtual class uvm_vreg_cbs extends uvm_callback; + typedef uvm_abstract_object_registry#(uvm_vreg_cbs,"uvm_vreg_cbs") type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_vreg_cbs"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_vreg_cbs"; + endfunction : get_type_name + string fname; + int lineno; + function new(string name = "uvm_reg_cbs"); + super.new(name); + endfunction + virtual task pre_write(uvm_vreg rg, + longint unsigned idx, + ref uvm_reg_data_t wdat, + ref uvm_door_e path, + ref uvm_reg_map map); + endtask: pre_write + virtual task post_write(uvm_vreg rg, + longint unsigned idx, + uvm_reg_data_t wdat, + uvm_door_e path, + uvm_reg_map map, + ref uvm_status_e status); + endtask: post_write + virtual task pre_read(uvm_vreg rg, + longint unsigned idx, + ref uvm_door_e path, + ref uvm_reg_map map); + endtask: pre_read + virtual task post_read(uvm_vreg rg, + longint unsigned idx, + ref uvm_reg_data_t rdat, + input uvm_door_e path, + input uvm_reg_map map, + ref uvm_status_e status); + endtask: post_read +endclass: uvm_vreg_cbs +typedef uvm_callbacks#(uvm_vreg, uvm_vreg_cbs) uvm_vreg_cb ; +typedef uvm_callback_iter#(uvm_vreg, uvm_vreg_cbs) uvm_vreg_cb_iter ; +function uvm_vreg::new(string name, + int unsigned n_bits); + super.new(name); + if (n_bits == 0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Virtual register \"%s\" cannot have 0 bits", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 425, "", 1); + end + n_bits = 1; + end + if (n_bits > 64) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Virtual register \"%s\" cannot have more than %0d bits (%0d)", this.get_full_name(), 64, n_bits), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 429, "", 1); + end + n_bits = 64; + end + this.n_bits = n_bits; + this.locked = 0; +endfunction: new +function void uvm_vreg::configure(uvm_reg_block parent, + uvm_mem mem = null, + longint unsigned size = 0, + uvm_reg_addr_t offset = 0, + int unsigned incr = 0); + this.parent = parent; + this.n_used_bits = 0; + if (mem != null) begin + void'(this.implement(size, mem, offset, incr)); + this.is_static = 1; + end + else begin + this.mem = null; + this.is_static = 0; + end + this.parent.add_vreg(this); + this.atomic = new(1); +endfunction: configure +function void uvm_vreg::Xlock_modelX(); + if (this.locked) return; + this.locked = 1; +endfunction: Xlock_modelX +function void uvm_vreg::add_field(uvm_vreg_field field); + int offset; + int idx; + if (this.locked) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", "Cannot add virtual field to locked virtual register model", UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 473, "", 1); + end + return; + end + if (field == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"RegModel")) + uvm_report_fatal ("RegModel", "Attempting to register NULL virtual field", UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 477, "", 1); + end + offset = field.get_lsb_pos_in_register(); + idx = -1; + foreach (this.fields[i]) begin + if (offset < this.fields[i].get_lsb_pos_in_register()) begin + int j = i; + this.fields.insert(j, field); + idx = i; + break; + end + end + if (idx < 0) begin + this.fields.push_back(field); + idx = this.fields.size()-1; + end + this.n_used_bits += field.get_n_bits(); + if (this.n_used_bits > this.n_bits) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Virtual fields use more bits (%0d) than available in virtual register \"%s\" (%0d)", this.n_used_bits, this.get_full_name(), this.n_bits), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 501, "", 1); + end + end + if (idx > 0) begin + if (this.fields[idx-1].get_lsb_pos_in_register() + + this.fields[idx-1].get_n_bits() > offset) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Field %s overlaps field %s in virtual register \"%s\"", this.fields[idx-1].get_name(), field.get_name(), this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 511, "", 1); + end + end + end + if (idx < this.fields.size()-1) begin + if (offset + field.get_n_bits() > + this.fields[idx+1].get_lsb_pos_in_register()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Field %s overlaps field %s in virtual register \"%s\"", field.get_name(), this.fields[idx+1].get_name(), this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 520, "", 1); + end + end + end +endfunction: add_field +task uvm_vreg::XatomicX(bit on); + if (on) this.atomic.get(1); + else begin + void'(this.atomic.try_get(1)); + this.atomic.put(1); + end +endtask: XatomicX +function void uvm_vreg::reset(string kind = "HARD"); + void'(this.atomic.try_get(1)); + this.atomic.put(1); +endfunction: reset +function string uvm_vreg::get_full_name(); + uvm_reg_block blk; + get_full_name = this.get_name(); + blk = this.get_block(); + if (blk == null) return get_full_name; + if (blk.get_parent() == null) return get_full_name; + get_full_name = {this.parent.get_full_name(), ".", get_full_name}; +endfunction: get_full_name +function void uvm_vreg::set_parent(uvm_reg_block parent); + this.parent = parent; +endfunction: set_parent +function uvm_reg_block uvm_vreg::get_parent(); + get_parent = this.parent; +endfunction: get_parent +function uvm_reg_block uvm_vreg::get_block(); + get_block = this.parent; +endfunction: get_block +function bit uvm_vreg::implement(longint unsigned n, + uvm_mem mem = null, + uvm_reg_addr_t offset = 0, + int unsigned incr = 0); + uvm_mem_region region; + if(n < 1) + begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Attempting to implement virtual register \"%s\" with a subscript less than one doesn't make sense",this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 579, "", 1); + end + return 0; + end + if (mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Attempting to implement virtual register \"%s\" using a NULL uvm_mem reference", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 584, "", 1); + end + return 0; + end + if (this.is_static) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Virtual register \"%s\" is static and cannot be dynamically implemented", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 589, "", 1); + end + return 0; + end + if (mem.get_block() != this.parent) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Attempting to implement virtual register \"%s\" on memory \"%s\" in a different block", this.get_full_name(), mem.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 596, "", 1); + end + return 0; + end + begin + int min_incr = (this.get_n_bytes()-1) / mem.get_n_bytes() + 1; + if (incr == 0) incr = min_incr; + if (min_incr > incr) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Virtual register \"%s\" increment is too small (%0d): Each virtual register requires at least %0d locations in memory \"%s\".", this.get_full_name(), incr, min_incr, mem.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 606, "", 1); + end + return 0; + end + end + if (offset + (n * incr) > mem.get_size()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Given Offset for Virtual register \"%s[%0d]\" is too big for memory %s@'h%0h", this.get_full_name(), n, mem.get_full_name(), offset), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 613, "", 1); + end + return 0; + end + region = mem.mam.reserve_region(offset,n*incr*mem.get_n_bytes()); + if (region == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Could not allocate a memory region for virtual register \"%s\"", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 620, "", 1); + end + return 0; + end + if (this.mem != null) begin + begin + if (uvm_report_enabled(UVM_MEDIUM,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", $sformatf("Virtual register \"%s\" is being moved re-implemented from %s@'h%0h to %s@'h%0h", this.get_full_name(), this.mem.get_full_name(), this.offset, mem.get_full_name(), offset), UVM_MEDIUM, "t/uvm/src/reg/uvm_vreg.svh", 629, "", 1); + end + this.release_region(); + end + this.region = region; + this.mem = mem; + this.size = n; + this.offset = offset; + this.incr = incr; + this.mem.Xadd_vregX(this); + return 1; +endfunction: implement +function uvm_mem_region uvm_vreg::allocate(longint unsigned n, + uvm_mem_mam mam, + uvm_mem_mam_policy alloc=null); + uvm_mem mem; + if(n < 1) + begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Attempting to implement virtual register \"%s\" with a subscript less than one doesn't make sense",this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 652, "", 1); + end + return null; + end + if (mam == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Attempting to implement virtual register \"%s\" using a NULL uvm_mem_mam reference", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 657, "", 1); + end + return null; + end + if (this.is_static) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Virtual register \"%s\" is static and cannot be dynamically allocated", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 662, "", 1); + end + return null; + end + mem = mam.get_memory(); + if (mem.get_block() != this.parent) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Attempting to allocate virtual register \"%s\" on memory \"%s\" in a different block", this.get_full_name(), mem.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 670, "", 1); + end + return null; + end + begin + int min_incr = (this.get_n_bytes()-1) / mem.get_n_bytes() + 1; + if (incr == 0) incr = min_incr; + if (min_incr < incr) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Virtual register \"%s\" increment is too small (%0d): Each virtual register requires at least %0d locations in memory \"%s\".", this.get_full_name(), incr, min_incr, mem.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 680, "", 1); + end + return null; + end + end + allocate = mam.request_region(n*incr*mem.get_n_bytes(), alloc); + if (allocate == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Could not allocate a memory region for virtual register \"%s\"", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 688, "", 1); + end + return null; + end + if (this.mem != null) begin + begin + if (uvm_report_enabled(UVM_MEDIUM,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", $sformatf("Virtual register \"%s\" is being moved from %s@'h%0h to %s@'h%0h", this.get_full_name(), this.mem.get_full_name(), this.offset, mem.get_full_name(), allocate.get_start_offset()), UVM_MEDIUM, "t/uvm/src/reg/uvm_vreg.svh", 698, "", 1); + end + this.release_region(); + end + this.region = allocate; + this.mem = mam.get_memory(); + this.offset = allocate.get_start_offset(); + this.size = n; + this.incr = incr; + this.mem.Xadd_vregX(this); +endfunction: allocate +function uvm_mem_region uvm_vreg::get_region(); + return this.region; +endfunction: get_region +function void uvm_vreg::release_region(); + if (this.is_static) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Virtual register \"%s\" is static and cannot be dynamically released", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 721, "", 1); + end + return; + end + if (this.mem != null) + this.mem.Xdelete_vregX(this); + if (this.region != null) begin + this.region.release_region(); + end + this.region = null; + this.mem = null; + this.size = 0; + this.offset = 0; + this.reset(); +endfunction: release_region +function uvm_mem uvm_vreg::get_memory(); + return this.mem; +endfunction: get_memory +function uvm_reg_addr_t uvm_vreg::get_offset_in_memory(longint unsigned idx); + if (this.mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot call uvm_vreg::get_offset_in_memory() on unimplemented virtual register \"%s\"", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 749, "", 1); + end + return 0; + end + return this.offset + idx * this.incr; +endfunction +function uvm_reg_addr_t uvm_vreg::get_address(longint unsigned idx, + uvm_reg_map map = null); + if (this.mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot get address of of unimplemented virtual register \"%s\".", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 760, "", 1); + end + return 0; + end + return this.mem.get_address(this.get_offset_in_memory(idx), map); +endfunction: get_address +function int unsigned uvm_vreg::get_size(); + if (this.size == 0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot call uvm_vreg::get_size() on unimplemented virtual register \"%s\"", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 771, "", 1); + end + return 0; + end + return this.size; +endfunction: get_size +function int unsigned uvm_vreg::get_n_bytes(); + return ((this.n_bits-1) / 8) + 1; +endfunction: get_n_bytes +function int unsigned uvm_vreg::get_n_memlocs(); + if (this.mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot call uvm_vreg::get_n_memlocs() on unimplemented virtual register \"%s\"", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 787, "", 1); + end + return 0; + end + return (this.get_n_bytes()-1) / this.mem.get_n_bytes() + 1; +endfunction: get_n_memlocs +function int unsigned uvm_vreg::get_incr(); + if (this.incr == 0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot call uvm_vreg::get_incr() on unimplemented virtual register \"%s\"", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 798, "", 1); + end + return 0; + end + return this.incr; +endfunction: get_incr +function int uvm_vreg::get_n_maps(); + if (this.mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot call uvm_vreg::get_n_maps() on unimplemented virtual register \"%s\"", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 809, "", 1); + end + return 0; + end + return this.mem.get_n_maps(); +endfunction: get_n_maps +function void uvm_vreg::get_maps(ref uvm_reg_map maps[$]); + if (this.mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot call uvm_vreg::get_maps() on unimplemented virtual register \"%s\"", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 820, "", 1); + end + return; + end + this.mem.get_maps(maps); +endfunction: get_maps +function bit uvm_vreg::is_in_map(uvm_reg_map map); + if (this.mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot call uvm_vreg::is_in_map() on unimplemented virtual register \"%s\"", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 831, "", 1); + end + return 0; + end + return this.mem.is_in_map(map); +endfunction +function string uvm_vreg::get_access(uvm_reg_map map = null); + if (this.mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot call uvm_vreg::get_rights() on unimplemented virtual register \"%s\"", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 842, "", 1); + end + return "RW"; + end + return this.mem.get_access(map); +endfunction: get_access +function string uvm_vreg::get_rights(uvm_reg_map map = null); + if (this.mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot call uvm_vreg::get_rights() on unimplemented virtual register \"%s\"", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 853, "", 1); + end + return "RW"; + end + return this.mem.get_rights(map); +endfunction: get_rights +function void uvm_vreg::get_fields(ref uvm_vreg_field fields[$]); + foreach(this.fields[i]) + fields.push_back(this.fields[i]); +endfunction: get_fields +function uvm_vreg_field uvm_vreg::get_field_by_name(string name); + foreach (this.fields[i]) begin + if (this.fields[i].get_name() == name) begin + return this.fields[i]; + end + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", $sformatf("Unable to locate field \"%s\" in virtual register \"%s\".", name, this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 874, "", 1); + end + get_field_by_name = null; +endfunction: get_field_by_name +task uvm_vreg::write(input longint unsigned idx, + output uvm_status_e status, + input uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_vreg_cb_iter cbs = new(this); + uvm_reg_addr_t addr; + uvm_reg_data_t tmp; + uvm_reg_data_t msk; + int lsb; + this.write_in_progress = 1'b1; + this.fname = fname; + this.lineno = lineno; + if (this.mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot write to unimplemented virtual register \"%s\".", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 899, "", 1); + end + status = UVM_NOT_OK; + return; + end + if (path == UVM_DEFAULT_DOOR) + path = this.parent.get_default_door(); + foreach (fields[i]) begin + uvm_vreg_field_cb_iter cbs = new(fields[i]); + uvm_vreg_field f = fields[i]; + lsb = f.get_lsb_pos_in_register(); + msk = ((1<> lsb; + f.pre_write(idx, tmp, path, map); + for (uvm_vreg_field_cbs cb = cbs.first(); cb != null; + cb = cbs.next()) begin + cb.fname = this.fname; + cb.lineno = this.lineno; + cb.pre_write(f, idx, tmp, path, map); + end + value = (value & ~msk) | (tmp << lsb); + end + this.pre_write(idx, value, path, map); + for (uvm_vreg_cbs cb = cbs.first(); cb != null; + cb = cbs.next()) begin + cb.fname = this.fname; + cb.lineno = this.lineno; + cb.pre_write(this, idx, value, path, map); + end + addr = this.offset + (idx * this.incr); + lsb = 0; + status = UVM_IS_OK; + for (int i = 0; i < this.get_n_memlocs(); i++) begin + uvm_status_e s; + msk = ((1<<(this.mem.get_n_bytes()*8))-1) << lsb; + tmp = (value & msk) >> lsb; + this.mem.write(s, addr + i, tmp, path, map , parent, , extension, fname, lineno); + if (s != UVM_IS_OK && s != UVM_HAS_X) status = s; + lsb += this.mem.get_n_bytes() * 8; + end + for (uvm_vreg_cbs cb = cbs.first(); cb != null; + cb = cbs.next()) begin + cb.fname = this.fname; + cb.lineno = this.lineno; + cb.post_write(this, idx, value, path, map, status); + end + this.post_write(idx, value, path, map, status); + foreach (fields[i]) begin + uvm_vreg_field_cb_iter cbs = new(fields[i]); + uvm_vreg_field f = fields[i]; + lsb = f.get_lsb_pos_in_register(); + msk = ((1<> lsb; + for (uvm_vreg_field_cbs cb = cbs.first(); cb != null; + cb = cbs.next()) begin + cb.fname = this.fname; + cb.lineno = this.lineno; + cb.post_write(f, idx, tmp, path, map, status); + end + f.post_write(idx, tmp, path, map, status); + value = (value & ~msk) | (tmp << lsb); + end + begin + if (uvm_report_enabled(UVM_MEDIUM,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", $sformatf("Wrote virtual register \"%s\"[%0d] via %s with: 'h%h", this.get_full_name(), idx, (path == UVM_FRONTDOOR) ? "frontdoor" : "backdoor", value), UVM_MEDIUM, "t/uvm/src/reg/uvm_vreg.svh", 976, "", 1); + end + this.write_in_progress = 1'b0; + this.fname = ""; + this.lineno = 0; +endtask: write +task uvm_vreg::read(input longint unsigned idx, + output uvm_status_e status, + output uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_vreg_cb_iter cbs = new(this); + uvm_reg_addr_t addr; + uvm_reg_data_t tmp; + uvm_reg_data_t msk; + int lsb; + this.read_in_progress = 1'b1; + this.fname = fname; + this.lineno = lineno; + if (this.mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot read from unimplemented virtual register \"%s\".", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 1005, "", 1); + end + status = UVM_NOT_OK; + return; + end + if (path == UVM_DEFAULT_DOOR) + path = this.parent.get_default_door(); + foreach (fields[i]) begin + uvm_vreg_field_cb_iter cbs = new(fields[i]); + uvm_vreg_field f = fields[i]; + f.pre_read(idx, path, map); + for (uvm_vreg_field_cbs cb = cbs.first(); cb != null; + cb = cbs.next()) begin + cb.fname = this.fname; + cb.lineno = this.lineno; + cb.pre_read(f, idx, path, map); + end + end + this.pre_read(idx, path, map); + for (uvm_vreg_cbs cb = cbs.first(); cb != null; + cb = cbs.next()) begin + cb.fname = this.fname; + cb.lineno = this.lineno; + cb.pre_read(this, idx, path, map); + end + addr = this.offset + (idx * this.incr); + lsb = 0; + value = 0; + status = UVM_IS_OK; + for (int i = 0; i < this.get_n_memlocs(); i++) begin + uvm_status_e s; + this.mem.read(s, addr + i, tmp, path, map, parent, , extension, fname, lineno); + if (s != UVM_IS_OK && s != UVM_HAS_X) status = s; + value |= tmp << lsb; + lsb += this.mem.get_n_bytes() * 8; + end + for (uvm_vreg_cbs cb = cbs.first(); cb != null; + cb = cbs.next()) begin + cb.fname = this.fname; + cb.lineno = this.lineno; + cb.post_read(this, idx, value, path, map, status); + end + this.post_read(idx, value, path, map, status); + foreach (fields[i]) begin + uvm_vreg_field_cb_iter cbs = new(fields[i]); + uvm_vreg_field f = fields[i]; + lsb = f.get_lsb_pos_in_register(); + msk = ((1<> lsb; + for (uvm_vreg_field_cbs cb = cbs.first(); cb != null; + cb = cbs.next()) begin + cb.fname = this.fname; + cb.lineno = this.lineno; + cb.post_read(f, idx, tmp, path, map, status); + end + f.post_read(idx, tmp, path, map, status); + value = (value & ~msk) | (tmp << lsb); + end + begin + if (uvm_report_enabled(UVM_MEDIUM,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", $sformatf("Read virtual register \"%s\"[%0d] via %s: 'h%h", this.get_full_name(), idx, (path == UVM_FRONTDOOR) ? "frontdoor" : "backdoor", value), UVM_MEDIUM, "t/uvm/src/reg/uvm_vreg.svh", 1078, "", 1); + end + this.read_in_progress = 1'b0; + this.fname = ""; + this.lineno = 0; +endtask: read +task uvm_vreg::poke(input longint unsigned idx, + output uvm_status_e status, + input uvm_reg_data_t value, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_addr_t addr; + uvm_reg_data_t tmp; + uvm_reg_data_t msk; + int lsb; + this.fname = fname; + this.lineno = lineno; + if (this.mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot poke in unimplemented virtual register \"%s\".", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 1101, "", 1); + end + status = UVM_NOT_OK; + return; + end + addr = this.offset + (idx * this.incr); + lsb = 0; + status = UVM_IS_OK; + for (int i = 0; i < this.get_n_memlocs(); i++) begin + uvm_status_e s; + msk = ((1<<(this.mem.get_n_bytes() * 8))-1) << lsb; + tmp = (value & msk) >> lsb; + this.mem.poke(status, addr + i, tmp, "", parent, extension, fname, lineno); + if (s != UVM_IS_OK && s != UVM_HAS_X) status = s; + lsb += this.mem.get_n_bytes() * 8; + end + begin + if (uvm_report_enabled(UVM_MEDIUM,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", $sformatf("Poked virtual register \"%s\"[%0d] with: 'h%h", this.get_full_name(), idx, value), UVM_MEDIUM, "t/uvm/src/reg/uvm_vreg.svh", 1123, "", 1); + end + this.fname = ""; + this.lineno = 0; +endtask: poke +task uvm_vreg::peek(input longint unsigned idx, + output uvm_status_e status, + output uvm_reg_data_t value, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_addr_t addr; + uvm_reg_data_t tmp; + uvm_reg_data_t msk; + int lsb; + this.fname = fname; + this.lineno = lineno; + if (this.mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot peek in from unimplemented virtual register \"%s\".", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 1145, "", 1); + end + status = UVM_NOT_OK; + return; + end + addr = this.offset + (idx * this.incr); + lsb = 0; + value = 0; + status = UVM_IS_OK; + for (int i = 0; i < this.get_n_memlocs(); i++) begin + uvm_status_e s; + this.mem.peek(status, addr + i, tmp, "", parent, extension, fname, lineno); + if (s != UVM_IS_OK && s != UVM_HAS_X) status = s; + value |= tmp << lsb; + lsb += this.mem.get_n_bytes() * 8; + end + begin + if (uvm_report_enabled(UVM_MEDIUM,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", $sformatf("Peeked virtual register \"%s\"[%0d]: 'h%h", this.get_full_name(), idx, value), UVM_MEDIUM, "t/uvm/src/reg/uvm_vreg.svh", 1166, "", 1); + end + this.fname = ""; + this.lineno = 0; +endtask: peek +function void uvm_vreg::do_print (uvm_printer printer); + super.do_print(printer); + printer.print_generic("initiator", parent.get_type_name(), -1, convert2string()); +endfunction +function string uvm_vreg::convert2string(); + string res_str; + string t_str; + bit with_debug_info; + $sformat(convert2string, "Virtual register %s -- ", + this.get_full_name()); + if (this.size == 0) + $sformat(convert2string, "%sunimplemented", convert2string); + else begin + uvm_reg_map maps[$]; + mem.get_maps(maps); + $sformat(convert2string, "%s[%0d] in %0s['h%0h+'h%0h]\n", convert2string, + this.size, this.mem.get_full_name(), this.offset, this.incr); + foreach (maps[i]) begin + uvm_reg_addr_t addr0 = this.get_address(0, maps[i]); + $sformat(convert2string, " Address in map '%s' -- @'h%0h+%0h", + maps[i].get_full_name(), addr0, this.get_address(1, maps[i]) - addr0); + end + end + foreach(this.fields[i]) begin + $sformat(convert2string, "%s\n%s", convert2string, + this.fields[i].convert2string()); + end +endfunction: convert2string +function uvm_object uvm_vreg::clone(); + return null; +endfunction +function void uvm_vreg::do_copy (uvm_object rhs); +endfunction +function bit uvm_vreg::do_compare (uvm_object rhs, + uvm_comparer comparer); + return 0; +endfunction +function void uvm_vreg::do_pack (uvm_packer packer); +endfunction +function void uvm_vreg::do_unpack (uvm_packer packer); +endfunction +class uvm_mem extends uvm_object; + typedef enum {UNKNOWNS, ZEROES, ONES, ADDRESS, VALUE, INCR, DECR} init_e; + local bit m_locked; + local bit m_read_in_progress; + local bit m_write_in_progress; + local string m_access; + local longint unsigned m_size; + local uvm_reg_block m_parent; + local bit m_maps[uvm_reg_map]; + local int unsigned m_n_bits; + local uvm_reg_backdoor m_backdoor; + local bit m_is_powered_down; + local int m_has_cover; + local int m_cover_on; + local string m_fname; + local int m_lineno; + local bit m_vregs[uvm_vreg]; + local uvm_object_string_pool + #(uvm_queue #(uvm_hdl_path_concat)) m_hdl_paths_pool; + local static int unsigned m_max_size; + extern function new (string name, + longint unsigned size, + int unsigned n_bits, + string access = "RW", + int has_coverage = UVM_NO_COVERAGE); + extern function void configure (uvm_reg_block parent, + string hdl_path = ""); + extern virtual function void set_offset (uvm_reg_map map, + uvm_reg_addr_t offset, + bit unmapped = 0); + extern virtual function void set_parent(uvm_reg_block parent); + extern function void add_map(uvm_reg_map map); + extern function void Xlock_modelX(); + extern function void Xadd_vregX(uvm_vreg vreg); + extern function void Xdelete_vregX(uvm_vreg vreg); + uvm_mem_mam mam; + extern virtual function string get_full_name(); + extern virtual function uvm_reg_block get_parent (); + extern virtual function uvm_reg_block get_block (); + extern virtual function int get_n_maps (); + extern function bit is_in_map (uvm_reg_map map); + extern virtual function void get_maps (ref uvm_reg_map maps[$]); + extern function uvm_reg_map get_local_map (uvm_reg_map map); + extern function uvm_reg_map get_default_map (); + extern virtual function string get_rights (uvm_reg_map map = null); + extern virtual function string get_access(uvm_reg_map map = null); + extern function longint unsigned get_size(); + extern function int unsigned get_n_bytes(); + extern function int unsigned get_n_bits(); + extern static function int unsigned get_max_size(); + extern virtual function void get_virtual_registers(ref uvm_vreg regs[$]); + extern virtual function void get_virtual_fields(ref uvm_vreg_field fields[$]); + extern virtual function uvm_vreg get_vreg_by_name(string name); + extern virtual function uvm_vreg_field get_vfield_by_name(string name); + extern virtual function uvm_vreg get_vreg_by_offset(uvm_reg_addr_t offset, + uvm_reg_map map = null); + extern virtual function uvm_reg_addr_t get_offset (uvm_reg_addr_t offset = 0, + uvm_reg_map map = null); + extern virtual function uvm_reg_addr_t get_address(uvm_reg_addr_t offset = 0, + uvm_reg_map map = null); + extern virtual function int get_addresses(uvm_reg_addr_t offset = 0, + uvm_reg_map map=null, + ref uvm_reg_addr_t addr[]); + extern virtual task write(output uvm_status_e status, + input uvm_reg_addr_t offset, + input uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + extern virtual task read(output uvm_status_e status, + input uvm_reg_addr_t offset, + output uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + extern virtual task burst_write(output uvm_status_e status, + input uvm_reg_addr_t offset, + input uvm_reg_data_t value[], + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + extern virtual task burst_read(output uvm_status_e status, + input uvm_reg_addr_t offset, + ref uvm_reg_data_t value[], + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + extern virtual task poke(output uvm_status_e status, + input uvm_reg_addr_t offset, + input uvm_reg_data_t value, + input string kind = "", + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + extern virtual task peek(output uvm_status_e status, + input uvm_reg_addr_t offset, + output uvm_reg_data_t value, + input string kind = "", + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + extern protected function bit Xcheck_accessX (input uvm_reg_item rw, + output uvm_reg_map_info map_info); + extern virtual task do_write (uvm_reg_item rw); + extern virtual task do_read (uvm_reg_item rw); + extern function void set_frontdoor(uvm_reg_frontdoor ftdr, + uvm_reg_map map = null, + string fname = "", + int lineno = 0); + extern function uvm_reg_frontdoor get_frontdoor(uvm_reg_map map = null); + extern function void set_backdoor (uvm_reg_backdoor bkdr, + string fname = "", + int lineno = 0); + extern function uvm_reg_backdoor get_backdoor(bit inherited = 1); + extern function void clear_hdl_path (string kind = "RTL"); + extern function void add_hdl_path (uvm_hdl_path_slice slices[], + string kind = "RTL"); + extern function void add_hdl_path_slice(string name, + int offset, + int size, + bit first = 0, + string kind = "RTL"); + extern function bit has_hdl_path (string kind = ""); + extern function void get_hdl_path (ref uvm_hdl_path_concat paths[$], + input string kind = ""); + extern function void get_full_hdl_path (ref uvm_hdl_path_concat paths[$], + input string kind = "", + input string separator = "."); + extern function void get_hdl_path_kinds (ref string kinds[$]); + extern virtual protected task backdoor_read(uvm_reg_item rw); + extern virtual task backdoor_write(uvm_reg_item rw); + extern virtual function uvm_status_e backdoor_read_func(uvm_reg_item rw); + static local bit m_register_cb_uvm_reg_cbs = uvm_callbacks#(uvm_mem,uvm_reg_cbs)::m_register_pair("uvm_mem","uvm_reg_cbs"); + virtual task pre_write(uvm_reg_item rw); endtask + virtual task post_write(uvm_reg_item rw); endtask + virtual task pre_read(uvm_reg_item rw); endtask + virtual task post_read(uvm_reg_item rw); endtask + extern protected function uvm_reg_cvr_t build_coverage(uvm_reg_cvr_t models); + extern virtual protected function void add_coverage(uvm_reg_cvr_t models); + extern virtual function bit has_coverage(uvm_reg_cvr_t models); + extern virtual function uvm_reg_cvr_t set_coverage(uvm_reg_cvr_t is_on); + extern virtual function bit get_coverage(uvm_reg_cvr_t is_on); + protected virtual function void sample(uvm_reg_addr_t offset, + bit is_read, + uvm_reg_map map); + endfunction + function void XsampleX(uvm_reg_addr_t addr, + bit is_read, + uvm_reg_map map); + sample(addr, is_read, map); + endfunction + extern virtual function void do_print (uvm_printer printer); + extern virtual function string convert2string(); + extern virtual function uvm_object clone(); + extern virtual function void do_copy (uvm_object rhs); + extern virtual function bit do_compare (uvm_object rhs, + uvm_comparer comparer); + extern virtual function void do_pack (uvm_packer packer); + extern virtual function void do_unpack (uvm_packer packer); +endclass: uvm_mem +function uvm_mem::new (string name, + longint unsigned size, + int unsigned n_bits, + string access = "RW", + int has_coverage = UVM_NO_COVERAGE); + super.new(name); + m_locked = 0; + if (n_bits == 0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Memory '",get_full_name(),"' cannot have 0 bits"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 537, "", 1); + end + n_bits = 1; + end + m_size = size; + m_n_bits = n_bits; + m_backdoor = null; + m_access = access.toupper(); + m_has_cover = has_coverage; + m_hdl_paths_pool = new("hdl_paths"); + if (n_bits > m_max_size) + m_max_size = n_bits; +endfunction: new +function void uvm_mem::configure(uvm_reg_block parent, + string hdl_path=""); + if (parent == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"REG/NULL_PARENT")) + uvm_report_fatal ("REG/NULL_PARENT", "configure: parent argument is null", UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 559, "", 1); + end + m_parent = parent; + if (m_access != "RW" && m_access != "RO") begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Memory '",get_full_name(),"' can only be RW or RO"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 564, "", 1); + end + m_access = "RW"; + end + begin + uvm_mem_mam_cfg cfg = new; + cfg.n_bytes = ((m_n_bits-1) / 8) + 1; + cfg.start_offset = 0; + cfg.end_offset = m_size-1; + cfg.mode = uvm_mem_mam::GREEDY; + cfg.locality = uvm_mem_mam::BROAD; + mam = new(get_full_name(), cfg, this); + end + m_parent.add_mem(this); + if (hdl_path != "") add_hdl_path_slice(hdl_path, -1, -1); +endfunction: configure +function void uvm_mem::set_offset (uvm_reg_map map, + uvm_reg_addr_t offset, + bit unmapped = 0); + uvm_reg_map orig_map = map; + if (m_maps.num() > 1 && map == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"set_offset requires a non-null map when memory '", get_full_name(),"' belongs to more than one map."}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 597, "", 1); + end + return; + end + map = get_local_map(map); + if (map == null) + return; + map.m_set_mem_offset(this, offset, unmapped); +endfunction +function void uvm_mem::add_map(uvm_reg_map map); + m_maps[map] = 1; +endfunction +function void uvm_mem::Xlock_modelX(); + m_locked = 1; +endfunction: Xlock_modelX +function string uvm_mem::get_full_name(); + if (m_parent == null) + return get_name(); + return {m_parent.get_full_name(), ".", get_name()}; +endfunction: get_full_name +function uvm_reg_block uvm_mem::get_block(); + return m_parent; +endfunction: get_block +function int uvm_mem::get_n_maps(); + return m_maps.num(); +endfunction: get_n_maps +function void uvm_mem::get_maps(ref uvm_reg_map maps[$]); + foreach (m_maps[map]) + maps.push_back(map); +endfunction +function bit uvm_mem::is_in_map(uvm_reg_map map); + if (m_maps.exists(map)) + return 1; + foreach (m_maps[l]) begin + uvm_reg_map local_map=l; + uvm_reg_map parent_map = local_map.get_parent_map(); + while (parent_map != null) begin + if (parent_map == map) + return 1; + parent_map = parent_map.get_parent_map(); + end + end + return 0; +endfunction +function uvm_reg_map uvm_mem::get_local_map(uvm_reg_map map); + if (map == null) + return get_default_map(); + if (m_maps.exists(map)) + return map; + foreach (m_maps[l]) begin + uvm_reg_map local_map = l; + uvm_reg_map parent_map = local_map.get_parent_map(); + while (parent_map != null) begin + if (parent_map == map) + return local_map; + parent_map = parent_map.get_parent_map(); + end + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Memory '",get_full_name(),"' is not contained within map '",map.get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 694, "", 1); + end + return null; +endfunction +function uvm_reg_map uvm_mem::get_default_map(); + if (m_maps.num() == 0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Memory '",get_full_name(),"' is not registered with any map"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 706, "", 1); + end + return null; + end + if (m_maps.num() == 1) begin + void'(m_maps.first(get_default_map)); + end + foreach (m_maps[l]) begin + uvm_reg_map map = l; + uvm_reg_block blk = map.get_parent(); + uvm_reg_map default_map = blk.get_default_map(); + if (default_map != null) begin + uvm_reg_map local_map = get_local_map(default_map); + if (local_map != null) + return local_map; + end + end + void'(m_maps.first(get_default_map)); +endfunction +function string uvm_mem::get_access(uvm_reg_map map = null); + get_access = m_access; + if (get_n_maps() == 1) return get_access; + map = get_local_map(map); + if (map == null) return get_access; + case (get_rights(map)) + "RW": + return get_access; + "RO": + case (get_access) + "RW", "RO": get_access = "RO"; + "WO": + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"WO memory '",get_full_name(), "' restricted to RO in map '",map.get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 754, "", 1); + end + default: + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Memory '",get_full_name(), "' has invalid access mode, '",get_access,"'"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 757, "", 1); + end + endcase + "WO": + case (get_access) + "RW", "WO": get_access = "WO"; + "RO": + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"RO memory '",get_full_name(), "' restricted to WO in map '",map.get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 765, "", 1); + end + default: + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Memory '",get_full_name(), "' has invalid access mode, '",get_access,"'"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 768, "", 1); + end + endcase + default: + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Shared memory '",get_full_name(), "' is not shared in map '",map.get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 772, "", 1); + end + endcase +endfunction: get_access +function string uvm_mem::get_rights(uvm_reg_map map = null); + uvm_reg_map_info info; + if (m_maps.num() <= 1) begin + return "RW"; + end + map = get_local_map(map); + if (map == null) + return "RW"; + info = map.get_mem_map_info(this); + return info.rights; +endfunction: get_rights +function uvm_reg_addr_t uvm_mem::get_offset(uvm_reg_addr_t offset = 0, + uvm_reg_map map = null); + uvm_reg_map_info map_info; + uvm_reg_map orig_map = map; + map = get_local_map(map); + if (map == null) + return -1; + map_info = map.get_mem_map_info(this); + if (map_info.unmapped) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Memory '",get_name(), "' is unmapped in map '", ((orig_map == null) ? map.get_full_name() : orig_map.get_full_name()),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 817, "", 1); + end + return -1; + end + return map_info.offset; +endfunction: get_offset +function void uvm_mem::get_virtual_registers(ref uvm_vreg regs[$]); + foreach (m_vregs[vreg]) + regs.push_back(vreg); +endfunction +function void uvm_mem::get_virtual_fields(ref uvm_vreg_field fields[$]); + foreach (m_vregs[l]) + begin + uvm_vreg vreg = l; + vreg.get_fields(fields); + end +endfunction: get_virtual_fields +function uvm_vreg_field uvm_mem::get_vfield_by_name(string name); + uvm_vreg_field vfields[$]; + get_virtual_fields(vfields); + foreach (vfields[i]) + if (vfields[i].get_name() == name) + return vfields[i]; + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Unable to find virtual field '",name, "' in memory '",get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 860, "", 1); + end + return null; +endfunction: get_vfield_by_name +function uvm_vreg uvm_mem::get_vreg_by_name(string name); + foreach (m_vregs[l]) + begin + uvm_vreg vreg = l; + if (vreg.get_name() == name) + return vreg; + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Unable to find virtual register '",name, "' in memory '",get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 877, "", 1); + end + return null; +endfunction: get_vreg_by_name +function uvm_vreg uvm_mem::get_vreg_by_offset(uvm_reg_addr_t offset, + uvm_reg_map map = null); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", "uvm_mem::get_vreg_by_offset() not yet implemented", UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 887, "", 1); + end + return null; +endfunction: get_vreg_by_offset +function int uvm_mem::get_addresses(uvm_reg_addr_t offset = 0, + uvm_reg_map map=null, + ref uvm_reg_addr_t addr[]); + uvm_reg_map_info map_info; + uvm_reg_map system_map; + uvm_reg_map orig_map = map; + map = get_local_map(map); + if (map == null) + return 0; + map_info = map.get_mem_map_info(this); + if (map_info.unmapped) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Memory '",get_name(), "' is unmapped in map '", ((orig_map == null) ? map.get_full_name() : orig_map.get_full_name()),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 913, "", 1); + end + return 0; + end + addr = map_info.addr; + foreach (addr[i]) + addr[i] = addr[i] + map_info.mem_range.stride * offset; + return map.get_n_bytes(); +endfunction +function uvm_reg_addr_t uvm_mem::get_address(uvm_reg_addr_t offset = 0, + uvm_reg_map map = null); + uvm_reg_addr_t addr[]; + void'(get_addresses(offset, map, addr)); + return addr[0]; +endfunction +function longint unsigned uvm_mem::get_size(); + return m_size; +endfunction: get_size +function int unsigned uvm_mem::get_n_bits(); + return m_n_bits; +endfunction: get_n_bits +function int unsigned uvm_mem::get_max_size(); + return m_max_size; +endfunction: get_max_size +function int unsigned uvm_mem::get_n_bytes(); + return (m_n_bits - 1) / 8 + 1; +endfunction: get_n_bytes +function uvm_reg_cvr_t uvm_mem::build_coverage(uvm_reg_cvr_t models); + build_coverage = UVM_NO_COVERAGE; + void'(uvm_reg_cvr_rsrc_db::read_by_name({"uvm_reg::", get_full_name()}, + "include_coverage", + build_coverage, this)); + return build_coverage & models; +endfunction: build_coverage +function void uvm_mem::add_coverage(uvm_reg_cvr_t models); + m_has_cover |= models; +endfunction: add_coverage +function bit uvm_mem::has_coverage(uvm_reg_cvr_t models); + return ((m_has_cover & models) == models); +endfunction: has_coverage +function uvm_reg_cvr_t uvm_mem::set_coverage(uvm_reg_cvr_t is_on); + if (is_on == uvm_reg_cvr_t'(UVM_NO_COVERAGE)) begin + m_cover_on = is_on; + return m_cover_on; + end + m_cover_on = m_has_cover & is_on; + return m_cover_on; +endfunction: set_coverage +function bit uvm_mem::get_coverage(uvm_reg_cvr_t is_on); + if (has_coverage(is_on) == 0) return 0; + return ((m_cover_on & is_on) == is_on); +endfunction: get_coverage +task uvm_mem::write(output uvm_status_e status, + input uvm_reg_addr_t offset, + input uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_item rw = uvm_reg_item::type_id_create("mem_write",,get_full_name()); + rw.element = this; + rw.element_kind = UVM_MEM; + rw.kind = UVM_WRITE; + rw.offset = offset; + rw.value[0] = value; + rw.path = path; + rw.map = map; + rw.parent = parent; + rw.prior = prior; + rw.extension = extension; + rw.fname = fname; + rw.lineno = lineno; + do_write(rw); + status = rw.status; +endtask: write +task uvm_mem::read(output uvm_status_e status, + input uvm_reg_addr_t offset, + output uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_item rw; + rw = uvm_reg_item::type_id_create("mem_read",,get_full_name()); + rw.element = this; + rw.element_kind = UVM_MEM; + rw.kind = UVM_READ; + rw.value[0] = 0; + rw.offset = offset; + rw.path = path; + rw.map = map; + rw.parent = parent; + rw.prior = prior; + rw.extension = extension; + rw.fname = fname; + rw.lineno = lineno; + do_read(rw); + status = rw.status; + value = rw.value[0]; +endtask: read +task uvm_mem::burst_write(output uvm_status_e status, + input uvm_reg_addr_t offset, + input uvm_reg_data_t value[], + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_item rw; + rw = uvm_reg_item::type_id_create("mem_burst_write",,get_full_name()); + rw.element = this; + rw.element_kind = UVM_MEM; + rw.kind = UVM_BURST_WRITE; + rw.offset = offset; + rw.value = value; + rw.path = path; + rw.map = map; + rw.parent = parent; + rw.prior = prior; + rw.extension = extension; + rw.fname = fname; + rw.lineno = lineno; + do_write(rw); + status = rw.status; +endtask: burst_write +task uvm_mem::burst_read(output uvm_status_e status, + input uvm_reg_addr_t offset, + ref uvm_reg_data_t value[], + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_item rw; + rw = uvm_reg_item::type_id_create("mem_burst_read",,get_full_name()); + rw.element = this; + rw.element_kind = UVM_MEM; + rw.kind = UVM_BURST_READ; + rw.offset = offset; + rw.value = value; + rw.path = path; + rw.map = map; + rw.parent = parent; + rw.prior = prior; + rw.extension = extension; + rw.fname = fname; + rw.lineno = lineno; + do_read(rw); + status = rw.status; + value = rw.value; +endtask: burst_read +task uvm_mem::do_write(uvm_reg_item rw); + uvm_mem_cb_iter cbs = new(this); + uvm_reg_map_info map_info; + m_fname = rw.fname; + m_lineno = rw.lineno; + if (!Xcheck_accessX(rw, map_info)) + return; + m_write_in_progress = 1'b1; + rw.status = UVM_IS_OK; + pre_write(rw); + for (uvm_reg_cbs cb=cbs.first(); cb!=null; cb=cbs.next()) + cb.pre_write(rw); + if (rw.status != UVM_IS_OK) begin + m_write_in_progress = 1'b0; + return; + end + rw.status = UVM_NOT_OK; + if (rw.path == UVM_FRONTDOOR) begin + uvm_reg_map system_map = rw.local_map.get_root_map(); + if (map_info.frontdoor != null) begin + uvm_reg_frontdoor fd = map_info.frontdoor; + fd.rw_info = rw; + if (fd.sequencer == null) + fd.sequencer = system_map.get_sequencer(); + fd.start(fd.sequencer, rw.parent); + end + else begin + rw.local_map.do_write(rw); + end + if (rw.status != UVM_NOT_OK) + for (uvm_reg_addr_t idx = rw.offset; + idx <= rw.offset + rw.value.size(); + idx++) begin + XsampleX(map_info.mem_range.stride * idx, 0, rw.map); + m_parent.XsampleX(map_info.offset + + (map_info.mem_range.stride * idx), + 0, rw.map); + end + end + else begin + if (get_access(rw.map) inside {"RW", "WO"}) begin + uvm_reg_backdoor bkdr = get_backdoor(); + if (bkdr != null) + bkdr.write(rw); + else + backdoor_write(rw); + end + else + rw.status = UVM_NOT_OK; + end + post_write(rw); + for (uvm_reg_cbs cb=cbs.first(); cb!=null; cb=cbs.next()) + cb.post_write(rw); + if (uvm_report_enabled(UVM_HIGH, UVM_INFO, "RegModel")) begin + string path_s,value_s,pre_s,range_s; + if (rw.path == UVM_FRONTDOOR) + path_s = (map_info.frontdoor != null) ? "user frontdoor" : + {"map ",rw.map.get_full_name()}; + else + path_s = (get_backdoor() != null) ? "user backdoor" : "DPI backdoor"; + if (rw.value.size() > 1) begin + value_s = "='{"; + pre_s = "Burst "; + foreach (rw.value[i]) + value_s = {value_s,$sformatf("%0h,",rw.value[i])}; + value_s[value_s.len()-1]="}"; + range_s = $sformatf("[%0d:%0d]",rw.offset,rw.offset+rw.value.size()); + end + else begin + value_s = $sformatf("=%0h",rw.value[0]); + range_s = $sformatf("[%0d]",rw.offset); + end + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", {pre_s,"Wrote memory via ",path_s,": ", get_full_name(),range_s,value_s}, UVM_HIGH, "t/uvm/src/reg/uvm_mem.svh", 1281, "", 1); + end + end + m_write_in_progress = 1'b0; +endtask: do_write +task uvm_mem::do_read(uvm_reg_item rw); + uvm_mem_cb_iter cbs = new(this); + uvm_reg_map_info map_info; + m_fname = rw.fname; + m_lineno = rw.lineno; + if (!Xcheck_accessX(rw, map_info)) + return; + m_read_in_progress = 1'b1; + rw.status = UVM_IS_OK; + pre_read(rw); + for (uvm_reg_cbs cb=cbs.first(); cb!=null; cb=cbs.next()) + cb.pre_read(rw); + if (rw.status != UVM_IS_OK) begin + m_read_in_progress = 1'b0; + return; + end + rw.status = UVM_NOT_OK; + if (rw.path == UVM_FRONTDOOR) begin + uvm_reg_map system_map = rw.local_map.get_root_map(); + if (map_info.frontdoor != null) begin + uvm_reg_frontdoor fd = map_info.frontdoor; + fd.rw_info = rw; + if (fd.sequencer == null) + fd.sequencer = system_map.get_sequencer(); + fd.start(fd.sequencer, rw.parent); + end + else begin + rw.local_map.do_read(rw); + end + if (rw.status != UVM_NOT_OK) + for (uvm_reg_addr_t idx = rw.offset; + idx <= rw.offset + rw.value.size(); + idx++) begin + XsampleX(map_info.mem_range.stride * idx, 1, rw.map); + m_parent.XsampleX(map_info.offset + + (map_info.mem_range.stride * idx), + 1, rw.map); + end + end + else begin + if (get_access(rw.map) inside {"RW", "RO"}) begin + uvm_reg_backdoor bkdr = get_backdoor(); + if (bkdr != null) + bkdr.read(rw); + else + backdoor_read(rw); + end + else + rw.status = UVM_NOT_OK; + end + post_read(rw); + for (uvm_reg_cbs cb=cbs.first(); cb!=null; cb=cbs.next()) + cb.post_read(rw); + if (uvm_report_enabled(UVM_HIGH, UVM_INFO, "RegModel")) begin + string path_s,value_s,pre_s,range_s; + if (rw.path == UVM_FRONTDOOR) + path_s = (map_info.frontdoor != null) ? "user frontdoor" : + {"map ",rw.map.get_full_name()}; + else + path_s = (get_backdoor() != null) ? "user backdoor" : "DPI backdoor"; + if (rw.value.size() > 1) begin + value_s = "='{"; + pre_s = "Burst "; + foreach (rw.value[i]) + value_s = {value_s,$sformatf("%0h,",rw.value[i])}; + value_s[value_s.len()-1]="}"; + range_s = $sformatf("[%0d:%0d]",rw.offset,(rw.offset+rw.value.size())); + end + else begin + value_s = $sformatf("=%0h",rw.value[0]); + range_s = $sformatf("[%0d]",rw.offset); + end + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", {pre_s,"Read memory via ",path_s,": ", get_full_name(),range_s,value_s}, UVM_HIGH, "t/uvm/src/reg/uvm_mem.svh", 1389, "", 1); + end + end + m_read_in_progress = 1'b0; +endtask: do_read +function bit uvm_mem::Xcheck_accessX(input uvm_reg_item rw, + output uvm_reg_map_info map_info); + if (rw.offset >= m_size) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,get_type_name())) + uvm_report_error (get_type_name(), $sformatf("Offset 'h%0h exceeds size of memory, 'h%0h", rw.offset, m_size), UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 1405, "", 1); + end + rw.status = UVM_NOT_OK; + return 0; + end + if (rw.path == UVM_DEFAULT_DOOR) + rw.path = m_parent.get_default_door(); + if (rw.path == UVM_BACKDOOR) begin + if (get_backdoor() == null && !has_hdl_path()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"No backdoor access available for memory '",get_full_name(), "' . Using frontdoor instead."}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 1417, "", 1); + end + rw.path = UVM_FRONTDOOR; + end + else if (rw.map == null) begin + if (get_default_map() != null) + rw.map = get_default_map(); + else + rw.map = uvm_reg_map::backdoor(); + end + end + if (rw.path != UVM_BACKDOOR) begin + rw.local_map = get_local_map(rw.map); + if (rw.local_map == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,get_type_name())) + uvm_report_error (get_type_name(), {"No transactor available to physically access memory from map '", rw.map.get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 1436, "", 1); + end + rw.status = UVM_NOT_OK; + return 0; + end + map_info = rw.local_map.get_mem_map_info(this); + if (map_info.frontdoor == null) begin + if (map_info.unmapped) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Memory '",get_full_name(), "' unmapped in map '", rw.map.get_full_name(), "' and does not have a user-defined frontdoor"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 1448, "", 1); + end + rw.status = UVM_NOT_OK; + return 0; + end + if ((rw.value.size() > 1)) begin + if (get_n_bits() > rw.local_map.get_n_bytes()*8) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot burst a %0d-bit memory through a narrower data path (%0d bytes)", get_n_bits(), rw.local_map.get_n_bytes()*8), UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 1457, "", 1); + end + rw.status = UVM_NOT_OK; + return 0; + end + if (rw.offset + rw.value.size() > m_size) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Burst of size 'd%0d starting at offset 'd%0d exceeds size of memory, 'd%0d", rw.value.size(), rw.offset, m_size), UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 1464, "", 1); + end + return 0; + end + end + end + if (rw.map == null) + rw.map = rw.local_map; + end + return 1; +endfunction +task uvm_mem::poke(output uvm_status_e status, + input uvm_reg_addr_t offset, + input uvm_reg_data_t value, + input string kind = "", + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_item rw; + uvm_reg_backdoor bkdr = get_backdoor(); + m_fname = fname; + m_lineno = lineno; + if (bkdr == null && !has_hdl_path(kind)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"No backdoor access available in memory '", get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 1500, "", 1); + end + status = UVM_NOT_OK; + return; + end + rw = uvm_reg_item::type_id_create("mem_poke_item",,get_full_name()); + rw.element = this; + rw.path = UVM_BACKDOOR; + rw.element_kind = UVM_MEM; + rw.kind = UVM_WRITE; + rw.offset = offset; + rw.value[0] = value & ((1 << m_n_bits)-1); + rw.bd_kind = kind; + rw.parent = parent; + rw.extension = extension; + rw.fname = fname; + rw.lineno = lineno; + if (bkdr != null) + bkdr.write(rw); + else + backdoor_write(rw); + status = rw.status; + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", $sformatf("Poked memory '%s[%0d]' with value 'h%h", get_full_name(), offset, value), UVM_HIGH, "t/uvm/src/reg/uvm_mem.svh", 1531, "", 1); + end +endtask: poke +task uvm_mem::peek(output uvm_status_e status, + input uvm_reg_addr_t offset, + output uvm_reg_data_t value, + input string kind = "", + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_backdoor bkdr = get_backdoor(); + uvm_reg_item rw; + m_fname = fname; + m_lineno = lineno; + if (bkdr == null && !has_hdl_path(kind)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"No backdoor access available in memory '", get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 1554, "", 1); + end + status = UVM_NOT_OK; + return; + end + rw = uvm_reg_item::type_id_create("mem_peek_item",,get_full_name()); + rw.element = this; + rw.path = UVM_BACKDOOR; + rw.element_kind = UVM_MEM; + rw.kind = UVM_READ; + rw.offset = offset; + rw.bd_kind = kind; + rw.parent = parent; + rw.extension = extension; + rw.fname = fname; + rw.lineno = lineno; + if (bkdr != null) + bkdr.read(rw); + else + backdoor_read(rw); + status = rw.status; + value = rw.value[0]; + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", $sformatf("Peeked memory '%s[%0d]' has value 'h%h", get_full_name(), offset, value), UVM_HIGH, "t/uvm/src/reg/uvm_mem.svh", 1585, "", 1); + end +endtask: peek +function void uvm_mem::set_frontdoor(uvm_reg_frontdoor ftdr, + uvm_reg_map map = null, + string fname = "", + int lineno = 0); + uvm_reg_map_info map_info; + m_fname = fname; + m_lineno = lineno; + map = get_local_map(map); + if (map == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Memory '",get_full_name(), "' not found in map '", map.get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 1607, "", 1); + end + return; + end + map_info = map.get_mem_map_info(this); + map_info.frontdoor = ftdr; +endfunction: set_frontdoor +function uvm_reg_frontdoor uvm_mem::get_frontdoor(uvm_reg_map map = null); + uvm_reg_map_info map_info; + map = get_local_map(map); + if (map == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Memory '",get_full_name(), "' not found in map '", map.get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 1626, "", 1); + end + return null; + end + map_info = map.get_mem_map_info(this); + return map_info.frontdoor; +endfunction: get_frontdoor +function void uvm_mem::set_backdoor(uvm_reg_backdoor bkdr, + string fname = "", + int lineno = 0); + m_fname = fname; + m_lineno = lineno; + m_backdoor = bkdr; +endfunction: set_backdoor +function uvm_reg_backdoor uvm_mem::get_backdoor(bit inherited = 1); + if (m_backdoor == null && inherited) begin + uvm_reg_block blk = get_parent(); + uvm_reg_backdoor bkdr; + while (blk != null) begin + bkdr = blk.get_backdoor(); + if (bkdr != null) begin + m_backdoor = bkdr; + break; + end + blk = blk.get_parent(); + end + end + return m_backdoor; +endfunction: get_backdoor +function uvm_status_e uvm_mem::backdoor_read_func(uvm_reg_item rw); + uvm_hdl_path_concat paths[$]; + uvm_hdl_data_t val; + bit ok=1; + get_full_hdl_path(paths,rw.bd_kind); + foreach (rw.value[mem_idx]) begin + string idx; + idx.itoa(rw.offset + mem_idx); + foreach (paths[i]) begin + uvm_hdl_path_concat hdl_concat = paths[i]; + val = 0; + foreach (hdl_concat.slices[j]) begin + string hdl_path = {hdl_concat.slices[j].path, "[", idx, "]"}; + begin + if (uvm_report_enabled(UVM_DEBUG,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", {"backdoor_read from ",hdl_path}, UVM_DEBUG, "t/uvm/src/reg/uvm_mem.svh", 1691, "", 1); + end + if (hdl_concat.slices[j].offset < 0) begin + ok &= uvm_hdl_read(hdl_path, val); + continue; + end + begin + uvm_reg_data_t slice; + int k = hdl_concat.slices[j].offset; + ok &= uvm_hdl_read(hdl_path, slice); + repeat (hdl_concat.slices[j].size) begin + val[k++] = slice[0]; + slice >>= 1; + end + end + end + val &= (1 << m_n_bits)-1; + if (i == 0) + rw.value[mem_idx] = val; + if (val != rw.value[mem_idx]) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Backdoor read of register %s with multiple HDL copies: values are not the same: %0h at path '%s', and %0h at path '%s'. Returning first value.", get_full_name(), rw.value[mem_idx], uvm_hdl_concat2string(paths[0]), val, uvm_hdl_concat2string(paths[i])), UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 1716, "", 1); + end + return UVM_NOT_OK; + end + end + end + rw.status = (ok) ? UVM_IS_OK : UVM_NOT_OK; + return rw.status; +endfunction +task uvm_mem::backdoor_read(uvm_reg_item rw); + rw.status = backdoor_read_func(rw); +endtask +task uvm_mem::backdoor_write(uvm_reg_item rw); + uvm_hdl_path_concat paths[$]; + bit ok=1; + get_full_hdl_path(paths,rw.bd_kind); + foreach (rw.value[mem_idx]) begin + string idx; + idx.itoa(rw.offset + mem_idx); + foreach (paths[i]) begin + uvm_hdl_path_concat hdl_concat = paths[i]; + foreach (hdl_concat.slices[j]) begin + begin + if (uvm_report_enabled(UVM_DEBUG,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", $sformatf("backdoor_write to %s ",hdl_concat.slices[j].path), UVM_DEBUG, "t/uvm/src/reg/uvm_mem.svh", 1751, "", 1); + end + if (hdl_concat.slices[j].offset < 0) begin + ok &= uvm_hdl_deposit({hdl_concat.slices[j].path,"[", idx, "]"},rw.value[mem_idx]); + continue; + end + begin + uvm_reg_data_t slice; + slice = rw.value[mem_idx] >> hdl_concat.slices[j].offset; + slice &= (1 << hdl_concat.slices[j].size)-1; + ok &= uvm_hdl_deposit({hdl_concat.slices[j].path, "[", idx, "]"}, slice); + end + end + end + end + rw.status = (ok ? UVM_IS_OK : UVM_NOT_OK); +endtask +function void uvm_mem::clear_hdl_path(string kind = "RTL"); + if (kind == "ALL") begin + m_hdl_paths_pool = new("hdl_paths"); + return; + end + if (kind == "") + kind = m_parent.get_default_hdl_path(); + if (!m_hdl_paths_pool.exists(kind)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Unknown HDL Abstraction '",kind,"'"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 1784, "", 1); + end + return; + end + m_hdl_paths_pool.delete(kind); +endfunction +function void uvm_mem::add_hdl_path(uvm_hdl_path_slice slices[], string kind = "RTL"); + uvm_queue #(uvm_hdl_path_concat) paths = m_hdl_paths_pool.get(kind); + uvm_hdl_path_concat concat = new(); + concat.set(slices); + paths.push_back(concat); +endfunction +function void uvm_mem::add_hdl_path_slice(string name, + int offset, + int size, + bit first = 0, + string kind = "RTL"); + uvm_queue #(uvm_hdl_path_concat) paths=m_hdl_paths_pool.get(kind); + uvm_hdl_path_concat concat; + if (first || paths.size() == 0) begin + concat = new(); + paths.push_back(concat); + end + else + concat = paths.get(paths.size()-1); + concat.add_path(name, offset, size); +endfunction +function bit uvm_mem::has_hdl_path(string kind = ""); + if (kind == "") + kind = m_parent.get_default_hdl_path(); + return m_hdl_paths_pool.exists(kind); +endfunction +function void uvm_mem::get_hdl_path(ref uvm_hdl_path_concat paths[$], + input string kind = ""); + uvm_queue #(uvm_hdl_path_concat) hdl_paths; + if (kind == "") + kind = m_parent.get_default_hdl_path(); + if (!has_hdl_path(kind)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Memory does not have hdl path defined for abstraction '",kind,"'"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 1846, "", 1); + end + return; + end + hdl_paths = m_hdl_paths_pool.get(kind); + for (int i=0; i= range.min && addrs[i] <= range.max) begin + string a; + a = $sformatf("%0h",addrs[i]); + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"In map '",get_full_name(),"' register '", rg.get_full_name(), "' overlaps with address range of memory '", top_map.m_mems_by_offset[range].get_full_name(),"': 'h",a}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 716, "", 1); + end + end + end + end + info.addr = addrs; + end + end + if (unmapped) begin + info.offset = -1; + info.unmapped = 1; + end + else begin + info.offset = offset; + info.unmapped = 0; + end + end +endfunction +function void uvm_reg_map::add_mem(uvm_mem mem, + uvm_reg_addr_t offset, + string rights = "RW", + bit unmapped=0, + uvm_reg_frontdoor frontdoor=null); + if (m_mems_info.exists(mem)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Memory '",mem.get_name(), "' has already been added to map '",get_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 746, "", 1); + end + return; + end + if (mem.get_parent() != get_parent()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Memory '",mem.get_full_name(),"' may not be added to address map '", get_full_name(),"' : they are not in the same block"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 753, "", 1); + end + return; + end + mem.add_map(this); + begin + uvm_reg_map_info info = new; + info.offset = offset; + info.rights = rights; + info.unmapped = unmapped; + info.frontdoor = frontdoor; + m_mems_info[mem] = info; + end +endfunction: add_mem +function void uvm_reg_map::m_set_mem_offset(uvm_mem mem, + uvm_reg_addr_t offset, + bit unmapped); + if (!m_mems_info.exists(mem)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Cannot modify offset of memory '",mem.get_full_name(), "' in address map '",get_full_name(), "' : memory not mapped in that address map"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 781, "", 1); + end + return; + end + begin + uvm_reg_map_info info = m_mems_info[mem]; + uvm_reg_block blk = get_parent(); + uvm_reg_map top_map = get_root_map(); + uvm_reg_addr_t addrs[]; + if (blk.is_locked()) begin + if (!info.unmapped) begin + foreach (top_map.m_mems_by_offset[range]) begin + if (top_map.m_mems_by_offset[range] == mem) + top_map.m_mems_by_offset.delete(range); + end + end + if (!unmapped) begin + uvm_reg_addr_t addrs[],addrs_max[]; + uvm_reg_addr_t min, max, min2, max2; + int unsigned stride; + void'(get_physical_addresses(offset,0,mem.get_n_bytes(),addrs)); + min = (addrs[0] < addrs[addrs.size()-1]) ? addrs[0] : addrs[addrs.size()-1]; + min2 = addrs[0]; + void'(get_physical_addresses(offset,(mem.get_size()-1), + mem.get_n_bytes(),addrs_max)); + max = (addrs_max[0] > addrs_max[addrs_max.size()-1]) ? + addrs_max[0] : addrs_max[addrs_max.size()-1]; + max2 = addrs_max[0]; + stride = mem.get_n_bytes()/get_addr_unit_bytes(); + foreach (top_map.m_regs_by_offset[reg_addr]) begin + if (reg_addr >= min && reg_addr <= max) begin + string a,b; + a = $sformatf("[%0h:%0h]",min,max); + b = $sformatf("%0h",reg_addr); + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"In map '",get_full_name(),"' memory '", mem.get_full_name(), "' with range ",a, " overlaps with address of existing register '", top_map.m_regs_by_offset[reg_addr].get_full_name(),"': 'h",b}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 829, "", 1); + end + end + end + foreach (top_map.m_mems_by_offset[range]) begin + if (min <= range.max && max >= range.max || + min <= range.min && max >= range.min || + min >= range.min && max <= range.max) begin + string a,b; + a = $sformatf("[%0h:%0h]",min,max); + b = $sformatf("[%0h:%0h]",range.min,range.max); + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"In map '",get_full_name(),"' memory '", mem.get_full_name(), "' with range ",a, " overlaps existing memory with range '", top_map.m_mems_by_offset[range].get_full_name(),"': ",b}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 843, "", 1); + end + end + end + begin + uvm_reg_map_addr_range range = '{ min, max, stride}; + top_map.m_mems_by_offset[range] = mem; + info.addr = addrs; + info.mem_range = range; + end + end + end + if (unmapped) begin + info.offset = -1; + info.unmapped = 1; + end + else begin + info.offset = offset; + info.unmapped = 0; + end + end +endfunction +function void uvm_reg_map::add_submap (uvm_reg_map child_map, + uvm_reg_addr_t offset); + uvm_reg_map parent_map; + if (child_map == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Attempting to add NULL map to map '",get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 877, "", 1); + end + return; + end + parent_map = child_map.get_parent_map(); + if (parent_map != null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Map '", child_map.get_full_name(), "' is already a child of map '", parent_map.get_full_name(), "'. Cannot also be a child of map '", get_full_name(), "'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 890, "", 1); + end + return; + end + begin : n_bytes_match_check + if (m_n_bytes > child_map.get_n_bytes(UVM_NO_HIER)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", $sformatf("Adding %0d-byte submap '%s' to %0d-byte parent map '%s'", child_map.get_n_bytes(UVM_NO_HIER), child_map.get_full_name(), m_n_bytes, get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 900, "", 1); + end + end + end + child_map.add_parent_map(this,offset); + set_submap_offset(child_map, offset); +endfunction: add_submap +function void uvm_reg_map::reset(string kind = "SOFT"); + uvm_reg regs[$]; + get_registers(regs); + foreach (regs[i]) begin + regs[i].reset(kind); + end +endfunction +function void uvm_reg_map::add_parent_map(uvm_reg_map parent_map, uvm_reg_addr_t offset); + if (parent_map == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Attempting to add NULL parent map to map '",get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 930, "", 1); + end + return; + end + if (m_parent_map != null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Map \"%s\" already a submap of map \"%s\" at offset 'h%h", get_full_name(), m_parent_map.get_full_name(), m_parent_map.get_submap_offset(this)), UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 938, "", 1); + end + return; + end + m_parent_map = parent_map; + parent_map.m_submaps[this] = offset; +endfunction: add_parent_map +function void uvm_reg_map::set_sequencer(uvm_sequencer_base sequencer, + uvm_reg_adapter adapter=null); + if (sequencer == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"REG_NULL_SQR")) + uvm_report_error ("REG_NULL_SQR", "Null reference specified for bus sequencer", UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 954, "", 1); + end + return; + end + if (adapter == null) begin + begin + if (uvm_report_enabled(UVM_MEDIUM,UVM_INFO,"REG_NO_ADAPT")) + uvm_report_info ("REG_NO_ADAPT", {"Adapter not specified for map '",get_full_name(), "'. Accesses via this map will send abstract 'uvm_reg_item' items to sequencer '", sequencer.get_full_name(),"'"}, UVM_MEDIUM, "t/uvm/src/reg/uvm_reg_map.svh", 961, "", 1); + end + end + m_sequencer = sequencer; + m_adapter = adapter; +endfunction +function uvm_reg_block uvm_reg_map::get_parent(); + return m_parent; +endfunction +function uvm_reg_map uvm_reg_map::get_parent_map(); + return m_parent_map; +endfunction +function uvm_reg_map uvm_reg_map::get_root_map(); + return (m_parent_map == null) ? this : m_parent_map.get_root_map(); +endfunction: get_root_map +function uvm_reg_addr_t uvm_reg_map::get_base_addr(uvm_hier_e hier=UVM_HIER); + uvm_reg_map child = this; + if (hier == UVM_NO_HIER || m_parent_map == null) + return m_base_addr; + get_base_addr = m_parent_map.get_submap_offset(this); + get_base_addr += m_parent_map.get_base_addr(UVM_HIER); +endfunction +function int unsigned uvm_reg_map::get_n_bytes(uvm_hier_e hier=UVM_HIER); + if (hier == UVM_NO_HIER) + return m_n_bytes; + return m_system_n_bytes; +endfunction +function int unsigned uvm_reg_map::get_addr_unit_bytes(); + return (m_byte_addressing) ? 1 : m_n_bytes; +endfunction +function uvm_endianness_e uvm_reg_map::get_endian(uvm_hier_e hier=UVM_HIER); + if (hier == UVM_NO_HIER || m_parent_map == null) + return m_endian; + return m_parent_map.get_endian(hier); +endfunction +function uvm_sequencer_base uvm_reg_map::get_sequencer(uvm_hier_e hier=UVM_HIER); + if (hier == UVM_NO_HIER || m_parent_map == null) + return m_sequencer; + return m_parent_map.get_sequencer(hier); +endfunction +function uvm_reg_adapter uvm_reg_map::get_adapter(uvm_hier_e hier=UVM_HIER); + if (hier == UVM_NO_HIER || m_parent_map == null) + return m_adapter; + return m_parent_map.get_adapter(hier); +endfunction +function void uvm_reg_map::get_submaps(ref uvm_reg_map maps[$], input uvm_hier_e hier=UVM_HIER); + foreach (m_submaps[submap]) + maps.push_back(submap); + if (hier == UVM_HIER) + foreach (m_submaps[submap_]) begin + uvm_reg_map submap=submap_; + submap.get_submaps(maps); + end +endfunction +function void uvm_reg_map::get_registers(ref uvm_reg regs[$], input uvm_hier_e hier=UVM_HIER); + foreach (m_regs_info[rg]) + regs.push_back(rg); + if (hier == UVM_HIER) + foreach (m_submaps[submap_]) begin + uvm_reg_map submap=submap_; + submap.get_registers(regs); + end +endfunction +function void uvm_reg_map::get_fields(ref uvm_reg_field fields[$], input uvm_hier_e hier=UVM_HIER); + foreach (m_regs_info[rg_]) begin + uvm_reg rg = rg_; + rg.get_fields(fields); + end + if (hier == UVM_HIER) + foreach (this.m_submaps[submap_]) begin + uvm_reg_map submap=submap_; + submap.get_fields(fields); + end +endfunction +function void uvm_reg_map::get_memories(ref uvm_mem mems[$], input uvm_hier_e hier=UVM_HIER); + foreach (m_mems_info[mem]) + mems.push_back(mem); + if (hier == UVM_HIER) + foreach (m_submaps[submap_]) begin + uvm_reg_map submap=submap_; + submap.get_memories(mems); + end +endfunction +function void uvm_reg_map::get_virtual_registers(ref uvm_vreg regs[$], input uvm_hier_e hier=UVM_HIER); + uvm_mem mems[$]; + get_memories(mems,hier); + foreach (mems[i]) + mems[i].get_virtual_registers(regs); +endfunction +function void uvm_reg_map::get_virtual_fields(ref uvm_vreg_field fields[$], input uvm_hier_e hier=UVM_HIER); + uvm_vreg regs[$]; + get_virtual_registers(regs,hier); + foreach (regs[i]) + regs[i].get_fields(fields); +endfunction +function string uvm_reg_map::get_full_name(); + if (m_parent == null) + return get_name(); + else + return {m_parent.get_full_name(), ".", get_name()}; +endfunction +function uvm_reg_map_info uvm_reg_map::get_mem_map_info(uvm_mem mem, bit error=1); + if (!m_mems_info.exists(mem)) begin + if (error) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"REG_NO_MAP")) + uvm_report_error ("REG_NO_MAP", {"Memory '",mem.get_name(),"' not in map '",get_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1157, "", 1); + end + return null; + end + return m_mems_info[mem]; +endfunction +function uvm_reg_map_info uvm_reg_map::get_reg_map_info(uvm_reg rg, bit error=1); + uvm_reg_map_info result; + if (!m_regs_info.exists(rg)) begin + if (error) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"REG_NO_MAP")) + uvm_report_error ("REG_NO_MAP", {"Register '",rg.get_name(),"' not in map '",get_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1170, "", 1); + end + return null; + end + result = m_regs_info[rg]; + if(!result.is_initialized) + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"map '",get_name(),"' does not seem to be initialized correctly, check that the top register model is locked()"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1175, "", 1); + end + return result; +endfunction +function void uvm_reg_map::set_base_addr(uvm_reg_addr_t offset); + if (m_parent_map != null) begin + m_parent_map.set_submap_offset(this, offset); + end + else begin + m_base_addr = offset; + if (m_parent.is_locked()) begin + uvm_reg_map top_map = get_root_map(); + top_map.Xinit_address_mapX(); + end + end +endfunction +function int unsigned uvm_reg_map::get_size(); + int unsigned max_addr; + int unsigned addr; + foreach (m_regs_info[rg_]) begin + uvm_reg rg = rg_; + addr = m_regs_info[rg].offset + ((rg.get_n_bytes()-1)/m_n_bytes); + if (addr > max_addr) max_addr = addr; + end + foreach (m_mems_info[mem_]) begin + uvm_mem mem = mem_; + addr = m_mems_info[mem].offset + (mem.get_size() * (((mem.get_n_bytes()-1)/m_n_bytes)+1)) -1; + if (addr > max_addr) max_addr = addr; + end + foreach (m_submaps[submap_]) begin + uvm_reg_map submap=submap_; + addr = m_submaps[submap] + submap.get_size(); + if (addr > max_addr) max_addr = addr; + end + return max_addr + 1; +endfunction +function void uvm_reg_map::Xverify_map_configX(); + bit error; + uvm_reg_map root_map = get_root_map(); + if (root_map.get_adapter() == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Map '",root_map.get_full_name(), "' does not have an adapter registered"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1243, "", 1); + end + error++; + end + if (root_map.get_sequencer() == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Map '",root_map.get_full_name(), "' does not have a sequencer registered"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1248, "", 1); + end + error++; + end + if (error) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"RegModel")) + uvm_report_fatal ("RegModel", {"Must register an adapter and sequencer ", "for each top-level map in RegModel model"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1253, "", 1); + end + return; + end +endfunction +function int uvm_reg_map::get_physical_addresses_to_map( + uvm_reg_addr_t base_addr, + uvm_reg_addr_t mem_offset, + int unsigned n_bytes, + ref uvm_reg_addr_t addr[], + input uvm_reg_map parent_map, + ref int unsigned byte_offset, + input uvm_mem mem=null + ); + int bus_width = get_n_bytes(UVM_NO_HIER); + uvm_reg_map up_map; + uvm_reg_addr_t local_addr[]; + uvm_reg_addr_t lbase_addr; + up_map = get_parent_map(); + lbase_addr = up_map==null ? get_base_addr(UVM_NO_HIER): up_map.get_submap_offset(this); + if(up_map!=parent_map) begin + uvm_reg_addr_t lb; + uvm_reg_addr_t laddr; + begin + if(mem_offset) begin + base_addr+=mem_offset*mem.get_n_bytes()/get_addr_unit_bytes(); + end + laddr=lbase_addr + base_addr*get_addr_unit_bytes()/up_map.get_addr_unit_bytes(); + lb = (base_addr*get_addr_unit_bytes()) % up_map.get_addr_unit_bytes(); + byte_offset += lb; + end + return up_map.get_physical_addresses_to_map(laddr, 0, n_bytes+lb, addr,parent_map,byte_offset); + end else begin + uvm_reg_addr_t lbase_addr2; + local_addr= new[ceil(n_bytes,bus_width)]; + lbase_addr2 = base_addr; + if(mem_offset) + if(mem!=null && (mem.get_n_bytes() >= get_addr_unit_bytes())) begin + lbase_addr2 = base_addr + mem_offset*mem.get_n_bytes()/get_addr_unit_bytes(); + byte_offset += (mem_offset*mem.get_n_bytes() % get_addr_unit_bytes()); + end else begin + lbase_addr2 = base_addr + mem_offset; + end + case (get_endian(UVM_NO_HIER)) + UVM_LITTLE_ENDIAN: begin + foreach (local_addr[i]) begin + local_addr[i] = lbase_addr2 + i*bus_width/get_addr_unit_bytes(); + end + end + UVM_BIG_ENDIAN: begin + foreach (local_addr[i]) begin + local_addr[i] = lbase_addr2 + (local_addr.size()-1-i)*bus_width/get_addr_unit_bytes() ; + end + end + UVM_LITTLE_FIFO: begin + foreach (local_addr[i]) begin + local_addr[i] = lbase_addr2; + end + end + UVM_BIG_FIFO: begin + foreach (local_addr[i]) begin + local_addr[i] = lbase_addr2; + end + end + default: begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/REG/MAPNOENDIANESS")) + uvm_report_error ("UVM/REG/MAPNOENDIANESS", {"Map has no specified endianness. ", $sformatf("Cannot access %0d bytes register via its %0d byte \"%s\" interface", n_bytes, bus_width, get_full_name())}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1347, "", 1); + end + end + endcase + addr = new [local_addr.size()] (local_addr); + foreach(addr[idx]) + addr[idx] += lbase_addr; + end +endfunction +function int uvm_reg_map::get_physical_addresses(uvm_reg_addr_t base_addr, + uvm_reg_addr_t mem_offset, + int unsigned n_bytes, + ref uvm_reg_addr_t addr[]); + int unsigned skip; + return get_physical_addresses_to_map(base_addr, mem_offset, n_bytes, addr,null,skip); +endfunction +function void uvm_reg_map::set_submap_offset(uvm_reg_map submap, uvm_reg_addr_t offset); + if (submap == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"REG/NULL")) + uvm_report_error ("REG/NULL", "set_submap_offset: submap handle is null", UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1385, "", 1); + end + return; + end + m_submaps[submap] = offset; + if (m_parent.is_locked()) begin + uvm_reg_map root_map = get_root_map(); + root_map.Xinit_address_mapX(); + end +endfunction +function uvm_reg_addr_t uvm_reg_map::get_submap_offset(uvm_reg_map submap); + if (submap == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"REG/NULL")) + uvm_report_error ("REG/NULL", "set_submap_offset: submap handle is null", UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1400, "", 1); + end + return -1; + end + if (!m_submaps.exists(submap)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Map '",submap.get_full_name(), "' is not a submap of '",get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1405, "", 1); + end + return -1; + end + return m_submaps[submap]; +endfunction +function uvm_reg uvm_reg_map::get_reg_by_offset(uvm_reg_addr_t offset, + bit read = 1); + if (!m_parent.is_locked()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot get register by offset: Block %s is not locked.", m_parent.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1417, "", 1); + end + return null; + end + if (!read && m_regs_by_offset_wo.exists(offset)) + return m_regs_by_offset_wo[offset]; + if (m_regs_by_offset.exists(offset)) + return m_regs_by_offset[offset]; + return null; +endfunction +function uvm_mem uvm_reg_map::get_mem_by_offset(uvm_reg_addr_t offset); + if (!m_parent.is_locked()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot memory register by offset: Block %s is not locked.", m_parent.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1435, "", 1); + end + return null; + end + foreach (m_mems_by_offset[range]) begin + if (range.min <= offset && offset <= range.max) begin + return m_mems_by_offset[range]; + end + end + return null; +endfunction +function void uvm_reg_map::Xinit_address_mapX(); + int unsigned bus_width; + uvm_reg_map top_map = get_root_map(); + if (this == top_map) begin + top_map.m_regs_by_offset.delete(); + top_map.m_regs_by_offset_wo.delete(); + top_map.m_mems_by_offset.delete(); + end + foreach (m_submaps[l]) begin + uvm_reg_map map=l; + map.Xinit_address_mapX(); + end + foreach (m_regs_info[rg_]) begin + uvm_reg rg = rg_; + m_regs_info[rg].is_initialized=1; + if (!m_regs_info[rg].unmapped) begin + string rg_acc = rg.Xget_fields_accessX(this); + uvm_reg_addr_t addrs[]; + bus_width = get_physical_addresses(m_regs_info[rg].offset,0,rg.get_n_bytes(),addrs); + foreach (addrs[i]) begin + uvm_reg_addr_t addr = addrs[i]; + if (top_map.m_regs_by_offset.exists(addr) && (top_map.m_regs_by_offset[addr] != rg)) begin + uvm_reg rg2 = top_map.m_regs_by_offset[addr]; + string rg2_acc = rg2.Xget_fields_accessX(this); + if (rg_acc == "RO" && rg2_acc == "WO") begin + top_map.m_regs_by_offset[addr] = rg; + uvm_reg_read_only_cbs::add(rg); + top_map.m_regs_by_offset_wo[addr] = rg2; + uvm_reg_write_only_cbs::add(rg2); + end + else if (rg_acc == "WO" && rg2_acc == "RO") begin + top_map.m_regs_by_offset_wo[addr] = rg; + uvm_reg_write_only_cbs::add(rg); + uvm_reg_read_only_cbs::add(rg2); + end + else begin + string a; + a = $sformatf("%0h",addr); + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"In map '",get_full_name(),"' register '", rg.get_full_name(), "' maps to same address as register '", top_map.m_regs_by_offset[addr].get_full_name(),"': 'h",a}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1503, "", 1); + end + end + end + else + top_map.m_regs_by_offset[addr] = rg; + foreach (top_map.m_mems_by_offset[range]) begin + if (addr >= range.min && addr <= range.max) begin + string a,b; + a = $sformatf("%0h",addr); + b = $sformatf("[%0h:%0h]",range.min,range.max); + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"In map '",get_full_name(),"' register '", rg.get_full_name(), "' with address ",a, "maps to same address as memory '", top_map.m_mems_by_offset[range].get_full_name(),"': ",b}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1517, "", 1); + end + end + end + end + m_regs_info[rg].addr = addrs; + end + end + foreach (m_mems_info[mem_]) begin + uvm_mem mem = mem_; + if (!m_mems_info[mem].unmapped) begin + uvm_reg_addr_t addrs[],addrs_max[]; + uvm_reg_addr_t min, max, min2, max2; + int unsigned stride; + int unsigned bo; + bus_width = get_physical_addresses_to_map(m_mems_info[mem].offset,0,mem.get_n_bytes(),addrs,null,bo,mem); + min = (addrs[0] < addrs[addrs.size()-1]) ? addrs[0] : addrs[addrs.size()-1]; + void'(get_physical_addresses_to_map(m_mems_info[mem].offset,(mem.get_size()-1),mem.get_n_bytes(),addrs_max,null,bo,mem)); + max = (addrs_max[0] > addrs_max[addrs_max.size()-1]) ? addrs_max[0] : addrs_max[addrs_max.size()-1]; + stride = mem.get_n_bytes()/get_addr_unit_bytes(); + if(mem.get_n_bytes() get_addr_unit_bytes()) + if(mem.get_n_bytes() % get_addr_unit_bytes()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/REG/ADDR")) + uvm_report_warning ("UVM/REG/ADDR", $sformatf("memory %s is not matching the word width of the enclosing map %s \ +(one memory word not fitting into k map addresses)", mem.get_full_name(),get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1571, "", 1); + end + end + if(mem.get_n_bytes() < get_addr_unit_bytes()) + if(get_addr_unit_bytes() % mem.get_n_bytes()) + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/REG/ADDR")) + uvm_report_warning ("UVM/REG/ADDR", $sformatf("the memory %s is not matching the word width of the enclosing map %s \ +(one map address doesnt cover k memory words)", mem.get_full_name(),get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1578, "", 1); + end + if(mem.get_n_bits() % 8) + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/REG/ADDR")) + uvm_report_warning ("UVM/REG/ADDR", $sformatf("this implementation of UVM requires memory words to be k*8 bits (mem %s \ +has %0d bit words)",mem.get_full_name(),mem.get_n_bits()), UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1582, "", 1); + end + foreach (top_map.m_regs_by_offset[reg_addr]) begin + if (reg_addr >= min && reg_addr <= max) begin + string a; + a = $sformatf("%0h",reg_addr); + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"In map '",get_full_name(),"' memory '", mem.get_full_name(), "' maps to same address as register '", top_map.m_regs_by_offset[reg_addr].get_full_name(),"': 'h",a}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1590, "", 1); + end + end + end + foreach (top_map.m_mems_by_offset[range]) begin + if (min <= range.max && max >= range.max || + min <= range.min && max >= range.min || + min >= range.min && max <= range.max) + if(top_map.m_mems_by_offset[range]!=mem) + begin + string a; + a = $sformatf("[%0h:%0h]",min,max); + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"In map '",get_full_name(),"' memory '", mem.get_full_name(), "' overlaps with address range of memory '", top_map.m_mems_by_offset[range].get_full_name(),"': 'h",a}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1604, "", 1); + end + end + end + begin + uvm_reg_map_addr_range range = '{ min, max, stride}; + top_map.m_mems_by_offset[ range ] = mem; + m_mems_info[mem].addr = addrs; + m_mems_info[mem].mem_range = range; + end + end + end + if (bus_width == 0) bus_width = m_n_bytes; + m_system_n_bytes = bus_width; +endfunction +function void uvm_reg_map::Xget_bus_infoX(uvm_reg_item rw, + output uvm_reg_map_info map_info, + output int size, + output int lsb, + output int addr_skip); + if (rw.element_kind == UVM_MEM) begin + uvm_mem mem; + if(rw.element == null || !$cast(mem,rw.element)) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"REG/CAST")) + uvm_report_fatal ("REG/CAST", {"uvm_reg_item 'element_kind' is UVM_MEM, ", "but 'element' does not point to a memory: ",rw.get_name()}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1639, "", 1); + end + map_info = get_mem_map_info(mem); + size = mem.get_n_bits(); + end + else if (rw.element_kind == UVM_REG) begin + uvm_reg rg; + if(rw.element == null || !$cast(rg,rw.element)) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"REG/CAST")) + uvm_report_fatal ("REG/CAST", {"uvm_reg_item 'element_kind' is UVM_REG, ", "but 'element' does not point to a register: ",rw.get_name()}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1647, "", 1); + end + map_info = get_reg_map_info(rg); + size = rg.get_n_bits(); + end + else if (rw.element_kind == UVM_FIELD) begin + uvm_reg_field field; + if(rw.element == null || !$cast(field,rw.element)) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"REG/CAST")) + uvm_report_fatal ("REG/CAST", {"uvm_reg_item 'element_kind' is UVM_FIELD, ", "but 'element' does not point to a field: ",rw.get_name()}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1655, "", 1); + end + map_info = get_reg_map_info(field.get_parent()); + size = field.get_n_bits(); + lsb = field.get_lsb_pos(); + addr_skip = lsb/(get_n_bytes()*8); + end +endfunction +task uvm_reg_map::do_write(uvm_reg_item rw); + uvm_sequence_base tmp_parent_seq; + uvm_reg_map system_map = get_root_map(); + uvm_reg_adapter adapter = system_map.get_adapter(); + uvm_sequencer_base sequencer = system_map.get_sequencer(); + uvm_reg_seq_base parent_proxy; + if (adapter != null && adapter.parent_sequence != null) begin + uvm_object o; + uvm_sequence_base seq; + o = adapter.parent_sequence.clone(); + if (o == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"REG/CLONE")) + uvm_report_fatal ("REG/CLONE", {"failed to clone adapter's parent sequence: '", adapter.parent_sequence.get_full_name(), "' (of type '", adapter.parent_sequence.get_type_name(), "')"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1686, "", 1); + end + if (!$cast(seq, o)) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"REG/CAST")) + uvm_report_fatal ("REG/CAST", {"failed to cast: '", o.get_full_name(), "' (of type '", o.get_type_name(), "') to uvm_sequence_base!"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1693, "", 1); + end + seq.set_parent_sequence(rw.parent); + rw.parent = seq; + tmp_parent_seq = seq; + end + if (rw.parent == null) begin + parent_proxy = new("default_parent_seq"); + rw.parent = parent_proxy; + tmp_parent_seq = rw.parent; + end + if (adapter == null) begin + uvm_event#(uvm_object) end_event ; + uvm_event_pool ep; + ep = rw.get_event_pool(); + end_event = ep.get("end") ; + rw.set_sequencer(sequencer); + rw.parent.start_item(rw,rw.prior); + rw.parent.finish_item(rw); + end_event.wait_on(); + end + else begin + do_bus_write(rw, sequencer, adapter); + end + if (tmp_parent_seq != null) + sequencer.m_sequence_exiting(tmp_parent_seq); +endtask +task uvm_reg_map::do_read(uvm_reg_item rw); + uvm_sequence_base tmp_parent_seq; + uvm_reg_map system_map = get_root_map(); + uvm_reg_adapter adapter = system_map.get_adapter(); + uvm_sequencer_base sequencer = system_map.get_sequencer(); + uvm_reg_seq_base parent_proxy; + if (adapter != null && adapter.parent_sequence != null) begin + uvm_object o; + uvm_sequence_base seq; + o = adapter.parent_sequence.clone(); + if (o == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"REG/CLONE")) + uvm_report_fatal ("REG/CLONE", {"failed to clone adapter's parent sequence: '", adapter.parent_sequence.get_full_name(), "' (of type '", adapter.parent_sequence.get_type_name(), "')"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1745, "", 1); + end + if (!$cast(seq, o)) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"REG/CAST")) + uvm_report_fatal ("REG/CAST", {"failed to cast: '", o.get_full_name(), "' (of type '", o.get_type_name(), "') to uvm_sequence_base!"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1752, "", 1); + end + seq.set_parent_sequence(rw.parent); + rw.parent = seq; + tmp_parent_seq = seq; + end + if (rw.parent == null) begin + parent_proxy = new("default_parent_seq"); + rw.parent = parent_proxy; + tmp_parent_seq = rw.parent; + end + if (adapter == null) begin + uvm_event#(uvm_object) end_event ; + uvm_event_pool ep; + ep = rw.get_event_pool(); + end_event = ep.get("end") ; + rw.set_sequencer(sequencer); + rw.parent.start_item(rw,rw.prior); + rw.parent.finish_item(rw); + end_event.wait_on(); + end + else begin + do_bus_read(rw, sequencer, adapter); + end + if (tmp_parent_seq != null) + sequencer.m_sequence_exiting(tmp_parent_seq); +endtask +task uvm_reg_map::do_bus_write (uvm_reg_item rw, + uvm_sequencer_base sequencer, + uvm_reg_adapter adapter); + do_bus_access(rw, sequencer, adapter); +endtask +task uvm_reg_map::perform_accesses(ref uvm_reg_bus_op accesses[$], + input uvm_reg_item rw, + input uvm_reg_adapter adapter, + input uvm_sequencer_base sequencer); + string op; + uvm_reg_data_logic_t data; + uvm_endianness_e endian; + op=(rw.kind inside {UVM_READ,UVM_BURST_READ}) ? "Read" : "Wrote"; + endian=get_endian(UVM_NO_HIER); + if(policy!=null) + policy.order(accesses); + foreach(accesses[i]) begin + uvm_reg_bus_op rw_access=accesses[i]; + uvm_sequence_item bus_req; + if ((rw_access.kind == UVM_WRITE) && (endian == UVM_BIG_ENDIAN)) begin + { >> { rw_access.data }} = { << byte { rw_access.data}}; + end + adapter.m_set_item(rw); + bus_req = adapter.reg2bus(rw_access); + adapter.m_set_item(null); + if (bus_req == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"RegMem")) + uvm_report_fatal ("RegMem", {"adapter [",adapter.get_name(),"] didnt return a bus transaction"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1823, "", 1); + end + bus_req.set_sequencer(sequencer); + rw.parent.start_item(bus_req,rw.prior); + if (rw.parent != null && i == 0) + rw.parent.mid_do(rw); + rw.parent.finish_item(bus_req); + begin + uvm_event#(uvm_object) end_event ; + uvm_event_pool ep; + ep = bus_req.get_event_pool(); + end_event = ep.get("end") ; + end_event.wait_on(); + end + if (adapter.provides_responses) begin + uvm_sequence_item bus_rsp; + uvm_access_e op; + rw.parent.get_base_response(bus_rsp,bus_req.get_transaction_id()); + adapter.bus2reg(bus_rsp,rw_access); + end + else begin + adapter.bus2reg(bus_req,rw_access); + end + if ((rw_access.kind == UVM_READ) && (endian == UVM_BIG_ENDIAN)) begin + { >> { rw_access.data }} = { << byte { rw_access.data}}; + end + rw.status = rw_access.status; + begin + data = rw_access.data & ((1<>bit_shift) & 'hff; + p[idx]=n; + end + if(extra_byte) + p.push_back(ac); + end + accesses.delete(); + foreach(adr[i]) begin + uvm_reg_bus_op rw_access; + uvm_reg_data_t data; + for(int i0=0;i0=0;i--) begin + if(rw_access.byte_en[i]==0) + rw_access.n_bits-=8; + else + break; + end + accesses.push_back(rw_access); + end + perform_accesses(accesses, rw, adapter, sequencer); + if(rw.kind inside {UVM_READ,UVM_BURST_READ}) begin + p.delete(); + foreach(accesses[i0]) + for(int i1=0;i1 max_size) + max_size = uvm_reg_field::get_max_size(); + if (uvm_mem::get_max_size() > max_size) + max_size = uvm_mem::get_max_size(); + if (max_size > 64) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"RegModel")) + uvm_report_fatal ("RegModel", $sformatf("Register model requires that UVM_REG_DATA_WIDTH be defined as %0d or greater. Currently defined as %0d", max_size, 64), UVM_NONE, "t/uvm/src/reg/uvm_reg_block.svh", 1153, "", 1); + end + end + Xinit_address_mapsX(); + if(m_root_names[get_name()]>1) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/REG/DUPLROOT")) + uvm_report_error ("UVM/REG/DUPLROOT", $sformatf("There are %0d root register models named \"%s\". The names of the root register models have to be unique", m_root_names[get_name()], get_name()), UVM_NONE, "t/uvm/src/reg/uvm_reg_block.svh", 1162, "", 1); + end + -> m_uvm_lock_model_complete; + end +endfunction +function string uvm_reg_block::get_full_name(); + if (parent == null) + return get_name(); + return {parent.get_full_name(), ".", get_name()}; +endfunction: get_full_name +function void uvm_reg_block::get_fields(ref uvm_reg_field fields[$], + input uvm_hier_e hier=UVM_HIER); + foreach (regs[rg_]) begin + uvm_reg rg = rg_; + rg.get_fields(fields); + end + if (hier == UVM_HIER) + foreach (blks[blk_]) + begin + uvm_reg_block blk = blk_; + blk.get_fields(fields); + end +endfunction: get_fields +function void uvm_reg_block::get_virtual_fields(ref uvm_vreg_field fields[$], + input uvm_hier_e hier=UVM_HIER); + foreach (vregs[vreg_]) begin + uvm_vreg vreg = vreg_; + vreg.get_fields(fields); + end + if (hier == UVM_HIER) + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + blk.get_virtual_fields(fields); + end +endfunction: get_virtual_fields +function void uvm_reg_block::get_registers(ref uvm_reg regs[$], + input uvm_hier_e hier=UVM_HIER); + foreach (this.regs[rg]) + regs.push_back(rg); + if (hier == UVM_HIER) + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + blk.get_registers(regs); + end +endfunction: get_registers +function void uvm_reg_block::get_virtual_registers(ref uvm_vreg regs[$], + input uvm_hier_e hier=UVM_HIER); + foreach (vregs[rg]) + regs.push_back(rg); + if (hier == UVM_HIER) + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + blk.get_virtual_registers(regs); + end +endfunction: get_virtual_registers +function void uvm_reg_block::get_memories(ref uvm_mem mems[$], + input uvm_hier_e hier=UVM_HIER); + foreach (this.mems[mem_]) begin + uvm_mem mem = mem_; + mems.push_back(mem); + end + if (hier == UVM_HIER) + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + blk.get_memories(mems); + end +endfunction: get_memories +function void uvm_reg_block::get_blocks(ref uvm_reg_block blks[$], + input uvm_hier_e hier=UVM_HIER); + foreach (this.blks[blk_]) begin + uvm_reg_block blk = blk_; + blks.push_back(blk); + if (hier == UVM_HIER) + blk.get_blocks(blks); + end +endfunction: get_blocks +function void uvm_reg_block::get_root_blocks(ref uvm_reg_block blks[$]); + foreach (m_roots[blk]) begin + blks.push_back(blk); + end +endfunction +function int uvm_reg_block::find_blocks(input string name, + ref uvm_reg_block blks[$], + input uvm_reg_block root = null, + input uvm_object accessor = null); + uvm_reg_block r[$]; + uvm_reg_block b[$]; + if (root != null) begin + name = {root.get_full_name(), ".", name}; + b='{root}; + end else begin + get_root_blocks(b); + end + foreach(b[idx]) begin + r.push_back(b[idx]); + b[idx].get_blocks(r); + end + blks.delete(); + foreach(r[idx]) begin + if ( uvm_is_match( name, r[idx].get_full_name() ) ) + blks.push_back(r[idx]); + end + return blks.size(); +endfunction +function uvm_reg_block uvm_reg_block::find_block(input string name, + input uvm_reg_block root = null, + input uvm_object accessor = null); + uvm_reg_block blks[$]; + if (!find_blocks(name, blks, root, accessor)) + return null; + if (blks.size() > 1) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"MRTH1BLK")) + uvm_report_warning ("MRTH1BLK", {"More than one block matched the name \"", name, "\"."}, UVM_NONE, "t/uvm/src/reg/uvm_reg_block.svh", 1341, "", 1); + end + end + return blks[0]; +endfunction +function void uvm_reg_block::get_maps(ref uvm_reg_map maps[$]); + foreach (this.maps[map]) + maps.push_back(map); +endfunction +function uvm_reg_block uvm_reg_block::get_parent(); + get_parent = this.parent; +endfunction: get_parent +function uvm_reg_block uvm_reg_block::get_block_by_name(string name); + if (get_name() == name) + return this; + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + if (blk.get_name() == name) + return blk; + end + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + uvm_reg_block subblks[$]; + blk_.get_blocks(subblks, UVM_HIER); + foreach (subblks[j]) + if (subblks[j].get_name() == name) + return subblks[j]; + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Unable to locate block '",name, "' in block '",get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_block.svh", 1395, "", 1); + end + return null; +endfunction: get_block_by_name +function uvm_reg uvm_reg_block::get_reg_by_name(string name); + foreach (regs[rg_]) begin + uvm_reg rg = rg_; + if (rg.get_name() == name) + return rg; + end + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + uvm_reg subregs[$]; + blk_.get_registers(subregs, UVM_HIER); + foreach (subregs[j]) + if (subregs[j].get_name() == name) + return subregs[j]; + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Unable to locate register '",name, "' in block '",get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_block.svh", 1422, "", 1); + end + return null; +endfunction: get_reg_by_name +function uvm_vreg uvm_reg_block::get_vreg_by_name(string name); + foreach (vregs[rg_]) begin + uvm_vreg rg = rg_; + if (rg.get_name() == name) + return rg; + end + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + uvm_vreg subvregs[$]; + blk_.get_virtual_registers(subvregs, UVM_HIER); + foreach (subvregs[j]) + if (subvregs[j].get_name() == name) + return subvregs[j]; + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Unable to locate virtual register '",name, "' in block '",get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_block.svh", 1449, "", 1); + end + return null; +endfunction: get_vreg_by_name +function uvm_mem uvm_reg_block::get_mem_by_name(string name); + foreach (mems[mem_]) begin + uvm_mem mem = mem_; + if (mem.get_name() == name) + return mem; + end + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + uvm_mem submems[$]; + blk_.get_memories(submems, UVM_HIER); + foreach (submems[j]) + if (submems[j].get_name() == name) + return submems[j]; + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Unable to locate memory '",name, "' in block '",get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_block.svh", 1476, "", 1); + end + return null; +endfunction: get_mem_by_name +function uvm_reg_field uvm_reg_block::get_field_by_name(string name); + foreach (regs[rg_]) begin + uvm_reg rg = rg_; + uvm_reg_field fields[$]; + rg.get_fields(fields); + foreach (fields[i]) + if (fields[i].get_name() == name) + return fields[i]; + end + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + uvm_reg subregs[$]; + blk_.get_registers(subregs, UVM_HIER); + foreach (subregs[j]) begin + uvm_reg_field fields[$]; + subregs[j].get_fields(fields); + foreach (fields[i]) + if (fields[i].get_name() == name) + return fields[i]; + end + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Unable to locate field '",name, "' in block '",get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_block.svh", 1511, "", 1); + end + return null; +endfunction: get_field_by_name +function uvm_vreg_field uvm_reg_block::get_vfield_by_name(string name); + foreach (vregs[rg_]) begin + uvm_vreg rg =rg_; + uvm_vreg_field fields[$]; + rg.get_fields(fields); + foreach (fields[i]) + if (fields[i].get_name() == name) + return fields[i]; + end + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + uvm_vreg subvregs[$]; + blk_.get_virtual_registers(subvregs, UVM_HIER); + foreach (subvregs[j]) begin + uvm_vreg_field fields[$]; + subvregs[j].get_fields(fields); + foreach (fields[i]) + if (fields[i].get_name() == name) + return fields[i]; + end + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Unable to locate virtual field '",name, "' in block '",get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_block.svh", 1547, "", 1); + end + return null; +endfunction: get_vfield_by_name +function uvm_reg_cvr_t uvm_reg_block::set_coverage(uvm_reg_cvr_t is_on); + this.cover_on = this.has_cover & is_on; + foreach (regs[rg_]) begin + uvm_reg rg = rg_; + void'(rg.set_coverage(is_on)); + end + foreach (mems[mem_]) begin + uvm_mem mem = mem_; + void'(mem.set_coverage(is_on)); + end + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + void'(blk.set_coverage(is_on)); + end + return this.cover_on; +endfunction: set_coverage +function void uvm_reg_block::sample_values(); + foreach (regs[rg_]) begin + uvm_reg rg = rg_; + rg.sample_values(); + end + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + blk.sample_values(); + end +endfunction +function void uvm_reg_block::XsampleX(uvm_reg_addr_t addr, + bit is_read, + uvm_reg_map map); + sample(addr, is_read, map); + if (parent != null) begin + end +endfunction +function uvm_reg_cvr_t uvm_reg_block::build_coverage(uvm_reg_cvr_t models); + build_coverage = UVM_NO_COVERAGE; + void'(uvm_reg_cvr_rsrc_db::read_by_name({"uvm_reg::", get_full_name()}, + "include_coverage", + build_coverage, this)); + return build_coverage & models; +endfunction: build_coverage +function void uvm_reg_block::add_coverage(uvm_reg_cvr_t models); + this.has_cover |= models; +endfunction: add_coverage +function bit uvm_reg_block::has_coverage(uvm_reg_cvr_t models); + return ((this.has_cover & models) == models); +endfunction: has_coverage +function bit uvm_reg_block::get_coverage(uvm_reg_cvr_t is_on = UVM_CVR_ALL); + if (this.has_coverage(is_on) == 0) return 0; + return ((this.cover_on & is_on) == is_on); +endfunction: get_coverage +function void uvm_reg_block::reset(string kind = "HARD"); + foreach (regs[rg_]) begin + uvm_reg rg = rg_; + rg.reset(kind); + end + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + blk.reset(kind); + end +endfunction +function bit uvm_reg_block::needs_update(); + needs_update = 0; + foreach (regs[rg_]) begin + uvm_reg rg = rg_; + if (rg.needs_update()) + return 1; + end + foreach (blks[blk_]) begin + uvm_reg_block blk =blk_; + if (blk.needs_update()) + return 1; + end +endfunction: needs_update +task uvm_reg_block::update(output uvm_status_e status, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + status = UVM_IS_OK; + if (!needs_update()) begin + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", $sformatf("%s:%0d - RegModel block %s does not need updating", fname, lineno, this.get_name()), UVM_HIGH, "t/uvm/src/reg/uvm_reg_block.svh", 1694, "", 1); + end + return; + end + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", $sformatf("%s:%0d - Updating model block %s with %s path", fname, lineno, this.get_name(), path.name ), UVM_HIGH, "t/uvm/src/reg/uvm_reg_block.svh", 1699, "", 1); + end + foreach (regs[rg_]) begin + uvm_reg rg = rg_; + if (rg.needs_update()) begin + rg.update(status, path, null, parent, prior, extension); + if (status != UVM_IS_OK && status != UVM_HAS_X) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Register \"%s\" could not be updated", rg.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_reg_block.svh", 1707, "", 1); + end + return; + end + end + end + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + blk.update(status,path,parent,prior,extension,fname,lineno); + end +endtask: update +task uvm_reg_block::mirror(output uvm_status_e status, + input uvm_check_e check = UVM_NO_CHECK, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_status_e final_status = UVM_IS_OK; + foreach (regs[rg_]) begin + uvm_reg rg = rg_; + rg.mirror(status, check, path, null, + parent, prior, extension, fname, lineno); + if (status != UVM_IS_OK && status != UVM_HAS_X) begin + final_status = status; + end + end + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + blk.mirror(status, check, path, parent, prior, extension, fname, lineno); + if (status != UVM_IS_OK && status != UVM_HAS_X) begin + final_status = status; + end + end +endtask: mirror +task uvm_reg_block::write_reg_by_name(output uvm_status_e status, + input string name, + input uvm_reg_data_t data, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg rg; + this.fname = fname; + this.lineno = lineno; + status = UVM_NOT_OK; + rg = this.get_reg_by_name(name); + if (rg != null) + rg.write(status, data, path, map, parent, prior, extension); +endtask: write_reg_by_name +task uvm_reg_block::read_reg_by_name(output uvm_status_e status, + input string name, + output uvm_reg_data_t data, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg rg; + this.fname = fname; + this.lineno = lineno; + status = UVM_NOT_OK; + rg = this.get_reg_by_name(name); + if (rg != null) + rg.read(status, data, path, map, parent, prior, extension); +endtask: read_reg_by_name +task uvm_reg_block::write_mem_by_name(output uvm_status_e status, + input string name, + input uvm_reg_addr_t offset, + input uvm_reg_data_t data, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_mem mem; + this.fname = fname; + this.lineno = lineno; + status = UVM_NOT_OK; + mem = get_mem_by_name(name); + if (mem != null) + mem.write(status, offset, data, path, map, parent, prior, extension); +endtask: write_mem_by_name +task uvm_reg_block::read_mem_by_name(output uvm_status_e status, + input string name, + input uvm_reg_addr_t offset, + output uvm_reg_data_t data, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_mem mem; + this.fname = fname; + this.lineno = lineno; + status = UVM_NOT_OK; + mem = get_mem_by_name(name); + if (mem != null) + mem.read(status, offset, data, path, map, parent, prior, extension); +endtask: read_mem_by_name +task uvm_reg_block::readmemh(string filename); +endtask: readmemh +task uvm_reg_block::writememh(string filename); +endtask: writememh +function uvm_reg_map uvm_reg_block::create_map(string name, + uvm_reg_addr_t base_addr, + int unsigned n_bytes, + uvm_endianness_e endian, + bit byte_addressing=1); + uvm_reg_map map; + map = uvm_reg_map::type_id_create(name,,this.get_full_name()); + map.configure(this,base_addr,n_bytes,endian,byte_addressing); + add_map(map); + return map; +endfunction +function void uvm_reg_block::add_map(uvm_reg_map map); + if (this.locked) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", "Cannot add map to locked model", UVM_NONE, "t/uvm/src/reg/uvm_reg_block.svh", 1894, "", 1); + end + return; + end + if (this.maps.exists(map)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Map '",map.get_name(), "' already exists in '",get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_block.svh", 1900, "", 1); + end + return; + end + this.maps[map] = 1; + if (maps.num() == 1) + default_map = map; +endfunction: add_map +function uvm_reg_map uvm_reg_block::get_map_by_name(string name); + uvm_reg_map maps[$]; + this.get_maps(maps); + foreach (maps[i]) + if (maps[i].get_name() == name) + return maps[i]; + foreach (maps[i]) begin + uvm_reg_map submaps[$]; + maps[i].get_submaps(submaps, UVM_HIER); + foreach (submaps[j]) + if (submaps[j].get_name() == name) + return submaps[j]; + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Map with name '",name,"' does not exist in block"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_block.svh", 1932, "", 1); + end + return null; +endfunction +function void uvm_reg_block::set_default_map(uvm_reg_map map); + if (!maps.exists(map)) + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Map '",map.get_full_name(),"' does not exist in block"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_block.svh", 1941, "", 1); + end + default_map = map; +endfunction +function uvm_reg_map uvm_reg_block::get_default_map(); + return default_map; +endfunction +function uvm_door_e uvm_reg_block::get_default_door(); + if (this.default_path != UVM_DEFAULT_DOOR) + return this.default_path; + if (this.parent != null) + return this.parent.get_default_door(); + return UVM_FRONTDOOR; +endfunction +function void uvm_reg_block::set_default_door(uvm_door_e door); + this.default_path = door; +endfunction +function void uvm_reg_block::Xinit_address_mapsX(); + foreach (maps[map_]) begin + uvm_reg_map map = map_; + map.Xinit_address_mapX(); + end +endfunction +function void uvm_reg_block::set_backdoor(uvm_reg_backdoor bkdr, + string fname = "", + int lineno = 0); + bkdr.fname = fname; + bkdr.lineno = lineno; + if (this.backdoor != null && + this.backdoor.has_update_threads()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", "Previous register backdoor still has update threads running. Backdoors with active mirroring should only be set before simulation starts.", UVM_NONE, "t/uvm/src/reg/uvm_reg_block.svh", 2004, "", 1); + end + end + this.backdoor = bkdr; +endfunction: set_backdoor +function uvm_reg_backdoor uvm_reg_block::get_backdoor(bit inherited = 1); + if (backdoor == null && inherited) begin + uvm_reg_block blk = get_parent(); + while (blk != null) begin + uvm_reg_backdoor bkdr = blk.get_backdoor(); + if (bkdr != null) + return bkdr; + blk = blk.get_parent(); + end + end + return this.backdoor; +endfunction: get_backdoor +function void uvm_reg_block::clear_hdl_path(string kind = "RTL"); + if (kind == "ALL") begin + hdl_paths_pool = new("hdl_paths"); + return; + end + if (kind == "") + kind = get_default_hdl_path(); + if (!hdl_paths_pool.exists(kind)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Unknown HDL Abstraction '",kind,"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_block.svh", 2040, "", 1); + end + return; + end + hdl_paths_pool.delete(kind); +endfunction +function void uvm_reg_block::add_hdl_path(string path, string kind = "RTL"); + uvm_queue #(string) paths; + paths = hdl_paths_pool.get(kind); + paths.push_back(path); +endfunction +function bit uvm_reg_block::has_hdl_path(string kind = ""); + if (kind == "") begin + kind = get_default_hdl_path(); + end + return hdl_paths_pool.exists(kind); +endfunction +function void uvm_reg_block::get_hdl_path(ref string paths[$], input string kind = ""); + uvm_queue #(string) hdl_paths; + if (kind == "") + kind = get_default_hdl_path(); + if (!has_hdl_path(kind)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Block does not have hdl path defined for abstraction '",kind,"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_block.svh", 2081, "", 1); + end + return; + end + hdl_paths = hdl_paths_pool.get(kind); + for (int i=0; i 0) begin + mem.read(status, k-1, val, UVM_FRONTDOOR, maps[j], this); + if (status != UVM_IS_OK) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"uvm_mem_walk_seq")) + uvm_report_error ("uvm_mem_walk_seq", $sformatf("Status was %s when reading \"%s[%0d]\" through map \"%s\".", status.name(), mem.get_full_name(), k, maps[j].get_full_name()), UVM_NONE, "t/uvm/src/reg/sequences/uvm_mem_walk_seq.svh", 143, "", 1); + end + end + else begin + exp = ~(k-1) & ((1'b1< 32) + val = uvm_reg_data_t'(val << 32) | $random; + if (mode == "RO") begin + mem.peek(status, k, exp); + if (status != UVM_IS_OK) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"uvm_mem_access_seq")) + uvm_report_error ("uvm_mem_access_seq", $sformatf("Status was %s when reading \"%s[%0d]\" through backdoor.", status.name(), mem.get_full_name(), k), UVM_NONE, "t/uvm/src/reg/sequences/uvm_mem_access_seq.svh", 124, "", 1); + end + end + end + else exp = val; + mem.write(status, k, val, UVM_FRONTDOOR, maps[j], this); + if (status != UVM_IS_OK) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"uvm_mem_access_seq")) + uvm_report_error ("uvm_mem_access_seq", $sformatf("Status was %s when writing \"%s[%0d]\" through map \"%s\".", status.name(), mem.get_full_name(), k, maps[j].get_full_name()), UVM_NONE, "t/uvm/src/reg/sequences/uvm_mem_access_seq.svh", 132, "", 1); + end + end + #1; + val = 'x; + mem.peek(status, k, val); + if (status != UVM_IS_OK) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"uvm_mem_access_seq")) + uvm_report_error ("uvm_mem_access_seq", $sformatf("Status was %s when reading \"%s[%0d]\" through backdoor.", status.name(), mem.get_full_name(), k), UVM_NONE, "t/uvm/src/reg/sequences/uvm_mem_access_seq.svh", 140, "", 1); + end + end + else begin + if (val !== exp) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"uvm_mem_access_seq")) + uvm_report_error ("uvm_mem_access_seq", $sformatf("Backdoor \"%s[%0d]\" read back as 'h%h instead of 'h%h.", mem.get_full_name(), k, val, exp), UVM_NONE, "t/uvm/src/reg/sequences/uvm_mem_access_seq.svh", 145, "", 1); + end + end + end + exp = ~exp & ((1'b1< local_size__) + abstractions = abstractions[0:local_size__-1]; + else + while (abstractions.size() < local_size__) abstractions.push_back(abstractions[local_size__]); + foreach (abstractions[i]) + abstractions[i] = __local_packer__.unpack_string(); + end +UVM_RECORD: + if (!((UVM_DEFAULT)&UVM_NORECORD)) begin + begin + int sz__; + foreach (abstractions[i]) + sz__ = i; + if(sz__ == 0) begin + if (__local_recorder__ != null && __local_recorder__.is_open()) begin + if (__local_recorder__.use_record_attribute()) + __local_recorder__.record_generic("abstractions", $sformatf("%p", 0)); + else + if (32 > 64) + __local_recorder__.record_field("abstractions", 0, 32, UVM_DEC); + else + __local_recorder__.record_field_int("abstractions", 0, 32, UVM_DEC); + end + end + else if(sz__ < 10) begin + foreach(abstractions[i]) begin + string nm__ = $sformatf("%s[%0d]", "abstractions", i); + if (__local_recorder__ != null && __local_recorder__.is_open()) begin + if (__local_recorder__.use_record_attribute()) + __local_recorder__.record_generic(nm__, $sformatf("%p", abstractions[i])); + else + __local_recorder__.record_string(nm__,abstractions[i]); + end + end + end + else begin + for(int i=0; i<5; ++i) begin + string nm__ = $sformatf("%s[%0d]", "abstractions", i); + if (__local_recorder__ != null && __local_recorder__.is_open()) begin + if (__local_recorder__.use_record_attribute()) + __local_recorder__.record_generic(nm__, $sformatf("%p", abstractions[i])); + else + __local_recorder__.record_string(nm__,abstractions[i]); + end + end + for(int i=sz__-5; i __tmp_curr) + __tmp_curr = __tmp_max - __tmp_end_elements; + if (__tmp_curr < __tmp_begin_elements) + __tmp_curr = __tmp_begin_elements; + else + __local_printer__.print_array_range(__tmp_begin_elements, __tmp_curr-1); + while (__tmp_curr < __tmp_max) begin + __local_printer__.print_string($sformatf("[%0d]", __tmp_curr), abstractions[__tmp_curr]); + __tmp_curr++; + end + end + end + end + __local_printer__.print_array_footer(__tmp_max); +end + end +UVM_SET: + if (!((UVM_DEFAULT)&UVM_NOSET)) begin + if(local_rsrc_name__ == "abstractions") begin +begin +begin + uvm_resource#(uvm_integral_t) __tmp_rsrc__; + local_success__ = $cast(__tmp_rsrc__, local_rsrc__); + if (local_success__) begin + local_size__ = __tmp_rsrc__.read(this); + end +end + if (!local_success__) +begin + uvm_resource#(uvm_bitstream_t) __tmp_rsrc__; + local_success__ = $cast(__tmp_rsrc__, local_rsrc__); + if (local_success__) begin + local_size__ = __tmp_rsrc__.read(this); + end +end + if (!local_success__) +begin + uvm_resource#(int) __tmp_rsrc__; + local_success__ = $cast(__tmp_rsrc__, local_rsrc__); + if (local_success__) begin + local_size__ = __tmp_rsrc__.read(this); + end +end + if (!local_success__) +begin + uvm_resource#(int unsigned) __tmp_rsrc__; + local_success__ = $cast(__tmp_rsrc__, local_rsrc__); + if (local_success__) begin + local_size__ = __tmp_rsrc__.read(this); + end +end +end + if (local_success__) + if (abstractions.size() > local_size__) + abstractions = abstractions[0:local_size__-1]; + else + while (abstractions.size() < local_size__) abstractions.push_back(abstractions[local_size__]); + end + else begin + string local_name__ = {"abstractions", "["}; + if (local_rsrc_name__.len() && + local_rsrc_name__[local_rsrc_name__.len()-1] == "]" && + local_rsrc_name__.substr(0, local_name__.len()-1) == local_name__) begin + string local_index_str__ = local_rsrc_name__.substr(local_name__.len(), + local_rsrc_name__.len()-2); + int local_index__; + int local_code__ = $sscanf(local_index_str__, "%d", local_index__); + if (local_code__ > 0) begin + if (local_index__ < 0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/FIELDS/QDA_IDX")) + uvm_report_warning ("UVM/FIELDS/QDA_IDX", $sformatf("Index '%0d' is not valid for field '%s.%s' of size '%0d'", local_index__, get_full_name(), "abstractions", abstractions.size() ), UVM_NONE, "t/uvm/src/reg/sequences/uvm_reg_mem_hdl_paths_seq.svh", 59, "", 1); + end + end + else begin + string tmp_string__; +begin + uvm_resource#(string) __tmp_rsrc__; + local_success__ = $cast(__tmp_rsrc__, local_rsrc__); + if (local_success__) begin + tmp_string__ = __tmp_rsrc__.read(this); + end +end + if (local_success__) begin + if (local_index__ >= abstractions.size()) + if (abstractions.size() > local_index__ + 1) + abstractions = abstractions[0:local_index__ + 1-1]; + else + while (abstractions.size() < local_index__ + 1) abstractions.push_back(abstractions[local_index__ + 1]); + abstractions[local_index__] = tmp_string__; + end + end + end + end + end + end + endcase + end +endfunction : __m_uvm_execute_field_op + function new(string name="uvm_reg_mem_hdl_paths_seq"); + super.new(name); + endfunction + virtual task body(); + if (model == null) begin + uvm_report_error("uvm_reg_mem_hdl_paths_seq", "Register model handle is null"); + return; + end + begin + if (uvm_report_enabled(UVM_LOW,UVM_INFO,"uvm_reg_mem_hdl_paths_seq")) + uvm_report_info ("uvm_reg_mem_hdl_paths_seq", {"checking HDL paths for all registers/memories in ", model.get_full_name()}, UVM_LOW, "t/uvm/src/reg/sequences/uvm_reg_mem_hdl_paths_seq.svh", 76, "", 1); + end + if (abstractions.size() == 0) + do_block(model, ""); + else begin + foreach (abstractions[i]) + do_block(model, abstractions[i]); + end + begin + if (uvm_report_enabled(UVM_LOW,UVM_INFO,"uvm_reg_mem_hdl_paths_seq")) + uvm_report_info ("uvm_reg_mem_hdl_paths_seq", "HDL path validation completed ", UVM_LOW, "t/uvm/src/reg/sequences/uvm_reg_mem_hdl_paths_seq.svh", 85, "", 1); + end + endtask: body + virtual task reset_blk(uvm_reg_block blk); + endtask + protected virtual function void do_block(uvm_reg_block blk, + string kind); + uvm_reg regs[$]; + uvm_mem mems[$]; + begin + if (uvm_report_enabled(UVM_MEDIUM,UVM_INFO,"uvm_reg_mem_hdl_paths_seq")) + uvm_report_info ("uvm_reg_mem_hdl_paths_seq", {"Validating HDL paths in ", blk.get_full_name(), " for ", (kind == "") ? "default" : kind, " design abstraction"}, UVM_MEDIUM, "t/uvm/src/reg/sequences/uvm_reg_mem_hdl_paths_seq.svh", 104, "", 1); + end + blk.get_registers(regs, UVM_NO_HIER); + foreach (regs[i]) + check_reg(regs[i], kind); + blk.get_memories(mems, UVM_NO_HIER); + foreach (mems[i]) + check_mem(mems[i], kind); + begin + uvm_reg_block blks[$]; + blk.get_blocks(blks); + foreach (blks[i]) begin + do_block(blks[i], kind); + end + end + endfunction: do_block + protected virtual function void check_reg(uvm_reg r, + string kind); + uvm_hdl_path_concat paths[$]; + if(!r.has_hdl_path(kind)) + return; + r.get_full_hdl_path(paths, kind); + if (paths.size() == 0) return; + foreach(paths[p]) begin + uvm_hdl_path_concat path=paths[p]; + foreach (path.slices[j]) begin + string p_ = path.slices[j].path; + uvm_reg_data_t d; + if (!uvm_hdl_read(p_,d)) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"uvm_reg_mem_hdl_paths_seq")) + uvm_report_error ("uvm_reg_mem_hdl_paths_seq", $sformatf("HDL path \"%s\" for register \"%s\" is not readable", p_, r.get_full_name()), UVM_NONE, "t/uvm/src/reg/sequences/uvm_reg_mem_hdl_paths_seq.svh", 145, "", 1); + end + if (!uvm_hdl_check_path(p_)) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"uvm_reg_mem_hdl_paths_seq")) + uvm_report_error ("uvm_reg_mem_hdl_paths_seq", $sformatf("HDL path \"%s\" for register \"%s\" is not accessible", p_, r.get_full_name()), UVM_NONE, "t/uvm/src/reg/sequences/uvm_reg_mem_hdl_paths_seq.svh", 149, "", 1); + end + end + end + endfunction + protected virtual function void check_mem(uvm_mem m, + string kind); + uvm_hdl_path_concat paths[$]; + if(!m.has_hdl_path(kind)) + return; + m.get_full_hdl_path(paths, kind); + if (paths.size() == 0) return; + foreach(paths[p]) begin + uvm_hdl_path_concat path=paths[p]; + foreach (path.slices[j]) + begin + string p_ = path.slices[j].path; + if(!uvm_hdl_check_path(p_)) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"uvm_reg_mem_hdl_paths_seq")) + uvm_report_error ("uvm_reg_mem_hdl_paths_seq", $sformatf("HDL path \"%s\" for memory \"%s\" is not accessible", p_, m.get_full_name()), UVM_NONE, "t/uvm/src/reg/sequences/uvm_reg_mem_hdl_paths_seq.svh", 174, "", 1); + end + end + end + endfunction +endclass: uvm_reg_mem_hdl_paths_seq +endpackage From cb5466a90b03e37dae73a464ffaf1f6313a5e224 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 9 Sep 2023 11:54:55 -0400 Subject: [PATCH 075/111] Tests: UVM passes V3Param stage --- src/V3Options.cpp | 1 + src/V3Options.h | 2 ++ src/Verilator.cpp | 10 ++++++++-- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 3cf91c24f..bc08b0256 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -1173,6 +1173,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char DECL_OPTION("-debug-emitv", OnOff, &m_debugEmitV).undocumented(); DECL_OPTION("-debug-exit-parse", OnOff, &m_debugExitParse).undocumented(); DECL_OPTION("-debug-exit-uvm", OnOff, &m_debugExitUvm).undocumented(); + DECL_OPTION("-debug-exit-uvm23", OnOff, &m_debugExitUvm23).undocumented(); DECL_OPTION("-debug-fatalsrc", CbCall, []() { v3fatalSrc("--debug-fatal-src"); }).undocumented(); // See also --debug-abort diff --git a/src/V3Options.h b/src/V3Options.h index 702ff680b..f9ee897bb 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -236,6 +236,7 @@ private: bool m_debugEmitV = false; // main switch: --debug-emitv bool m_debugExitParse = false; // main switch: --debug-exit-parse bool m_debugExitUvm = false; // main switch: --debug-exit-uvm + bool m_debugExitUvm23 = false; // main switch: --debug-exit-uvm23 bool m_debugLeak = true; // main switch: --debug-leak bool m_debugNondeterminism = false; // main switch: --debug-nondeterminism bool m_debugPartition = false; // main switch: --debug-partition @@ -461,6 +462,7 @@ public: bool debugEmitV() const VL_MT_SAFE { return m_debugEmitV; } bool debugExitParse() const { return m_debugExitParse; } bool debugExitUvm() const { return m_debugExitUvm; } + bool debugExitUvm23() const { return m_debugExitUvm23; } bool debugLeak() const { return m_debugLeak; } bool debugNondeterminism() const { return m_debugNondeterminism; } bool debugPartition() const { return m_debugPartition; } diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 243b4c4ae..57b8a90c0 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -143,16 +143,22 @@ static void process() { V3Error::abortIfErrors(); if (v3Global.opt.stats()) V3Stats::statsStageAll(v3Global.rootp(), "Link"); - if (v3Global.opt.debugExitUvm()) { + if (v3Global.opt.debugExitUvm23()) { V3Error::abortIfErrors(); if (v3Global.opt.xmlOnly()) V3EmitXml::emitxml(); - cout << "--debug-exit-uvm: Exiting after UVM-supported pass\n"; + cout << "--debug-exit-uvm23: Exiting after UVM-supported pass\n"; std::exit(0); } // Remove parameters by cloning modules to de-parameterized versions // This requires some width calculations and constant propagation V3Param::param(v3Global.rootp()); + if (v3Global.opt.debugExitUvm()) { + V3Error::abortIfErrors(); + if (v3Global.opt.xmlOnly()) V3EmitXml::emitxml(); + cout << "--debug-exit-uvm: Exiting after UVM-supported pass\n"; + std::exit(0); + } V3LinkDot::linkDotParamed(v3Global.rootp()); // Cleanup as made new modules V3LinkLValue::linkLValue(v3Global.rootp()); // Resolve new VarRefs V3Error::abortIfErrors(); From b5b278d0722350d5f3ea55000987d4695f9e1ba3 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 10 Sep 2023 08:53:21 -0400 Subject: [PATCH 076/111] Fix fork crash with no init, test for (#4471) --- src/V3Fork.cpp | 10 ++++++---- test_regress/t/t_fork_initial.pl | 26 ++++++++++++++++++++++++++ test_regress/t/t_fork_initial.v | 15 +++++++++++++++ 3 files changed, 47 insertions(+), 4 deletions(-) create mode 100755 test_regress/t/t_fork_initial.pl create mode 100644 test_regress/t/t_fork_initial.v diff --git a/src/V3Fork.cpp b/src/V3Fork.cpp index bd7763776..31fdca34b 100644 --- a/src/V3Fork.cpp +++ b/src/V3Fork.cpp @@ -218,10 +218,12 @@ private: beginp->stmtsp()->addNext(instAsgnp); beginp->stmtsp()->addNext(forkp); - forkp->initsp()->foreach([forkp](AstAssign* asgnp) { - asgnp->unlinkFrBack(); - forkp->addHereThisAsNext(asgnp); - }); + if (forkp->initsp()) { + forkp->initsp()->foreach([forkp](AstAssign* asgnp) { + asgnp->unlinkFrBack(); + forkp->addHereThisAsNext(asgnp); + }); + } UASSERT_OBJ(!forkp->initsp(), forkp, "Leftover nodes in block_item_declaration"); m_modp->addStmtsp(m_instance.m_classp); diff --git a/test_regress/t/t_fork_initial.pl b/test_regress/t/t_fork_initial.pl new file mode 100755 index 000000000..fccceb96e --- /dev/null +++ b/test_regress/t/t_fork_initial.pl @@ -0,0 +1,26 @@ +#!/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(simulator => 1); + +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + # bug#4471 - remove this + verilator_make_gmake => 0, + ); + +#bug#4471 - add this +#execute( +# check_finished => 1, +# ); + +ok(1); +1; diff --git a/test_regress/t/t_fork_initial.v b/test_regress/t/t_fork_initial.v new file mode 100644 index 000000000..24780ede3 --- /dev/null +++ b/test_regress/t/t_fork_initial.v @@ -0,0 +1,15 @@ +// 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 + +module t(); + initial fork + reg i; + i = 1'b1; + if (i != 1'b1) $stop; + $write("*-* All Finished *-*\n"); + $finish; + join +endmodule From d72f1b89fc53dbe11530681405094032e7966560 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 10 Sep 2023 18:53:51 -0400 Subject: [PATCH 077/111] Internals: Minor internal code coverage cleanups --- src/V3Fork.cpp | 2 +- src/V3Graph.cpp | 20 -------------------- src/V3Graph.h | 2 -- src/V3PreLex.l | 12 ++++++------ test_regress/t/t_dist_warn_coverage.pl | 1 - test_regress/t/t_foreach_bad.out | 3 +++ test_regress/t/t_foreach_bad.v | 2 ++ 7 files changed, 12 insertions(+), 30 deletions(-) diff --git a/src/V3Fork.cpp b/src/V3Fork.cpp index 31fdca34b..0cfc7dd00 100644 --- a/src/V3Fork.cpp +++ b/src/V3Fork.cpp @@ -247,7 +247,7 @@ private: } else if (AstNodeFTask* taskp = VN_CAST(m_procp, NodeFTask)) { stmtsp = taskp->stmtsp(); } else { - v3fatal("m_procp is not a begin block or a procedure"); + m_procp->v3fatalSrc("m_procp is not a begin block or a procedure"); } return stmtsp; } diff --git a/src/V3Graph.cpp b/src/V3Graph.cpp index b2c3c4756..9eca82238 100644 --- a/src/V3Graph.cpp +++ b/src/V3Graph.cpp @@ -92,26 +92,6 @@ void V3GraphVertex::rerouteEdges(V3Graph* graphp) { bool V3GraphVertex::inSize1() const { return !inEmpty() && !inBeginp()->inNextp(); } bool V3GraphVertex::outSize1() const { return !outEmpty() && !outBeginp()->outNextp(); } -uint32_t V3GraphVertex::inHash() const { - // We want the same hash ignoring the order of edges. - // So we need an associative operator, like XOR. - // However with XOR multiple edges to the same source will cancel out, - // so we use ADD. (Generally call this only after removing duplicates though) - uint32_t hash = 0; - for (V3GraphEdge* edgep = this->inBeginp(); edgep; edgep = edgep->inNextp()) { - hash += cvtToHash(edgep->fromp()); - } - return hash; -} - -uint32_t V3GraphVertex::outHash() const { - uint32_t hash = 0; - for (V3GraphEdge* edgep = this->outBeginp(); edgep; edgep = edgep->outNextp()) { - hash += cvtToHash(edgep->top()); - } - return hash; -} - V3GraphEdge* V3GraphVertex::findConnectingEdgep(GraphWay way, const V3GraphVertex* waywardp) { // O(edges) linear search. Searches search both nodes' edge lists in // parallel. The lists probably aren't _both_ huge, so this is diff --git a/src/V3Graph.h b/src/V3Graph.h index 2d277826c..84dd4f85f 100644 --- a/src/V3Graph.h +++ b/src/V3Graph.h @@ -276,11 +276,9 @@ public: V3GraphEdge* inBeginp() const { return m_ins.begin(); } bool inEmpty() const { return inBeginp() == nullptr; } bool inSize1() const; - uint32_t inHash() const; V3GraphEdge* outBeginp() const { return m_outs.begin(); } bool outEmpty() const { return outBeginp() == nullptr; } bool outSize1() const; - uint32_t outHash() const; V3GraphEdge* beginp(GraphWay way) const { return way.forward() ? outBeginp() : inBeginp(); } // METHODS /// Error reporting diff --git a/src/V3PreLex.l b/src/V3PreLex.l index 4524374b4..1daee9a31 100644 --- a/src/V3PreLex.l +++ b/src/V3PreLex.l @@ -501,11 +501,11 @@ size_t V3PreLex::inputToLex(char* buf, size_t max_size) { // become a stale invalid pointer. // VPreStream* streamp = curStreamp(); - if (debug() >= 10) { + if (debug() >= 10) { // LCOV_EXCL_START cout << "- pp:inputToLex ITL s=" << max_size << " bs=" << streamp->m_buffers.size() << endl; dumpStack(); - } + } // LCOV_EXCL_STOP // For testing, use really small chunks // if (max_size > 13) max_size=13; again: @@ -696,16 +696,16 @@ void V3PreLex::warnBackslashSpace() { BSSPACE, "Backslash followed by whitespace, perhaps the whitespace is accidental?"); } -void V3PreLex::dumpSummary() { +void V3PreLex::dumpSummary() { // LCOV_EXCL_START cout << "- pp::dumpSummary curBuf=" << cvtToHex(currentBuffer()); #ifdef FLEX_DEBUG // Else peeking at internals may cause portability issues ssize_t left = (yy_n_chars - (yy_c_buf_p - currentBuffer()->yy_ch_buf)); cout << " left=" << std::dec << left; #endif cout << endl; -} +} // LCOV_EXCL_STOP -void V3PreLex::dumpStack() { +void V3PreLex::dumpStack() { // LCOV_EXCL_START // For debug use dumpSummary(); std::stack tmpstack = LEXP->m_streampStack; @@ -717,7 +717,7 @@ void V3PreLex::dumpStack() { << (streamp->m_eof ? " [EOF]" : "") << (streamp->m_file ? " [FILE]" : "") << endl; tmpstack.pop(); } -} +} // LCOV_EXCL_STOP string V3PreLex::cleanDbgStrg(const string& in) { string result = in; diff --git a/test_regress/t/t_dist_warn_coverage.pl b/test_regress/t/t_dist_warn_coverage.pl index 2a69f2402..25b6be901 100755 --- a/test_regress/t/t_dist_warn_coverage.pl +++ b/test_regress/t/t_dist_warn_coverage.pl @@ -101,7 +101,6 @@ foreach my $s ( 'Unsupported: no_inline for tasks', 'Unsupported: static cast to ', 'Unsupported: super', - '\'foreach\' loop variable expects simple variable name', ) { $Suppressed{$s} = 1; } if (!-r "$root/.git") { diff --git a/test_regress/t/t_foreach_bad.out b/test_regress/t/t_foreach_bad.out index 799c765f5..2b09380d7 100644 --- a/test_regress/t/t_foreach_bad.out +++ b/test_regress/t/t_foreach_bad.out @@ -1,4 +1,7 @@ %Error: t/t_foreach_bad.v:14:7: Syntax error; foreach missing bracketed loop variable (IEEE 1800-2017 12.7.3) 14 | foreach (array); | ^~~~~~~ +%Error: t/t_foreach_bad.v:18:23: 'foreach' loop variable expects simple variable name + 18 | foreach (array[a.b]); + | ^ %Error: Exiting due to diff --git a/test_regress/t/t_foreach_bad.v b/test_regress/t/t_foreach_bad.v index be94993af..ac2d7bd68 100644 --- a/test_regress/t/t_foreach_bad.v +++ b/test_regress/t/t_foreach_bad.v @@ -15,6 +15,8 @@ module t (/*AUTOARG*/); foreach (array.array[a]); // not supported + foreach (array[a.b]); // no index + $write("*-* All Finished *-*\n"); $finish; end From b66c4153b1b22e69e014fcb14d97a93593c3b6c3 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Mon, 11 Sep 2023 13:06:15 +0200 Subject: [PATCH 078/111] Compute purity of AstCMethodHard (#4460) --- src/V3AstNodeExpr.h | 5 +++- src/V3AstNodes.cpp | 68 +++++++++++++++++++++++++++++++++++++++++++++ src/V3Sched.cpp | 2 -- src/V3Width.cpp | 3 -- 4 files changed, 72 insertions(+), 6 deletions(-) diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 1a421e928..828bb4d11 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -600,6 +600,7 @@ public: , m_name{name} { this->fromp(fromp); this->addPinsp(pinsp); + setPurity(); } ASTGEN_MEMBERS_AstCMethodHard; string name() const override VL_MT_STABLE { return m_name; } // * = Var name @@ -609,11 +610,13 @@ public: return (m_name == asamep->m_name); } bool isPure() const override { return m_pure; } - void pure(bool flag) { m_pure = flag; } int instrCount() const override; string emitVerilog() override { V3ERROR_NA_RETURN(""); } string emitC() override { V3ERROR_NA_RETURN(""); } bool cleanOut() const override { return true; } + +private: + void setPurity(); }; class AstCast final : public AstNodeExpr { // Cast to appropriate data type diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 5a411d606..a2caf2621 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -2326,6 +2326,74 @@ int AstCMethodHard::instrCount() const { } return 0; } +void AstCMethodHard::setPurity() { + static const std::map isPureMethod{{"andNot", false}, + {"any", true}, + {"assign", false}, + {"at", true}, + {"atBack", true}, + {"awaitingCurrentTime", true}, + {"clear", false}, + {"clearFired", false}, + {"commit", false}, + {"delay", false}, + {"done", false}, + {"erase", false}, + {"evaluate", false}, + {"evaluation", false}, + {"exists", true}, + {"find", true}, + {"find_first", true}, + {"find_first_index", true}, + {"find_index", true}, + {"find_last", true}, + {"find_last_index", true}, + {"fire", false}, + {"first", false}, + {"init", false}, + {"insert", false}, + {"isFired", true}, + {"isTriggered", true}, + {"join", false}, + {"last", false}, + {"max", true}, + {"min", true}, + {"neq", true}, + {"next", false}, + {"pop", false}, + {"pop_back", false}, + {"pop_front", false}, + {"prev", false}, + {"push", false}, + {"push_back", false}, + {"push_front", false}, + {"r_and", true}, + {"r_or", true}, + {"r_product", true}, + {"r_sum", true}, + {"r_xor", true}, + {"renew", false}, + {"renew_copy", false}, + {"resume", false}, + {"reverse", false}, + {"rsort", false}, + {"set", false}, + {"shuffle", false}, + {"size", true}, + {"slice", true}, + {"sliceBackBack", true}, + {"sliceFrontBack", true}, + {"sort", false}, + {"thisOr", false}, + {"trigger", false}, + {"unique", true}, + {"unique_index", true}, + {"word", true}}; + + auto isPureIt = isPureMethod.find(name()); + UASSERT_OBJ(isPureIt != isPureMethod.end(), this, "Unknown purity of method " + name()); + m_pure = isPureIt->second; +} const char* AstCFunc::broken() const { BROKEN_RTN((m_scopep && !m_scopep->brokeExists())); return nullptr; diff --git a/src/V3Sched.cpp b/src/V3Sched.cpp index 8948730bf..897cb6343 100644 --- a/src/V3Sched.cpp +++ b/src/V3Sched.cpp @@ -393,7 +393,6 @@ AstSenTree* createTriggerSenTree(AstNetlist* netlistp, AstVarScope* const vscp, AstCMethodHard* const callp = new AstCMethodHard{flp, vrefp, "word", new AstConst{flp, wordIndex}}; callp->dtypeSetUInt64(); - callp->pure(true); AstNodeExpr* const termp = new AstAnd{flp, new AstConst{flp, AstConst::Unsized64{}, 1ULL << bitIndex}, callp}; AstSenItem* const senItemp = new AstSenItem{flp, VEdgeType::ET_TRUE, termp}; @@ -479,7 +478,6 @@ const TriggerKit createTriggers(AstNetlist* netlistp, AstCFunc* const initFuncp, AstCMethodHard* const callp = new AstCMethodHard{flp, vrefp, "word", new AstConst{flp, wordIndex}}; callp->dtypeSetUInt64(); - callp->pure(true); AstNodeExpr* const termp = new AstAnd{flp, new AstConst{flp, AstConst::Unsized64{}, 1ULL << bitIndex}, callp}; return termp; diff --git a/src/V3Width.cpp b/src/V3Width.cpp index ebc770fc3..e428c072a 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -3107,7 +3107,6 @@ private: newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), "exists", index_exprp->unlinkFrBack()}; newp->dtypeSetSigned32(); - newp->pure(true); } else if (nodep->name() == "delete") { // function void delete([input integer index]) methodOkArguments(nodep, 0, 1); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); @@ -3192,7 +3191,6 @@ private: newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), "exists", index_exprp->unlinkFrBack()}; newp->dtypeSetSigned32(); - newp->pure(true); } else if (nodep->name() == "delete") { // function void delete([input integer index]) methodOkArguments(nodep, 0, 1); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); @@ -3657,7 +3655,6 @@ private: AstCMethodHard* const callp = new AstCMethodHard{ nodep->fileline(), nodep->fromp()->unlinkFrBack(), "isTriggered"}; callp->dtypeSetBit(); - callp->pure(true); nodep->replaceWith(callp); VL_DO_DANGLING(pushDeletep(nodep), nodep); } else { From c446cc259616dbfdc645cbd77a2e3d41c1c40bf7 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Mon, 11 Sep 2023 13:10:33 +0200 Subject: [PATCH 079/111] Internals: Remove unused constructor. No functional change. (#4473) Signed-off-by: Ryszard Rozak --- src/V3AstNodeExpr.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 828bb4d11..4c4250b96 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -585,15 +585,6 @@ class AstCMethodHard final : public AstNodeExpr { string m_name; // Name of method bool m_pure = false; // Pure optimizable public: - AstCMethodHard(FileLine* fl, AstNodeExpr* fromp, VFlagChildDType, const string& name, - AstNodeExpr* pinsp = nullptr) - : ASTGEN_SUPER_CMethodHard(fl) - , m_name{name} { - // TODO: this constructor is exactly the same as the other, bar the ignored tag argument - this->fromp(fromp); - this->addPinsp(pinsp); - dtypep(nullptr); // V3Width will resolve - } AstCMethodHard(FileLine* fl, AstNodeExpr* fromp, const string& name, AstNodeExpr* pinsp = nullptr) : ASTGEN_SUPER_CMethodHard(fl) From 0baee84e96114343811f5fb635eb0cf903294e0d Mon Sep 17 00:00:00 2001 From: Kamil Rakoczy Date: Mon, 11 Sep 2023 15:01:09 +0200 Subject: [PATCH 080/111] Move `dpiTemporaryVarSuffix()` to header. (#4474) Co-authored-by: Mariusz Glebocki --- src/V3Task.cpp | 7 ++----- src/V3Task.h | 4 +++- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/V3Task.cpp b/src/V3Task.cpp index b5af41942..0a1880e67 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -1554,6 +1554,8 @@ public: //###################################################################### // Task class functions +const char* const V3Task::s_dpiTemporaryVarSuffix = "__Vcvt"; + V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp) { // Output list will be in order of the port declaration variables (so // func calls are made right in C) @@ -1811,11 +1813,6 @@ string V3Task::assignDpiToInternal(const string& lhsName, AstVar* varp) { return statements; } -const char* V3Task::dpiTemporaryVarSuffix() { - static const char* const suffix = "__Vcvt"; - return suffix; -} - void V3Task::taskAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { diff --git a/src/V3Task.h b/src/V3Task.h index 1a1a5ef8e..1d7397da6 100644 --- a/src/V3Task.h +++ b/src/V3Task.h @@ -34,6 +34,8 @@ using V3TaskConnects = std::vector; // [ [port, pin-connects-to] //============================================================================ class V3Task final { + static const char* const s_dpiTemporaryVarSuffix; + public: static void taskAll(AstNetlist* nodep); /// Return vector of [port, pin-connects-to] (SLOW) @@ -41,7 +43,7 @@ public: static string assignInternalToDpi(AstVar* portp, bool isPtr, const string& frSuffix, const string& toSuffix, const string& frPrefix = ""); static string assignDpiToInternal(const string& lhsName, AstVar* rhsp); - static const char* dpiTemporaryVarSuffix(); + static const char* dpiTemporaryVarSuffix() VL_MT_SAFE { return s_dpiTemporaryVarSuffix; } }; #endif // Guard From e77d847671ba3b6a5c088a82da1eb1809d5dd665 Mon Sep 17 00:00:00 2001 From: Kamil Rakoczy Date: Mon, 11 Sep 2023 15:01:34 +0200 Subject: [PATCH 081/111] Check whether V3ERROR_NO_GLOBAL_ is not already defined. (#4475) Co-authored-by: Mariusz Glebocki --- src/VlcBucket.h | 2 ++ src/VlcMain.cpp | 2 ++ src/VlcPoint.h | 2 ++ 3 files changed, 6 insertions(+) diff --git a/src/VlcBucket.h b/src/VlcBucket.h index cca198bde..3d46bd4c7 100644 --- a/src/VlcBucket.h +++ b/src/VlcBucket.h @@ -20,7 +20,9 @@ #include "config_build.h" #include "verilatedos.h" +#ifndef V3ERROR_NO_GLOBAL_ #define V3ERROR_NO_GLOBAL_ +#endif #include "V3Error.h" //******************************************************************** diff --git a/src/VlcMain.cpp b/src/VlcMain.cpp index b26753c62..c0c75cdc7 100644 --- a/src/VlcMain.cpp +++ b/src/VlcMain.cpp @@ -24,7 +24,9 @@ #include "verilatedos.h" // Cheat for speed and compile .cpp files into one object TODO: Reconsider +#ifndef V3ERROR_NO_GLOBAL_ #define V3ERROR_NO_GLOBAL_ +#endif #include "V3Error.h" static int debug() { return V3Error::debugDefault(); } #include "V3Error.cpp" diff --git a/src/VlcPoint.h b/src/VlcPoint.h index 81578f9b1..5c51b7adf 100644 --- a/src/VlcPoint.h +++ b/src/VlcPoint.h @@ -25,7 +25,9 @@ #include #include +#ifndef V3ERROR_NO_GLOBAL_ #define V3ERROR_NO_GLOBAL_ +#endif #include "verilated_cov_key.h" #include "V3Error.h" From 5676443139b4153b33eec51af04e083cc01fe1f7 Mon Sep 17 00:00:00 2001 From: Kamil Rakoczy Date: Mon, 11 Sep 2023 19:43:26 +0200 Subject: [PATCH 082/111] Internals: Rename and slightly change other threads stopping/resuming methods. (#4478) Co-authored-by: Mariusz Glebocki --- src/V3ThreadPool.cpp | 7 ++++--- src/V3ThreadPool.h | 22 +++++++++++++--------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/V3ThreadPool.cpp b/src/V3ThreadPool.cpp index 8eadc7b61..36a6d6c50 100644 --- a/src/V3ThreadPool.cpp +++ b/src/V3ThreadPool.cpp @@ -84,11 +84,11 @@ void V3ThreadPool::workerJobLoop(int id) VL_MT_SAFE { bool V3ThreadPool::waitIfStopRequested() VL_MT_SAFE VL_EXCLUDES(m_stoppedJobsMutex) { if (!stopRequested()) return false; V3LockGuard stoppedJobLock(m_stoppedJobsMutex); - waitStopRequested(); + waitForResumeRequest(); return true; } -void V3ThreadPool::waitStopRequested() VL_REQUIRES(m_stoppedJobsMutex) { +void V3ThreadPool::waitForResumeRequest() VL_REQUIRES(m_stoppedJobsMutex) { ++m_stoppedJobs; m_stoppedJobsCV.notify_all(); m_stoppedJobsCV.wait(m_stoppedJobsMutex, [&]() VL_REQUIRES(m_stoppedJobsMutex) { @@ -98,8 +98,9 @@ void V3ThreadPool::waitStopRequested() VL_REQUIRES(m_stoppedJobsMutex) { m_stoppedJobsCV.notify_all(); } -void V3ThreadPool::waitOtherThreads() VL_MT_SAFE_EXCLUDES(m_mutex) +void V3ThreadPool::stopOtherThreads() VL_MT_SAFE_EXCLUDES(m_mutex) VL_REQUIRES(m_stoppedJobsMutex) { + m_stopRequested = true; ++m_stoppedJobs; m_stoppedJobsCV.notify_all(); m_cv.notify_all(); diff --git a/src/V3ThreadPool.h b/src/V3ThreadPool.h index 7d21d157a..ad47ec093 100644 --- a/src/V3ThreadPool.h +++ b/src/V3ThreadPool.h @@ -192,11 +192,17 @@ private: return m_stopRequested; } - // Waits until exclusive access job completes its job - void waitStopRequested() VL_REQUIRES(m_stoppedJobsMutex); + // Waits until `resumeOtherThreads()` is called or exclusive access scope end. + void waitForResumeRequest() VL_REQUIRES(m_stoppedJobsMutex); - // Waits until all other jobs are stopped - void waitOtherThreads() VL_MT_SAFE_EXCLUDES(m_mutex) VL_REQUIRES(m_stoppedJobsMutex); + // Sends stop request to other threads and waits until they stop. + void stopOtherThreads() VL_MT_SAFE_EXCLUDES(m_mutex) VL_REQUIRES(m_stoppedJobsMutex); + + // Resumes threads stopped through previous call to `stopOtherThreads()`. + void resumeOtherThreads() VL_MT_SAFE_EXCLUDES(m_mutex) VL_REQUIRES(m_stoppedJobsMutex) { + m_stopRequested = false; + m_stoppedJobsCV.notify_all(); + } void workerJobLoop(int id) VL_MT_SAFE; @@ -209,9 +215,8 @@ public: if (!V3ThreadPool::s().willExecuteSynchronously()) { V3ThreadPool::s().m_stoppedJobsMutex.lock(); - if (V3ThreadPool::s().stopRequested()) { V3ThreadPool::s().waitStopRequested(); } - V3ThreadPool::s().m_stopRequested = true; - V3ThreadPool::s().waitOtherThreads(); + if (V3ThreadPool::s().stopRequested()) { V3ThreadPool::s().waitForResumeRequest(); } + V3ThreadPool::s().stopOtherThreads(); V3ThreadPool::s().m_exclusiveAccess = true; } else { V3ThreadPool::s().m_stoppedJobsMutex.assumeLocked(); @@ -221,8 +226,7 @@ public: // Can't use `willExecuteSynchronously`, we're still in exclusive execution state. if (V3ThreadPool::s().m_exclusiveAccess) { V3ThreadPool::s().m_exclusiveAccess = false; - V3ThreadPool::s().m_stopRequested = false; - V3ThreadPool::s().m_stoppedJobsCV.notify_all(); + V3ThreadPool::s().resumeOtherThreads(); V3ThreadPool::s().m_stoppedJobsMutex.unlock(); } else { From 6c6f03cf7c05987245dbb421166cd451f853d478 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Tue, 12 Sep 2023 17:06:12 +0200 Subject: [PATCH 083/111] Fix static cast from a stream type (#4469) (#4485) --- src/V3Width.cpp | 12 +++++++----- test_regress/t/t_stream_dynamic.v | 25 ++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/V3Width.cpp b/src/V3Width.cpp index e428c072a..eaffda787 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -1970,8 +1970,10 @@ private: newp = new AstNToI{nodep->fileline(), nodep->fromp()->unlinkFrBack(), toDtp}; } else if (!basicp->isDouble() && !fromDtp->isDouble()) { AstNodeDType* const origDTypep = nodep->dtypep(); - const int width = toDtp->width(); - castSized(nodep, nodep->fromp(), width); + if (!VN_IS(fromDtp, StreamDType)) { + const int width = toDtp->width(); + castSized(nodep, nodep->fromp(), width); + } nodep->dtypeFrom(origDTypep); // If was enum, need dtype to preserve as enum // Note castSized might modify nodep->fromp() } else { @@ -7362,9 +7364,9 @@ private: // UNSUP unpacked struct/unions (treated like BasicDType) const AstNodeDType* fromBaseDtp = computeCastableBase(fromDtp); - const bool fromNumericable = VN_IS(fromBaseDtp, BasicDType) - || VN_IS(fromBaseDtp, EnumDType) - || VN_IS(fromBaseDtp, NodeUOrStructDType); + const bool fromNumericable + = VN_IS(fromBaseDtp, BasicDType) || VN_IS(fromBaseDtp, EnumDType) + || VN_IS(fromBaseDtp, StreamDType) || VN_IS(fromBaseDtp, NodeUOrStructDType); const AstNodeDType* toBaseDtp = computeCastableBase(toDtp); const bool toNumericable diff --git a/test_regress/t/t_stream_dynamic.v b/test_regress/t/t_stream_dynamic.v index 0c02f1db8..f92b250ea 100644 --- a/test_regress/t/t_stream_dynamic.v +++ b/test_regress/t/t_stream_dynamic.v @@ -8,15 +8,20 @@ `define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); `define checks(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); +typedef enum bit [5:0] { + A = 6'b111000, + B = 6,b111111 +} enum_t; + module t (/*AUTOARG*/); initial begin bit arr[]; bit [1:0] arr2[$]; - bit [4:0] arr5[]; bit [5:0] arr6[$]; string v; bit [5:0] bit6 = 6'b111000; bit [5:0] ans; + enum_t ans_enum; { >> bit {arr}} = bit6; v = $sformatf("%p", arr); `checks(v, "'{'h0, 'h0, 'h0, 'h1, 'h1, 'h1} "); @@ -24,36 +29,54 @@ module t (/*AUTOARG*/); ans = { >> bit {arr} }; `checkh(ans, bit6); + ans_enum = enum_t'({ >> bit {arr} }); + `checkh(ans_enum, bit6); + { << bit {arr}} = bit6; v = $sformatf("%p", arr); `checks(v, "'{'h1, 'h1, 'h1, 'h0, 'h0, 'h0} "); ans = { << bit {arr} }; `checkh(ans, bit6); + ans_enum = enum_t'({ << bit {arr} }); + `checkh(ans_enum, bit6); + { >> bit[1:0] {arr2}} = bit6; v = $sformatf("%p", arr2); `checks(v, "'{'h0, 'h2, 'h3} "); ans = { >> bit[1:0] {arr2} }; `checkh(ans, bit6); + ans_enum = enum_t'({ >> bit[1:0] {arr2} }); + `checkh(ans_enum, bit6); + { << bit[1:0] {arr2}} = bit6; v = $sformatf("%p", arr2); `checks(v, "'{'h3, 'h2, 'h0} "); ans = { << bit[1:0] {arr2} }; `checkh(ans, bit6); + ans_enum = enum_t'({ << bit[1:0] {arr2} }); + `checkh(ans_enum, bit6); + { >> bit [5:0] {arr6} } = bit6; v = $sformatf("%p", arr6); `checks(v, "'{'h38} "); ans = { >> bit[5:0] {arr6} }; `checkh(ans, bit6); + ans_enum = enum_t'({ >> bit[5:0] {arr6} }); + `checkh(ans_enum, bit6); + { << bit [5:0] {arr6} } = bit6; v = $sformatf("%p", arr6); `checks(v, "'{'h38} "); ans = { << bit[5:0] {arr6} }; `checkh(ans, bit6); + ans_enum = enum_t'({ << bit[5:0] {arr6} }); + `checkh(ans_enum, bit6); + $write("*-* All Finished *-*\n"); $finish; end From 24917a187aace78fa459a9b6b83ab8425b746b42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Boro=C5=84ski?= <94375110+kboronski-ant@users.noreply.github.com> Date: Tue, 12 Sep 2023 17:59:57 +0200 Subject: [PATCH 084/111] Fix V3CUse, do not consider implementations (.cpp) at all (#4386) --- src/V3Ast.h | 22 +++++++++++------- src/V3CUse.cpp | 53 +++++++++++++++--------------------------- src/V3EmitCBase.h | 7 +++--- src/V3EmitCHeaders.cpp | 7 +++--- 4 files changed, 39 insertions(+), 50 deletions(-) diff --git a/src/V3Ast.h b/src/V3Ast.h index dc2a6b523..0e6508036 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -1183,30 +1183,34 @@ inline std::ostream& operator<<(std::ostream& os, const VNumRange& rhs) { class VUseType final { public: enum en : uint8_t { - IMP_INCLUDE, // Implementation (.cpp) needs an include - INT_INCLUDE, // Interface (.h) needs an include - IMP_FWD_CLASS, // Implementation (.cpp) needs a forward class declaration - INT_FWD_CLASS, // Interface (.h) needs a forward class declaration + // Enum values are compared with <, so order matters + INT_FWD_CLASS = 1 << 0, // Interface (.h) needs a forward class declaration + INT_INCLUDE = 1 << 1, // Interface (.h) needs an include }; enum en m_e; VUseType() - : m_e{IMP_FWD_CLASS} {} + : m_e{INT_FWD_CLASS} {} // cppcheck-suppress noExplicitConstructor constexpr VUseType(en _e) : m_e{_e} {} explicit VUseType(int _e) : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning - bool isInclude() const { return m_e == IMP_INCLUDE || m_e == INT_INCLUDE; } - bool isFwdClass() const { return m_e == IMP_FWD_CLASS || m_e == INT_FWD_CLASS; } constexpr operator en() const { return m_e; } + bool containsAny(VUseType other) { return m_e & other.m_e; } const char* ascii() const { - static const char* const names[] = {"IMP_INC", "INT_INC", "IMP_FWD", "INT_FWD"}; - return names[m_e]; + static const char* const names[] = {"INT_FWD", "INT_INC", "INT_FWD_INC"}; + return names[m_e - 1]; } }; constexpr bool operator==(const VUseType& lhs, const VUseType& rhs) { return lhs.m_e == rhs.m_e; } constexpr bool operator==(const VUseType& lhs, VUseType::en rhs) { return lhs.m_e == rhs; } constexpr bool operator==(VUseType::en lhs, const VUseType& rhs) { return lhs == rhs.m_e; } +constexpr VUseType::en operator|(VUseType::en lhs, VUseType::en rhs) { + return VUseType::en((uint8_t)lhs | (uint8_t)rhs); +} +constexpr VUseType::en operator&(VUseType::en lhs, VUseType::en rhs) { + return VUseType::en((uint8_t)lhs & (uint8_t)rhs); +} inline std::ostream& operator<<(std::ostream& os, const VUseType& rhs) { return os << rhs.ascii(); } diff --git a/src/V3CUse.cpp b/src/V3CUse.cpp index e53c8b3d1..1fae654db 100644 --- a/src/V3CUse.cpp +++ b/src/V3CUse.cpp @@ -28,9 +28,11 @@ #include "V3CUse.h" #include "V3Ast.h" +#include "V3FileLine.h" #include "V3Global.h" -#include +#include +#include VL_DEFINE_DEBUG_FUNCTIONS; @@ -46,54 +48,31 @@ class CUseVisitor final : public VNVisitor { // MEMBERS AstNodeModule* const m_modp; // Current module - std::set> m_didUse; // What we already used - bool m_dtypesImplOnly = false; + std::map> m_didUse; // What we already used // METHODS void addNewUse(AstNode* nodep, VUseType useType, const string& name) { - if (m_dtypesImplOnly - && (useType == VUseType::INT_INCLUDE || useType == VUseType::INT_FWD_CLASS)) - return; - - if (m_didUse.emplace(useType, name).second) { - AstCUse* const newp = new AstCUse{nodep->fileline(), useType, name}; - m_modp->addStmtsp(newp); - UINFO(8, "Insert " << newp << endl); + auto e = m_didUse.emplace(name, std::make_pair(nodep->fileline(), useType)); + if (e.second || ((e.first->second.second & useType) != useType)) { + e.first->second.second = e.first->second.second | useType; } } // VISITORS void visit(AstClassRefDType* nodep) override { - if (nodep->user1()) return; // Process once - if (!m_dtypesImplOnly) // We might need to revisit this type for interface - nodep->user1(true); addNewUse(nodep, VUseType::INT_FWD_CLASS, nodep->classp()->name()); } void visit(AstCFunc* nodep) override { - if (nodep->user1SetOnce()) return; // Process once + if (nodep->user1SetOnce()) return; iterateAndNextNull(nodep->argsp()); - - { - VL_RESTORER(m_dtypesImplOnly); - m_dtypesImplOnly = true; - - iterateAndNextNull(nodep->initsp()); - iterateAndNextNull(nodep->stmtsp()); - iterateAndNextNull(nodep->finalsp()); - } + iterateAndNextNull(nodep->stmtsp()); } + void visit(AstCCall* nodep) override { return; } void visit(AstCReturn* nodep) override { - if (nodep->user1SetOnce()) return; // Process once - if (m_dtypesImplOnly) { - for (AstNode* exprp = nodep->op1p(); exprp; exprp = exprp->nextp()) { - if (exprp->dtypep()) iterate(exprp->dtypep()); - } - } else { - iterateChildren(nodep); - } + UASSERT(!nodep->user1SetOnce(), "Visited same return twice."); + iterate(nodep->lhsp()->dtypep()); } void visit(AstNodeDType* nodep) override { - if (nodep->user1SetOnce()) return; // Process once if (nodep->virtRefDTypep()) iterate(nodep->virtRefDTypep()); if (nodep->virtRefDType2p()) iterate(nodep->virtRefDType2p()); @@ -108,7 +87,7 @@ class CUseVisitor final : public VNVisitor { } void visit(AstNode* nodep) override { if (nodep->user1SetOnce()) return; // Process once - if (nodep->dtypep() && !nodep->dtypep()->user1()) iterate(nodep->dtypep()); + if (nodep->dtypep()) iterate(nodep->dtypep()); iterateChildren(nodep); } void visit(AstCell* nodep) override { @@ -123,6 +102,12 @@ public: explicit CUseVisitor(AstNodeModule* modp) : m_modp(modp) { iterate(modp); + + for (auto& used : m_didUse) { + AstCUse* const newp = new AstCUse{used.second.first, used.second.second, used.first}; + m_modp->addStmtsp(newp); + UINFO(8, "Insert " << newp << endl); + } } ~CUseVisitor() override = default; VL_UNCOPYABLE(CUseVisitor); diff --git a/src/V3EmitCBase.h b/src/V3EmitCBase.h index 88fa6cae6..d3d797e3a 100644 --- a/src/V3EmitCBase.h +++ b/src/V3EmitCBase.h @@ -117,11 +117,12 @@ public: static void forModCUse(const AstNodeModule* modp, VUseType useType, F action) { for (AstNode* itemp = modp->stmtsp(); itemp; itemp = itemp->nextp()) { if (AstCUse* const usep = VN_CAST(itemp, CUse)) { - if (usep->useType() == useType) { - if (usep->useType().isInclude()) { + if (usep->useType().containsAny(useType)) { + if (usep->useType().containsAny(VUseType::INT_INCLUDE)) { action("#include \"" + prefixNameProtect(usep) + ".h\"\n"); + continue; // Forward declaration is not necessary } - if (usep->useType().isFwdClass()) { + if (usep->useType().containsAny(VUseType::INT_FWD_CLASS)) { action("class " + prefixNameProtect(usep) + ";\n"); } } diff --git a/src/V3EmitCHeaders.cpp b/src/V3EmitCHeaders.cpp index 04e38e172..4f63aa5b0 100644 --- a/src/V3EmitCHeaders.cpp +++ b/src/V3EmitCHeaders.cpp @@ -380,11 +380,10 @@ class EmitCHeader final : public EmitCConstInit { std::set cuse_set; auto add_to_cuse_set = [&](string s) { cuse_set.insert(s); }; - forModCUse(modp, VUseType::INT_INCLUDE, add_to_cuse_set); - forModCUse(modp, VUseType::INT_FWD_CLASS, add_to_cuse_set); + forModCUse(modp, VUseType::INT_FWD_CLASS | VUseType::INT_INCLUDE, add_to_cuse_set); if (const AstClassPackage* const packagep = VN_CAST(modp, ClassPackage)) { - forModCUse(packagep->classp(), VUseType::INT_INCLUDE, add_to_cuse_set); - forModCUse(packagep->classp(), VUseType::INT_FWD_CLASS, add_to_cuse_set); + forModCUse(packagep->classp(), VUseType::INT_INCLUDE | VUseType::INT_FWD_CLASS, + add_to_cuse_set); } for (const string& s : cuse_set) puts(s); From 839a8fa4d9211c4048d241897a55c43f9827898a Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 12 Sep 2023 17:47:57 -0400 Subject: [PATCH 085/111] Fix error on enum with VARHIDDEN of cell (#4482). --- Changes | 1 + src/V3LinkDot.cpp | 4 ++-- test_regress/t/t_enum_bad_cell.out | 9 +++++++++ test_regress/t/t_enum_bad_cell.pl | 20 ++++++++++++++++++++ test_regress/t/t_enum_bad_cell.v | 17 +++++++++++++++++ test_regress/t/t_enum_bad_hide.out | 4 ++-- 6 files changed, 51 insertions(+), 4 deletions(-) create mode 100644 test_regress/t/t_enum_bad_cell.out create mode 100755 test_regress/t/t_enum_bad_cell.pl create mode 100644 test_regress/t/t_enum_bad_cell.v diff --git a/Changes b/Changes index 7106cfbb9..fea08cd9e 100644 --- a/Changes +++ b/Changes @@ -31,6 +31,7 @@ Verilator 5.015 devel * Fix false MULTITOP on bound interfaces (#4438). [Alex Solomatnikov] * Fix internal error on real conversion (#4447). [vdhotre-ventana] * Fix lifetime unknown error on enum.name (#4448). [jwoutersymatra] +* Fix error on enum with VARHIDDEN of cell (#4482). [Michail Rontionov] * Fix display %x formatting of real. * Fix mis-warning on #() in classes' own functions. diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index f376457f0..81a522577 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -1351,7 +1351,7 @@ class LinkDotFindVisitor final : public VNVisitor { if (!foundp && m_modSymp && nodep->name() == m_modSymp->nodep()->name()) { foundp = m_modSymp; // Conflicts with modname? } - AstEnumItem* const findvarp = foundp ? VN_AS(foundp->nodep(), EnumItem) : nullptr; + AstEnumItem* const findvarp = foundp ? VN_CAST(foundp->nodep(), EnumItem) : nullptr; bool ins = false; if (!foundp) { ins = true; @@ -1375,7 +1375,7 @@ class LinkDotFindVisitor final : public VNVisitor { << nodep->warnContextPrimary() << '\n' << foundp->nodep()->warnOther() << "... Location of original declaration\n" - << nodep->warnContextSecondary()); + << foundp->nodep()->warnContextSecondary()); } ins = true; } diff --git a/test_regress/t/t_enum_bad_cell.out b/test_regress/t/t_enum_bad_cell.out new file mode 100644 index 000000000..95db9e884 --- /dev/null +++ b/test_regress/t/t_enum_bad_cell.out @@ -0,0 +1,9 @@ +%Warning-VARHIDDEN: t/t_enum_bad_cell.v:12:14: Declaration of enum value hides declaration in upper scope: s1 + 12 | enum {s0, s1} state; + | ^~ + t/t_enum_bad_cell.v:8:8: ... Location of original declaration + 8 | sub s1(); + | ^~ + ... For warning description see https://verilator.org/warn/VARHIDDEN?v=latest + ... Use "/* verilator lint_off VARHIDDEN */" and lint_on around source to disable this message. +%Error: Exiting due to diff --git a/test_regress/t/t_enum_bad_cell.pl b/test_regress/t/t_enum_bad_cell.pl new file mode 100755 index 000000000..f1eef1686 --- /dev/null +++ b/test_regress/t/t_enum_bad_cell.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 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(linter => 1); + +lint( + verilator_flags2 => ["--lint-only -Wwarn-VARHIDDEN"], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_enum_bad_cell.v b/test_regress/t/t_enum_bad_cell.v new file mode 100644 index 000000000..acd66c8ce --- /dev/null +++ b/test_regress/t/t_enum_bad_cell.v @@ -0,0 +1,17 @@ +// 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 + +module t (/*AUTOARG*/); + sub s1(); +endmodule + +module sub (/*AUTOARG*/); + enum {s0, s1} state; + initial begin + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_enum_bad_hide.out b/test_regress/t/t_enum_bad_hide.out index 037bd0eae..56f69e656 100644 --- a/test_regress/t/t_enum_bad_hide.out +++ b/test_regress/t/t_enum_bad_hide.out @@ -2,8 +2,8 @@ 11 | typedef enum { HIDE_VALUE = 0 } hide_enum_t; | ^~~~~~~~~~ t/t_enum_bad_hide.v:7:16: ... Location of original declaration - 11 | typedef enum { HIDE_VALUE = 0 } hide_enum_t; - | ^~~~~~~~~~ + 7 | typedef enum { HIDE_VALUE = 0 } hide_enum_t; + | ^~~~~~~~~~ ... For warning description see https://verilator.org/warn/VARHIDDEN?v=latest ... Use "/* verilator lint_off VARHIDDEN */" and lint_on around source to disable this message. %Error: Exiting due to From 8bd6d7c5b1bb85e0e7998801287c14e37671a00e Mon Sep 17 00:00:00 2001 From: Kamil Rakoczy Date: Wed, 13 Sep 2023 13:57:48 +0200 Subject: [PATCH 086/111] Internals: Add V3ThreadSafety (#4477) --- include/verilatedos.h | 45 ++++++++++++++++++--------- src/CMakeLists.txt | 1 + src/Makefile_obj.in | 1 + src/V3ThreadPool.cpp | 10 ++++++ src/V3ThreadPool.h | 6 ++++ src/V3ThreadSafety.h | 71 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 120 insertions(+), 14 deletions(-) create mode 100644 src/V3ThreadSafety.h diff --git a/include/verilatedos.h b/include/verilatedos.h index f065ed6f6..a3a515518 100644 --- a/include/verilatedos.h +++ b/include/verilatedos.h @@ -94,20 +94,6 @@ // Function requires a capability inbound (-fthread-safety) #define VL_CAPABILITY(x) \ VL_CLANG_ATTR(capability(x)) -// Function requires not having a capability inbound (-fthread-safety) -#define VL_REQUIRES(x) \ - VL_CLANG_ATTR(annotate("REQUIRES")) \ - VL_CLANG_ATTR(requires_capability(x)) -// Name of capability/lock (-fthread-safety) -#define VL_GUARDED_BY(x) \ - VL_CLANG_ATTR(annotate("GUARDED_BY")) \ - VL_CLANG_ATTR(guarded_by(x)) -// The data that the annotated pointer points to is protected by the given capability. -// The pointer itself is not protected. -// Allowed on: pointer data member. (-fthread-safety) -#define VL_PT_GUARDED_BY(x) \ - VL_CLANG_ATTR(annotate("PT_GUARDED_BY")) \ - VL_CLANG_ATTR(pt_guarded_by(x)) // Name of mutex protecting this variable (-fthread-safety) #define VL_EXCLUDES(x) \ VL_CLANG_ATTR(annotate("EXCLUDES")) \ @@ -124,6 +110,32 @@ #define VL_ASSERT_CAPABILITY(x) \ VL_CLANG_ATTR(assert_capability(x)) +// Require mutex locks only in code units which work with enabled multi-threading. +#if !defined(VL_MT_DISABLED_CODE_UNIT) +// Function requires not having a capability inbound (-fthread-safety) +# define VL_REQUIRES(x) \ + VL_CLANG_ATTR(annotate("REQUIRES")) \ + VL_CLANG_ATTR(requires_capability(x)) +// Name of capability/lock (-fthread-safety) +# define VL_GUARDED_BY(x) \ + VL_CLANG_ATTR(annotate("GUARDED_BY")) \ + VL_CLANG_ATTR(guarded_by(x)) +// The data that the annotated pointer points to is protected by the given capability. +// The pointer itself is not protected. +// Allowed on: pointer data member. (-fthread-safety) +# define VL_PT_GUARDED_BY(x) \ + VL_CLANG_ATTR(annotate("PT_GUARDED_BY")) \ + VL_CLANG_ATTR(pt_guarded_by(x)) +#else +// Keep annotations for clang_check_attributes +# define VL_REQUIRES(x) \ + VL_CLANG_ATTR(annotate("REQUIRES")) +# define VL_GUARDED_BY(x) \ + VL_CLANG_ATTR(annotate("GUARDED_BY")) +# define VL_PT_GUARDED_BY(x) \ + VL_CLANG_ATTR(annotate("PT_GUARDED_BY")) +#endif + // Defaults for unsupported compiler features #ifndef VL_ATTR_ALWINLINE # define VL_ATTR_ALWINLINE ///< Attribute to inline, even when not optimizing @@ -430,6 +442,11 @@ using ssize_t = uint32_t; ///< signed size_t; returned from read() Type(const Type& other) = delete; \ Type& operator=(const Type&) = delete +// Declare a class as unmovable; put after a private: +#define VL_UNMOVABLE(Type) \ + Type(Type&& other) = delete; \ + Type& operator=(Type&&) = delete + //========================================================================= // Verilated function size macros diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 47471a1bd..396d79fd6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -151,6 +151,7 @@ set(HEADERS V3Table.h V3Task.h V3ThreadPool.h + V3ThreadSafety.h V3Timing.h V3Trace.h V3TraceDecl.h diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index 4d364ef6c..471af2c79 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -289,6 +289,7 @@ NON_STANDALONE_HEADERS = \ V3AstNodeExpr.h \ V3AstNodeOther.h \ V3DfgVertices.h \ + V3ThreadPool.h \ V3WidthCommit.h \ AST_DEFS := \ diff --git a/src/V3ThreadPool.cpp b/src/V3ThreadPool.cpp index 36a6d6c50..d19a449bd 100644 --- a/src/V3ThreadPool.cpp +++ b/src/V3ThreadPool.cpp @@ -111,6 +111,10 @@ void V3ThreadPool::stopOtherThreads() VL_MT_SAFE_EXCLUDES(m_mutex) --m_stoppedJobs; } +void V3ThreadPool::selfTestMtDisabled() { + // empty +} + void V3ThreadPool::selfTest() { V3Mutex commonMutex; int commonValue{0}; @@ -164,4 +168,10 @@ void V3ThreadPool::selfTest() { futuresInt.push_back(s().enqueue(forthJob)); auto result = V3ThreadPool::waitForFutures(futuresInt); UASSERT(result.back() == 1234, "unexpected future result = " << result.back()); + { + const V3MtDisabledLockGuard mtDisabler{v3MtDisabledLock()}; + selfTestMtDisabled(); + } } + +V3MtDisabledLock V3MtDisabledLock::s_mtDisabledLock; diff --git a/src/V3ThreadPool.h b/src/V3ThreadPool.h index ad47ec093..0ecb6fde8 100644 --- a/src/V3ThreadPool.h +++ b/src/V3ThreadPool.h @@ -17,7 +17,12 @@ #ifndef _V3THREADPOOL_H_ #define _V3THREADPOOL_H_ 1 +#if defined(VL_MT_DISABLED_CODE_UNIT) +#error "Source file has been declared as MT_DISABLED, threads use is prohibited." +#endif + #include "V3Mutex.h" +#include "V3ThreadSafety.h" #include #include @@ -163,6 +168,7 @@ public: } static void selfTest(); + static void selfTestMtDisabled() VL_MT_DISABLED; private: template diff --git a/src/V3ThreadSafety.h b/src/V3ThreadSafety.h new file mode 100644 index 000000000..12cc6e627 --- /dev/null +++ b/src/V3ThreadSafety.h @@ -0,0 +1,71 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Definitions for thread safety checing +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-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 +// +//************************************************************************* + +#ifndef VERILATOR_V3THREADSAFETY_H_ +#define VERILATOR_V3THREADSAFETY_H_ + +#include + +#include + +// A class that works as an indicator of MT_DISABLED context. +// It uses Clang's thread safety analysis (-fthread-safety) to do its work. +// Its use will most likely be optimized out (or at least reduced to a few insignificant symbols +// or instructions) during compilation. +class VL_CAPABILITY("lock") V3MtDisabledLock final { + friend class V3MtDisabledLockInstanceAccessor; + + static V3MtDisabledLock s_mtDisabledLock; + + constexpr V3MtDisabledLock() = default; + ~V3MtDisabledLock() = default; + VL_UNCOPYABLE(V3MtDisabledLock); + VL_UNMOVABLE(V3MtDisabledLock); + +public: + constexpr void lock() VL_ACQUIRE() VL_MT_SAFE {} + constexpr void unlock() VL_RELEASE() VL_MT_SAFE {} + + static constexpr V3MtDisabledLock& instance() + VL_RETURN_CAPABILITY(V3MtDisabledLock::s_mtDisabledLock) { + return s_mtDisabledLock; + } +}; + +// A class providing mutable access to V3MtDisabledLock::s_mtDisabledLock. +// This is a class because VL_RETURN_CAPABILITY works only on methods, not free functions. +// This is not a method in V3MtDisabledLock itself as a method declaration inside #ifdef block +// woudl break ODR. +class V3MtDisabledLockInstanceAccessor final { +public: + constexpr V3MtDisabledLock& operator()() const + VL_RETURN_CAPABILITY(V3MtDisabledLock::s_mtDisabledLock) { + return V3MtDisabledLock::s_mtDisabledLock; + } +}; +// Create a global object which can be called like a function. +static constexpr V3MtDisabledLockInstanceAccessor v3MtDisabledLock VL_ATTR_UNUSED; + +using V3MtDisabledLockGuard = V3LockGuardImp; + +// Annotated function can be called only in MT_DISABLED context, i.e. either in a code unit +// compiled with VL_MT_DISABLED_CODE_UNIT preprocessor definition, or after obtaining a lock on +// v3MtDisabledLock(). +#define VL_MT_DISABLED \ + VL_CLANG_ATTR(annotate("MT_DISABLED")) \ + VL_REQUIRES(V3MtDisabledLock::instance()) + +#endif // guard From 823e0723fbb35d382e9bd01a0b8911c820d54dfa Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 13 Sep 2023 08:46:51 -0400 Subject: [PATCH 087/111] Internals: Remove legacy define. No functional change. --- src/V3PreProc.cpp | 24 ++++++++++++------------ src/V3PreProc.h | 3 --- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/V3PreProc.cpp b/src/V3PreProc.cpp index 28058644f..cea6db1f2 100644 --- a/src/V3PreProc.cpp +++ b/src/V3PreProc.cpp @@ -212,7 +212,7 @@ private: void parsingOn() { m_off--; - if (m_off < 0) fatalSrc("Underflow of parsing cmds"); + if (m_off < 0) v3fatalSrc("Underflow of parsing cmds"); // addLineComment no longer needed; getFinalToken will correct. } void parsingOff() { m_off++; } @@ -541,7 +541,7 @@ void V3PreProcImp::unputString(const string& strg) { // so instead we scan from a temporary buffer, then on EOF return. // This is also faster than the old scheme, amazingly. if (VL_UNCOVERABLE(m_lexp->m_bufferState != m_lexp->currentBuffer())) { - fatalSrc("bufferStack missing current buffer; will return incorrectly"); + v3fatalSrc("bufferStack missing current buffer; will return incorrectly"); // Hard to debug lost text as won't know till much later } m_lexp->scanBytes(strg); @@ -1091,7 +1091,7 @@ int V3PreProcImp::getStateToken() { m_lexp->pushStateDefForm(); goto next_tok; } else { // LCOV_EXCL_LINE - fatalSrc("Bad case\n"); + v3fatalSrc("Bad case\n"); } goto next_tok; } else if (tok == VP_TEXT) { @@ -1165,7 +1165,7 @@ int V3PreProcImp::getStateToken() { } else { const string msg = std::string{"Bad define text, unexpected "} + tokenName(tok) + "\n"; - fatalSrc(msg); + v3fatalSrc(msg); } statePop(); // DEFVALUE is terminated by a return, but lex can't return both tokens. @@ -1179,7 +1179,7 @@ int V3PreProcImp::getStateToken() { goto next_tok; } else { if (VL_UNCOVERABLE(m_defRefs.empty())) { - fatalSrc("Shouldn't be in DEFPAREN w/o active defref"); + v3fatalSrc("Shouldn't be in DEFPAREN w/o active defref"); } const VDefineRef* const refp = &(m_defRefs.top()); error(std::string{"Expecting ( to begin argument list for define reference `"} @@ -1190,7 +1190,7 @@ int V3PreProcImp::getStateToken() { } case ps_DEFARG: { if (VL_UNCOVERABLE(m_defRefs.empty())) { - fatalSrc("Shouldn't be in DEFARG w/o active defref"); + v3fatalSrc("Shouldn't be in DEFARG w/o active defref"); } VDefineRef* refp = &(m_defRefs.top()); refp->nextarg(refp->nextarg() + m_lexp->m_defValue); @@ -1217,7 +1217,7 @@ int V3PreProcImp::getStateToken() { if (state() == ps_JOIN) { // Handle {left}```FOO(ARG) where `FOO(ARG) might be empty if (VL_UNCOVERABLE(m_joinStack.empty())) { - fatalSrc("`` join stack empty, but in a ``"); + v3fatalSrc("`` join stack empty, but in a ``"); } const string lhs = m_joinStack.top(); m_joinStack.pop(); @@ -1307,7 +1307,7 @@ int V3PreProcImp::getStateToken() { case ps_JOIN: { if (tok == VP_SYMBOL || tok == VP_TEXT) { if (VL_UNCOVERABLE(m_joinStack.empty())) { - fatalSrc("`` join stack empty, but in a ``"); + v3fatalSrc("`` join stack empty, but in a ``"); } const string lhs = m_joinStack.top(); m_joinStack.pop(); @@ -1363,7 +1363,7 @@ int V3PreProcImp::getStateToken() { goto next_tok; } } - default: fatalSrc("Bad case\n"); + default: v3fatalSrc("Bad case\n"); } // Default is to do top level expansion of some tokens switch (tok) { @@ -1445,7 +1445,7 @@ int V3PreProcImp::getStateToken() { // Just output the substitution if (state() == ps_JOIN) { // Handle {left}```FOO where `FOO might be empty if (VL_UNCOVERABLE(m_joinStack.empty())) { - fatalSrc("`` join stack empty, but in a ``"); + v3fatalSrc("`` join stack empty, but in a ``"); } const string lhs = m_joinStack.top(); m_joinStack.pop(); @@ -1481,7 +1481,7 @@ int V3PreProcImp::getStateToken() { goto next_tok; } } - fatalSrc("Bad case\n"); // FALLTHRU + v3fatalSrc("Bad case\n"); // FALLTHRU goto next_tok; // above fatal means unreachable, but fixes static analysis warning } case VP_ERROR: { @@ -1518,7 +1518,7 @@ int V3PreProcImp::getStateToken() { case VP_DEFFORM: // Handled by state=ps_DEFFORM; case VP_DEFVALUE: // Handled by state=ps_DEFVALUE; default: // LCOV_EXCL_LINE - fatalSrc(std::string{"Internal error: Unexpected token "} + tokenName(tok) + "\n"); + v3fatalSrc(std::string{"Internal error: Unexpected token "} + tokenName(tok) + "\n"); break; // LCOV_EXCL_LINE } return tok; diff --git a/src/V3PreProc.h b/src/V3PreProc.h index 72126141e..f13ef98ed 100644 --- a/src/V3PreProc.h +++ b/src/V3PreProc.h @@ -28,9 +28,6 @@ #include #include -// Compatibility with Verilog-Perl's preprocessor -#define fatalSrc(msg) v3fatalSrc(msg) - class VInFilter; class VSpellCheck; From 9fe459c82073bdc980775d47b56c10ae2c7f120b Mon Sep 17 00:00:00 2001 From: Kamil Rakoczy Date: Wed, 13 Sep 2023 19:52:59 +0200 Subject: [PATCH 088/111] Internals: V3LockGuard: Add constructor for adopting already locked mutex. (#4476) --- src/V3Error.h | 2 +- src/V3Mutex.h | 9 +++-- src/V3ThreadPool.cpp | 82 ++++++++++++++++++++++++++++++++++++-------- src/V3ThreadPool.h | 49 +++++++++++++++++++++++--- src/V3ThreadSafety.h | 6 ++-- 5 files changed, 125 insertions(+), 23 deletions(-) diff --git a/src/V3Error.h b/src/V3Error.h index f3a815775..b6c92e8af 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -531,7 +531,7 @@ public: // Global versions, so that if the class doesn't define an operator, we get the functions anyway. void v3errorEnd(std::ostringstream& sstr) VL_RELEASE(V3Error::s().m_mutex); -void v3errorEndFatal(std::ostringstream& sstr) VL_RELEASE(V3Error::s().m_mutex); +void v3errorEndFatal(std::ostringstream& sstr) VL_RELEASE(V3Error::s().m_mutex) VL_ATTR_NORETURN; // Theses allow errors using << operators: v3error("foo"<<"bar"); // Careful, you can't put () around msg, as you would in most macro definitions. diff --git a/src/V3Mutex.h b/src/V3Mutex.h index 7f4bc20cf..e08fed7c6 100644 --- a/src/V3Mutex.h +++ b/src/V3Mutex.h @@ -139,12 +139,17 @@ private: T& m_mutexr; public: - /// Construct and hold given mutex lock until destruction or unlock() + /// Lock given mutex and hold it for the object lifetime. explicit V3LockGuardImp(T& mutexr) VL_ACQUIRE(mutexr) VL_MT_SAFE : m_mutexr(mutexr) { // Need () or GCC 4.8 false warning mutexr.lock(); } - /// Destruct and unlock the mutex + /// Take already locked mutex, and and hold the lock for the object lifetime. + explicit V3LockGuardImp(T& mutexr, std::adopt_lock_t) VL_REQUIRES(mutexr) VL_MT_SAFE + : m_mutexr(mutexr) { // Need () or GCC 4.8 false warning + } + + /// Unlock the mutex ~V3LockGuardImp() VL_RELEASE() { m_mutexr.unlock(); } }; diff --git a/src/V3ThreadPool.cpp b/src/V3ThreadPool.cpp index d19a449bd..c2173eae9 100644 --- a/src/V3ThreadPool.cpp +++ b/src/V3ThreadPool.cpp @@ -24,13 +24,16 @@ constexpr unsigned int V3ThreadPool::FUTUREWAITFOR_MS; void V3ThreadPool::resize(unsigned n) VL_MT_UNSAFE VL_EXCLUDES(m_mutex) - VL_EXCLUDES(m_stoppedJobsMutex) { + VL_EXCLUDES(m_stoppedJobsMutex) VL_EXCLUDES(V3MtDisabledLock::instance()) { + // At least one thread (main) + n = std::max(1u, n); + if (n == (m_workers.size() + 1)) { return; } // This function is not thread-safe and can result in race between threads UASSERT(V3MutexConfig::s().lockConfig(), "Mutex config needs to be locked before starting ThreadPool"); { - V3LockGuard lock{m_mutex}; V3LockGuard stoppedJobsLock{m_stoppedJobsMutex}; + V3LockGuard lock{m_mutex}; UASSERT(m_queue.empty(), "Resizing busy thread pool"); // Shut down old threads @@ -38,6 +41,7 @@ void V3ThreadPool::resize(unsigned n) VL_MT_UNSAFE VL_EXCLUDES(m_mutex) m_stoppedJobs = 0; m_cv.notify_all(); m_stoppedJobsCV.notify_all(); + m_exclusiveAccessThreadCV.notify_all(); } while (!m_workers.empty()) { m_workers.front().join(); @@ -53,6 +57,37 @@ void V3ThreadPool::resize(unsigned n) VL_MT_UNSAFE VL_EXCLUDES(m_mutex) } } +void V3ThreadPool::suspendMultithreading() VL_MT_SAFE VL_EXCLUDES(m_mutex) + VL_EXCLUDES(m_stoppedJobsMutex) { + V3LockGuard stoppedJobsLock{m_stoppedJobsMutex}; + if (!m_workers.empty()) { stopOtherThreads(); } + + if (!m_mutex.try_lock()) { + v3fatal("Tried to suspend thread pool when other thread uses it."); + } + V3LockGuard lock{m_mutex, std::adopt_lock_t{}}; + + UASSERT(m_queue.empty(), "Thread pool has pending jobs"); + UASSERT(m_jobsInProgress == 0, "Thread pool has jobs in progress"); + m_exclusiveAccess = true; + m_multithreadingSuspended = true; +} + +void V3ThreadPool::resumeMultithreading() VL_MT_SAFE VL_EXCLUDES(m_mutex) + VL_EXCLUDES(m_stoppedJobsMutex) { + if (!m_mutex.try_lock()) { v3fatal("Tried to resume thread pool when other thread uses it."); } + { + V3LockGuard lock{m_mutex, std::adopt_lock_t{}}; + UASSERT(m_multithreadingSuspended, "Multithreading is not suspended"); + m_multithreadingSuspended = false; + m_exclusiveAccess = false; + } + if (!m_workers.empty()) { + V3LockGuard stoppedJobsLock{m_stoppedJobsMutex}; + resumeOtherThreads(); + } +} + void V3ThreadPool::startWorker(V3ThreadPool* selfThreadp, int id) VL_MT_SAFE { selfThreadp->workerJobLoop(id); } @@ -74,10 +109,14 @@ void V3ThreadPool::workerJobLoop(int id) VL_MT_SAFE { job = std::move(m_queue.front()); m_queue.pop(); + ++m_jobsInProgress; } // Execute the job job(); + // Note that a context switch can happen here. This means `m_jobsInProgress` could still + // contain old value even after the job promise has been fulfilled. + --m_jobsInProgress; } } @@ -90,25 +129,22 @@ bool V3ThreadPool::waitIfStopRequested() VL_MT_SAFE VL_EXCLUDES(m_stoppedJobsMut void V3ThreadPool::waitForResumeRequest() VL_REQUIRES(m_stoppedJobsMutex) { ++m_stoppedJobs; - m_stoppedJobsCV.notify_all(); - m_stoppedJobsCV.wait(m_stoppedJobsMutex, [&]() VL_REQUIRES(m_stoppedJobsMutex) { - return !m_stopRequested.load(); - }); + m_exclusiveAccessThreadCV.notify_one(); + m_stoppedJobsCV.wait(m_stoppedJobsMutex, + [&]() VL_REQUIRES(m_stoppedJobsMutex) { return !m_stopRequested; }); --m_stoppedJobs; - m_stoppedJobsCV.notify_all(); } void V3ThreadPool::stopOtherThreads() VL_MT_SAFE_EXCLUDES(m_mutex) VL_REQUIRES(m_stoppedJobsMutex) { m_stopRequested = true; - ++m_stoppedJobs; - m_stoppedJobsCV.notify_all(); - m_cv.notify_all(); - m_stoppedJobsCV.wait(m_stoppedJobsMutex, [&]() VL_REQUIRES(m_stoppedJobsMutex) { - // count also the main thread - return m_stoppedJobs == (m_workers.size() + 1); + { + V3LockGuard lock{m_mutex}; + m_cv.notify_all(); + } + m_exclusiveAccessThreadCV.wait(m_stoppedJobsMutex, [&]() VL_REQUIRES(m_stoppedJobsMutex) { + return m_stoppedJobs == m_workers.size(); }); - --m_stoppedJobs; } void V3ThreadPool::selfTestMtDisabled() { @@ -171,7 +207,25 @@ void V3ThreadPool::selfTest() { { const V3MtDisabledLockGuard mtDisabler{v3MtDisabledLock()}; selfTestMtDisabled(); + { + V3LockGuard lock{V3ThreadPool::s().m_mutex}; + UASSERT(V3ThreadPool::s().m_multithreadingSuspended, + "Multithreading should be suspended at this point"); + } + } + { + V3LockGuard lock{V3ThreadPool::s().m_mutex}; + UASSERT(!V3ThreadPool::s().m_multithreadingSuspended, + "Multithreading should not be suspended at this point"); } } V3MtDisabledLock V3MtDisabledLock::s_mtDisabledLock; + +void V3MtDisabledLock::lock() VL_ACQUIRE() VL_MT_SAFE { + V3ThreadPool::s().suspendMultithreading(); +} + +void V3MtDisabledLock::unlock() VL_RELEASE() VL_MT_SAFE { + V3ThreadPool::s().resumeMultithreading(); +} diff --git a/src/V3ThreadPool.h b/src/V3ThreadPool.h index 0ecb6fde8..f2564710e 100644 --- a/src/V3ThreadPool.h +++ b/src/V3ThreadPool.h @@ -81,7 +81,11 @@ class V3ThreadPool final { // MEMBERS static constexpr unsigned int FUTUREWAITFOR_MS = 100; + // some functions locks both of this mutexes, be careful of lock inversion problems + // 'm_stoppedJobsMutex' mutex should always be locked before 'm_mutex' mutex + // check usage of both of them when you use either of them V3Mutex m_mutex; // Mutex for use by m_queue + V3Mutex m_stoppedJobsMutex; // Used to signal stopped jobs std::queue m_queue VL_GUARDED_BY(m_mutex); // Queue of jobs // We don't need to guard this condition_variable as // both `notify_one` and `notify_all` functions are atomic, @@ -89,20 +93,36 @@ class V3ThreadPool final { // used by this condition_variable, so clang checks that we have mutex locked std::condition_variable_any m_cv; // Conditions to wake up workers std::list m_workers; // Worker threads - V3Mutex m_stoppedJobsMutex; // Used to signal stopped jobs + // Number of started and not yet finished jobs. + // Reading is valid only after call to `stopOtherThreads()` or when no worker threads exist. + std::atomic_uint m_jobsInProgress{0}; // Conditions to wake up stopped jobs std::condition_variable_any m_stoppedJobsCV VL_GUARDED_BY(m_stoppedJobsMutex); + // Conditions to wake up exclusive access thread + std::condition_variable_any m_exclusiveAccessThreadCV VL_GUARDED_BY(m_stoppedJobsMutex); std::atomic_uint m_stoppedJobs{0}; // Currently stopped jobs waiting for wake up std::atomic_bool m_stopRequested{false}; // Signals to resume stopped jobs std::atomic_bool m_exclusiveAccess{false}; // Signals that all other threads are stopped std::atomic_bool m_shutdown{false}; // Termination pending + // Indicates whether multithreading has been suspended. + // Used for error detection in resumeMultithreading only. You probably should use + // m_exclusiveAccess for information whether something should be run in current thread. + bool m_multithreadingSuspended VL_GUARDED_BY(m_mutex) = false; + // CONSTRUCTORS V3ThreadPool() = default; ~V3ThreadPool() { - { - V3LockGuard lock{m_mutex}; + if (!m_mutex.try_lock()) { + if (m_jobsInProgress != 0) { + // ThreadPool shouldn't be destroyed when jobs are running and mutex is locked, + // something is wrong. Most likely Verilator is exitting as a result of failed + // assert in critical section. Do nothing, let it exit. + return; + } + } else { + V3LockGuard lock{m_mutex, std::adopt_lock_t{}}; m_queue = {}; // make sure queue is empty } resize(0); @@ -120,7 +140,8 @@ public: } // Resize thread pool to n workers (queue must be empty) - void resize(unsigned n) VL_MT_UNSAFE VL_EXCLUDES(m_mutex) VL_EXCLUDES(m_stoppedJobsMutex); + void resize(unsigned n) VL_MT_UNSAFE VL_EXCLUDES(m_mutex) VL_EXCLUDES(m_stoppedJobsMutex) + VL_EXCLUDES(V3MtDisabledLock::instance()); // Enqueue a job for asynchronous execution // Due to missing support for lambda annotations in c++11, @@ -171,6 +192,24 @@ public: static void selfTestMtDisabled() VL_MT_DISABLED; private: + // For access to suspendMultithreading() and resumeMultithreading() + friend class V3MtDisabledLock; + + // Temporarily suspends multithreading. + // + // Existing worker threads are not terminated. All jobs enqueued when multithreading is + // suspended are executed synchronously. + // Must be called from the main thread. Jobs queue must be empty. Existing worker threads must + // be idle. + // + // Only V3MtDisabledLock class is supposed to use this function. + void suspendMultithreading() VL_MT_SAFE VL_EXCLUDES(m_mutex) VL_EXCLUDES(m_stoppedJobsMutex); + + // Resumes multithreading suspended previously by call tosuspendMultithreading(). + // + // Only V3MtDisabledLock class is supposed to use this function. + void resumeMultithreading() VL_MT_SAFE VL_EXCLUDES(m_mutex) VL_EXCLUDES(m_stoppedJobsMutex); + template static std::list waitForFuturesImp(std::list>& futures) { std::list results; @@ -235,6 +274,8 @@ public: V3ThreadPool::s().resumeOtherThreads(); V3ThreadPool::s().m_stoppedJobsMutex.unlock(); + // wait for all threads to resume + while (V3ThreadPool::s().m_stoppedJobs != 0) {} } else { V3ThreadPool::s().m_stoppedJobsMutex.pretendUnlock(); } diff --git a/src/V3ThreadSafety.h b/src/V3ThreadSafety.h index 12cc6e627..61b75aa95 100644 --- a/src/V3ThreadSafety.h +++ b/src/V3ThreadSafety.h @@ -36,8 +36,10 @@ class VL_CAPABILITY("lock") V3MtDisabledLock final { VL_UNMOVABLE(V3MtDisabledLock); public: - constexpr void lock() VL_ACQUIRE() VL_MT_SAFE {} - constexpr void unlock() VL_RELEASE() VL_MT_SAFE {} + // lock() will disable multithreading while in MT Disabled regions + void lock() VL_ACQUIRE() VL_MT_SAFE; + // unlock() will reenable multithreading while in MT Disabled regions + void unlock() VL_RELEASE() VL_MT_SAFE; static constexpr V3MtDisabledLock& instance() VL_RETURN_CAPABILITY(V3MtDisabledLock::s_mtDisabledLock) { From ec2e3ec0e4f398795b3a2f9046723384a5c95f2d Mon Sep 17 00:00:00 2001 From: Kamil Rakoczy Date: Wed, 13 Sep 2023 22:32:18 +0200 Subject: [PATCH 089/111] Update clang_check_attributes to take into account MT_DISABLED (#4479) --- nodist/clang_check_attributes | 258 ++- test_regress/t/t_a5_attributes_src.pl | 15 +- .../t/t_dist_attributes/mt_disabled.cpp | 44 + .../t/t_dist_attributes/mt_disabled.h | 50 + .../mt_enabled.cpp} | 2 +- .../mt_enabled.h} | 6 +- test_regress/t/t_dist_attributes_bad.out | 1887 +++++++++-------- test_regress/t/t_dist_attributes_bad.pl | 62 +- 8 files changed, 1338 insertions(+), 986 deletions(-) create mode 100644 test_regress/t/t_dist_attributes/mt_disabled.cpp create mode 100644 test_regress/t/t_dist_attributes/mt_disabled.h rename test_regress/t/{t_dist_attributes_bad.cpp => t_dist_attributes/mt_enabled.cpp} (99%) rename test_regress/t/{t_dist_attributes_bad.h => t_dist_attributes/mt_enabled.h} (99%) diff --git a/nodist/clang_check_attributes b/nodist/clang_check_attributes index 9aacc015f..cedb1655b 100755 --- a/nodist/clang_check_attributes +++ b/nodist/clang_check_attributes @@ -10,23 +10,37 @@ import argparse import os import sys import shlex -from typing import Callable, Iterable, Optional, Union +from typing import Callable, Iterable, Optional, Union, TYPE_CHECKING import dataclasses from dataclasses import dataclass import enum from enum import Enum import multiprocessing +import re import tempfile import clang.cindex from clang.cindex import ( - CursorKind, Index, TranslationUnitSaveError, TranslationUnitLoadError, CompilationDatabase, ) +if not TYPE_CHECKING: + from clang.cindex import CursorKind +else: + # Workaround for missing support for members defined out-of-class in Pylance: + # https://github.com/microsoft/pylance-release/issues/2365#issuecomment-1035803067 + + class CursorKindMeta(type): + + def __getattr__(cls, name: str) -> clang.cindex.CursorKind: + return getattr(clang.cindex.CursorKind, name) + + class CursorKind(clang.cindex.CursorKind, metaclass=CursorKindMeta): + pass + def fully_qualified_name(node): if node is None: @@ -66,6 +80,7 @@ class VlAnnotations: stable_tree: bool = False mt_safe_postinit: bool = False mt_unsafe: bool = False + mt_disabled: bool = False mt_unsafe_one: bool = False pure: bool = False guarded: bool = False @@ -87,7 +102,7 @@ class VlAnnotations: return self.stable_tree or self.mt_start def is_mt_unsafe_call(self): - return self.mt_unsafe or self.mt_unsafe_one + return self.mt_unsafe or self.mt_unsafe_one or self.mt_disabled def is_mt_safe_call(self): return (not self.is_mt_unsafe_call() @@ -137,6 +152,8 @@ class VlAnnotations: result.mt_unsafe = True elif node.displayname == "MT_UNSAFE_ONE": result.mt_unsafe_one = True + elif node.displayname == "MT_DISABLED": + result.mt_disabled = True elif node.displayname == "PURE": result.pure = True elif node.displayname in ["ACQUIRE", "ACQUIRE_SHARED"]: @@ -209,6 +226,19 @@ class FunctionInfo: def copy(self, /, **changes): return dataclasses.replace(self, **changes) + @staticmethod + def from_decl_file_line_and_refd_node(file: str, line: int, + refd: clang.cindex.Cursor, + annotations: VlAnnotations): + file = os.path.abspath(file) + refd = refd.canonical + assert refd is not None + name_parts = fully_qualified_name(refd) + usr = refd.get_usr() + ftype = FunctionType.from_node(refd) + + return FunctionInfo(name_parts, usr, file, line, annotations, ftype) + @staticmethod def from_node(node: clang.cindex.Cursor, refd: Optional[clang.cindex.Cursor] = None, @@ -234,6 +264,7 @@ class DiagnosticKind(Enum): NON_PURE_CALL_IN_PURE_CTX = enum.auto() NON_MT_SAFE_CALL_IN_MT_SAFE_CTX = enum.auto() NON_STABLE_TREE_CALL_IN_STABLE_TREE_CTX = enum.auto() + MISSING_MT_DISABLED_ANNOTATION = enum.auto() def __lt__(self, other): return self.value < other.value @@ -271,35 +302,142 @@ class CallAnnotationsValidator: self._index = Index.create() - self._processed_headers: set[str] = set() + # Map key represents translation unit initial defines + # (from command line and source's lines before any include) + self._processed_headers: dict[str, set[str]] = {} + self._external_decls: dict[str, set[tuple[str, int]]] = {} # Current context + self._main_source_file: str = "" + self._defines: dict[str, str] = {} self._call_location: Optional[FunctionInfo] = None self._caller: Optional[FunctionInfo] = None - self._level: int = 0 self._constructor_context: list[clang.cindex.Cursor] = [] + self._level: int = 0 + + def is_mt_disabled_code_unit(self): + return "VL_MT_DISABLED_CODE_UNIT" in self._defines def is_constructor_context(self): return len(self._constructor_context) > 0 + # Parses all lines in a form: `#define KEY VALUE` located before any `#include` line. + # The parsing is very simple, there is no support for line breaks, etc. + @staticmethod + def parse_initial_defines(source_file: str) -> dict[str, str]: + defs: dict[str, str] = {} + with open(source_file, "r", encoding="utf-8") as file: + for line in file: + line = line.strip() + match = re.fullmatch( + r"^#\s*(define\s+(\w+)(?:\s+(.*))?|include\s+.*)$", line) + if match: + if match.group(1).startswith("define"): + key = match.group(2) + value = match.groups("1")[2] + defs[key] = value + elif match.group(1).startswith("include"): + break + return defs + + @staticmethod + def filter_out_unsupported_compiler_args( + args: list[str]) -> tuple[list[str], dict[str, str]]: + filtered_args = [] + defines = {} + args_iter = iter(args) + try: + while arg := next(args_iter): + # Skip positional arguments (input file name). + if not arg.startswith("-") and (arg.endswith(".cpp") + or arg.endswith(".c") + or arg.endswith(".h")): + continue + + # Skipped options with separate value argument. + if arg in ["-o", "-T", "-MT", "-MQ", "-MF" + "-L"]: + next(args_iter) + continue + + # Skipped options without separate value argument. + if arg == "-c" or arg.startswith("-W") or arg.startswith("-L"): + continue + + # Preserved options with separate value argument. + if arg in [ + "-x" + "-Xclang", "-I", "-isystem", "-iquote", "-include", + "-include-pch" + ]: + filtered_args += [arg, next(args_iter)] + continue + + kv_str = None + d_or_u = None + # Preserve define/undefine with separate value argument. + if arg in ["-D", "-U"]: + filtered_args.append(arg) + d_or_u = arg[1] + kv_str = next(args_iter) + filtered_args.append(kv_str) + # Preserve define/undefine without separate value argument. + elif arg[0:2] in ["-D", "-U"]: + filtered_args.append(arg) + kv_str = arg[2:] + d_or_u = arg[1] + # Preserve everything else. + else: + filtered_args.append(arg) + continue + + # Keep track of defines for class' internal purposes. + key_value = kv_str.split("=", 1) + key = key_value[0] + val = "1" if len(key_value) == 1 else key_value[1] + + if d_or_u == "D": + defines[key] = val + elif d_or_u == "U" and key in defines: + del defines[key] + + except StopIteration: + pass + + return (filtered_args, defines) + def compile_and_analyze_file(self, source_file: str, compiler_args: list[str], build_dir: Optional[str]): filename = os.path.abspath(source_file) initial_cwd = "." + filtered_args, defines = self.filter_out_unsupported_compiler_args( + compiler_args) + defines.update(self.parse_initial_defines(source_file)) + if build_dir: initial_cwd = os.getcwd() os.chdir(build_dir) - translation_unit = self._index.parse(filename, compiler_args) - has_errors = False - for diag in translation_unit.diagnostics: - if diag.severity > clang.cindex.Diagnostic.Error: - has_errors = True - if translation_unit and not has_errors: + try: + translation_unit = self._index.parse(filename, filtered_args) + except TranslationUnitLoadError: + translation_unit = None + errors = [] + if translation_unit: + for diag in translation_unit.diagnostics: + if diag.severity >= clang.cindex.Diagnostic.Error: + errors.append(str(diag)) + if translation_unit and len(errors) == 0: + self._defines = defines + self._main_source_file = filename self.process_translation_unit(translation_unit) + self._main_source_file = "" + self._defines = {} else: print(f"%Error: parsing failed: {filename}", file=sys.stderr) + for error in errors: + print(f" {error}", file=sys.stderr) if build_dir: os.chdir(initial_cwd) @@ -569,6 +707,18 @@ class CallAnnotationsValidator: f" from: {node.location.file.name}:{node.location.line}") return True + def process_function_declaration(self, node: clang.cindex.Cursor): + # Ignore declarations in main .cpp file + if node.location.file.name != self._main_source_file: + children = list(node.get_children()) + annotations = VlAnnotations.from_nodes_list(children) + if not annotations.mt_disabled: + self._external_decls.setdefault(node.get_usr(), set()).add( + (str(node.location.file.name), int(node.location.line))) + return self.iterate_children(children, self.dispatch_node) + + return self.iterate_children(node.get_children(), self.dispatch_node) + # Definition handling def dispatch_node_inside_definition(self, node: clang.cindex.Cursor): @@ -599,6 +749,18 @@ class CallAnnotationsValidator: assert refd is not None def_annotations = VlAnnotations.from_nodes_list(node_children) + # Implicitly mark definitions in VL_MT_DISABLED_CODE_UNIT .cpp files as + # VL_MT_DISABLED. Existence of the annotation on declarations in .h + # files is verified below. + # Also sets VL_REQUIRES, as this annotation is added together with + # explicit VL_MT_DISABLED. + if self.is_mt_disabled_code_unit(): + if node.location.file.name == self._main_source_file: + annotations.mt_disabled = True + annotations.requires = True + if refd.location.file.name == self._main_source_file: + def_annotations.mt_disabled = True + def_annotations.requires = True if not (def_annotations.is_empty() or def_annotations == annotations): # Use definition's annotations for the diagnostic @@ -611,12 +773,26 @@ class CallAnnotationsValidator: DiagnosticKind.ANNOTATIONS_DEF_DECL_MISMATCH) # Use concatenation of definition and declaration annotations - # for callees validation. + # for calls validation. self._caller = FunctionInfo.from_node(node, refd, def_annotations | annotations) prev_call_location = self._call_location self._call_location = self._caller + if self.is_mt_disabled_code_unit(): + # Report declarations of this functions that don't have MT_DISABLED annotation + # and are located in headers. + if node.location.file.name == self._main_source_file: + usr = node.get_usr() + declarations = self._external_decls.get(usr, set()) + for file, line in declarations: + self.emit_diagnostic( + FunctionInfo.from_decl_file_line_and_refd_node( + file, line, refd, def_annotations), + DiagnosticKind.MISSING_MT_DISABLED_ANNOTATION) + if declarations: + del self._external_decls[usr] + self.iterate_children(node_children, self.dispatch_node_inside_definition) @@ -628,34 +804,36 @@ class CallAnnotationsValidator: # Nodes not located inside definition def dispatch_node(self, node: clang.cindex.Cursor): - if node.is_definition() and node.kind in [ + if node.kind in [ CursorKind.CXX_METHOD, CursorKind.FUNCTION_DECL, CursorKind.CONSTRUCTOR, CursorKind.CONVERSION_FUNCTION ]: - return self.process_function_definition(node) - if node.is_definition() and node.kind in [ - CursorKind.NAMESPACE, CursorKind.STRUCT_DECL, - CursorKind.UNION_DECL, CursorKind.CLASS_DECL - ]: - return self.iterate_children(node.get_children(), - self.dispatch_node) + if node.is_definition(): + return self.process_function_definition(node) + # else: + return self.process_function_declaration(node) return self.iterate_children(node.get_children(), self.dispatch_node) def process_translation_unit( self, translation_unit: clang.cindex.TranslationUnit): self._level += 1 + kv_defines = sorted([f"{k}={v}" for k, v in self._defines.items()]) + concat_defines = '\n'.join(kv_defines) + # List of headers already processed in a TU with specified set of defines. + tu_processed_headers = self._processed_headers.setdefault( + concat_defines, set()) for child in translation_unit.cursor.get_children(): if self._is_ignored_top_level(child): continue - if self._processed_headers: + if tu_processed_headers: filename = os.path.abspath(child.location.file.name) - if filename in self._processed_headers: + if filename in tu_processed_headers: continue self.dispatch_node(child) self._level -= 1 - self._processed_headers.update([ + tu_processed_headers.update([ os.path.abspath(str(hdr.source)) for hdr in translation_unit.get_includes() ]) @@ -717,34 +895,40 @@ def get_filter_funcs(verilator_root: str): def precompile_header(compile_command: CompileCommand, tmp_dir: str) -> str: + initial_cwd = os.getcwd() + errors = [] try: - initial_cwd = os.getcwd() os.chdir(compile_command.directory) index = Index.create() translation_unit = index.parse(compile_command.filename, compile_command.args) for diag in translation_unit.diagnostics: - if diag.severity > clang.cindex.Diagnostic.Error: - pch_file = None - break - else: + if diag.severity >= clang.cindex.Diagnostic.Error: + errors.append(str(diag)) + + if len(errors) == 0: pch_file = os.path.join( tmp_dir, f"{compile_command.refid:02}_{os.path.basename(compile_command.filename)}.pch" ) translation_unit.save(pch_file) + if pch_file: + return pch_file + + except (TranslationUnitSaveError, TranslationUnitLoadError, + OSError) as exception: + print(f"%Warning: {exception}", file=sys.stderr) + + finally: os.chdir(initial_cwd) - if pch_file: - return pch_file - - except (TranslationUnitSaveError, TranslationUnitLoadError, OSError): - pass - print( - f"%Warning: Precompiling failed, skipping: {compile_command.filename}") + f"%Warning: Precompilation failed, skipping: {compile_command.filename}", + file=sys.stderr) + for error in errors: + print(f" {error}", file=sys.stderr) return "" @@ -887,6 +1071,10 @@ class TopDownSummaryPrinter(): name += "is pure but calls non-pure function(s)" elif func.reason == DiagnosticKind.NON_STABLE_TREE_CALL_IN_STABLE_TREE_CTX: name += "is stable_tree but calls non-stable_tree or non-mtsafe" + elif func.reason == DiagnosticKind.MISSING_MT_DISABLED_ANNOTATION: + name += ("defined in a file marked as " + + "VL_MT_DISABLED_CODE_UNIT has declaration(s) " + + "without VL_MT_DISABLED annotation") else: name += "for unknown reason (please add description)" diff --git a/test_regress/t/t_a5_attributes_src.pl b/test_regress/t/t_a5_attributes_src.pl index 01c750bdf..df7f4d841 100755 --- a/test_regress/t/t_a5_attributes_src.pl +++ b/test_regress/t/t_a5_attributes_src.pl @@ -10,20 +10,20 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(dist => 1); rerunnable(0); +my $root = ".."; if ($ENV{VERILATOR_TEST_NO_ATTRIBUTES}) { skip("Skipping due to VERILATOR_TEST_NO_ATTRIBUTES"); +} elsif (! -e "$root/src/obj_dbg/compile_commands.json") { + skip("compile_commands.json not found. Please install 'bear > 3.0' and rebuild Verilator."); } else { check(); } sub check { - my $root = ".."; # some of the files are only used in Verilation # and are only in "include" folder my @srcfiles = grep { !/\/(V3Const|Vlc\w*|\w*_test|\w*_sc|\w*.yy).cpp$/ } - glob("$root/src/*.cpp $root/src/obj_opt/V3Const__gen.cpp"); + glob("$root/src/*.cpp $root/src/obj_dbg/V3Const__gen.cpp"); my $srcfiles_str = join(" ", @srcfiles); - my $precompile_args = "-c $root/src/V3Ast.h"; - my $clang_args = "-I$root/src/ -I$root/include/ -I$root/src/obj_opt/ -fcoroutines-ts"; sub run_clang_check { { @@ -34,7 +34,12 @@ sub check { } run(logfile => $Self->{run_log_filename}, tee => 1, - cmd => ["python3", "$root/nodist/clang_check_attributes --verilator-root=$root --cxxflags='$clang_args' $precompile_args $srcfiles_str"]); + cmd => ["python3", + "$root/nodist/clang_check_attributes", + "--verilator-root=$root", + "--compilation-root=$root/src/obj_dbg", + "--compile-commands-dir=$root/src/obj_dbg", + "$srcfiles_str"]); file_grep($Self->{run_log_filename}, "Number of functions reported unsafe: 0"); } diff --git a/test_regress/t/t_dist_attributes/mt_disabled.cpp b/test_regress/t/t_dist_attributes/mt_disabled.cpp new file mode 100644 index 000000000..f292d422a --- /dev/null +++ b/test_regress/t/t_dist_attributes/mt_disabled.cpp @@ -0,0 +1,44 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +// +//************************************************************************* +// +// Code available from: https://verilator.org +// +// Copyright 2022-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 +// +//************************************************************************* + +#define VL_MT_DISABLED_CODE_UNIT 1 + +#include "mt_disabled.h" +#include "mt_enabled.h" + +void unannotatedMtDisabledFunctionBad() { +} + +void UnannotatedMtDisabledClass::unannotatedMtDisabledMethodBad() { +} + +void UnannotatedMtDisabledClass::unannotatedMtDisabledStaticMethodBad() { +} + +// Declarations in .cpp don't have to be annotated with VL_MT_DISABLED. +void annotatedMtDisabledFunctionOK(); + +void annotatedMtDisabledFunctionOK() { + VerilatedMutex m; + // REQUIRES should be ignored and mutex locking not needed. + nsf_aa_VL_REQUIRES(m); +} + +void AnnotatedMtDisabledClass::annotatedMtDisabledMethodOK() { + annotatedMtDisabledFunctionOK(); +} + +void AnnotatedMtDisabledClass::annotatedMtDisabledStaticMethodOK() { + annotatedMtDisabledFunctionOK(); +} diff --git a/test_regress/t/t_dist_attributes/mt_disabled.h b/test_regress/t/t_dist_attributes/mt_disabled.h new file mode 100644 index 000000000..5e085526d --- /dev/null +++ b/test_regress/t/t_dist_attributes/mt_disabled.h @@ -0,0 +1,50 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +// +//************************************************************************* +// +// Code available from: https://verilator.org +// +// Copyright 2022-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 +// +//************************************************************************* + +#ifndef T_DIST_ATTRIBUTES_MT_DISABLED_H_ +#define T_DIST_ATTRIBUTES_MT_DISABLED_H_ + +#include "verilatedos.h" + +#include "V3ThreadSafety.h" + +void unannotatedMtDisabledFunctionBad(); + +// Duplicate to check that every declaration is reported +void unannotatedMtDisabledFunctionBad(); + +class UnannotatedMtDisabledClass final { +public: + void unannotatedMtDisabledMethodBad(); + static void unannotatedMtDisabledStaticMethodBad(); + + int unannotatedInlineMethodOK() const { return 42; } + static int unannotatedInlineStaticMethodOK() { return -42; } +}; + +void annotatedMtDisabledFunctionOK() VL_MT_DISABLED; + +// Duplicate +void annotatedMtDisabledFunctionOK() VL_MT_DISABLED; + +class AnnotatedMtDisabledClass final { +public: + void annotatedMtDisabledMethodOK() VL_MT_DISABLED; + static void annotatedMtDisabledStaticMethodOK() VL_MT_DISABLED; + + int annotatedInlineMethodOK() const VL_MT_DISABLED { return 42; } + static int annotatedInlineStaticMethodOK() VL_MT_DISABLED { return -42; } +}; + +#endif // T_DIST_ATTRIBUTES_MT_DISABLED_H_ diff --git a/test_regress/t/t_dist_attributes_bad.cpp b/test_regress/t/t_dist_attributes/mt_enabled.cpp similarity index 99% rename from test_regress/t/t_dist_attributes_bad.cpp rename to test_regress/t/t_dist_attributes/mt_enabled.cpp index cc68d5111..20bc2eb5d 100644 --- a/test_regress/t/t_dist_attributes_bad.cpp +++ b/test_regress/t/t_dist_attributes/mt_enabled.cpp @@ -14,7 +14,7 @@ #include "verilatedos.h" -#include "t_dist_attributes_bad.h" +#include "mt_enabled.h" // Non-Static Functions, Annotated declaration, Unannotated definition. // (definitions) diff --git a/test_regress/t/t_dist_attributes_bad.h b/test_regress/t/t_dist_attributes/mt_enabled.h similarity index 99% rename from test_regress/t/t_dist_attributes_bad.h rename to test_regress/t/t_dist_attributes/mt_enabled.h index 7473d57ff..3a71f1ad7 100644 --- a/test_regress/t/t_dist_attributes_bad.h +++ b/test_regress/t/t_dist_attributes/mt_enabled.h @@ -12,8 +12,8 @@ // //************************************************************************* -#ifndef T_DIST_ATTRIBUTES_BAD_H_ -#define T_DIST_ATTRIBUTES_BAD_H_ +#ifndef T_DIST_ATTRIBUTES_MT_ENABLED_H_ +#define T_DIST_ATTRIBUTES_MT_ENABLED_H_ #include "verilatedos.h" @@ -410,4 +410,4 @@ class TestClassConstructor { } }; -#endif // T_DIST_ATTRIBUTES_BAD_H_ +#endif // T_DIST_ATTRIBUTES_MT_ENABLED_H_ diff --git a/test_regress/t/t_dist_attributes_bad.out b/test_regress/t/t_dist_attributes_bad.out index f302da187..e5cfe9c4a 100644 --- a/test_regress/t/t_dist_attributes_bad.out +++ b/test_regress/t/t_dist_attributes_bad.out @@ -1,1196 +1,1209 @@ %Error: "TestClass::cm_ae_NO_ANNOTATION(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:204: [] TestClass::cm_ae_NO_ANNOTATION(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:146: [mt_safe, pure] TestClass::cm_ae_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [] TestClass::cm_ae_NO_ANNOTATION(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:146: [mt_safe, pure] TestClass::cm_ae_NO_ANNOTATION(VerilatedMutex &) %Error: "TestClass::cm_ae_VL_ACQUIRE(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:204: [acquire] TestClass::cm_ae_VL_ACQUIRE(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:146: [mt_safe, pure, acquire] TestClass::cm_ae_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [acquire] TestClass::cm_ae_VL_ACQUIRE(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:146: [mt_safe, pure, acquire] TestClass::cm_ae_VL_ACQUIRE(VerilatedMutex &) %Error: "TestClass::cm_ae_VL_ACQUIRE_SHARED(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:204: [acquire] TestClass::cm_ae_VL_ACQUIRE_SHARED(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:146: [mt_safe, pure, acquire] TestClass::cm_ae_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [acquire] TestClass::cm_ae_VL_ACQUIRE_SHARED(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:146: [mt_safe, pure, acquire] TestClass::cm_ae_VL_ACQUIRE_SHARED(VerilatedMutex &) %Error: "TestClass::cm_ae_VL_EXCLUDES(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:204: [excludes] TestClass::cm_ae_VL_EXCLUDES(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:146: [mt_safe, pure, excludes] TestClass::cm_ae_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [excludes] TestClass::cm_ae_VL_EXCLUDES(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:146: [mt_safe, pure, excludes] TestClass::cm_ae_VL_EXCLUDES(VerilatedMutex &) %Error: "TestClass::cm_ae_VL_MT_SAFE(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:204: [mt_safe] TestClass::cm_ae_VL_MT_SAFE(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:146: [mt_safe, pure] TestClass::cm_ae_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [mt_safe] TestClass::cm_ae_VL_MT_SAFE(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:146: [mt_safe, pure] TestClass::cm_ae_VL_MT_SAFE(VerilatedMutex &) %Error: "TestClass::cm_ae_VL_MT_SAFE_EXCLUDES(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:204: [excludes] TestClass::cm_ae_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:146: [mt_safe, pure, excludes] TestClass::cm_ae_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [excludes] TestClass::cm_ae_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:146: [mt_safe, pure, excludes] TestClass::cm_ae_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) %Error: "TestClass::cm_ae_VL_MT_SAFE_POSTINIT(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:204: [mt_safe_postinit] TestClass::cm_ae_VL_MT_SAFE_POSTINIT(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:146: [mt_safe, mt_safe_postinit, pure] TestClass::cm_ae_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [mt_safe_postinit] TestClass::cm_ae_VL_MT_SAFE_POSTINIT(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:146: [mt_safe, mt_safe_postinit, pure] TestClass::cm_ae_VL_MT_SAFE_POSTINIT(VerilatedMutex &) %Error: "TestClass::cm_ae_VL_MT_START(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:204: [mt_start] TestClass::cm_ae_VL_MT_START(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:146: [mt_start, mt_safe, pure] TestClass::cm_ae_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [mt_start] TestClass::cm_ae_VL_MT_START(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:146: [mt_start, mt_safe, pure] TestClass::cm_ae_VL_MT_START(VerilatedMutex &) %Error: "TestClass::cm_ae_VL_MT_UNSAFE(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:204: [mt_unsafe] TestClass::cm_ae_VL_MT_UNSAFE(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:146: [mt_safe, mt_unsafe, pure] TestClass::cm_ae_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [mt_unsafe] TestClass::cm_ae_VL_MT_UNSAFE(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:146: [mt_safe, mt_unsafe, pure] TestClass::cm_ae_VL_MT_UNSAFE(VerilatedMutex &) %Error: "TestClass::cm_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:204: [mt_unsafe_one] TestClass::cm_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:146: [mt_safe, mt_unsafe_one, pure] TestClass::cm_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [mt_unsafe_one] TestClass::cm_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:146: [mt_safe, mt_unsafe_one, pure] TestClass::cm_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) %Error: "TestClass::cm_ae_VL_PURE(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:204: [pure] TestClass::cm_ae_VL_PURE(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:146: [mt_safe, pure] TestClass::cm_ae_VL_PURE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [pure] TestClass::cm_ae_VL_PURE(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:146: [mt_safe, pure] TestClass::cm_ae_VL_PURE(VerilatedMutex &) %Error: "TestClass::cm_ae_VL_RELEASE(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:204: [release] TestClass::cm_ae_VL_RELEASE(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:146: [mt_safe, pure, release] TestClass::cm_ae_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [release] TestClass::cm_ae_VL_RELEASE(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:146: [mt_safe, pure, release] TestClass::cm_ae_VL_RELEASE(VerilatedMutex &) %Error: "TestClass::cm_ae_VL_RELEASE_SHARED(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:204: [release] TestClass::cm_ae_VL_RELEASE_SHARED(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:146: [mt_safe, pure, release] TestClass::cm_ae_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [release] TestClass::cm_ae_VL_RELEASE_SHARED(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:146: [mt_safe, pure, release] TestClass::cm_ae_VL_RELEASE_SHARED(VerilatedMutex &) %Error: "TestClass::cm_ae_VL_REQUIRES(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:204: [requires] TestClass::cm_ae_VL_REQUIRES(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:146: [mt_safe, pure, requires] TestClass::cm_ae_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [requires] TestClass::cm_ae_VL_REQUIRES(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:146: [mt_safe, pure, requires] TestClass::cm_ae_VL_REQUIRES(VerilatedMutex &) %Error: "TestClass::cm_test_caller_smethod_VL_MT_SAFE(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) -t/t_dist_attributes_bad.cpp:155: [mt_safe] TestClass::cm_test_caller_smethod_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:191: [mt_unsafe] TestClass::cm_au_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:191: [mt_unsafe_one] TestClass::cm_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:199: [mt_unsafe] TestClass::cm_aa_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:199: [mt_unsafe_one] TestClass::cm_aa_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:204: [mt_unsafe] TestClass::cm_ae_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:204: [mt_unsafe_one] TestClass::cm_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:209: [mt_safe, mt_unsafe, pure] TestClass::cm_ea_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:209: [mt_safe, mt_unsafe_one, pure] TestClass::cm_ea_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:155: [mt_safe] TestClass::cm_test_caller_smethod_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:191: [mt_unsafe] TestClass::cm_au_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:191: [mt_unsafe_one] TestClass::cm_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:199: [mt_unsafe] TestClass::cm_aa_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:199: [mt_unsafe_one] TestClass::cm_aa_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [mt_unsafe] TestClass::cm_ae_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [mt_unsafe_one] TestClass::cm_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:209: [mt_safe, mt_unsafe, pure] TestClass::cm_ea_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:209: [mt_safe, mt_unsafe_one, pure] TestClass::cm_ea_VL_MT_UNSAFE_ONE(VerilatedMutex &) %Error: "TestClass::cm_test_caller_smethod_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe -t/t_dist_attributes_bad.cpp:155: [mt_start] TestClass::cm_test_caller_smethod_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:191: [mt_unsafe] TestClass::cm_au_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:191: [mt_unsafe_one] TestClass::cm_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:199: [mt_unsafe] TestClass::cm_aa_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:199: [mt_unsafe_one] TestClass::cm_aa_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:204: [mt_unsafe] TestClass::cm_ae_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:204: [mt_unsafe_one] TestClass::cm_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:209: [mt_safe, mt_unsafe, pure] TestClass::cm_ea_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:209: [mt_safe, mt_unsafe_one, pure] TestClass::cm_ea_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:155: [mt_start] TestClass::cm_test_caller_smethod_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:191: [mt_unsafe] TestClass::cm_au_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:191: [mt_unsafe_one] TestClass::cm_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:199: [mt_unsafe] TestClass::cm_aa_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:199: [mt_unsafe_one] TestClass::cm_aa_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [mt_unsafe] TestClass::cm_ae_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [mt_unsafe_one] TestClass::cm_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:209: [mt_safe, mt_unsafe, pure] TestClass::cm_ea_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:209: [mt_safe, mt_unsafe_one, pure] TestClass::cm_ea_VL_MT_UNSAFE_ONE(VerilatedMutex &) %Error: "TestClass::cm_test_caller_smethod_VL_PURE(VerilatedMutex &)" is pure but calls non-pure function(s) -t/t_dist_attributes_bad.cpp:155: [pure] TestClass::cm_test_caller_smethod_VL_PURE(VerilatedMutex &) -t/t_dist_attributes_bad.h:191: [] TestClass::cm_au_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:191: [acquire] TestClass::cm_au_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:191: [acquire] TestClass::cm_au_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:191: [excludes] TestClass::cm_au_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:191: [mt_safe] TestClass::cm_au_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:191: [excludes] TestClass::cm_au_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:191: [mt_safe_postinit] TestClass::cm_au_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:191: [mt_start] TestClass::cm_au_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:191: [mt_unsafe] TestClass::cm_au_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:191: [mt_unsafe_one] TestClass::cm_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:191: [release] TestClass::cm_au_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:191: [release] TestClass::cm_au_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:191: [requires] TestClass::cm_au_VL_REQUIRES(VerilatedMutex &) -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_PURE(VerilatedMutex &) -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_REQUIRES(VerilatedMutex &) -t/t_dist_attributes_bad.h:199: [] TestClass::cm_aa_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:199: [acquire] TestClass::cm_aa_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:199: [acquire] TestClass::cm_aa_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:199: [excludes] TestClass::cm_aa_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:199: [mt_safe] TestClass::cm_aa_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:199: [excludes] TestClass::cm_aa_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:199: [mt_safe_postinit] TestClass::cm_aa_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:199: [mt_start] TestClass::cm_aa_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:199: [mt_unsafe] TestClass::cm_aa_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:199: [mt_unsafe_one] TestClass::cm_aa_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:199: [release] TestClass::cm_aa_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:199: [release] TestClass::cm_aa_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:199: [requires] TestClass::cm_aa_VL_REQUIRES(VerilatedMutex &) -t/t_dist_attributes_bad.h:204: [] TestClass::cm_ae_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:204: [acquire] TestClass::cm_ae_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:204: [acquire] TestClass::cm_ae_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:204: [excludes] TestClass::cm_ae_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:204: [mt_safe] TestClass::cm_ae_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:204: [excludes] TestClass::cm_ae_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:204: [mt_safe_postinit] TestClass::cm_ae_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:204: [mt_start] TestClass::cm_ae_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:204: [mt_unsafe] TestClass::cm_ae_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:204: [mt_unsafe_one] TestClass::cm_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:204: [release] TestClass::cm_ae_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:204: [release] TestClass::cm_ae_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:204: [requires] TestClass::cm_ae_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:155: [pure] TestClass::cm_test_caller_smethod_VL_PURE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:191: [] TestClass::cm_au_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:191: [acquire] TestClass::cm_au_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:191: [acquire] TestClass::cm_au_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:191: [excludes] TestClass::cm_au_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:191: [mt_safe] TestClass::cm_au_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:191: [excludes] TestClass::cm_au_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:191: [mt_safe_postinit] TestClass::cm_au_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:191: [mt_start] TestClass::cm_au_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:191: [mt_unsafe] TestClass::cm_au_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:191: [mt_unsafe_one] TestClass::cm_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:191: [release] TestClass::cm_au_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:191: [release] TestClass::cm_au_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:191: [requires] TestClass::cm_au_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_PURE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:199: [] TestClass::cm_aa_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:199: [acquire] TestClass::cm_aa_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:199: [acquire] TestClass::cm_aa_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:199: [excludes] TestClass::cm_aa_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:199: [mt_safe] TestClass::cm_aa_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:199: [excludes] TestClass::cm_aa_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:199: [mt_safe_postinit] TestClass::cm_aa_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:199: [mt_start] TestClass::cm_aa_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:199: [mt_unsafe] TestClass::cm_aa_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:199: [mt_unsafe_one] TestClass::cm_aa_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:199: [release] TestClass::cm_aa_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:199: [release] TestClass::cm_aa_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:199: [requires] TestClass::cm_aa_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [] TestClass::cm_ae_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [acquire] TestClass::cm_ae_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [acquire] TestClass::cm_ae_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [excludes] TestClass::cm_ae_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [mt_safe] TestClass::cm_ae_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [excludes] TestClass::cm_ae_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [mt_safe_postinit] TestClass::cm_ae_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [mt_start] TestClass::cm_ae_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [mt_unsafe] TestClass::cm_ae_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [mt_unsafe_one] TestClass::cm_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [release] TestClass::cm_ae_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [release] TestClass::cm_ae_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [requires] TestClass::cm_ae_VL_REQUIRES(VerilatedMutex &) %Error: "TestClass::cm_test_caller_smethod_hdr_VL_MT_SAFE(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) -t/t_dist_attributes_bad.h:212: [mt_safe] TestClass::cm_test_caller_smethod_hdr_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:191: [mt_unsafe] TestClass::cm_au_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:191: [mt_unsafe_one] TestClass::cm_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:199: [mt_unsafe] TestClass::cm_aa_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:199: [mt_unsafe_one] TestClass::cm_aa_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:204: [mt_unsafe] TestClass::cm_ae_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:204: [mt_unsafe_one] TestClass::cm_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:209: [mt_safe, mt_unsafe, pure] TestClass::cm_ea_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:209: [mt_safe, mt_unsafe_one, pure] TestClass::cm_ea_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:212: [mt_safe] TestClass::cm_test_caller_smethod_hdr_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:191: [mt_unsafe] TestClass::cm_au_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:191: [mt_unsafe_one] TestClass::cm_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:199: [mt_unsafe] TestClass::cm_aa_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:199: [mt_unsafe_one] TestClass::cm_aa_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [mt_unsafe] TestClass::cm_ae_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [mt_unsafe_one] TestClass::cm_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:209: [mt_safe, mt_unsafe, pure] TestClass::cm_ea_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:209: [mt_safe, mt_unsafe_one, pure] TestClass::cm_ea_VL_MT_UNSAFE_ONE(VerilatedMutex &) %Error: "TestClass::cm_test_caller_smethod_hdr_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe -t/t_dist_attributes_bad.h:212: [mt_start] TestClass::cm_test_caller_smethod_hdr_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:191: [mt_unsafe] TestClass::cm_au_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:191: [mt_unsafe_one] TestClass::cm_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:199: [mt_unsafe] TestClass::cm_aa_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:199: [mt_unsafe_one] TestClass::cm_aa_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:204: [mt_unsafe] TestClass::cm_ae_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:204: [mt_unsafe_one] TestClass::cm_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:209: [mt_safe, mt_unsafe, pure] TestClass::cm_ea_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:209: [mt_safe, mt_unsafe_one, pure] TestClass::cm_ea_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:212: [mt_start] TestClass::cm_test_caller_smethod_hdr_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:191: [mt_unsafe] TestClass::cm_au_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:191: [mt_unsafe_one] TestClass::cm_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:199: [mt_unsafe] TestClass::cm_aa_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:199: [mt_unsafe_one] TestClass::cm_aa_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [mt_unsafe] TestClass::cm_ae_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [mt_unsafe_one] TestClass::cm_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:209: [mt_safe, mt_unsafe, pure] TestClass::cm_ea_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:209: [mt_safe, mt_unsafe_one, pure] TestClass::cm_ea_VL_MT_UNSAFE_ONE(VerilatedMutex &) %Error: "TestClass::cm_test_caller_smethod_hdr_VL_PURE(VerilatedMutex &)" is pure but calls non-pure function(s) -t/t_dist_attributes_bad.h:212: [pure] TestClass::cm_test_caller_smethod_hdr_VL_PURE(VerilatedMutex &) -t/t_dist_attributes_bad.h:191: [] TestClass::cm_au_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:191: [acquire] TestClass::cm_au_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:191: [acquire] TestClass::cm_au_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:191: [excludes] TestClass::cm_au_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:191: [mt_safe] TestClass::cm_au_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:191: [excludes] TestClass::cm_au_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:191: [mt_safe_postinit] TestClass::cm_au_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:191: [mt_start] TestClass::cm_au_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:191: [mt_unsafe] TestClass::cm_au_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:191: [mt_unsafe_one] TestClass::cm_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:191: [release] TestClass::cm_au_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:191: [release] TestClass::cm_au_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:191: [requires] TestClass::cm_au_VL_REQUIRES(VerilatedMutex &) -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_PURE(VerilatedMutex &) -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_REQUIRES(VerilatedMutex &) -t/t_dist_attributes_bad.h:199: [] TestClass::cm_aa_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:199: [acquire] TestClass::cm_aa_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:199: [acquire] TestClass::cm_aa_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:199: [excludes] TestClass::cm_aa_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:199: [mt_safe] TestClass::cm_aa_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:199: [excludes] TestClass::cm_aa_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:199: [mt_safe_postinit] TestClass::cm_aa_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:199: [mt_start] TestClass::cm_aa_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:199: [mt_unsafe] TestClass::cm_aa_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:199: [mt_unsafe_one] TestClass::cm_aa_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:199: [release] TestClass::cm_aa_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:199: [release] TestClass::cm_aa_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:199: [requires] TestClass::cm_aa_VL_REQUIRES(VerilatedMutex &) -t/t_dist_attributes_bad.h:204: [] TestClass::cm_ae_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:204: [acquire] TestClass::cm_ae_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:204: [acquire] TestClass::cm_ae_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:204: [excludes] TestClass::cm_ae_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:204: [mt_safe] TestClass::cm_ae_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:204: [excludes] TestClass::cm_ae_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:204: [mt_safe_postinit] TestClass::cm_ae_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:204: [mt_start] TestClass::cm_ae_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:204: [mt_unsafe] TestClass::cm_ae_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:204: [mt_unsafe_one] TestClass::cm_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:204: [release] TestClass::cm_ae_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:204: [release] TestClass::cm_ae_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:204: [requires] TestClass::cm_ae_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:212: [pure] TestClass::cm_test_caller_smethod_hdr_VL_PURE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:191: [] TestClass::cm_au_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:191: [acquire] TestClass::cm_au_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:191: [acquire] TestClass::cm_au_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:191: [excludes] TestClass::cm_au_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:191: [mt_safe] TestClass::cm_au_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:191: [excludes] TestClass::cm_au_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:191: [mt_safe_postinit] TestClass::cm_au_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:191: [mt_start] TestClass::cm_au_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:191: [mt_unsafe] TestClass::cm_au_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:191: [mt_unsafe_one] TestClass::cm_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:191: [release] TestClass::cm_au_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:191: [release] TestClass::cm_au_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:191: [requires] TestClass::cm_au_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_PURE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:199: [] TestClass::cm_aa_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:199: [acquire] TestClass::cm_aa_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:199: [acquire] TestClass::cm_aa_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:199: [excludes] TestClass::cm_aa_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:199: [mt_safe] TestClass::cm_aa_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:199: [excludes] TestClass::cm_aa_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:199: [mt_safe_postinit] TestClass::cm_aa_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:199: [mt_start] TestClass::cm_aa_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:199: [mt_unsafe] TestClass::cm_aa_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:199: [mt_unsafe_one] TestClass::cm_aa_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:199: [release] TestClass::cm_aa_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:199: [release] TestClass::cm_aa_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:199: [requires] TestClass::cm_aa_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [] TestClass::cm_ae_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [acquire] TestClass::cm_ae_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [acquire] TestClass::cm_ae_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [excludes] TestClass::cm_ae_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [mt_safe] TestClass::cm_ae_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [excludes] TestClass::cm_ae_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [mt_safe_postinit] TestClass::cm_ae_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [mt_start] TestClass::cm_ae_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [mt_unsafe] TestClass::cm_ae_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [mt_unsafe_one] TestClass::cm_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [release] TestClass::cm_ae_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [release] TestClass::cm_ae_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:204: [requires] TestClass::cm_ae_VL_REQUIRES(VerilatedMutex &) %Error: "TestClass::cm_ua_VL_ACQUIRE(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_ACQUIRE(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:137: [acquire] TestClass::cm_ua_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_ACQUIRE(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:137: [acquire] TestClass::cm_ua_VL_ACQUIRE(VerilatedMutex &) %Error: "TestClass::cm_ua_VL_ACQUIRE_SHARED(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:137: [acquire] TestClass::cm_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:137: [acquire] TestClass::cm_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) %Error: "TestClass::cm_ua_VL_EXCLUDES(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_EXCLUDES(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:137: [excludes] TestClass::cm_ua_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_EXCLUDES(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:137: [excludes] TestClass::cm_ua_VL_EXCLUDES(VerilatedMutex &) %Error: "TestClass::cm_ua_VL_MT_SAFE(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_MT_SAFE(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:137: [mt_safe] TestClass::cm_ua_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_MT_SAFE(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:137: [mt_safe] TestClass::cm_ua_VL_MT_SAFE(VerilatedMutex &) %Error: "TestClass::cm_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:137: [excludes] TestClass::cm_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:137: [excludes] TestClass::cm_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) %Error: "TestClass::cm_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:137: [mt_safe_postinit] TestClass::cm_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:137: [mt_safe_postinit] TestClass::cm_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) %Error: "TestClass::cm_ua_VL_MT_START(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_MT_START(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:137: [mt_start] TestClass::cm_ua_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_MT_START(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:137: [mt_start] TestClass::cm_ua_VL_MT_START(VerilatedMutex &) %Error: "TestClass::cm_ua_VL_MT_UNSAFE(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_MT_UNSAFE(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:137: [mt_unsafe] TestClass::cm_ua_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_MT_UNSAFE(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:137: [mt_unsafe] TestClass::cm_ua_VL_MT_UNSAFE(VerilatedMutex &) %Error: "TestClass::cm_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:137: [mt_unsafe_one] TestClass::cm_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:137: [mt_unsafe_one] TestClass::cm_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) %Error: "TestClass::cm_ua_VL_PURE(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_PURE(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:137: [pure] TestClass::cm_ua_VL_PURE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_PURE(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:137: [pure] TestClass::cm_ua_VL_PURE(VerilatedMutex &) %Error: "TestClass::cm_ua_VL_RELEASE(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_RELEASE(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:137: [release] TestClass::cm_ua_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_RELEASE(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:137: [release] TestClass::cm_ua_VL_RELEASE(VerilatedMutex &) %Error: "TestClass::cm_ua_VL_RELEASE_SHARED(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_RELEASE_SHARED(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:137: [release] TestClass::cm_ua_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_RELEASE_SHARED(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:137: [release] TestClass::cm_ua_VL_RELEASE_SHARED(VerilatedMutex &) %Error: "TestClass::cm_ua_VL_REQUIRES(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:195: [] TestClass::cm_ua_VL_REQUIRES(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:137: [requires] TestClass::cm_ua_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:195: [] TestClass::cm_ua_VL_REQUIRES(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:137: [requires] TestClass::cm_ua_VL_REQUIRES(VerilatedMutex &) %Error: "TestClass::guarded_by_test_fail()" is mtsafe but calls non-mtsafe function(s) -t/t_dist_attributes_bad.h:269: [mt_safe] TestClass::guarded_by_test_fail() -t/t_dist_attributes_bad.h:104: [] GuardMe::safe_if_guarded_or_local() -t/t_dist_attributes_bad.h:106: [] GuardMe::operator int() -t/t_dist_attributes_bad.h:108: [] GuardMe::operator+=(int) +t/t_dist_attributes/mt_enabled.h:269: [mt_safe] TestClass::guarded_by_test_fail() +t/t_dist_attributes/mt_enabled.h:104: [] GuardMe::safe_if_guarded_or_local() +t/t_dist_attributes/mt_enabled.h:106: [] GuardMe::operator int() +t/t_dist_attributes/mt_enabled.h:108: [] GuardMe::operator+=(int) %Error: "TestClass::icm_test_caller_smethod_VL_MT_SAFE(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) -t/t_dist_attributes_bad.cpp:175: [mt_safe] TestClass::icm_test_caller_smethod_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:235: [mt_unsafe] TestClass::icm_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:235: [mt_unsafe_one] TestClass::icm_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:175: [mt_safe] TestClass::icm_test_caller_smethod_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:235: [mt_unsafe] TestClass::icm_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:235: [mt_unsafe_one] TestClass::icm_VL_MT_UNSAFE_ONE(VerilatedMutex &) %Error: "TestClass::icm_test_caller_smethod_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe -t/t_dist_attributes_bad.cpp:175: [mt_start] TestClass::icm_test_caller_smethod_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:235: [mt_unsafe] TestClass::icm_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:235: [mt_unsafe_one] TestClass::icm_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:175: [mt_start] TestClass::icm_test_caller_smethod_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:235: [mt_unsafe] TestClass::icm_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:235: [mt_unsafe_one] TestClass::icm_VL_MT_UNSAFE_ONE(VerilatedMutex &) %Error: "TestClass::icm_test_caller_smethod_VL_PURE(VerilatedMutex &)" is pure but calls non-pure function(s) -t/t_dist_attributes_bad.cpp:175: [pure] TestClass::icm_test_caller_smethod_VL_PURE(VerilatedMutex &) -t/t_dist_attributes_bad.h:235: [] TestClass::icm_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:235: [acquire] TestClass::icm_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:235: [acquire] TestClass::icm_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:235: [excludes] TestClass::icm_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:235: [mt_safe] TestClass::icm_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:235: [excludes] TestClass::icm_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:235: [mt_safe_postinit] TestClass::icm_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:235: [mt_start] TestClass::icm_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:235: [mt_unsafe] TestClass::icm_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:235: [mt_unsafe_one] TestClass::icm_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:235: [release] TestClass::icm_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:235: [release] TestClass::icm_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:235: [requires] TestClass::icm_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:175: [pure] TestClass::icm_test_caller_smethod_VL_PURE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:235: [] TestClass::icm_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:235: [acquire] TestClass::icm_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:235: [acquire] TestClass::icm_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:235: [excludes] TestClass::icm_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:235: [mt_safe] TestClass::icm_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:235: [excludes] TestClass::icm_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:235: [mt_safe_postinit] TestClass::icm_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:235: [mt_start] TestClass::icm_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:235: [mt_unsafe] TestClass::icm_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:235: [mt_unsafe_one] TestClass::icm_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:235: [release] TestClass::icm_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:235: [release] TestClass::icm_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:235: [requires] TestClass::icm_VL_REQUIRES(VerilatedMutex &) %Error: "TestClass::icm_test_caller_smethod_hdr_VL_MT_SAFE(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) -t/t_dist_attributes_bad.h:238: [mt_safe] TestClass::icm_test_caller_smethod_hdr_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:235: [mt_unsafe] TestClass::icm_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:235: [mt_unsafe_one] TestClass::icm_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:238: [mt_safe] TestClass::icm_test_caller_smethod_hdr_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:235: [mt_unsafe] TestClass::icm_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:235: [mt_unsafe_one] TestClass::icm_VL_MT_UNSAFE_ONE(VerilatedMutex &) %Error: "TestClass::icm_test_caller_smethod_hdr_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe -t/t_dist_attributes_bad.h:238: [mt_start] TestClass::icm_test_caller_smethod_hdr_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:235: [mt_unsafe] TestClass::icm_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:235: [mt_unsafe_one] TestClass::icm_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:238: [mt_start] TestClass::icm_test_caller_smethod_hdr_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:235: [mt_unsafe] TestClass::icm_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:235: [mt_unsafe_one] TestClass::icm_VL_MT_UNSAFE_ONE(VerilatedMutex &) %Error: "TestClass::icm_test_caller_smethod_hdr_VL_PURE(VerilatedMutex &)" is pure but calls non-pure function(s) -t/t_dist_attributes_bad.h:238: [pure] TestClass::icm_test_caller_smethod_hdr_VL_PURE(VerilatedMutex &) -t/t_dist_attributes_bad.h:235: [] TestClass::icm_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:235: [acquire] TestClass::icm_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:235: [acquire] TestClass::icm_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:235: [excludes] TestClass::icm_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:235: [mt_safe] TestClass::icm_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:235: [excludes] TestClass::icm_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:235: [mt_safe_postinit] TestClass::icm_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:235: [mt_start] TestClass::icm_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:235: [mt_unsafe] TestClass::icm_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:235: [mt_unsafe_one] TestClass::icm_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:235: [release] TestClass::icm_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:235: [release] TestClass::icm_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:235: [requires] TestClass::icm_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:238: [pure] TestClass::icm_test_caller_smethod_hdr_VL_PURE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:235: [] TestClass::icm_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:235: [acquire] TestClass::icm_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:235: [acquire] TestClass::icm_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:235: [excludes] TestClass::icm_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:235: [mt_safe] TestClass::icm_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:235: [excludes] TestClass::icm_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:235: [mt_safe_postinit] TestClass::icm_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:235: [mt_start] TestClass::icm_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:235: [mt_unsafe] TestClass::icm_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:235: [mt_unsafe_one] TestClass::icm_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:235: [release] TestClass::icm_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:235: [release] TestClass::icm_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:235: [requires] TestClass::icm_VL_REQUIRES(VerilatedMutex &) %Error: "TestClass::iscm_test_caller_smethod_VL_MT_SAFE(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) -t/t_dist_attributes_bad.cpp:119: [mt_safe] TestClass::iscm_test_caller_smethod_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [] TestClass::iscm_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [mt_start] TestClass::iscm_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [mt_unsafe] TestClass::iscm_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [mt_unsafe_one] TestClass::iscm_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:119: [mt_safe] TestClass::iscm_test_caller_smethod_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [] TestClass::iscm_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [mt_start] TestClass::iscm_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [mt_unsafe] TestClass::iscm_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [mt_unsafe_one] TestClass::iscm_VL_MT_UNSAFE_ONE(VerilatedMutex &) %Error: "TestClass::iscm_test_caller_smethod_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe -t/t_dist_attributes_bad.cpp:119: [mt_start] TestClass::iscm_test_caller_smethod_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [] TestClass::iscm_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [mt_start] TestClass::iscm_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [mt_unsafe] TestClass::iscm_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [mt_unsafe_one] TestClass::iscm_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:119: [mt_start] TestClass::iscm_test_caller_smethod_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [] TestClass::iscm_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [mt_start] TestClass::iscm_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [mt_unsafe] TestClass::iscm_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [mt_unsafe_one] TestClass::iscm_VL_MT_UNSAFE_ONE(VerilatedMutex &) %Error: "TestClass::iscm_test_caller_smethod_VL_PURE(VerilatedMutex &)" is pure but calls non-pure function(s) -t/t_dist_attributes_bad.cpp:119: [pure] TestClass::iscm_test_caller_smethod_VL_PURE(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [] TestClass::iscm_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [acquire] TestClass::iscm_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [acquire] TestClass::iscm_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [excludes] TestClass::iscm_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [mt_safe] TestClass::iscm_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [excludes] TestClass::iscm_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [mt_safe_postinit] TestClass::iscm_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [mt_start] TestClass::iscm_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [mt_unsafe] TestClass::iscm_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [mt_unsafe_one] TestClass::iscm_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [release] TestClass::iscm_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [release] TestClass::iscm_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [requires] TestClass::iscm_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:119: [pure] TestClass::iscm_test_caller_smethod_VL_PURE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [] TestClass::iscm_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [acquire] TestClass::iscm_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [acquire] TestClass::iscm_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [excludes] TestClass::iscm_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [mt_safe] TestClass::iscm_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [excludes] TestClass::iscm_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [mt_safe_postinit] TestClass::iscm_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [mt_start] TestClass::iscm_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [mt_unsafe] TestClass::iscm_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [mt_unsafe_one] TestClass::iscm_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [release] TestClass::iscm_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [release] TestClass::iscm_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [requires] TestClass::iscm_VL_REQUIRES(VerilatedMutex &) %Error: "TestClass::iscm_test_caller_smethod_hdr_VL_MT_SAFE(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) -t/t_dist_attributes_bad.h:173: [mt_safe] TestClass::iscm_test_caller_smethod_hdr_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [] TestClass::iscm_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [mt_start] TestClass::iscm_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [mt_unsafe] TestClass::iscm_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [mt_unsafe_one] TestClass::iscm_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:173: [mt_safe] TestClass::iscm_test_caller_smethod_hdr_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [] TestClass::iscm_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [mt_start] TestClass::iscm_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [mt_unsafe] TestClass::iscm_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [mt_unsafe_one] TestClass::iscm_VL_MT_UNSAFE_ONE(VerilatedMutex &) %Error: "TestClass::iscm_test_caller_smethod_hdr_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe -t/t_dist_attributes_bad.h:173: [mt_start] TestClass::iscm_test_caller_smethod_hdr_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [] TestClass::iscm_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [mt_start] TestClass::iscm_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [mt_unsafe] TestClass::iscm_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [mt_unsafe_one] TestClass::iscm_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:173: [mt_start] TestClass::iscm_test_caller_smethod_hdr_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [] TestClass::iscm_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [mt_start] TestClass::iscm_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [mt_unsafe] TestClass::iscm_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [mt_unsafe_one] TestClass::iscm_VL_MT_UNSAFE_ONE(VerilatedMutex &) %Error: "TestClass::iscm_test_caller_smethod_hdr_VL_PURE(VerilatedMutex &)" is pure but calls non-pure function(s) -t/t_dist_attributes_bad.h:173: [pure] TestClass::iscm_test_caller_smethod_hdr_VL_PURE(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [] TestClass::iscm_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [acquire] TestClass::iscm_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [acquire] TestClass::iscm_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [excludes] TestClass::iscm_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [mt_safe] TestClass::iscm_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [excludes] TestClass::iscm_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [mt_safe_postinit] TestClass::iscm_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [mt_start] TestClass::iscm_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [mt_unsafe] TestClass::iscm_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [mt_unsafe_one] TestClass::iscm_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [release] TestClass::iscm_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [release] TestClass::iscm_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:170: [requires] TestClass::iscm_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:173: [pure] TestClass::iscm_test_caller_smethod_hdr_VL_PURE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [] TestClass::iscm_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [acquire] TestClass::iscm_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [acquire] TestClass::iscm_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [excludes] TestClass::iscm_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [mt_safe] TestClass::iscm_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [excludes] TestClass::iscm_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [mt_safe_postinit] TestClass::iscm_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [mt_start] TestClass::iscm_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [mt_unsafe] TestClass::iscm_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [mt_unsafe_one] TestClass::iscm_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [release] TestClass::iscm_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [release] TestClass::iscm_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:170: [requires] TestClass::iscm_VL_REQUIRES(VerilatedMutex &) %Error: "TestClass::scm_ae_NO_ANNOTATION(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:133: [] TestClass::scm_ae_NO_ANNOTATION(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:84: [mt_safe, pure] TestClass::scm_ae_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [] TestClass::scm_ae_NO_ANNOTATION(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:84: [mt_safe, pure] TestClass::scm_ae_NO_ANNOTATION(VerilatedMutex &) %Error: "TestClass::scm_ae_VL_ACQUIRE(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:133: [acquire] TestClass::scm_ae_VL_ACQUIRE(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:84: [mt_safe, pure, acquire] TestClass::scm_ae_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [acquire] TestClass::scm_ae_VL_ACQUIRE(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:84: [mt_safe, pure, acquire] TestClass::scm_ae_VL_ACQUIRE(VerilatedMutex &) %Error: "TestClass::scm_ae_VL_ACQUIRE_SHARED(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:133: [acquire] TestClass::scm_ae_VL_ACQUIRE_SHARED(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:84: [mt_safe, pure, acquire] TestClass::scm_ae_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [acquire] TestClass::scm_ae_VL_ACQUIRE_SHARED(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:84: [mt_safe, pure, acquire] TestClass::scm_ae_VL_ACQUIRE_SHARED(VerilatedMutex &) %Error: "TestClass::scm_ae_VL_EXCLUDES(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:133: [excludes] TestClass::scm_ae_VL_EXCLUDES(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:84: [mt_safe, pure, excludes] TestClass::scm_ae_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [excludes] TestClass::scm_ae_VL_EXCLUDES(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:84: [mt_safe, pure, excludes] TestClass::scm_ae_VL_EXCLUDES(VerilatedMutex &) %Error: "TestClass::scm_ae_VL_MT_SAFE(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:133: [mt_safe] TestClass::scm_ae_VL_MT_SAFE(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:84: [mt_safe, pure] TestClass::scm_ae_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [mt_safe] TestClass::scm_ae_VL_MT_SAFE(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:84: [mt_safe, pure] TestClass::scm_ae_VL_MT_SAFE(VerilatedMutex &) %Error: "TestClass::scm_ae_VL_MT_SAFE_EXCLUDES(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:133: [excludes] TestClass::scm_ae_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:84: [mt_safe, pure, excludes] TestClass::scm_ae_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [excludes] TestClass::scm_ae_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:84: [mt_safe, pure, excludes] TestClass::scm_ae_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) %Error: "TestClass::scm_ae_VL_MT_SAFE_POSTINIT(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:133: [mt_safe_postinit] TestClass::scm_ae_VL_MT_SAFE_POSTINIT(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:84: [mt_safe, mt_safe_postinit, pure] TestClass::scm_ae_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [mt_safe_postinit] TestClass::scm_ae_VL_MT_SAFE_POSTINIT(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:84: [mt_safe, mt_safe_postinit, pure] TestClass::scm_ae_VL_MT_SAFE_POSTINIT(VerilatedMutex &) %Error: "TestClass::scm_ae_VL_MT_START(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:133: [mt_start] TestClass::scm_ae_VL_MT_START(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:84: [mt_start, mt_safe, pure] TestClass::scm_ae_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [mt_start] TestClass::scm_ae_VL_MT_START(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:84: [mt_start, mt_safe, pure] TestClass::scm_ae_VL_MT_START(VerilatedMutex &) %Error: "TestClass::scm_ae_VL_MT_UNSAFE(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:133: [mt_unsafe] TestClass::scm_ae_VL_MT_UNSAFE(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:84: [mt_safe, mt_unsafe, pure] TestClass::scm_ae_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [mt_unsafe] TestClass::scm_ae_VL_MT_UNSAFE(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:84: [mt_safe, mt_unsafe, pure] TestClass::scm_ae_VL_MT_UNSAFE(VerilatedMutex &) %Error: "TestClass::scm_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:133: [mt_unsafe_one] TestClass::scm_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:84: [mt_safe, mt_unsafe_one, pure] TestClass::scm_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [mt_unsafe_one] TestClass::scm_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:84: [mt_safe, mt_unsafe_one, pure] TestClass::scm_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) %Error: "TestClass::scm_ae_VL_PURE(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:133: [pure] TestClass::scm_ae_VL_PURE(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:84: [mt_safe, pure] TestClass::scm_ae_VL_PURE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [pure] TestClass::scm_ae_VL_PURE(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:84: [mt_safe, pure] TestClass::scm_ae_VL_PURE(VerilatedMutex &) %Error: "TestClass::scm_ae_VL_RELEASE(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:133: [release] TestClass::scm_ae_VL_RELEASE(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:84: [mt_safe, pure, release] TestClass::scm_ae_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [release] TestClass::scm_ae_VL_RELEASE(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:84: [mt_safe, pure, release] TestClass::scm_ae_VL_RELEASE(VerilatedMutex &) %Error: "TestClass::scm_ae_VL_RELEASE_SHARED(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:133: [release] TestClass::scm_ae_VL_RELEASE_SHARED(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:84: [mt_safe, pure, release] TestClass::scm_ae_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [release] TestClass::scm_ae_VL_RELEASE_SHARED(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:84: [mt_safe, pure, release] TestClass::scm_ae_VL_RELEASE_SHARED(VerilatedMutex &) %Error: "TestClass::scm_ae_VL_REQUIRES(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:133: [requires] TestClass::scm_ae_VL_REQUIRES(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:84: [mt_safe, pure, requires] TestClass::scm_ae_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [requires] TestClass::scm_ae_VL_REQUIRES(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:84: [mt_safe, pure, requires] TestClass::scm_ae_VL_REQUIRES(VerilatedMutex &) %Error: "TestClass::scm_test_caller_smethod_VL_MT_SAFE(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) -t/t_dist_attributes_bad.cpp:93: [mt_safe] TestClass::scm_test_caller_smethod_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [] TestClass::scm_au_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [mt_start] TestClass::scm_au_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [mt_unsafe] TestClass::scm_au_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [mt_unsafe_one] TestClass::scm_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_PURE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_REQUIRES(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [] TestClass::scm_aa_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [mt_start] TestClass::scm_aa_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [mt_unsafe] TestClass::scm_aa_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [mt_unsafe_one] TestClass::scm_aa_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [] TestClass::scm_ae_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [mt_start] TestClass::scm_ae_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [mt_unsafe] TestClass::scm_ae_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [mt_unsafe_one] TestClass::scm_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:138: [mt_safe, mt_unsafe, pure] TestClass::scm_ea_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:138: [mt_safe, mt_unsafe_one, pure] TestClass::scm_ea_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:93: [mt_safe] TestClass::scm_test_caller_smethod_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [] TestClass::scm_au_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [mt_start] TestClass::scm_au_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [mt_unsafe] TestClass::scm_au_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [mt_unsafe_one] TestClass::scm_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_PURE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [] TestClass::scm_aa_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [mt_start] TestClass::scm_aa_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [mt_unsafe] TestClass::scm_aa_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [mt_unsafe_one] TestClass::scm_aa_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [] TestClass::scm_ae_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [mt_start] TestClass::scm_ae_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [mt_unsafe] TestClass::scm_ae_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [mt_unsafe_one] TestClass::scm_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:138: [mt_safe, mt_unsafe, pure] TestClass::scm_ea_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:138: [mt_safe, mt_unsafe_one, pure] TestClass::scm_ea_VL_MT_UNSAFE_ONE(VerilatedMutex &) %Error: "TestClass::scm_test_caller_smethod_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe -t/t_dist_attributes_bad.cpp:93: [mt_start] TestClass::scm_test_caller_smethod_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [] TestClass::scm_au_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [mt_start] TestClass::scm_au_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [mt_unsafe] TestClass::scm_au_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [mt_unsafe_one] TestClass::scm_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_PURE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_REQUIRES(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [] TestClass::scm_aa_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [mt_start] TestClass::scm_aa_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [mt_unsafe] TestClass::scm_aa_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [mt_unsafe_one] TestClass::scm_aa_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [] TestClass::scm_ae_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [mt_start] TestClass::scm_ae_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [mt_unsafe] TestClass::scm_ae_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [mt_unsafe_one] TestClass::scm_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:138: [mt_safe, mt_unsafe, pure] TestClass::scm_ea_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:138: [mt_safe, mt_unsafe_one, pure] TestClass::scm_ea_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:93: [mt_start] TestClass::scm_test_caller_smethod_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [] TestClass::scm_au_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [mt_start] TestClass::scm_au_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [mt_unsafe] TestClass::scm_au_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [mt_unsafe_one] TestClass::scm_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_PURE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [] TestClass::scm_aa_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [mt_start] TestClass::scm_aa_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [mt_unsafe] TestClass::scm_aa_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [mt_unsafe_one] TestClass::scm_aa_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [] TestClass::scm_ae_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [mt_start] TestClass::scm_ae_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [mt_unsafe] TestClass::scm_ae_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [mt_unsafe_one] TestClass::scm_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:138: [mt_safe, mt_unsafe, pure] TestClass::scm_ea_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:138: [mt_safe, mt_unsafe_one, pure] TestClass::scm_ea_VL_MT_UNSAFE_ONE(VerilatedMutex &) %Error: "TestClass::scm_test_caller_smethod_VL_PURE(VerilatedMutex &)" is pure but calls non-pure function(s) -t/t_dist_attributes_bad.cpp:93: [pure] TestClass::scm_test_caller_smethod_VL_PURE(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [] TestClass::scm_au_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [acquire] TestClass::scm_au_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [acquire] TestClass::scm_au_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [excludes] TestClass::scm_au_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [mt_safe] TestClass::scm_au_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [excludes] TestClass::scm_au_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [mt_safe_postinit] TestClass::scm_au_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [mt_start] TestClass::scm_au_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [mt_unsafe] TestClass::scm_au_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [mt_unsafe_one] TestClass::scm_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [release] TestClass::scm_au_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [release] TestClass::scm_au_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [requires] TestClass::scm_au_VL_REQUIRES(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_PURE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_REQUIRES(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [] TestClass::scm_aa_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [acquire] TestClass::scm_aa_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [acquire] TestClass::scm_aa_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [excludes] TestClass::scm_aa_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [mt_safe] TestClass::scm_aa_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [excludes] TestClass::scm_aa_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [mt_safe_postinit] TestClass::scm_aa_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [mt_start] TestClass::scm_aa_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [mt_unsafe] TestClass::scm_aa_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [mt_unsafe_one] TestClass::scm_aa_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [release] TestClass::scm_aa_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [release] TestClass::scm_aa_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [requires] TestClass::scm_aa_VL_REQUIRES(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [] TestClass::scm_ae_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [acquire] TestClass::scm_ae_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [acquire] TestClass::scm_ae_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [excludes] TestClass::scm_ae_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [mt_safe] TestClass::scm_ae_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [excludes] TestClass::scm_ae_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [mt_safe_postinit] TestClass::scm_ae_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [mt_start] TestClass::scm_ae_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [mt_unsafe] TestClass::scm_ae_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [mt_unsafe_one] TestClass::scm_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [release] TestClass::scm_ae_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [release] TestClass::scm_ae_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [requires] TestClass::scm_ae_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:93: [pure] TestClass::scm_test_caller_smethod_VL_PURE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [] TestClass::scm_au_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [acquire] TestClass::scm_au_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [acquire] TestClass::scm_au_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [excludes] TestClass::scm_au_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [mt_safe] TestClass::scm_au_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [excludes] TestClass::scm_au_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [mt_safe_postinit] TestClass::scm_au_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [mt_start] TestClass::scm_au_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [mt_unsafe] TestClass::scm_au_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [mt_unsafe_one] TestClass::scm_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [release] TestClass::scm_au_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [release] TestClass::scm_au_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [requires] TestClass::scm_au_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_PURE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [] TestClass::scm_aa_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [acquire] TestClass::scm_aa_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [acquire] TestClass::scm_aa_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [excludes] TestClass::scm_aa_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [mt_safe] TestClass::scm_aa_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [excludes] TestClass::scm_aa_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [mt_safe_postinit] TestClass::scm_aa_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [mt_start] TestClass::scm_aa_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [mt_unsafe] TestClass::scm_aa_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [mt_unsafe_one] TestClass::scm_aa_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [release] TestClass::scm_aa_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [release] TestClass::scm_aa_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [requires] TestClass::scm_aa_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [] TestClass::scm_ae_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [acquire] TestClass::scm_ae_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [acquire] TestClass::scm_ae_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [excludes] TestClass::scm_ae_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [mt_safe] TestClass::scm_ae_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [excludes] TestClass::scm_ae_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [mt_safe_postinit] TestClass::scm_ae_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [mt_start] TestClass::scm_ae_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [mt_unsafe] TestClass::scm_ae_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [mt_unsafe_one] TestClass::scm_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [release] TestClass::scm_ae_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [release] TestClass::scm_ae_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [requires] TestClass::scm_ae_VL_REQUIRES(VerilatedMutex &) %Error: "TestClass::scm_test_caller_smethod_hdr_VL_MT_SAFE(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) -t/t_dist_attributes_bad.h:141: [mt_safe] TestClass::scm_test_caller_smethod_hdr_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [] TestClass::scm_au_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [mt_start] TestClass::scm_au_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [mt_unsafe] TestClass::scm_au_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [mt_unsafe_one] TestClass::scm_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_PURE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_REQUIRES(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [] TestClass::scm_aa_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [mt_start] TestClass::scm_aa_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [mt_unsafe] TestClass::scm_aa_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [mt_unsafe_one] TestClass::scm_aa_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [] TestClass::scm_ae_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [mt_start] TestClass::scm_ae_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [mt_unsafe] TestClass::scm_ae_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [mt_unsafe_one] TestClass::scm_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:138: [mt_safe, mt_unsafe, pure] TestClass::scm_ea_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:138: [mt_safe, mt_unsafe_one, pure] TestClass::scm_ea_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:141: [mt_safe] TestClass::scm_test_caller_smethod_hdr_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [] TestClass::scm_au_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [mt_start] TestClass::scm_au_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [mt_unsafe] TestClass::scm_au_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [mt_unsafe_one] TestClass::scm_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_PURE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [] TestClass::scm_aa_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [mt_start] TestClass::scm_aa_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [mt_unsafe] TestClass::scm_aa_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [mt_unsafe_one] TestClass::scm_aa_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [] TestClass::scm_ae_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [mt_start] TestClass::scm_ae_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [mt_unsafe] TestClass::scm_ae_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [mt_unsafe_one] TestClass::scm_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:138: [mt_safe, mt_unsafe, pure] TestClass::scm_ea_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:138: [mt_safe, mt_unsafe_one, pure] TestClass::scm_ea_VL_MT_UNSAFE_ONE(VerilatedMutex &) %Error: "TestClass::scm_test_caller_smethod_hdr_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe -t/t_dist_attributes_bad.h:141: [mt_start] TestClass::scm_test_caller_smethod_hdr_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [] TestClass::scm_au_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [mt_start] TestClass::scm_au_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [mt_unsafe] TestClass::scm_au_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [mt_unsafe_one] TestClass::scm_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_PURE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_REQUIRES(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [] TestClass::scm_aa_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [mt_start] TestClass::scm_aa_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [mt_unsafe] TestClass::scm_aa_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [mt_unsafe_one] TestClass::scm_aa_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [] TestClass::scm_ae_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [mt_start] TestClass::scm_ae_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [mt_unsafe] TestClass::scm_ae_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [mt_unsafe_one] TestClass::scm_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:138: [mt_safe, mt_unsafe, pure] TestClass::scm_ea_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:138: [mt_safe, mt_unsafe_one, pure] TestClass::scm_ea_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:141: [mt_start] TestClass::scm_test_caller_smethod_hdr_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [] TestClass::scm_au_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [mt_start] TestClass::scm_au_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [mt_unsafe] TestClass::scm_au_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [mt_unsafe_one] TestClass::scm_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_PURE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [] TestClass::scm_aa_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [mt_start] TestClass::scm_aa_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [mt_unsafe] TestClass::scm_aa_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [mt_unsafe_one] TestClass::scm_aa_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [] TestClass::scm_ae_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [mt_start] TestClass::scm_ae_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [mt_unsafe] TestClass::scm_ae_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [mt_unsafe_one] TestClass::scm_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:138: [mt_safe, mt_unsafe, pure] TestClass::scm_ea_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:138: [mt_safe, mt_unsafe_one, pure] TestClass::scm_ea_VL_MT_UNSAFE_ONE(VerilatedMutex &) %Error: "TestClass::scm_test_caller_smethod_hdr_VL_PURE(VerilatedMutex &)" is pure but calls non-pure function(s) -t/t_dist_attributes_bad.h:141: [pure] TestClass::scm_test_caller_smethod_hdr_VL_PURE(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [] TestClass::scm_au_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [acquire] TestClass::scm_au_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [acquire] TestClass::scm_au_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [excludes] TestClass::scm_au_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [mt_safe] TestClass::scm_au_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [excludes] TestClass::scm_au_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [mt_safe_postinit] TestClass::scm_au_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [mt_start] TestClass::scm_au_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [mt_unsafe] TestClass::scm_au_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [mt_unsafe_one] TestClass::scm_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [release] TestClass::scm_au_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [release] TestClass::scm_au_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:120: [requires] TestClass::scm_au_VL_REQUIRES(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_PURE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_REQUIRES(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [] TestClass::scm_aa_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [acquire] TestClass::scm_aa_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [acquire] TestClass::scm_aa_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [excludes] TestClass::scm_aa_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [mt_safe] TestClass::scm_aa_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [excludes] TestClass::scm_aa_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [mt_safe_postinit] TestClass::scm_aa_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [mt_start] TestClass::scm_aa_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [mt_unsafe] TestClass::scm_aa_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [mt_unsafe_one] TestClass::scm_aa_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [release] TestClass::scm_aa_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [release] TestClass::scm_aa_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:128: [requires] TestClass::scm_aa_VL_REQUIRES(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [] TestClass::scm_ae_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [acquire] TestClass::scm_ae_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [acquire] TestClass::scm_ae_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [excludes] TestClass::scm_ae_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [mt_safe] TestClass::scm_ae_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [excludes] TestClass::scm_ae_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [mt_safe_postinit] TestClass::scm_ae_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [mt_start] TestClass::scm_ae_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [mt_unsafe] TestClass::scm_ae_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [mt_unsafe_one] TestClass::scm_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [release] TestClass::scm_ae_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [release] TestClass::scm_ae_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:133: [requires] TestClass::scm_ae_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:141: [pure] TestClass::scm_test_caller_smethod_hdr_VL_PURE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [] TestClass::scm_au_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [acquire] TestClass::scm_au_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [acquire] TestClass::scm_au_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [excludes] TestClass::scm_au_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [mt_safe] TestClass::scm_au_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [excludes] TestClass::scm_au_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [mt_safe_postinit] TestClass::scm_au_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [mt_start] TestClass::scm_au_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [mt_unsafe] TestClass::scm_au_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [mt_unsafe_one] TestClass::scm_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [release] TestClass::scm_au_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [release] TestClass::scm_au_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:120: [requires] TestClass::scm_au_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_PURE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [] TestClass::scm_aa_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [acquire] TestClass::scm_aa_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [acquire] TestClass::scm_aa_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [excludes] TestClass::scm_aa_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [mt_safe] TestClass::scm_aa_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [excludes] TestClass::scm_aa_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [mt_safe_postinit] TestClass::scm_aa_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [mt_start] TestClass::scm_aa_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [mt_unsafe] TestClass::scm_aa_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [mt_unsafe_one] TestClass::scm_aa_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [release] TestClass::scm_aa_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [release] TestClass::scm_aa_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:128: [requires] TestClass::scm_aa_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [] TestClass::scm_ae_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [acquire] TestClass::scm_ae_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [acquire] TestClass::scm_ae_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [excludes] TestClass::scm_ae_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [mt_safe] TestClass::scm_ae_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [excludes] TestClass::scm_ae_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [mt_safe_postinit] TestClass::scm_ae_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [mt_start] TestClass::scm_ae_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [mt_unsafe] TestClass::scm_ae_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [mt_unsafe_one] TestClass::scm_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [release] TestClass::scm_ae_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [release] TestClass::scm_ae_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:133: [requires] TestClass::scm_ae_VL_REQUIRES(VerilatedMutex &) %Error: "TestClass::scm_ua_VL_ACQUIRE(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_ACQUIRE(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:75: [acquire] TestClass::scm_ua_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_ACQUIRE(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:75: [acquire] TestClass::scm_ua_VL_ACQUIRE(VerilatedMutex &) %Error: "TestClass::scm_ua_VL_ACQUIRE_SHARED(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:75: [acquire] TestClass::scm_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:75: [acquire] TestClass::scm_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) %Error: "TestClass::scm_ua_VL_EXCLUDES(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_EXCLUDES(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:75: [excludes] TestClass::scm_ua_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_EXCLUDES(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:75: [excludes] TestClass::scm_ua_VL_EXCLUDES(VerilatedMutex &) %Error: "TestClass::scm_ua_VL_MT_SAFE(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_SAFE(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:75: [mt_safe] TestClass::scm_ua_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_SAFE(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:75: [mt_safe] TestClass::scm_ua_VL_MT_SAFE(VerilatedMutex &) %Error: "TestClass::scm_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:75: [excludes] TestClass::scm_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:75: [excludes] TestClass::scm_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) %Error: "TestClass::scm_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:75: [mt_safe_postinit] TestClass::scm_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:75: [mt_safe_postinit] TestClass::scm_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) %Error: "TestClass::scm_ua_VL_MT_START(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_START(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:75: [mt_start] TestClass::scm_ua_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_START(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:75: [mt_start] TestClass::scm_ua_VL_MT_START(VerilatedMutex &) %Error: "TestClass::scm_ua_VL_MT_UNSAFE(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_UNSAFE(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:75: [mt_unsafe] TestClass::scm_ua_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_UNSAFE(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:75: [mt_unsafe] TestClass::scm_ua_VL_MT_UNSAFE(VerilatedMutex &) %Error: "TestClass::scm_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:75: [mt_unsafe_one] TestClass::scm_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:75: [mt_unsafe_one] TestClass::scm_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) %Error: "TestClass::scm_ua_VL_PURE(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_PURE(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:75: [pure] TestClass::scm_ua_VL_PURE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_PURE(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:75: [pure] TestClass::scm_ua_VL_PURE(VerilatedMutex &) %Error: "TestClass::scm_ua_VL_RELEASE(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_RELEASE(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:75: [release] TestClass::scm_ua_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_RELEASE(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:75: [release] TestClass::scm_ua_VL_RELEASE(VerilatedMutex &) %Error: "TestClass::scm_ua_VL_RELEASE_SHARED(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_RELEASE_SHARED(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:75: [release] TestClass::scm_ua_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_RELEASE_SHARED(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:75: [release] TestClass::scm_ua_VL_RELEASE_SHARED(VerilatedMutex &) %Error: "TestClass::scm_ua_VL_REQUIRES(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_REQUIRES(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:75: [requires] TestClass::scm_ua_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:124: [] TestClass::scm_ua_VL_REQUIRES(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:75: [requires] TestClass::scm_ua_VL_REQUIRES(VerilatedMutex &) %Error: "TestClassConstructor::safe_function_calls_constructor_global_object_bad()" is stable_tree but calls non-stable_tree or non-mtsafe -t/t_dist_attributes_bad.h:405: [stable_tree] TestClassConstructor::safe_function_calls_constructor_global_object_bad() -t/t_dist_attributes_bad.h:355: [] DummyClass::dummy_function() +t/t_dist_attributes/mt_enabled.h:405: [stable_tree] TestClassConstructor::safe_function_calls_constructor_global_object_bad() +t/t_dist_attributes/mt_enabled.h:355: [] DummyClass::dummy_function() %Error: "TestClassConstructor::safe_function_calls_constructor_global_object_member_bad()" is stable_tree but calls non-stable_tree or non-mtsafe -t/t_dist_attributes_bad.h:408: [stable_tree] TestClassConstructor::safe_function_calls_constructor_global_object_member_bad() -t/t_dist_attributes_bad.h:350: [] DummyClass2::dummy_function2() +t/t_dist_attributes/mt_enabled.h:408: [stable_tree] TestClassConstructor::safe_function_calls_constructor_global_object_member_bad() +t/t_dist_attributes/mt_enabled.h:350: [] DummyClass2::dummy_function2() %Error: "TestClassConstructor::safe_function_calls_constructor_local_calls_class_global_bad()" is mtsafe but calls non-mtsafe function(s) -t/t_dist_attributes_bad.h:402: [mt_safe] TestClassConstructor::safe_function_calls_constructor_local_calls_class_global_bad() -t/t_dist_attributes_bad.h:280: [] StaticClass::static_class_function() +t/t_dist_attributes/mt_enabled.h:402: [mt_safe] TestClassConstructor::safe_function_calls_constructor_local_calls_class_global_bad() +t/t_dist_attributes/mt_enabled.h:280: [] StaticClass::static_class_function() %Error: "TestClassConstructor::safe_function_calls_constructor_local_calls_global_bad()" is mtsafe but calls non-mtsafe function(s) -t/t_dist_attributes_bad.h:399: [mt_safe] TestClassConstructor::safe_function_calls_constructor_local_calls_global_bad() -t/t_dist_attributes_bad.h:276: [] static_function() +t/t_dist_attributes/mt_enabled.h:399: [mt_safe] TestClassConstructor::safe_function_calls_constructor_local_calls_global_bad() +t/t_dist_attributes/mt_enabled.h:276: [] static_function() %Error: "TestClassConstructor::safe_function_calls_constructor_with_unsafepointer_bad()" is mtsafe but calls non-mtsafe function(s) -t/t_dist_attributes_bad.h:391: [mt_safe] TestClassConstructor::safe_function_calls_constructor_with_unsafepointer_bad() -t/t_dist_attributes_bad.h:311: [mt_unsafe] UnsafeFunction::unsafe_function() +t/t_dist_attributes/mt_enabled.h:391: [mt_safe] TestClassConstructor::safe_function_calls_constructor_with_unsafepointer_bad() +t/t_dist_attributes/mt_enabled.h:311: [mt_unsafe] UnsafeFunction::unsafe_function() %Error: "TestClassConstructor::safe_function_calls_constructor_with_unsafereference_bad()" is mtsafe but calls non-mtsafe function(s) -t/t_dist_attributes_bad.h:395: [mt_safe] TestClassConstructor::safe_function_calls_constructor_with_unsafereference_bad() -t/t_dist_attributes_bad.h:311: [mt_unsafe] UnsafeFunction::unsafe_function() +t/t_dist_attributes/mt_enabled.h:395: [mt_safe] TestClassConstructor::safe_function_calls_constructor_with_unsafereference_bad() +t/t_dist_attributes/mt_enabled.h:311: [mt_unsafe] UnsafeFunction::unsafe_function() %Error: "TestClassConstructor::safe_function_local_function_global_bad()" is mtsafe but calls non-mtsafe function(s) -t/t_dist_attributes_bad.h:377: [mt_safe] TestClassConstructor::safe_function_local_function_global_bad() -t/t_dist_attributes_bad.h:276: [] static_function() +t/t_dist_attributes/mt_enabled.h:377: [mt_safe] TestClassConstructor::safe_function_local_function_global_bad() +t/t_dist_attributes/mt_enabled.h:276: [] static_function() %Error: "TestClassConstructor::safe_function_static_constructor_bad()" is mtsafe but calls non-mtsafe function(s) -t/t_dist_attributes_bad.h:374: [mt_safe] TestClassConstructor::safe_function_static_constructor_bad() -t/t_dist_attributes_bad.h:276: [] static_function() +t/t_dist_attributes/mt_enabled.h:374: [mt_safe] TestClassConstructor::safe_function_static_constructor_bad() +t/t_dist_attributes/mt_enabled.h:276: [] static_function() %Error: "TestClassConstructor::safe_function_unsafe_constructor_bad()" is mtsafe but calls non-mtsafe function(s) -t/t_dist_attributes_bad.h:371: [mt_safe] TestClassConstructor::safe_function_unsafe_constructor_bad() -t/t_dist_attributes_bad.h:285: [mt_unsafe] ConstructorCallsUnsafeLocalFunction::unsafe_function() +t/t_dist_attributes/mt_enabled.h:371: [mt_safe] TestClassConstructor::safe_function_unsafe_constructor_bad() +t/t_dist_attributes/mt_enabled.h:285: [mt_unsafe] ConstructorCallsUnsafeLocalFunction::unsafe_function() + +%Error: "UnannotatedMtDisabledClass::unannotatedMtDisabledMethodBad()" defined in a file marked as VL_MT_DISABLED_CODE_UNIT has declaration(s) without VL_MT_DISABLED annotation +t/t_dist_attributes/mt_disabled.cpp:23: [mt_disabled, requires] UnannotatedMtDisabledClass::unannotatedMtDisabledMethodBad() +t/t_dist_attributes/mt_disabled.h:29: [] UnannotatedMtDisabledClass::unannotatedMtDisabledMethodBad() + +%Error: "UnannotatedMtDisabledClass::unannotatedMtDisabledStaticMethodBad()" defined in a file marked as VL_MT_DISABLED_CODE_UNIT has declaration(s) without VL_MT_DISABLED annotation +t/t_dist_attributes/mt_disabled.cpp:26: [mt_disabled, requires] UnannotatedMtDisabledClass::unannotatedMtDisabledStaticMethodBad() +t/t_dist_attributes/mt_disabled.h:30: [] UnannotatedMtDisabledClass::unannotatedMtDisabledStaticMethodBad() %Error: "ifh_test_caller_func_VL_MT_SAFE(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) -t/t_dist_attributes_bad.cpp:53: [mt_safe] ifh_test_caller_func_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [] ifh_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [mt_start] ifh_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [mt_unsafe] ifh_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [mt_unsafe_one] ifh_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:53: [mt_safe] ifh_test_caller_func_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [] ifh_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [mt_start] ifh_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [mt_unsafe] ifh_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [mt_unsafe_one] ifh_VL_MT_UNSAFE_ONE(VerilatedMutex &) %Error: "ifh_test_caller_func_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe -t/t_dist_attributes_bad.cpp:53: [mt_start] ifh_test_caller_func_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [] ifh_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [mt_start] ifh_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [mt_unsafe] ifh_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [mt_unsafe_one] ifh_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:53: [mt_start] ifh_test_caller_func_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [] ifh_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [mt_start] ifh_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [mt_unsafe] ifh_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [mt_unsafe_one] ifh_VL_MT_UNSAFE_ONE(VerilatedMutex &) %Error: "ifh_test_caller_func_VL_PURE(VerilatedMutex &)" is pure but calls non-pure function(s) -t/t_dist_attributes_bad.cpp:53: [pure] ifh_test_caller_func_VL_PURE(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [] ifh_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [acquire] ifh_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [acquire] ifh_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [excludes] ifh_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [mt_safe] ifh_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [excludes] ifh_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [mt_safe_postinit] ifh_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [mt_start] ifh_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [mt_unsafe] ifh_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [mt_unsafe_one] ifh_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [release] ifh_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [release] ifh_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [requires] ifh_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:53: [pure] ifh_test_caller_func_VL_PURE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [] ifh_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [acquire] ifh_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [acquire] ifh_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [excludes] ifh_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [mt_safe] ifh_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [excludes] ifh_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [mt_safe_postinit] ifh_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [mt_start] ifh_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [mt_unsafe] ifh_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [mt_unsafe_one] ifh_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [release] ifh_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [release] ifh_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [requires] ifh_VL_REQUIRES(VerilatedMutex &) %Error: "ifh_test_caller_func_hdr_VL_MT_SAFE(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) -t/t_dist_attributes_bad.h:97: [mt_safe] ifh_test_caller_func_hdr_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [] ifh_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [mt_start] ifh_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [mt_unsafe] ifh_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [mt_unsafe_one] ifh_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:97: [mt_safe] ifh_test_caller_func_hdr_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [] ifh_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [mt_start] ifh_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [mt_unsafe] ifh_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [mt_unsafe_one] ifh_VL_MT_UNSAFE_ONE(VerilatedMutex &) %Error: "ifh_test_caller_func_hdr_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe -t/t_dist_attributes_bad.h:97: [mt_start] ifh_test_caller_func_hdr_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [] ifh_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [mt_start] ifh_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [mt_unsafe] ifh_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [mt_unsafe_one] ifh_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:97: [mt_start] ifh_test_caller_func_hdr_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [] ifh_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [mt_start] ifh_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [mt_unsafe] ifh_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [mt_unsafe_one] ifh_VL_MT_UNSAFE_ONE(VerilatedMutex &) %Error: "ifh_test_caller_func_hdr_VL_PURE(VerilatedMutex &)" is pure but calls non-pure function(s) -t/t_dist_attributes_bad.h:97: [pure] ifh_test_caller_func_hdr_VL_PURE(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [] ifh_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [acquire] ifh_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [acquire] ifh_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [excludes] ifh_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [mt_safe] ifh_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [excludes] ifh_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [mt_safe_postinit] ifh_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [mt_start] ifh_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [mt_unsafe] ifh_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [mt_unsafe_one] ifh_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [release] ifh_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [release] ifh_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:94: [requires] ifh_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:97: [pure] ifh_test_caller_func_hdr_VL_PURE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [] ifh_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [acquire] ifh_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [acquire] ifh_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [excludes] ifh_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [mt_safe] ifh_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [excludes] ifh_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [mt_safe_postinit] ifh_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [mt_start] ifh_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [mt_unsafe] ifh_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [mt_unsafe_one] ifh_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [release] ifh_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [release] ifh_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:94: [requires] ifh_VL_REQUIRES(VerilatedMutex &) %Error: "nsf_ae_NO_ANNOTATION(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:75: [] nsf_ae_NO_ANNOTATION(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:34: [mt_safe, pure] nsf_ae_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [] nsf_ae_NO_ANNOTATION(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:34: [mt_safe, pure] nsf_ae_NO_ANNOTATION(VerilatedMutex &) %Error: "nsf_ae_VL_ACQUIRE(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:75: [acquire] nsf_ae_VL_ACQUIRE(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:34: [mt_safe, pure, acquire] nsf_ae_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [acquire] nsf_ae_VL_ACQUIRE(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:34: [mt_safe, pure, acquire] nsf_ae_VL_ACQUIRE(VerilatedMutex &) %Error: "nsf_ae_VL_ACQUIRE_SHARED(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:75: [acquire] nsf_ae_VL_ACQUIRE_SHARED(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:34: [mt_safe, pure, acquire] nsf_ae_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [acquire] nsf_ae_VL_ACQUIRE_SHARED(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:34: [mt_safe, pure, acquire] nsf_ae_VL_ACQUIRE_SHARED(VerilatedMutex &) %Error: "nsf_ae_VL_EXCLUDES(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:75: [excludes] nsf_ae_VL_EXCLUDES(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:34: [mt_safe, pure, excludes] nsf_ae_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [excludes] nsf_ae_VL_EXCLUDES(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:34: [mt_safe, pure, excludes] nsf_ae_VL_EXCLUDES(VerilatedMutex &) %Error: "nsf_ae_VL_MT_SAFE(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:75: [mt_safe] nsf_ae_VL_MT_SAFE(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:34: [mt_safe, pure] nsf_ae_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [mt_safe] nsf_ae_VL_MT_SAFE(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:34: [mt_safe, pure] nsf_ae_VL_MT_SAFE(VerilatedMutex &) %Error: "nsf_ae_VL_MT_SAFE_EXCLUDES(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:75: [excludes] nsf_ae_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:34: [mt_safe, pure, excludes] nsf_ae_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [excludes] nsf_ae_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:34: [mt_safe, pure, excludes] nsf_ae_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) %Error: "nsf_ae_VL_MT_SAFE_POSTINIT(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:75: [mt_safe_postinit] nsf_ae_VL_MT_SAFE_POSTINIT(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:34: [mt_safe, mt_safe_postinit, pure] nsf_ae_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [mt_safe_postinit] nsf_ae_VL_MT_SAFE_POSTINIT(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:34: [mt_safe, mt_safe_postinit, pure] nsf_ae_VL_MT_SAFE_POSTINIT(VerilatedMutex &) %Error: "nsf_ae_VL_MT_START(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:75: [mt_start] nsf_ae_VL_MT_START(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:34: [mt_start, mt_safe, pure] nsf_ae_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [mt_start] nsf_ae_VL_MT_START(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:34: [mt_start, mt_safe, pure] nsf_ae_VL_MT_START(VerilatedMutex &) %Error: "nsf_ae_VL_MT_UNSAFE(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:75: [mt_unsafe] nsf_ae_VL_MT_UNSAFE(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:34: [mt_safe, mt_unsafe, pure] nsf_ae_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [mt_unsafe] nsf_ae_VL_MT_UNSAFE(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:34: [mt_safe, mt_unsafe, pure] nsf_ae_VL_MT_UNSAFE(VerilatedMutex &) %Error: "nsf_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:75: [mt_unsafe_one] nsf_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:34: [mt_safe, mt_unsafe_one, pure] nsf_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [mt_unsafe_one] nsf_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:34: [mt_safe, mt_unsafe_one, pure] nsf_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) %Error: "nsf_ae_VL_PURE(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:75: [pure] nsf_ae_VL_PURE(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:34: [mt_safe, pure] nsf_ae_VL_PURE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [pure] nsf_ae_VL_PURE(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:34: [mt_safe, pure] nsf_ae_VL_PURE(VerilatedMutex &) %Error: "nsf_ae_VL_RELEASE(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:75: [release] nsf_ae_VL_RELEASE(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:34: [mt_safe, pure, release] nsf_ae_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [release] nsf_ae_VL_RELEASE(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:34: [mt_safe, pure, release] nsf_ae_VL_RELEASE(VerilatedMutex &) %Error: "nsf_ae_VL_RELEASE_SHARED(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:75: [release] nsf_ae_VL_RELEASE_SHARED(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:34: [mt_safe, pure, release] nsf_ae_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [release] nsf_ae_VL_RELEASE_SHARED(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:34: [mt_safe, pure, release] nsf_ae_VL_RELEASE_SHARED(VerilatedMutex &) %Error: "nsf_ae_VL_REQUIRES(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:75: [requires] nsf_ae_VL_REQUIRES(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:34: [mt_safe, pure, requires] nsf_ae_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [requires] nsf_ae_VL_REQUIRES(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:34: [mt_safe, pure, requires] nsf_ae_VL_REQUIRES(VerilatedMutex &) %Error: "nsf_test_caller_func_VL_MT_SAFE(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) -t/t_dist_attributes_bad.cpp:42: [mt_safe] nsf_test_caller_func_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [] nsf_au_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [mt_start] nsf_au_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [mt_unsafe] nsf_au_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [mt_unsafe_one] nsf_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_PURE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_REQUIRES(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [] nsf_aa_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [mt_start] nsf_aa_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [mt_unsafe] nsf_aa_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [mt_unsafe_one] nsf_aa_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [] nsf_ae_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [mt_start] nsf_ae_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [mt_unsafe] nsf_ae_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [mt_unsafe_one] nsf_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:80: [mt_safe, mt_unsafe, pure] nsf_ea_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:80: [mt_safe, mt_unsafe_one, pure] nsf_ea_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:42: [mt_safe] nsf_test_caller_func_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [] nsf_au_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [mt_start] nsf_au_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [mt_unsafe] nsf_au_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [mt_unsafe_one] nsf_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_PURE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [] nsf_aa_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [mt_start] nsf_aa_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [mt_unsafe] nsf_aa_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [mt_unsafe_one] nsf_aa_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [] nsf_ae_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [mt_start] nsf_ae_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [mt_unsafe] nsf_ae_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [mt_unsafe_one] nsf_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:80: [mt_safe, mt_unsafe, pure] nsf_ea_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:80: [mt_safe, mt_unsafe_one, pure] nsf_ea_VL_MT_UNSAFE_ONE(VerilatedMutex &) %Error: "nsf_test_caller_func_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe -t/t_dist_attributes_bad.cpp:42: [mt_start] nsf_test_caller_func_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [] nsf_au_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [mt_start] nsf_au_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [mt_unsafe] nsf_au_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [mt_unsafe_one] nsf_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_PURE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_REQUIRES(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [] nsf_aa_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [mt_start] nsf_aa_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [mt_unsafe] nsf_aa_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [mt_unsafe_one] nsf_aa_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [] nsf_ae_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [mt_start] nsf_ae_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [mt_unsafe] nsf_ae_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [mt_unsafe_one] nsf_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:80: [mt_safe, mt_unsafe, pure] nsf_ea_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:80: [mt_safe, mt_unsafe_one, pure] nsf_ea_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:42: [mt_start] nsf_test_caller_func_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [] nsf_au_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [mt_start] nsf_au_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [mt_unsafe] nsf_au_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [mt_unsafe_one] nsf_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_PURE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [] nsf_aa_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [mt_start] nsf_aa_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [mt_unsafe] nsf_aa_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [mt_unsafe_one] nsf_aa_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [] nsf_ae_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [mt_start] nsf_ae_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [mt_unsafe] nsf_ae_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [mt_unsafe_one] nsf_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:80: [mt_safe, mt_unsafe, pure] nsf_ea_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:80: [mt_safe, mt_unsafe_one, pure] nsf_ea_VL_MT_UNSAFE_ONE(VerilatedMutex &) %Error: "nsf_test_caller_func_VL_PURE(VerilatedMutex &)" is pure but calls non-pure function(s) -t/t_dist_attributes_bad.cpp:42: [pure] nsf_test_caller_func_VL_PURE(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [] nsf_au_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [acquire] nsf_au_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [acquire] nsf_au_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [excludes] nsf_au_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [mt_safe] nsf_au_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [excludes] nsf_au_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [mt_safe_postinit] nsf_au_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [mt_start] nsf_au_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [mt_unsafe] nsf_au_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [mt_unsafe_one] nsf_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [release] nsf_au_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [release] nsf_au_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [requires] nsf_au_VL_REQUIRES(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_PURE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_REQUIRES(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [] nsf_aa_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [acquire] nsf_aa_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [acquire] nsf_aa_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [excludes] nsf_aa_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [mt_safe] nsf_aa_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [excludes] nsf_aa_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [mt_safe_postinit] nsf_aa_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [mt_start] nsf_aa_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [mt_unsafe] nsf_aa_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [mt_unsafe_one] nsf_aa_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [release] nsf_aa_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [release] nsf_aa_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [requires] nsf_aa_VL_REQUIRES(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [] nsf_ae_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [acquire] nsf_ae_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [acquire] nsf_ae_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [excludes] nsf_ae_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [mt_safe] nsf_ae_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [excludes] nsf_ae_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [mt_safe_postinit] nsf_ae_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [mt_start] nsf_ae_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [mt_unsafe] nsf_ae_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [mt_unsafe_one] nsf_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [release] nsf_ae_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [release] nsf_ae_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [requires] nsf_ae_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:42: [pure] nsf_test_caller_func_VL_PURE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [] nsf_au_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [acquire] nsf_au_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [acquire] nsf_au_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [excludes] nsf_au_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [mt_safe] nsf_au_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [excludes] nsf_au_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [mt_safe_postinit] nsf_au_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [mt_start] nsf_au_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [mt_unsafe] nsf_au_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [mt_unsafe_one] nsf_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [release] nsf_au_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [release] nsf_au_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [requires] nsf_au_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_PURE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [] nsf_aa_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [acquire] nsf_aa_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [acquire] nsf_aa_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [excludes] nsf_aa_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [mt_safe] nsf_aa_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [excludes] nsf_aa_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [mt_safe_postinit] nsf_aa_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [mt_start] nsf_aa_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [mt_unsafe] nsf_aa_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [mt_unsafe_one] nsf_aa_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [release] nsf_aa_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [release] nsf_aa_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [requires] nsf_aa_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [] nsf_ae_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [acquire] nsf_ae_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [acquire] nsf_ae_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [excludes] nsf_ae_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [mt_safe] nsf_ae_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [excludes] nsf_ae_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [mt_safe_postinit] nsf_ae_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [mt_start] nsf_ae_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [mt_unsafe] nsf_ae_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [mt_unsafe_one] nsf_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [release] nsf_ae_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [release] nsf_ae_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [requires] nsf_ae_VL_REQUIRES(VerilatedMutex &) %Error: "nsf_test_caller_func_hdr_VL_MT_SAFE(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) -t/t_dist_attributes_bad.h:83: [mt_safe] nsf_test_caller_func_hdr_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [] nsf_au_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [mt_start] nsf_au_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [mt_unsafe] nsf_au_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [mt_unsafe_one] nsf_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_PURE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_REQUIRES(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [] nsf_aa_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [mt_start] nsf_aa_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [mt_unsafe] nsf_aa_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [mt_unsafe_one] nsf_aa_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [] nsf_ae_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [mt_start] nsf_ae_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [mt_unsafe] nsf_ae_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [mt_unsafe_one] nsf_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:80: [mt_safe, mt_unsafe, pure] nsf_ea_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:80: [mt_safe, mt_unsafe_one, pure] nsf_ea_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:83: [mt_safe] nsf_test_caller_func_hdr_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [] nsf_au_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [mt_start] nsf_au_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [mt_unsafe] nsf_au_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [mt_unsafe_one] nsf_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_PURE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [] nsf_aa_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [mt_start] nsf_aa_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [mt_unsafe] nsf_aa_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [mt_unsafe_one] nsf_aa_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [] nsf_ae_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [mt_start] nsf_ae_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [mt_unsafe] nsf_ae_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [mt_unsafe_one] nsf_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:80: [mt_safe, mt_unsafe, pure] nsf_ea_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:80: [mt_safe, mt_unsafe_one, pure] nsf_ea_VL_MT_UNSAFE_ONE(VerilatedMutex &) %Error: "nsf_test_caller_func_hdr_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe -t/t_dist_attributes_bad.h:83: [mt_start] nsf_test_caller_func_hdr_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [] nsf_au_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [mt_start] nsf_au_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [mt_unsafe] nsf_au_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [mt_unsafe_one] nsf_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_PURE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_REQUIRES(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [] nsf_aa_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [mt_start] nsf_aa_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [mt_unsafe] nsf_aa_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [mt_unsafe_one] nsf_aa_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [] nsf_ae_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [mt_start] nsf_ae_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [mt_unsafe] nsf_ae_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [mt_unsafe_one] nsf_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:80: [mt_safe, mt_unsafe, pure] nsf_ea_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:80: [mt_safe, mt_unsafe_one, pure] nsf_ea_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:83: [mt_start] nsf_test_caller_func_hdr_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [] nsf_au_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [mt_start] nsf_au_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [mt_unsafe] nsf_au_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [mt_unsafe_one] nsf_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_PURE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [] nsf_aa_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [mt_start] nsf_aa_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [mt_unsafe] nsf_aa_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [mt_unsafe_one] nsf_aa_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [] nsf_ae_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [mt_start] nsf_ae_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [mt_unsafe] nsf_ae_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [mt_unsafe_one] nsf_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:80: [mt_safe, mt_unsafe, pure] nsf_ea_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:80: [mt_safe, mt_unsafe_one, pure] nsf_ea_VL_MT_UNSAFE_ONE(VerilatedMutex &) %Error: "nsf_test_caller_func_hdr_VL_PURE(VerilatedMutex &)" is pure but calls non-pure function(s) -t/t_dist_attributes_bad.h:83: [pure] nsf_test_caller_func_hdr_VL_PURE(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [] nsf_au_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [acquire] nsf_au_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [acquire] nsf_au_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [excludes] nsf_au_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [mt_safe] nsf_au_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [excludes] nsf_au_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [mt_safe_postinit] nsf_au_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [mt_start] nsf_au_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [mt_unsafe] nsf_au_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [mt_unsafe_one] nsf_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [release] nsf_au_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [release] nsf_au_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:62: [requires] nsf_au_VL_REQUIRES(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_PURE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_REQUIRES(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [] nsf_aa_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [acquire] nsf_aa_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [acquire] nsf_aa_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [excludes] nsf_aa_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [mt_safe] nsf_aa_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [excludes] nsf_aa_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [mt_safe_postinit] nsf_aa_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [mt_start] nsf_aa_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [mt_unsafe] nsf_aa_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [mt_unsafe_one] nsf_aa_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [release] nsf_aa_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [release] nsf_aa_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:70: [requires] nsf_aa_VL_REQUIRES(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [] nsf_ae_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [acquire] nsf_ae_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [acquire] nsf_ae_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [excludes] nsf_ae_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [mt_safe] nsf_ae_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [excludes] nsf_ae_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [mt_safe_postinit] nsf_ae_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [mt_start] nsf_ae_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [mt_unsafe] nsf_ae_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [mt_unsafe_one] nsf_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [release] nsf_ae_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [release] nsf_ae_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.h:75: [requires] nsf_ae_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:83: [pure] nsf_test_caller_func_hdr_VL_PURE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [] nsf_au_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [acquire] nsf_au_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [acquire] nsf_au_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [excludes] nsf_au_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [mt_safe] nsf_au_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [excludes] nsf_au_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [mt_safe_postinit] nsf_au_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [mt_start] nsf_au_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [mt_unsafe] nsf_au_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [mt_unsafe_one] nsf_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [release] nsf_au_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [release] nsf_au_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:62: [requires] nsf_au_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_PURE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [] nsf_aa_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [acquire] nsf_aa_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [acquire] nsf_aa_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [excludes] nsf_aa_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [mt_safe] nsf_aa_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [excludes] nsf_aa_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [mt_safe_postinit] nsf_aa_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [mt_start] nsf_aa_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [mt_unsafe] nsf_aa_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [mt_unsafe_one] nsf_aa_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [release] nsf_aa_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [release] nsf_aa_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:70: [requires] nsf_aa_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [] nsf_ae_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [acquire] nsf_ae_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [acquire] nsf_ae_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [excludes] nsf_ae_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [mt_safe] nsf_ae_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [excludes] nsf_ae_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [mt_safe_postinit] nsf_ae_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [mt_start] nsf_ae_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [mt_unsafe] nsf_ae_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [mt_unsafe_one] nsf_ae_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [release] nsf_ae_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [release] nsf_ae_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:75: [requires] nsf_ae_VL_REQUIRES(VerilatedMutex &) %Error: "nsf_ua_VL_ACQUIRE(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_ACQUIRE(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:25: [acquire] nsf_ua_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_ACQUIRE(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:25: [acquire] nsf_ua_VL_ACQUIRE(VerilatedMutex &) %Error: "nsf_ua_VL_ACQUIRE_SHARED(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:25: [acquire] nsf_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:25: [acquire] nsf_ua_VL_ACQUIRE_SHARED(VerilatedMutex &) %Error: "nsf_ua_VL_EXCLUDES(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_EXCLUDES(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:25: [excludes] nsf_ua_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_EXCLUDES(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:25: [excludes] nsf_ua_VL_EXCLUDES(VerilatedMutex &) %Error: "nsf_ua_VL_MT_SAFE(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_SAFE(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:25: [mt_safe] nsf_ua_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_SAFE(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:25: [mt_safe] nsf_ua_VL_MT_SAFE(VerilatedMutex &) %Error: "nsf_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:25: [excludes] nsf_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:25: [excludes] nsf_ua_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) %Error: "nsf_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:25: [mt_safe_postinit] nsf_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:25: [mt_safe_postinit] nsf_ua_VL_MT_SAFE_POSTINIT(VerilatedMutex &) %Error: "nsf_ua_VL_MT_START(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_START(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:25: [mt_start] nsf_ua_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_START(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:25: [mt_start] nsf_ua_VL_MT_START(VerilatedMutex &) %Error: "nsf_ua_VL_MT_UNSAFE(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_UNSAFE(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:25: [mt_unsafe] nsf_ua_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_UNSAFE(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:25: [mt_unsafe] nsf_ua_VL_MT_UNSAFE(VerilatedMutex &) %Error: "nsf_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:25: [mt_unsafe_one] nsf_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:25: [mt_unsafe_one] nsf_ua_VL_MT_UNSAFE_ONE(VerilatedMutex &) %Error: "nsf_ua_VL_PURE(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_PURE(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:25: [pure] nsf_ua_VL_PURE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_PURE(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:25: [pure] nsf_ua_VL_PURE(VerilatedMutex &) %Error: "nsf_ua_VL_RELEASE(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_RELEASE(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:25: [release] nsf_ua_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_RELEASE(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:25: [release] nsf_ua_VL_RELEASE(VerilatedMutex &) %Error: "nsf_ua_VL_RELEASE_SHARED(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_RELEASE_SHARED(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:25: [release] nsf_ua_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_RELEASE_SHARED(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:25: [release] nsf_ua_VL_RELEASE_SHARED(VerilatedMutex &) %Error: "nsf_ua_VL_REQUIRES(VerilatedMutex &)" declaration does not match definition -t/t_dist_attributes_bad.h:66: [] nsf_ua_VL_REQUIRES(VerilatedMutex &) [declaration] -t/t_dist_attributes_bad.cpp:25: [requires] nsf_ua_VL_REQUIRES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.h:66: [] nsf_ua_VL_REQUIRES(VerilatedMutex &) [declaration] +t/t_dist_attributes/mt_enabled.cpp:25: [requires] nsf_ua_VL_REQUIRES(VerilatedMutex &) %Error: "sfc_test_caller_func_VL_MT_SAFE(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) -t/t_dist_attributes_bad.cpp:63: [mt_safe] sfc_test_caller_func_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.cpp:60: [] sfc_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.cpp:60: [mt_start] sfc_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.cpp:60: [mt_unsafe] sfc_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.cpp:60: [mt_unsafe_one] sfc_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:63: [mt_safe] sfc_test_caller_func_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:60: [] sfc_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:60: [mt_start] sfc_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:60: [mt_unsafe] sfc_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:60: [mt_unsafe_one] sfc_VL_MT_UNSAFE_ONE(VerilatedMutex &) %Error: "sfc_test_caller_func_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe -t/t_dist_attributes_bad.cpp:63: [mt_start] sfc_test_caller_func_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.cpp:60: [] sfc_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.cpp:60: [mt_start] sfc_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.cpp:60: [mt_unsafe] sfc_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.cpp:60: [mt_unsafe_one] sfc_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:63: [mt_start] sfc_test_caller_func_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:60: [] sfc_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:60: [mt_start] sfc_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:60: [mt_unsafe] sfc_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:60: [mt_unsafe_one] sfc_VL_MT_UNSAFE_ONE(VerilatedMutex &) %Error: "sfc_test_caller_func_VL_PURE(VerilatedMutex &)" is pure but calls non-pure function(s) -t/t_dist_attributes_bad.cpp:63: [pure] sfc_test_caller_func_VL_PURE(VerilatedMutex &) -t/t_dist_attributes_bad.cpp:60: [] sfc_NO_ANNOTATION(VerilatedMutex &) -t/t_dist_attributes_bad.cpp:60: [acquire] sfc_VL_ACQUIRE(VerilatedMutex &) -t/t_dist_attributes_bad.cpp:60: [acquire] sfc_VL_ACQUIRE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.cpp:60: [excludes] sfc_VL_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.cpp:60: [mt_safe] sfc_VL_MT_SAFE(VerilatedMutex &) -t/t_dist_attributes_bad.cpp:60: [excludes] sfc_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) -t/t_dist_attributes_bad.cpp:60: [mt_safe_postinit] sfc_VL_MT_SAFE_POSTINIT(VerilatedMutex &) -t/t_dist_attributes_bad.cpp:60: [mt_start] sfc_VL_MT_START(VerilatedMutex &) -t/t_dist_attributes_bad.cpp:60: [mt_unsafe] sfc_VL_MT_UNSAFE(VerilatedMutex &) -t/t_dist_attributes_bad.cpp:60: [mt_unsafe_one] sfc_VL_MT_UNSAFE_ONE(VerilatedMutex &) -t/t_dist_attributes_bad.cpp:60: [release] sfc_VL_RELEASE(VerilatedMutex &) -t/t_dist_attributes_bad.cpp:60: [release] sfc_VL_RELEASE_SHARED(VerilatedMutex &) -t/t_dist_attributes_bad.cpp:60: [requires] sfc_VL_REQUIRES(VerilatedMutex &) -Number of functions reported unsafe: 226 +t/t_dist_attributes/mt_enabled.cpp:63: [pure] sfc_test_caller_func_VL_PURE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:60: [] sfc_NO_ANNOTATION(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:60: [acquire] sfc_VL_ACQUIRE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:60: [acquire] sfc_VL_ACQUIRE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:60: [excludes] sfc_VL_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:60: [mt_safe] sfc_VL_MT_SAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:60: [excludes] sfc_VL_MT_SAFE_EXCLUDES(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:60: [mt_safe_postinit] sfc_VL_MT_SAFE_POSTINIT(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:60: [mt_start] sfc_VL_MT_START(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:60: [mt_unsafe] sfc_VL_MT_UNSAFE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:60: [mt_unsafe_one] sfc_VL_MT_UNSAFE_ONE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:60: [release] sfc_VL_RELEASE(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:60: [release] sfc_VL_RELEASE_SHARED(VerilatedMutex &) +t/t_dist_attributes/mt_enabled.cpp:60: [requires] sfc_VL_REQUIRES(VerilatedMutex &) + +%Error: "unannotatedMtDisabledFunctionBad()" defined in a file marked as VL_MT_DISABLED_CODE_UNIT has declaration(s) without VL_MT_DISABLED annotation +t/t_dist_attributes/mt_disabled.cpp:20: [mt_disabled, requires] unannotatedMtDisabledFunctionBad() +t/t_dist_attributes/mt_disabled.h:22: [] unannotatedMtDisabledFunctionBad() +t/t_dist_attributes/mt_disabled.h:25: [] unannotatedMtDisabledFunctionBad() +Number of functions reported unsafe: 229 diff --git a/test_regress/t/t_dist_attributes_bad.pl b/test_regress/t/t_dist_attributes_bad.pl index 15a8060cf..d7c45df75 100755 --- a/test_regress/t/t_dist_attributes_bad.pl +++ b/test_regress/t/t_dist_attributes_bad.pl @@ -8,17 +8,65 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +use Cwd qw(abs_path); +use JSON::PP; +use IO::File; + scenarios(dist => 1); if ($ENV{VERILATOR_TEST_NO_ATTRIBUTES}) { skip("Skipping due to VERILATOR_TEST_NO_ATTRIBUTES"); } else { check(); } + +sub gen_compile_commands_json { + my $json = JSON::PP->new->utf8->pretty; + + my $root_dir = abs_path(".."); + my $srcs_dir = abs_path("./t/t_dist_attributes"); + my @common_args = ("clang++", + "-std=c++14", + "-I$root_dir/include", + "-I$root_dir/src", + "-c"); + + my $ccjson = [ + {"directory" => "$srcs_dir", + "file" => "$srcs_dir/mt_enabled.cpp", + "output" => undef, + "arguments" => [@common_args]}, + {"directory" => "$srcs_dir", + "file" => "$srcs_dir/mt_disabled.cpp", + "output" => undef, + "arguments" => [@common_args]}, + ]; + + my @srcfiles; + foreach my $entry (@$ccjson) { + # Add "output" key + ($entry->{"output"} = $entry->{"file"}) =~ s/\.cpp$/.o/; + # Add "-o src.o src.cpp" arguments + push @{$entry->{"arguments"}}, ("-o", $entry->{"output"}, $entry->{"file"}); + + push @srcfiles, $entry->{"file"}; + } + + return ( + \@srcfiles, + $json->encode($ccjson) + ); +} + sub check { - my $root = ".."; - my @srcfiles = glob("$root/test_regress/t/t_dist_attributes_bad.cpp"); - my $srcfiles_str = join(" ", @srcfiles); - my $clang_args = "-I$root/include"; + my $root = abs_path(".."); + my $ccjson_file = "$Self->{obj_dir}/compile_commands.json"; + my ($srcfiles, $ccjson) = gen_compile_commands_json(); + my $srcfiles_str = join(" ", @$srcfiles); + { + my $fh = IO::File->new(">$ccjson_file") or die "%Error: $! $ccjson_file"; + print $fh $ccjson; + $fh->close(); + } sub run_clang_check { { @@ -32,7 +80,11 @@ sub check { # With `--verilator-root` set to the current directory # (i.e. `test_regress`) the script will skip annotation issues in # headers from the `../include` directory. - cmd => ["python3", "$root/nodist/clang_check_attributes --verilator-root=. --cxxflags='$clang_args' $srcfiles_str"]); + cmd => ["python3", + "$root/nodist/clang_check_attributes", + "--verilator-root=.", + "--compile-commands-dir=$Self->{obj_dir}", + "$srcfiles_str"]); files_identical($Self->{run_log_filename}, $Self->{golden_filename}); } From 3dde57d539c5f6ffa0481843b663f128fcbe6621 Mon Sep 17 00:00:00 2001 From: Anthony Donlon <4056887+donlon@users.noreply.github.com> Date: Thu, 14 Sep 2023 19:22:49 +0800 Subject: [PATCH 090/111] Fix lint of case statements with enum and wildcard bits (#4464) (#4487) --- src/V3Ast.h | 2 +- src/V3Case.cpp | 123 ++++++++++++------ src/verilog.y | 2 +- test_regress/t/t_case_enum_complete.v | 9 +- .../t/t_case_enum_complete_wildcard.pl | 18 +++ .../t/t_case_enum_complete_wildcard.v | 74 +++++++++++ test_regress/t/t_case_enum_incomplete_bad.out | 2 +- .../t/t_case_enum_incomplete_wildcard_bad.out | 15 +++ .../t/t_case_enum_incomplete_wildcard_bad.pl | 20 +++ .../t/t_case_enum_incomplete_wildcard_bad.v | 46 +++++++ test_regress/t/t_case_inside_bad.out | 4 +- test_regress/t/t_case_overlap_bad.out | 33 +++++ test_regress/t/t_case_overlap_bad.pl | 19 +++ test_regress/t/t_case_overlap_bad.v | 44 +++++++ test_regress/t/t_param_scope_bad.out | 5 +- test_regress/t/t_priority_case.out | 10 +- 16 files changed, 376 insertions(+), 50 deletions(-) create mode 100755 test_regress/t/t_case_enum_complete_wildcard.pl create mode 100644 test_regress/t/t_case_enum_complete_wildcard.v create mode 100644 test_regress/t/t_case_enum_incomplete_wildcard_bad.out create mode 100755 test_regress/t/t_case_enum_incomplete_wildcard_bad.pl create mode 100644 test_regress/t/t_case_enum_incomplete_wildcard_bad.v create mode 100644 test_regress/t/t_case_overlap_bad.out create mode 100755 test_regress/t/t_case_overlap_bad.pl create mode 100644 test_regress/t/t_case_overlap_bad.v diff --git a/src/V3Ast.h b/src/V3Ast.h index 0e6508036..b925d7f26 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -1702,7 +1702,7 @@ public: const char* typeName() const VL_MT_SAFE { return type().ascii(); } // See also prettyTypeName AstNode* nextp() const VL_MT_STABLE { return m_nextp; } AstNode* backp() const VL_MT_STABLE { return m_backp; } - AstNode* abovep() const; // Parent node above, only when no nextp() as otherwise slow + AstNode* abovep() const; // Get parent node above, only for list head and tail AstNode* op1p() const VL_MT_STABLE { return m_op1p; } AstNode* op2p() const VL_MT_STABLE { return m_op2p; } AstNode* op3p() const VL_MT_STABLE { return m_op3p; } diff --git a/src/V3Case.cpp b/src/V3Case.cpp index c8cd473c2..8297c1b69 100644 --- a/src/V3Case.cpp +++ b/src/V3Case.cpp @@ -139,32 +139,42 @@ private: std::array m_valueItem; // METHODS - bool caseIsEnumComplete(AstCase* nodep, uint32_t numCases) { - // Return true if case is across an enum, and every value in the case - // statement corresponds to one of the enum values - if (!nodep->uniquePragma() && !nodep->unique0Pragma()) return false; - AstEnumDType* const enumDtp + //! Determine whether we should check case items are complete + //! @return Enum's dtype if should check, nullptr if shouldn't + const AstEnumDType* getEnumCompletionCheckDType(const AstCase* const nodep) { + if (!nodep->uniquePragma() && !nodep->unique0Pragma()) return nullptr; + const AstEnumDType* const enumDtp = VN_CAST(nodep->exprp()->dtypep()->skipRefToEnump(), EnumDType); - if (!enumDtp) return false; // Case isn't enum - AstBasicDType* const basicp = enumDtp->subDTypep()->basicp(); - if (!basicp) return false; // Not simple type (perhaps IEEE illegal) - if (basicp->width() > 32) return false; - // Find all case values into a set - std::set caseSet; - for (uint32_t i = 0; i < numCases; ++i) { // All case items - if (m_valueItem[i]) caseSet.emplace(i); - } - // Find all enum values into a set - std::set enumSet; - for (AstEnumItem* itemp = enumDtp->itemsp(); itemp; + if (!enumDtp) return nullptr; // Case isn't enum + const AstBasicDType* const basicp = enumDtp->subDTypep()->basicp(); + if (!basicp) return nullptr; // Not simple type (perhaps IEEE illegal) + if (basicp->width() > 32) return nullptr; + return enumDtp; + } + //! @return True if case items are complete, false if there are uncovered enums + bool checkCaseEnumComplete(const AstCase* const nodep, const AstEnumDType* const dtype) { + const uint32_t numCases = 1UL << m_caseWidth; + for (AstEnumItem* itemp = dtype->itemsp(); itemp; itemp = VN_AS(itemp->nextp(), EnumItem)) { AstConst* const econstp = VN_AS(itemp->valuep(), Const); - const uint32_t val = econstp->toUInt(); - // UINFO(9, "Complete enum item " << val << ": " << itemp << endl); - enumSet.emplace(val); + V3Number nummask{itemp, econstp->width()}; + nummask.opBitsNonX(econstp->num()); + const uint32_t mask = nummask.toUInt(); + V3Number numval{itemp, econstp->width()}; + numval.opBitsOne(econstp->num()); + const uint32_t val = numval.toUInt(); + + for (uint32_t i = 0; i < numCases; ++i) { + if ((i & mask) == val) { + if (!m_valueItem[i]) { + nodep->v3warn(CASEINCOMPLETE, "Enum item " << itemp->prettyNameQ() + << " not covered by case\n"); + return false; // enum has uncovered value by case items + } + } + } } - // If sets match, all covered - return (caseSet == enumSet); + return true; // enum is fully covered } bool isCaseTreeFast(AstCase* nodep) { int width = 0; @@ -193,6 +203,8 @@ private: // We can cheat and use uint32_t's because we only support narrow case's bool reportedOverlap = false; bool reportedSubcase = false; + bool hasDefaultCase = false; + std::map caseItemMap; // case condition -> case item for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp = VN_AS(itemp->nextp(), CaseItem)) { for (AstNode* icondp = itemp->condsp(); icondp; icondp = icondp->nextp()) { @@ -202,6 +214,7 @@ private: if (neverItem(nodep, iconstp)) { // X in casez can't ever be executed } else { + const bool isCondWildcard = iconstp->num().isAnyXZ(); V3Number nummask{itemp, iconstp->width()}; nummask.opBitsNonX(iconstp->num()); const uint32_t mask = nummask.toUInt(); @@ -210,16 +223,17 @@ private: const uint32_t val = numval.toUInt(); uint32_t firstOverlap = 0; - bool foundOverlap = false; + AstNode* overlappedCondp = nullptr; bool foundHit = false; for (uint32_t i = 0; i < numCases; ++i) { if ((i & mask) == val) { if (!m_valueItem[i]) { - m_valueItem[i] = itemp; + m_valueItem[i] = icondp; + caseItemMap[icondp] = itemp; foundHit = true; - } else if (!foundOverlap) { + } else if (!overlappedCondp) { firstOverlap = i; - foundOverlap = true; + overlappedCondp = m_valueItem[i]; m_caseNoOverlapsAllCovered = false; } } @@ -227,9 +241,19 @@ private: if (!nodep->priorityPragma()) { // If this case statement doesn't have the priority // keyword, we want to warn on any overlap. - if (!reportedOverlap && foundOverlap) { - icondp->v3warn(CASEOVERLAP, "Case values overlap (example pattern 0x" - << std::hex << firstOverlap << ")"); + if (!reportedOverlap && overlappedCondp) { + std::ostringstream examplePattern; + if (isCondWildcard) { + examplePattern << " (example pattern 0x" << std::hex + << firstOverlap << ")"; + } + icondp->v3warn(CASEOVERLAP, + "Case conditions overlap" + << examplePattern.str() << "\n" + << icondp->warnContextPrimary() << '\n' + << overlappedCondp->warnOther() + << "... Location of overlapping condition\n" + << overlappedCondp->warnContextSecondary()); reportedOverlap = true; } } else { @@ -240,7 +264,11 @@ private: if (!reportedSubcase && !foundHit) { icondp->v3warn(CASEOVERLAP, "Case item ignored: every matching value is covered " - "by an earlier item"); + "by an earlier condition\n" + << icondp->warnContextPrimary() << '\n' + << overlappedCondp->warnOther() + << "... Location of previous condition\n" + << overlappedCondp->warnContextPrimary()); reportedSubcase = true; } } @@ -251,17 +279,28 @@ private: for (uint32_t i = 0; i < numCases; ++i) { if (!m_valueItem[i]) m_valueItem[i] = itemp; } + caseItemMap[itemp] = itemp; + hasDefaultCase = true; } } - if (!caseIsEnumComplete(nodep, numCases)) { - for (uint32_t i = 0; i < numCases; ++i) { - if (!m_valueItem[i]) { - nodep->v3warn(CASEINCOMPLETE, "Case values incompletely covered " - "(example pattern 0x" - << std::hex << i << ")"); + if (!hasDefaultCase) { + const AstEnumDType* const dtype = getEnumCompletionCheckDType(nodep); + if (dtype) { + if (!checkCaseEnumComplete(nodep, dtype)) { + // checkCaseEnumComplete has already warned of incompletion m_caseNoOverlapsAllCovered = false; return false; } + } else { + for (uint32_t i = 0; i < numCases; ++i) { + if (!m_valueItem[i]) { // has uncovered case + nodep->v3warn(CASEINCOMPLETE, "Case values incompletely covered " + "(example pattern 0x" + << std::hex << i << ")"); + m_caseNoOverlapsAllCovered = false; + return false; + } + } } } @@ -274,8 +313,10 @@ private: // Convert valueItem from AstCaseItem* to the expression // Not done earlier, as we may now have a nullptr because it's just a ";" NOP branch for (uint32_t i = 0; i < numCases; ++i) { - if (AstCaseItem* const itemp = VN_AS(m_valueItem[i], CaseItem)) { - m_valueItem[i] = itemp->stmtsp(); + if (AstNode* const condp = m_valueItem[i]) { + AstCaseItem* caseItemp = caseItemMap[condp]; + UASSERT(caseItemp, "caseItemp should exist"); + m_valueItem[i] = caseItemp->stmtsp(); } } return true; // All is fine @@ -543,10 +584,12 @@ private: } } //-------------------- - void visit(AstNode* nodep) override { - if (VN_IS(nodep, Always)) m_alwaysp = nodep; + void visit(AstAlways* nodep) override { + VL_RESTORER(m_alwaysp) + m_alwaysp = nodep; iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS diff --git a/src/verilog.y b/src/verilog.y index 16dc3c644..34410ffdc 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -3527,7 +3527,7 @@ statement_item: // IEEE: statement_item { $$ = nullptr; BBUNSUP($4, "Unsupported: matches (for tagged union)"); } | unique_priorityE caseStart caseAttrE yINSIDE case_insideListE yENDCASE { $$ = $2; if ($5) $2->addItemsp($5); - if (!$2->caseSimple()) $2->v3error("Illegal to have inside on a casex/casez"); + if (!$2->caseSimple()) $4->v3error("Illegal to have inside on a casex/casez"); $2->caseInsideSet(); if ($1 == uniq_UNIQUE) $2->uniquePragma(true); if ($1 == uniq_UNIQUE0) $2->unique0Pragma(true); diff --git a/test_regress/t/t_case_enum_complete.v b/test_regress/t/t_case_enum_complete.v index 7ee354cfd..cd0d02f92 100644 --- a/test_regress/t/t_case_enum_complete.v +++ b/test_regress/t/t_case_enum_complete.v @@ -8,13 +8,18 @@ module t; enum logic [2:0] {S0, S1, S2} state; + int v = 0; + initial begin state = S1; unique case (state) - S0: $stop; - S1: $finish; + S0, S2: $stop; + S1: v++; + endcase + unique case (state) S2: $stop; + default: v++; endcase end endmodule diff --git a/test_regress/t/t_case_enum_complete_wildcard.pl b/test_regress/t/t_case_enum_complete_wildcard.pl new file mode 100755 index 000000000..59837c4db --- /dev/null +++ b/test_regress/t/t_case_enum_complete_wildcard.pl @@ -0,0 +1,18 @@ +#!/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(linter => 1); + +lint( + verilator_flags2 => ["--lint-only -Wwarn-CASEINCOMPLETE"], + ); + +ok(1); +1; diff --git a/test_regress/t/t_case_enum_complete_wildcard.v b/test_regress/t/t_case_enum_complete_wildcard.v new file mode 100644 index 000000000..0beb75014 --- /dev/null +++ b/test_regress/t/t_case_enum_complete_wildcard.v @@ -0,0 +1,74 @@ +// DESCRIPTION: Verilator: SystemVerilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Anthony Donlon. +// SPDX-License-Identifier: CC0-1.0 + +// Fix bug4464 + +module t; + + enum logic [1:0] { + S00 = 'b00, + S01 = 'b01, + S10 = 'b10, + + S0X = 2'b0?, + SX0 = 2'b?0 + } state; + + int v = 0; + + initial begin + state = S01; + unique case (state) + S00: $stop; + S01: v++; + S10: $stop; + endcase + unique case (state) + S00: $stop; + default: v++; // default + endcase + unique case (state) + 2'd0: $stop; + 2'd1: v++; + 2'd2: $stop; + endcase + unique case (state) + 2'd0: $stop; + 2'd1: v++; + 2'd2: $stop; + 2'd3: $stop; // extra case + endcase + + unique case (state) inside + 2'd0: $stop; + 2'd1: v++; + [2'd2:2'd3]: $stop; + endcase + unique case (state) inside + [S00:S10]: v++; + endcase + + unique casez (state) + S10: $stop; + S0X: v++; // fully covered + endcase + unique casez (state) + S10: $stop; + S0X: v++; + 2'b11: $stop; // extra case + endcase + unique casez (state) + S0X: v++; + default: $stop; + endcase + + case (state) + S00: $stop; + S01: v++; + S10, 2'b11: $stop; + endcase + end +endmodule diff --git a/test_regress/t/t_case_enum_incomplete_bad.out b/test_regress/t/t_case_enum_incomplete_bad.out index 4a88a83dc..f7713d73b 100644 --- a/test_regress/t/t_case_enum_incomplete_bad.out +++ b/test_regress/t/t_case_enum_incomplete_bad.out @@ -1,4 +1,4 @@ -%Warning-CASEINCOMPLETE: t/t_case_enum_incomplete_bad.v:14:14: Case values incompletely covered (example pattern 0x1) +%Warning-CASEINCOMPLETE: t/t_case_enum_incomplete_bad.v:14:14: Enum item 'S1' not covered by case 14 | unique case (state) | ^~~~ ... For warning description see https://verilator.org/warn/CASEINCOMPLETE?v=latest diff --git a/test_regress/t/t_case_enum_incomplete_wildcard_bad.out b/test_regress/t/t_case_enum_incomplete_wildcard_bad.out new file mode 100644 index 000000000..18337e745 --- /dev/null +++ b/test_regress/t/t_case_enum_incomplete_wildcard_bad.out @@ -0,0 +1,15 @@ +%Warning-CASEINCOMPLETE: t/t_case_enum_incomplete_wildcard_bad.v:26:16: Enum item 'S10' not covered by case + 26 | unique case (state) + | ^~~~ + ... For warning description see https://verilator.org/warn/CASEINCOMPLETE?v=latest + ... Use "/* verilator lint_off CASEINCOMPLETE */" and lint_on around source to disable this message. +%Warning-CASEINCOMPLETE: t/t_case_enum_incomplete_wildcard_bad.v:30:16: Enum item 'S00' not covered by case + 30 | unique case (state) + | ^~~~ +%Warning-CASEINCOMPLETE: t/t_case_enum_incomplete_wildcard_bad.v:35:16: Enum item 'S10' not covered by case + 35 | unique casez (state) + | ^~~~~ +%Warning-CASEINCOMPLETE: t/t_case_enum_incomplete_wildcard_bad.v:40:9: Case values incompletely covered (example pattern 0x3) + 40 | case (state) + | ^~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_case_enum_incomplete_wildcard_bad.pl b/test_regress/t/t_case_enum_incomplete_wildcard_bad.pl new file mode 100755 index 000000000..1d5773686 --- /dev/null +++ b/test_regress/t/t_case_enum_incomplete_wildcard_bad.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 2022 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_case_enum_incomplete_wildcard_bad.v b/test_regress/t/t_case_enum_incomplete_wildcard_bad.v new file mode 100644 index 000000000..e0e6965ba --- /dev/null +++ b/test_regress/t/t_case_enum_incomplete_wildcard_bad.v @@ -0,0 +1,46 @@ +// DESCRIPTION: Verilator: SystemVerilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Anthony Donlon. +// SPDX-License-Identifier: CC0-1.0 + +module t; + t1 i_t1(); +endmodule + +module t1; + + enum logic [1:0] { + S00 = 'b00, + S01 = 'b01, + S10 = 'b10, + + SX0 = 2'b?0, + S0X = 'b0? + } state; + + int v = 0; + + initial begin + state = S10; + unique case (state) + S00: $stop; + 2'b01: $stop; + endcase + unique case (state) + 2'd2: v++; + 2'd1: $stop; + endcase + + unique casez (state) + S0X: $stop; + 2'b11: $stop; + endcase + + case (state) + S00: $stop; + S01: $stop; + S10: v++; + endcase + end +endmodule diff --git a/test_regress/t/t_case_inside_bad.out b/test_regress/t/t_case_inside_bad.out index b683c04e3..2be995ce2 100644 --- a/test_regress/t/t_case_inside_bad.out +++ b/test_regress/t/t_case_inside_bad.out @@ -1,4 +1,4 @@ -%Error: t/t_case_inside_bad.v:9:7: Illegal to have inside on a casex/casez +%Error: t/t_case_inside_bad.v:9:20: Illegal to have inside on a casex/casez 9 | casex (1'bx) inside - | ^~~~~ + | ^~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_case_overlap_bad.out b/test_regress/t/t_case_overlap_bad.out new file mode 100644 index 000000000..3362705db --- /dev/null +++ b/test_regress/t/t_case_overlap_bad.out @@ -0,0 +1,33 @@ +%Warning-CASEOVERLAP: t/t_case_overlap_bad.v:20:21: Case conditions overlap (example pattern 0x6) + 20 | 3'b11?, 3'b???: v++; + | ^~~~~~ + t/t_case_overlap_bad.v:20:13: ... Location of overlapping condition + 20 | 3'b11?, 3'b???: v++; + | ^~~~~~ + ... For warning description see https://verilator.org/warn/CASEOVERLAP?v=latest + ... Use "/* verilator lint_off CASEOVERLAP */" and lint_on around source to disable this message. +%Warning-CASEOVERLAP: t/t_case_overlap_bad.v:25:13: Case conditions overlap + 25 | 3'b001, 3'b000: $stop; + | ^~~~~~ + t/t_case_overlap_bad.v:24:13: ... Location of overlapping condition + 24 | 3'b00?: $stop; + | ^~~~~~ +%Warning-CASEOVERLAP: t/t_case_overlap_bad.v:30:13: Case conditions overlap (example pattern 0x7) + 30 | 3'b11?: $stop; + | ^~~~~~ + t/t_case_overlap_bad.v:29:13: ... Location of overlapping condition + 29 | 3'b111, 3'b0??: v++; + | ^~~~~~ +%Warning-CASEOVERLAP: t/t_case_overlap_bad.v:35:13: Case conditions overlap + 35 | 3'b001: $stop; + | ^~~~~~ + t/t_case_overlap_bad.v:34:21: ... Location of overlapping condition + 34 | 3'b000, 3'b001, 3'b010, 3'b011: v++; + | ^~~~~~ +%Warning-CASEOVERLAP: t/t_case_overlap_bad.v:40:13: Case conditions overlap + 40 | 3'b011: $stop; + | ^~~~~~ + t/t_case_overlap_bad.v:39:37: ... Location of overlapping condition + 39 | 3'b000, 3'b001, 3'b010, 3'b011: v++; + | ^~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_case_overlap_bad.pl b/test_regress/t/t_case_overlap_bad.pl new file mode 100755 index 000000000..a60503a1f --- /dev/null +++ b/test_regress/t/t_case_overlap_bad.pl @@ -0,0 +1,19 @@ +#!/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(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_case_overlap_bad.v b/test_regress/t/t_case_overlap_bad.v new file mode 100644 index 000000000..39cf8d4c6 --- /dev/null +++ b/test_regress/t/t_case_overlap_bad.v @@ -0,0 +1,44 @@ +// DESCRIPTION: Verilator: SystemVerilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Anthony Donlon. +// SPDX-License-Identifier: CC0-1.0 + +module t; + t1 i_t1(); +endmodule + +module t1; + + int v = 0; + + logic [2:0] state; + + initial begin + state = 2; + casez (state) + 3'b11?, 3'b???: v++; + default; + endcase + casez (state) + 3'b00?: $stop; + 3'b001, 3'b000: $stop; + default; + endcase + casez (state) + 3'b111, 3'b0??: v++; + 3'b11?: $stop; + default; + endcase + casez (state) + 3'b000, 3'b001, 3'b010, 3'b011: v++; + 3'b001: $stop; + default; + endcase + casez (state) + 3'b000, 3'b001, 3'b010, 3'b011: v++; + 3'b011: $stop; + default; + endcase + end +endmodule diff --git a/test_regress/t/t_param_scope_bad.out b/test_regress/t/t_param_scope_bad.out index eddd36bd1..babd1fe25 100644 --- a/test_regress/t/t_param_scope_bad.out +++ b/test_regress/t/t_param_scope_bad.out @@ -1,6 +1,9 @@ -%Warning-CASEOVERLAP: t/t_param_scope_bad.v:28:9: Case values overlap (example pattern 0x2) +%Warning-CASEOVERLAP: t/t_param_scope_bad.v:28:9: Case conditions overlap 28 | 2'h2: $stop; | ^~~~ + t/t_param_scope_bad.v:27:9: ... Location of overlapping condition + 27 | CASEVAL: ; + | ^~~~~~~ ... For warning description see https://verilator.org/warn/CASEOVERLAP?v=latest ... Use "/* verilator lint_off CASEOVERLAP */" and lint_on around source to disable this message. %Error: Exiting due to diff --git a/test_regress/t/t_priority_case.out b/test_regress/t/t_priority_case.out index 468773b6c..6a725e733 100644 --- a/test_regress/t/t_priority_case.out +++ b/test_regress/t/t_priority_case.out @@ -1,9 +1,15 @@ -%Warning-CASEOVERLAP: t/t_priority_case.v:34:7: Case item ignored: every matching value is covered by an earlier item +%Warning-CASEOVERLAP: t/t_priority_case.v:34:7: Case item ignored: every matching value is covered by an earlier condition 34 | 2'b ?1: out1 = 3'd1; + | ^~~~~~ + t/t_priority_case.v:33:7: ... Location of previous condition + 33 | 2'b ?1: out1 = 3'd0; | ^~~~~~ ... For warning description see https://verilator.org/warn/CASEOVERLAP?v=latest ... Use "/* verilator lint_off CASEOVERLAP */" and lint_on around source to disable this message. -%Warning-CASEOVERLAP: t/t_priority_case.v:44:7: Case item ignored: every matching value is covered by an earlier item +%Warning-CASEOVERLAP: t/t_priority_case.v:44:7: Case item ignored: every matching value is covered by an earlier condition 44 | 2'b ?1: out1 = 3'd1; + | ^~~~~~ + t/t_priority_case.v:43:7: ... Location of previous condition + 43 | 2'b ?1: out1 = 3'd0; | ^~~~~~ %Error: Exiting due to From 0d67caff775f1ea68fa2667811720030a453c212 Mon Sep 17 00:00:00 2001 From: Kamil Rakoczy Date: Thu, 14 Sep 2023 13:24:49 +0200 Subject: [PATCH 091/111] Internals: V3Task: refactor common code to connectPort. No functional change intended (#4488) Signed-off-by: Kamil Rakoczy --- src/V3Task.cpp | 207 +++++++++++++++++++++---------------------------- 1 file changed, 90 insertions(+), 117 deletions(-) diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 0a1880e67..53137c807 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -412,6 +412,84 @@ private: }); } + void connectPort(AstVar* portp, AstArg* argp, const string& namePrefix, AstNode* beginp, + bool inlineTask) { + AstNodeExpr* const pinp = argp->exprp(); + if (inlineTask) { + portp->unlinkFrBack(); + pushDeletep(portp); // Remove it from the clone (not original) + } + if (!pinp) { + // Too few arguments in function call + } else { + UINFO(9, " Port " << portp << endl); + UINFO(9, " pin " << pinp << endl); + if (inlineTask) { + pinp->unlinkFrBack(); // Relinked to assignment below + VL_DO_DANGLING(argp->unlinkFrBack()->deleteTree(), argp); // Args no longer needed + } + if (portp->isWritable() && VN_IS(pinp, Const)) { + pinp->v3error("Function/task " + portp->direction().prettyName() // e.g. "output" + + " connected to constant instead of variable: " + + portp->prettyNameQ()); + } else if (portp->isInoutish()) { + // Correct lvalue; see comments below + V3LinkLValue::linkLValueSet(pinp); + + if (AstVarRef* const varrefp = VN_CAST(pinp, VarRef)) { + // Connect to this exact variable + if (inlineTask) { + AstVarScope* const localVscp = varrefp->varScopep(); + UASSERT_OBJ(localVscp, varrefp, "Null var scope"); + portp->user2p(localVscp); + pushDeletep(pinp); + } + } else { + pinp->v3warn( + E_TASKNSVAR, + "Unsupported: Function/task input argument is not simple variable"); + } + } else if (portp->isWritable()) { + // Make output variables + // Correct lvalue; we didn't know when we linked + // This is slightly scary; are we sure no decisions were made + // before here based on this not being a lvalue? + // Doesn't seem so; V3Unknown uses it earlier, but works ok. + V3LinkLValue::linkLValueSet(pinp); + // Even if it's referencing a varref, we still make a temporary + // Else task(x,x,x) might produce incorrect results + AstVarScope* const newvscp + = createVarScope(portp, namePrefix + "__" + portp->shortName()); + portp->user2p(newvscp); + if (!inlineTask) + pinp->replaceWith(new AstVarRef{newvscp->fileline(), newvscp, VAccess::WRITE}); + AstAssign* const assp + = new AstAssign{pinp->fileline(), pinp, + new AstVarRef{newvscp->fileline(), newvscp, VAccess::READ}}; + assp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, + true); // Ok if in <= block + // Put assignment BEHIND of all other statements + beginp->addNext(assp); + } else if (inlineTask && portp->isNonOutput()) { + // Make input variable + AstVarScope* const inVscp + = createVarScope(portp, namePrefix + "__" + portp->shortName()); + portp->user2p(inVscp); + AstAssign* const assp = new AstAssign{ + pinp->fileline(), new AstVarRef{inVscp->fileline(), inVscp, VAccess::WRITE}, + pinp}; + assp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, + true); // Ok if in <= block + // Put assignment in FRONT of all other statements + if (AstNode* const afterp = beginp->nextp()) { + afterp->unlinkFrBackWithNext(); + AstNode::addNext(assp, afterp); + } + beginp->addNext(assp); + } + } + } + AstNode* createInlinedFTask(AstNodeFTaskRef* refp, const string& namePrefix, AstVarScope* outvscp) { // outvscp is the variable for functions only, if nullptr, it's a task @@ -425,77 +503,12 @@ private: // // Create input variables AstNode::user2ClearTree(); - const V3TaskConnects tconnects = V3Task::taskConnects(refp, beginp); - for (const auto& itr : tconnects) { - AstVar* const portp = itr.first; - AstArg* const argp = itr.second; - AstNodeExpr* const pinp = argp->exprp(); - portp->unlinkFrBack(); - pushDeletep(portp); // Remove it from the clone (not original) - if (!pinp) { - // Too few arguments in function call - } else { - UINFO(9, " Port " << portp << endl); - UINFO(9, " pin " << pinp << endl); - pinp->unlinkFrBack(); // Relinked to assignment below - VL_DO_DANGLING(argp->unlinkFrBack()->deleteTree(), argp); // Args no longer needed - // - if (portp->isWritable() && VN_IS(pinp, Const)) { - pinp->v3error( - "Function/task " + portp->direction().prettyName() // e.g. "output" - + " connected to constant instead of variable: " + portp->prettyNameQ()); - } else if (portp->isInoutish()) { - // Correct lvalue; see comments below - V3LinkLValue::linkLValueSet(pinp); - - if (AstVarRef* const varrefp = VN_CAST(pinp, VarRef)) { - // Connect to this exact variable - AstVarScope* const localVscp = varrefp->varScopep(); - UASSERT_OBJ(localVscp, varrefp, "Null var scope"); - portp->user2p(localVscp); - pushDeletep(pinp); - } else { - pinp->v3warn( - E_TASKNSVAR, - "Unsupported: Function/task input argument is not simple variable"); - } - } else if (portp->isWritable()) { - // Make output variables - // Correct lvalue; we didn't know when we linked - // This is slightly scary; are we sure no decisions were made - // before here based on this not being a lvalue? - // Doesn't seem so; V3Unknown uses it earlier, but works ok. - V3LinkLValue::linkLValueSet(pinp); - - // Even if it's referencing a varref, we still make a temporary - // Else task(x,x,x) might produce incorrect results - AstVarScope* const tempvscp - = createVarScope(portp, namePrefix + "__" + portp->shortName()); - portp->user2p(tempvscp); - AstAssign* const assp = new AstAssign{ - pinp->fileline(), pinp, - new AstVarRef{tempvscp->fileline(), tempvscp, VAccess::READ}}; - assp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, - true); // Ok if in <= block - // Put assignment BEHIND of all other statements - beginp->addNext(assp); - } else if (portp->isNonOutput()) { - // Make input variable - AstVarScope* const inVscp - = createVarScope(portp, namePrefix + "__" + portp->shortName()); - portp->user2p(inVscp); - AstAssign* const assp = new AstAssign{ - pinp->fileline(), - new AstVarRef{inVscp->fileline(), inVscp, VAccess::WRITE}, pinp}; - assp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, - true); // Ok if in <= block - // Put assignment in FRONT of all other statements - if (AstNode* const afterp = beginp->nextp()) { - afterp->unlinkFrBackWithNext(); - AstNode::addNext(assp, afterp); - } - beginp->addNext(assp); - } + { + const V3TaskConnects tconnects = V3Task::taskConnects(refp, beginp); + for (const auto& itr : tconnects) { + AstVar* const portp = itr.first; + AstArg* const argp = itr.second; + connectPort(portp, argp, namePrefix, beginp, true); } } UASSERT_OBJ(!refp->pinsp(), refp, "Pin wasn't removed by above loop"); @@ -555,52 +568,12 @@ private: } // Convert complicated outputs to temp signals - const V3TaskConnects tconnects = V3Task::taskConnects(refp, refp->taskp()->stmtsp()); - for (const auto& itr : tconnects) { - AstVar* const portp = itr.first; - AstNodeExpr* const pinp = itr.second->exprp(); - if (!pinp) { - // Too few arguments in function call - } else { - UINFO(9, " Port " << portp << endl); - UINFO(9, " pin " << pinp << endl); - if (portp->isWritable() && VN_IS(pinp, Const)) { - pinp->v3error( - "Function/task " + portp->direction().prettyName() // e.g. "output" - + " connected to constant instead of variable: " + portp->prettyNameQ()); - } else if (portp->isInoutish()) { - // Correct lvalue; see comments below - V3LinkLValue::linkLValueSet(pinp); - - if (VN_IS(pinp, VarRef)) { - // Connect to this exact variable - } else { - pinp->v3warn( - E_TASKNSVAR, - "Unsupported: Function/task input argument is not simple variable"); - } - } else if (portp->isWritable()) { - // Make output variables - // Correct lvalue; we didn't know when we linked - // This is slightly scary; are we sure no decisions were made - // before here based on this not being a lvalue? - // Seems correct assumption; V3Unknown uses it earlier, but works ok. - V3LinkLValue::linkLValueSet(pinp); - - // Even if it's referencing a varref, we still make a temporary - // Else task(x,x,x) might produce incorrect results - AstVarScope* const newvscp - = createVarScope(portp, namePrefix + "__" + portp->shortName()); - portp->user2p(newvscp); - pinp->replaceWith(new AstVarRef{newvscp->fileline(), newvscp, VAccess::WRITE}); - AstAssign* const assp = new AstAssign{ - pinp->fileline(), pinp, - new AstVarRef{newvscp->fileline(), newvscp, VAccess::READ}}; - assp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, - true); // Ok if in <= block - // Put assignment BEHIND of all other statements - beginp->addNext(assp); - } + { + const V3TaskConnects tconnects = V3Task::taskConnects(refp, refp->taskp()->stmtsp()); + for (const auto& itr : tconnects) { + AstVar* const portp = itr.first; + AstArg* const argp = itr.second; + connectPort(portp, argp, namePrefix, beginp, false); } } // First argument is symbol table, then output if a function From 2c84b37bf763892ab0f7fd452f22fc97b9a323cb Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 14 Sep 2023 20:06:20 -0400 Subject: [PATCH 092/111] Internals: Rename some V3LinkDot variables. No functional change. --- src/V3LinkDot.cpp | 46 ++++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 81a522577..64a7aab4a 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2246,9 +2246,9 @@ private: } } void importSymbolsFromExtended(AstClass* const nodep, AstClassExtends* const cextp) { - AstClass* const classp = cextp->classp(); - VSymEnt* const srcp = m_statep->getNodeSym(classp); - if (classp->isInterfaceClass()) importImplementsClass(nodep, srcp, classp); + AstClass* const baseClassp = cextp->classp(); + VSymEnt* const srcp = m_statep->getNodeSym(baseClassp); + if (baseClassp->isInterfaceClass()) importImplementsClass(nodep, srcp, baseClassp); if (!cextp->isImplements()) m_curSymp->importFromClass(m_statep->symsp(), srcp); } bool checkPinRef(AstPin* pinp, VVarType refVarType) { @@ -2445,9 +2445,9 @@ private: } else { const auto cextp = classp->extendsp(); UASSERT_OBJ(cextp, nodep, "Bad super extends link"); - const auto sclassp = cextp->classp(); - UASSERT_OBJ(sclassp, nodep, "Bad superclass"); - m_ds.m_dotSymp = m_statep->getNodeSym(sclassp); + const auto baseClassp = cextp->classp(); + UASSERT_OBJ(baseClassp, nodep, "Bad superclass"); + m_ds.m_dotSymp = m_statep->getNodeSym(baseClassp); UINFO(8, " super. " << m_ds.ascii() << endl); } } @@ -2896,15 +2896,16 @@ private: "class reference parameter not removed by V3Param"); VL_RESTORER(m_ds); VL_RESTORER(m_pinSymp); - { - // ClassRef's have pins, so track - if (nodep->classOrPackagep()) { - m_pinSymp = m_statep->getNodeSym(nodep->classOrPackagep()); - } - m_ds.init(m_curSymp); - UINFO(4, "(Backto) Link ClassOrPackageRef: " << nodep << endl); - iterateChildren(nodep); + + // ClassRef's have pins, so track + if (nodep->classOrPackagep()) { + m_pinSymp = m_statep->getNodeSym(nodep->classOrPackagep()); } + m_ds.init(m_curSymp); + UINFO(4, "(Backto) Link ClassOrPackageRef: " << nodep << endl); + + iterateChildren(nodep); + AstClass* const refClassp = VN_CAST(nodep->classOrPackagep(), Class); AstClass* const modClassp = VN_CAST(m_modp, Class); if (m_statep->forPrimary() && refClassp && !nodep->paramsp() @@ -3506,26 +3507,26 @@ private: } } - if (AstClass* const classp = cextp->classOrNullp()) { + if (AstClass* const baseClassp = cextp->classOrNullp()) { // Already converted. Update symbol table to link unlinked members. // Base class has to be visited in a case if its extends statement // needs to be handled. Recursive inheritance was already checked. - if (classp == nodep) { + if (baseClassp == nodep) { cextp->v3error("Attempting to extend class " << nodep->prettyNameQ() << " from itself"); - } else if (cextp->isImplements() && !classp->isInterfaceClass()) { + } else if (cextp->isImplements() && !baseClassp->isInterfaceClass()) { cextp->v3error("Attempting to implement from non-interface class " - << classp->prettyNameQ() << '\n' + << baseClassp->prettyNameQ() << '\n' << "... Suggest use 'extends'"); } else if (!cextp->isImplements() && !nodep->isInterfaceClass() - && classp->isInterfaceClass()) { + && baseClassp->isInterfaceClass()) { cextp->v3error("Attempting to extend from interface class " - << classp->prettyNameQ() << '\n' + << baseClassp->prettyNameQ() << '\n' << "... Suggest use 'implements'"); } - classp->isExtended(true); + baseClassp->isExtended(true); nodep->isExtended(true); - iterate(classp); + iterate(baseClassp); importSymbolsFromExtended(nodep, cextp); continue; } @@ -3742,6 +3743,7 @@ void V3LinkDot::linkDotGuts(AstNetlist* rootp, VLinkDotStep step) { state.computeScopeAliases(); state.dumpSelf(); { LinkDotResolveVisitor{rootp, &state}; } + state.dumpSelf(); } void V3LinkDot::linkDotPrimary(AstNetlist* nodep) { From 6e589377f4ffb4080d40f437fb74e18dc7318564 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 14 Sep 2023 20:07:49 -0400 Subject: [PATCH 093/111] Fix reference to extended class in parameterized class (#4466). --- Changes | 1 + src/V3LinkDot.cpp | 17 ++++++- test_regress/t/t_class_param_extends3.pl | 21 ++++++++ test_regress/t/t_class_param_extends3.v | 63 ++++++++++++++++++++++++ 4 files changed, 100 insertions(+), 2 deletions(-) create mode 100755 test_regress/t/t_class_param_extends3.pl create mode 100644 test_regress/t/t_class_param_extends3.v diff --git a/Changes b/Changes index fea08cd9e..843177436 100644 --- a/Changes +++ b/Changes @@ -32,6 +32,7 @@ Verilator 5.015 devel * Fix internal error on real conversion (#4447). [vdhotre-ventana] * Fix lifetime unknown error on enum.name (#4448). [jwoutersymatra] * Fix error on enum with VARHIDDEN of cell (#4482). [Michail Rontionov] +* Fix reference to extended class in parameterized class (#4466). * Fix display %x formatting of real. * Fix mis-warning on #() in classes' own functions. diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 64a7aab4a..ceb1f2284 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2251,6 +2251,15 @@ private: if (baseClassp->isInterfaceClass()) importImplementsClass(nodep, srcp, baseClassp); if (!cextp->isImplements()) m_curSymp->importFromClass(m_statep->symsp(), srcp); } + void classExtendImport(AstClass* nodep) { + // A class reference might be to a class that is later in Ast due to + // e.g. parmaeterization or referring to a "class (type T) extends T" + // Resolve it so later Class:: references into its base classes work + VL_RESTORER(m_ds); + VSymEnt* const srcp = m_statep->getNodeSym(nodep); + m_ds.init(srcp); + iterate(nodep); + } bool checkPinRef(AstPin* pinp, VVarType refVarType) { // In instantiations of modules/ifaces, we shouldn't connect port pins to submodule's // parameters or vice versa @@ -2901,12 +2910,14 @@ private: if (nodep->classOrPackagep()) { m_pinSymp = m_statep->getNodeSym(nodep->classOrPackagep()); } + AstClass* const refClassp = VN_CAST(nodep->classOrPackagep(), Class); + // Make sure any extends() are properly imported within referenced class + if (refClassp && !m_statep->forPrimary()) classExtendImport(refClassp); + m_ds.init(m_curSymp); UINFO(4, "(Backto) Link ClassOrPackageRef: " << nodep << endl); - iterateChildren(nodep); - AstClass* const refClassp = VN_CAST(nodep->classOrPackagep(), Class); AstClass* const modClassp = VN_CAST(m_modp, Class); if (m_statep->forPrimary() && refClassp && !nodep->paramsp() && nodep->classOrPackagep()->hasGParam() @@ -3511,6 +3522,8 @@ private: // Already converted. Update symbol table to link unlinked members. // Base class has to be visited in a case if its extends statement // needs to be handled. Recursive inheritance was already checked. + // Must be here instead of in LinkDotParam to handle + // "class (type T) extends T". if (baseClassp == nodep) { cextp->v3error("Attempting to extend class " << nodep->prettyNameQ() << " from itself"); diff --git a/test_regress/t/t_class_param_extends3.pl b/test_regress/t/t_class_param_extends3.pl new file mode 100755 index 000000000..859050d63 --- /dev/null +++ b/test_regress/t/t_class_param_extends3.pl @@ -0,0 +1,21 @@ +#!/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(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_param_extends3.v b/test_regress/t/t_class_param_extends3.v new file mode 100644 index 000000000..3447076ec --- /dev/null +++ b/test_regress/t/t_class_param_extends3.v @@ -0,0 +1,63 @@ +// 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 + +package u_pkg; + typedef class u_report_object; + typedef class u_callback; + + virtual class u_object; + endclass + + class u_queue #(type T=int) extends u_object; + int m_value = 6; + endclass + + class u_callbacks_base extends u_object; + typedef u_callbacks_base this_type; + endclass + + class u_typed_callbacks#(type T=u_object) extends u_callbacks_base; + typedef u_typed_callbacks#(T) this_type; + static this_type m_t_inst; + static u_queue#(u_callback) m_tw_cb_q; + endclass + + class u_callbacks #(type T=u_object, type CB=u_callback) + extends u_typed_callbacks#(T); + static function bit m_register_pair(); + endfunction + static function void add(u_callback cb); + u_queue#(u_callback) qr; + qr = u_callbacks#(u_report_object,u_callback)::m_t_inst.m_tw_cb_q; //<<<< + if (qr.m_value != 6) $stop; + endfunction + endclass + + class u_callback extends u_object; + endclass + + virtual class u_report_catcher extends u_callback; + static local bit m_register_cb_u_report_catcher = u_callbacks#(u_report_object,u_report_catcher)::m_register_pair(); + endclass + + // Having this class (versus using #(u_object) is needed to hit the bug + class u_report_object extends u_object; + endclass + +endpackage + +module t; + + u_pkg::u_callback cb; + + initial begin + cb = new; + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule From 131eb319e0759d29d73cfd0765a0986ceac9f7da Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 14 Sep 2023 20:09:43 -0400 Subject: [PATCH 094/111] Tests: Advance UVM through V3LinkDot Param (#1538 partial) --- src/Verilator.cpp | 12 ++++++------ test_regress/t/t_uvm_all.pl | 4 +++- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 57b8a90c0..1e98874b8 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -153,12 +153,6 @@ static void process() { // Remove parameters by cloning modules to de-parameterized versions // This requires some width calculations and constant propagation V3Param::param(v3Global.rootp()); - if (v3Global.opt.debugExitUvm()) { - V3Error::abortIfErrors(); - if (v3Global.opt.xmlOnly()) V3EmitXml::emitxml(); - cout << "--debug-exit-uvm: Exiting after UVM-supported pass\n"; - std::exit(0); - } V3LinkDot::linkDotParamed(v3Global.rootp()); // Cleanup as made new modules V3LinkLValue::linkLValue(v3Global.rootp()); // Resolve new VarRefs V3Error::abortIfErrors(); @@ -177,6 +171,12 @@ static void process() { return; } } + if (v3Global.opt.debugExitUvm()) { + V3Error::abortIfErrors(); + if (v3Global.opt.xmlOnly()) V3EmitXml::emitxml(); + cout << "--debug-exit-uvm: Exiting after UVM-supported pass\n"; + std::exit(0); + } // Calculate and check widths, edit tree to TRUNC/EXTRACT any width mismatches V3Width::width(v3Global.rootp()); diff --git a/test_regress/t/t_uvm_all.pl b/test_regress/t/t_uvm_all.pl index d4b291ae6..f61c40c4f 100755 --- a/test_regress/t/t_uvm_all.pl +++ b/test_regress/t/t_uvm_all.pl @@ -11,7 +11,9 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); lint( - v_flags2 => ["-Wno-PKGNODECL -Wno-UNPACKED -Wno-RANDC -Wno-IMPLICITSTATIC -Wno-CONSTRAINTIGN -Wno-MISINDENT", + v_flags2 => ["--timing", + "-Wno-PKGNODECL -Wno-UNPACKED -Wno-RANDC -Wno-IMPLICITSTATIC -Wno-CONSTRAINTIGN -Wno-MISINDENT", + "-Wno-WIDTHEXPAND -Wno-WIDTHTRUNC -Wno-CASTCONST -Wno-REALCVT", "--error-limit 200 --debug-exit-uvm"], ); From 96857c5f95118f21e38702f2e5ecfb9139f2dbb0 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Fri, 15 Sep 2023 13:17:24 +0200 Subject: [PATCH 095/111] Fix the error message when the type of ref argument is wrong (#4490) --- src/V3Width.cpp | 19 +++++++++++-------- test_regress/t/t_class_param_enum_bad.out | 2 +- test_regress/t/t_func_refio_bad.out | 2 +- test_regress/t/t_var_ref_bad2.out | 2 +- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/V3Width.cpp b/src/V3Width.cpp index eaffda787..a24f57345 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -5577,12 +5577,14 @@ private: const AstArg* const argp = tconnect.second; AstNode* const pinp = argp->exprp(); if (!pinp) continue; // Argument error we'll find later + AstNodeDType* const portDTypep = portp->dtypep()->skipRefToEnump(); + const AstNodeDType* const pinDTypep = pinp->dtypep()->skipRefToEnump(); if (portp->direction() == VDirection::REF - && !similarDTypeRecurse(portp->dtypep(), pinp->dtypep())) { + && !similarDTypeRecurse(portDTypep, pinDTypep)) { pinp->v3error("Ref argument requires matching types;" << " port " << portp->prettyNameQ() << " requires " - << portp->prettyTypeName() << " but connection is " - << pinp->prettyTypeName() << "."); + << portDTypep->prettyDTypeName() << " but connection is " + << pinDTypep->prettyDTypeName() << "."); } else if (portp->isWritable() && pinp->width() != portp->width()) { pinp->v3warn(E_UNSUPPORTED, "Unsupported: Function output argument " << portp->prettyNameQ() << " requires " @@ -5593,10 +5595,10 @@ private: // (get an ASSIGN with EXTEND on the lhs instead of rhs) } if (!portp->basicp() || portp->basicp()->isOpaque()) { - checkClassAssign(nodep, "Function Argument", pinp, portp->dtypep()); - userIterate(pinp, WidthVP{portp->dtypep(), FINAL}.p()); + checkClassAssign(nodep, "Function Argument", pinp, portDTypep); + userIterate(pinp, WidthVP{portDTypep, FINAL}.p()); } else { - iterateCheckAssign(nodep, "Function Argument", pinp, FINAL, portp->dtypep()); + iterateCheckAssign(nodep, "Function Argument", pinp, FINAL, portDTypep); } } } @@ -6402,7 +6404,7 @@ private: return false; } void checkClassAssign(AstNode* nodep, const char* side, AstNode* rhsp, - AstNodeDType* lhsDTypep) { + const AstNodeDType* const lhsDTypep) { if (AstClassRefDType* const lhsClassRefp = VN_CAST(lhsDTypep->skipRefp(), ClassRefDType)) { UASSERT_OBJ(rhsp->dtypep(), rhsp, "Node has no type"); AstNodeDType* const rhsDtypep = rhsp->dtypep()->skipRefp(); @@ -6415,7 +6417,8 @@ private: << rhsDtypep->prettyTypeName()); } } - static bool similarDTypeRecurse(AstNodeDType* node1p, AstNodeDType* node2p) { + static bool similarDTypeRecurse(const AstNodeDType* const node1p, + const AstNodeDType* const node2p) { return node1p->skipRefp()->similarDType(node2p->skipRefp()); } void iterateCheckFileDesc(AstNode* nodep, AstNode* underp, Stage stage) { diff --git a/test_regress/t/t_class_param_enum_bad.out b/test_regress/t/t_class_param_enum_bad.out index fd4e547e9..4f5f727f9 100644 --- a/test_regress/t/t_class_param_enum_bad.out +++ b/test_regress/t/t_class_param_enum_bad.out @@ -2,7 +2,7 @@ : ... In instance t 20 | Converter#(bit) conv2 = conv1; | ^~~~~ -%Error-ENUMVALUE: t/t_class_param_enum_bad.v:21:19: Implicit conversion to enum 'T' from 'logic[31:0]' (IEEE 1800-2017 6.19.3) +%Error-ENUMVALUE: t/t_class_param_enum_bad.v:21:19: Implicit conversion to enum 'ENUMDTYPE '$unit::enum_t'' from 'logic[31:0]' (IEEE 1800-2017 6.19.3) : ... In instance t : ... Suggest use enum's mnemonic, or static cast 21 | conv1.toInt(0); diff --git a/test_regress/t/t_func_refio_bad.out b/test_regress/t/t_func_refio_bad.out index 7d92bd42a..b92a72d8d 100644 --- a/test_regress/t/t_func_refio_bad.out +++ b/test_regress/t/t_func_refio_bad.out @@ -1,4 +1,4 @@ -%Error: t/t_func_refio_bad.v:16:17: Ref argument requires matching types; port 'q' requires VAR 'q' but connection is CONST '?32?sh2a'. +%Error: t/t_func_refio_bad.v:16:17: Ref argument requires matching types; port 'q' requires integer[$] but connection is logic[31:0]. : ... In instance t 16 | queue_set(42); | ^~ diff --git a/test_regress/t/t_var_ref_bad2.out b/test_regress/t/t_var_ref_bad2.out index 28a384b6b..7a14ae05e 100644 --- a/test_regress/t/t_var_ref_bad2.out +++ b/test_regress/t/t_var_ref_bad2.out @@ -2,7 +2,7 @@ : ... In instance t 13 | bad_const_set = 32'h4567; | ^~~~~~~~~~~~~ -%Error: t/t_var_ref_bad2.v:23:17: Ref argument requires matching types; port 'int_ref' requires VAR 'int_ref' but connection is VARREF 'bad_non_int'. +%Error: t/t_var_ref_bad2.v:23:17: Ref argument requires matching types; port 'int_ref' requires int but connection is byte. : ... In instance t 23 | checkset2(bad_non_int); | ^~~~~~~~~~~ From 2fbd41e13b1e9b45ee8c278955d6aee8890ecd54 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 15 Sep 2023 07:59:06 -0400 Subject: [PATCH 096/111] Tests: Add t_queue_persistence.pl as broken test (#3385) (#4489) --- test_regress/t/t_func_complex.v | 2 + test_regress/t/t_queue_persistence.pl | 31 +++++++++++++++ test_regress/t/t_queue_persistence.v | 43 +++++++++++++++++++++ test_regress/t/t_queue_persistence_noinl.pl | 31 +++++++++++++++ 4 files changed, 107 insertions(+) create mode 100755 test_regress/t/t_queue_persistence.pl create mode 100644 test_regress/t/t_queue_persistence.v create mode 100755 test_regress/t/t_queue_persistence_noinl.pl diff --git a/test_regress/t/t_func_complex.v b/test_regress/t/t_func_complex.v index 142088d35..d249426b5 100644 --- a/test_regress/t/t_func_complex.v +++ b/test_regress/t/t_func_complex.v @@ -12,6 +12,7 @@ module t(); // verilator no_inline_task `endif q.push_back(42); + if (q.size() != 1) $stop; endfunction function void queue_check_nref(q_t q); @@ -39,6 +40,7 @@ module t(); initial begin q_t iq; queue_set(iq); + if (iq.size() != 1) $stop; queue_check_ref(iq); iq[0] = 44; diff --git a/test_regress/t/t_queue_persistence.pl b/test_regress/t/t_queue_persistence.pl new file mode 100755 index 000000000..c9515ce9b --- /dev/null +++ b/test_regress/t/t_queue_persistence.pl @@ -0,0 +1,31 @@ +#!/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(simulator => 1); + +top_filename("t/t_queue_persistence.v"); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + compile( + timing_loop => 1, + verilator_flags2 => ["--timing"], + ); + + execute( + fails => $Self->{vlt_all}, # bug3385 need to fix "ref" + check_finished => !$Self->{vlt_all}, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_queue_persistence.v b/test_regress/t/t_queue_persistence.v new file mode 100644 index 000000000..a0ee23905 --- /dev/null +++ b/test_regress/t/t_queue_persistence.v @@ -0,0 +1,43 @@ +// 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); + +module t(/*AUTOARG*/); + + int q[$]; + + task automatic func(ref int vrefed); +`ifdef TEST_NOINLINE + // verilator no_inline_task +`endif + `checkd(vrefed, 2); + #100; + vrefed = 10; + `checkd(vrefed, 10); + endtask + + initial begin + q.push_back(1); + q.push_back(2); + q.push_back(3); + `checkd(q[0], 1); + `checkd(q[1], 2); + `checkd(q[2], 3); + func(q[1]); + end + + initial begin + #50; + `checkd(q[1], 2); + q.delete(); + #100; + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_queue_persistence_noinl.pl b/test_regress/t/t_queue_persistence_noinl.pl new file mode 100755 index 000000000..afaa948eb --- /dev/null +++ b/test_regress/t/t_queue_persistence_noinl.pl @@ -0,0 +1,31 @@ +#!/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(simulator => 1); + +top_filename("t/t_queue_persistence.v"); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + compile( + timing_loop => 1, + verilator_flags2 => ["--timing --fno-inline +define+TEST_NOINLINE"], + ); + + execute( + fails => $Self->{vlt_all}, # bug3385 need to fix "ref" + check_finished => !$Self->{vlt_all}, + ); +} + +ok(1); +1; From 10c1653e725f72ce5b447284d415dc7d8d38746d Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 15 Sep 2023 08:53:29 -0400 Subject: [PATCH 097/111] Fix ZERODLY to not warn on 'wait(0)'. --- Changes | 1 + docs/guide/warnings.rst | 6 +++++- src/V3LinkParse.cpp | 11 +++++++++++ src/V3Timing.cpp | 4 +++- test_regress/t/t_lint_wait_bad.out | 3 --- test_regress/t/t_timing_wait1.v | 2 +- 6 files changed, 21 insertions(+), 6 deletions(-) diff --git a/Changes b/Changes index 843177436..f1d8d0b3d 100644 --- a/Changes +++ b/Changes @@ -35,6 +35,7 @@ Verilator 5.015 devel * Fix reference to extended class in parameterized class (#4466). * Fix display %x formatting of real. * Fix mis-warning on #() in classes' own functions. +* Fix ZERODLY to not warn on 'wait(0)'. Verilator 5.014 2023-08-06 diff --git a/docs/guide/warnings.rst b/docs/guide/warnings.rst index f44082085..7f0898b5d 100644 --- a/docs/guide/warnings.rst +++ b/docs/guide/warnings.rst @@ -1990,11 +1990,15 @@ List Of Warnings .. code-block:: sv - wait(0); // Blocks forever + wait(1); // Blocks forever Warns that a `wait` statement awaits a constant condition, which means it either blocks forever or never blocks. + As a special case `wait(0)` with the literal constant `0` (as opposed to + something that elaborates to zero), does not warn, as it is presumed the + code is making the intent clear. + .. option:: WIDTH diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index a7b6b9923..e61ff5f59 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -591,6 +591,17 @@ private: iterateChildren(nodep); } } + void visit(AstWait* nodep) override { + cleanFileline(nodep); + iterateChildren(nodep); + if (nodep->condp()->isZero()) { + // Special case "wait(0)" we won't throw WAITCONST as user wrote + // it that way with presumed intent - UVM does this. + FileLine* const newfl = nodep->fileline(); + newfl->warnOff(V3ErrorCode::WAITCONST, true); + nodep->fileline(newfl); + } + } void visit(AstWhile* nodep) override { cleanFileline(nodep); VL_RESTORER(m_insideLoop); diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp index 15b5a2e0d..a21892e00 100644 --- a/src/V3Timing.cpp +++ b/src/V3Timing.cpp @@ -997,7 +997,9 @@ private: AstNodeExpr* const condp = V3Const::constifyEdit(nodep->condp()->unlinkFrBack()); auto* const constp = VN_CAST(condp, Const); if (constp) { - condp->v3warn(WAITCONST, "Wait statement condition is constant"); + if (!nodep->fileline()->warnIsOff(V3ErrorCode::WAITCONST)) { + condp->v3warn(WAITCONST, "Wait statement condition is constant"); + } if (constp->isZero()) { // We have to await forever instead of simply returning in case we're deep in a // callstack diff --git a/test_regress/t/t_lint_wait_bad.out b/test_regress/t/t_lint_wait_bad.out index 8cc25f02c..b108720dc 100644 --- a/test_regress/t/t_lint_wait_bad.out +++ b/test_regress/t/t_lint_wait_bad.out @@ -6,9 +6,6 @@ %Warning-WAITCONST: t/t_timing_wait1.v:54:14: Wait statement condition is constant 54 | wait(0 < 1) $write("*-* All Finished *-*\n"); | ^ -%Warning-WAITCONST: t/t_timing_wait1.v:58:17: Wait statement condition is constant - 58 | initial wait(0) $stop; - | ^ %Warning-WAITCONST: t/t_timing_wait1.v:59:19: Wait statement condition is constant 59 | initial wait(1 == 0) $stop; | ^~ diff --git a/test_regress/t/t_timing_wait1.v b/test_regress/t/t_timing_wait1.v index 7ec77a5b4..146e84ab2 100644 --- a/test_regress/t/t_timing_wait1.v +++ b/test_regress/t/t_timing_wait1.v @@ -55,7 +55,7 @@ module t; $finish; end - initial wait(0) $stop; + initial wait(0) $stop; // Note this doesn't give WAITCONST initial wait(1 == 0) $stop; initial #12 $stop; // timeout From c52ba28dd078181b59cf3bd7ef5a70bc7efa1f3d Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 15 Sep 2023 18:12:11 -0400 Subject: [PATCH 098/111] Tests: Fix commentary to unify issue references. --- src/V3AstNodes.cpp | 2 +- src/V3Global.h | 2 +- src/V3Partition.cpp | 2 +- test_regress/t/t_bitsel_const_bad.v | 2 +- test_regress/t/t_bitsel_wire_array_bad.v | 2 +- test_regress/t/t_clk_inp_init.v | 2 +- test_regress/t/t_const_opt.v | 8 ++++---- test_regress/t/t_const_slicesel.v | 2 +- test_regress/t/t_delay.v | 2 +- test_regress/t/t_fork_initial.pl | 4 ++-- test_regress/t/t_gen_index.v | 2 +- test_regress/t/t_lint_latch_1.v | 2 +- test_regress/t/t_lint_latch_2.v | 2 +- test_regress/t/t_lint_latch_3.v | 2 +- test_regress/t/t_lint_latch_4.v | 2 +- test_regress/t/t_lint_latch_5.v | 2 +- test_regress/t/t_lint_latch_6.v | 2 +- test_regress/t/t_lint_latch_bad_2.v | 2 +- test_regress/t/t_lint_latch_bad_3.v | 2 +- test_regress/t/t_lint_nolatch_bad.v | 2 +- test_regress/t/t_merge_cond_bug_3409.v | 2 +- test_regress/t/t_mod_nomod.v | 2 +- test_regress/t/t_order_loop_bad.v | 2 +- test_regress/t/t_order_quad.v | 2 +- test_regress/t/t_package_ddecl.v | 2 +- test_regress/t/t_package_export.v | 2 +- test_regress/t/t_package_twodeep.v | 2 +- test_regress/t/t_param.v | 2 +- test_regress/t/t_param_wide_io.v | 2 +- test_regress/t/t_param_width.v | 2 +- test_regress/t/t_randcase_bad.v | 2 +- test_regress/t/t_struct_unaligned.v | 2 +- test_regress/t/t_sys_plusargs.v | 6 +++--- test_regress/t/t_tri_select_unsized.v | 4 ++-- test_regress/t/t_vpi_get.cpp | 4 ++-- 35 files changed, 43 insertions(+), 43 deletions(-) diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index a2caf2621..b08d56f9e 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -2317,7 +2317,7 @@ void AstCAwait::dump(std::ostream& str) const { int AstCMethodHard::instrCount() const { if (AstBasicDType* const basicp = fromp()->dtypep()->basicp()) { // TODO: add a more structured description of library methods, rather than using string - // matching. See #3715. + // matching. See issue #3715. if (basicp->isTriggerVec() && m_name == "word") { // This is an important special case for scheduling so we compute it precisely, // it is simply a load. diff --git a/src/V3Global.h b/src/V3Global.h index f9ee59dd0..90f8bc59b 100644 --- a/src/V3Global.h +++ b/src/V3Global.h @@ -102,7 +102,7 @@ class V3Global final { bool m_assertDTypesResolved = false; // Tree should have dtypep()'s bool m_assertScoped = false; // Tree is scoped bool m_constRemoveXs = false; // Const needs to strip any Xs - // Experimenting with always requiring heavy, see (#2701) + // Experimenting with always requiring heavy, see issue #2701 bool m_needTraceDumper = false; // Need __Vm_dumperp in symbols bool m_dpi = false; // Need __Dpi include files bool m_hasEvents = false; // Design uses SystemVerilog named events diff --git a/src/V3Partition.cpp b/src/V3Partition.cpp index 37a8b923d..a67f92d7b 100644 --- a/src/V3Partition.cpp +++ b/src/V3Partition.cpp @@ -1974,7 +1974,7 @@ private: } // Not: Find all reader tasks for this variable, group by rank. // There was "broken" code here to find readers, but fixing it to - // work properly harmed performance on some tests, see #3360. + // work properly harmed performance on some tests, see issue #3360. } void mergeSameRankTasks(const TasksByRank& tasksByRank) { LogicMTask* lastRecipientp = nullptr; diff --git a/test_regress/t/t_bitsel_const_bad.v b/test_regress/t/t_bitsel_const_bad.v index 53aa133e4..26eed4d95 100644 --- a/test_regress/t/t_bitsel_const_bad.v +++ b/test_regress/t/t_bitsel_const_bad.v @@ -1,6 +1,6 @@ // DESCRIPTION: Verilator: Test of select from constant // -// This tests issue 508, bit select of constant fails +// This tests issue #508, bit select of constant fails // // This file ONLY is placed into the Public Domain, for any use, // without warranty, 2012 by Jeremy Bennett. diff --git a/test_regress/t/t_bitsel_wire_array_bad.v b/test_regress/t/t_bitsel_wire_array_bad.v index 729b272f9..fba95f691 100644 --- a/test_regress/t/t_bitsel_wire_array_bad.v +++ b/test_regress/t/t_bitsel_wire_array_bad.v @@ -1,6 +1,6 @@ // DESCRIPTION: Verilator: Test of select from constant // -// This tests issue 509, bit select of constant fails +// This tests issue #509, bit select of constant fails // // This file ONLY is placed into the Public Domain, for any use, // without warranty, 2012 by Jeremy Bennett. diff --git a/test_regress/t/t_clk_inp_init.v b/test_regress/t/t_clk_inp_init.v index e9399c661..a17e544db 100644 --- a/test_regress/t/t_clk_inp_init.v +++ b/test_regress/t/t_clk_inp_init.v @@ -1,6 +1,6 @@ // DESCRIPTION: Verilator: Check initialisation of cloned clock variables // -// This tests issue 1327 (Strange initialisation behaviour with +// This tests issue #1327 (Strange initialisation behaviour with // "VinpClk" cloned clock variables) // // This file ONLY is placed into the Public Domain, for any use, diff --git a/test_regress/t/t_const_opt.v b/test_regress/t/t_const_opt.v index cfdcc3917..ff0cebd38 100644 --- a/test_regress/t/t_const_opt.v +++ b/test_regress/t/t_const_opt.v @@ -166,14 +166,14 @@ module bug3197(input wire clk, input wire [31:0] in, output out); endmodule -// Bug #3445 +// See issue #3445 // An unoptimized node is kept as frozen node, but its LSB and polarity were not saved. // AST of RHS of result0 looks as below: // AND(SHIFTR(AND(WORDSEL(ARRAYSEL(VARREF)), WORDSEL(ARRAYSEL(VARREF)))), 32'd11) // ~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~ // Two of WORDSELs are frozen nodes. They are under SHIFTR of 11 bits. // -// Fixing #3445 needs to +// Fixing issue #3445 needs to // 1. Take AstShiftR and AstNot into op count when diciding optimizable or not // (result0 and result2 in the test) // 2. Insert AstShiftR if LSB of the frozen node is not 0 (result1 in the test) @@ -368,10 +368,10 @@ module bug3824(input wire clk, input wire [31:0] in, output wire out); assign out = d_and ^ d_or ^ d_xor; endmodule -/// Bug4059 +/// See issue #4059 // Frozen node in an xor tree held unnecessary poloarity. // In an XOR tree, the entire result is flipped if necessary according to -// total polarity. This bug was introduced when fixing #3445. +// total polarity. This bug was introduced when fixing issue #3445. module bug4059(input wire clk, input wire [31:0] in, output wire out); wire [127:0] words_i; for (genvar i = 0; i < $bits(in); ++i) begin diff --git a/test_regress/t/t_const_slicesel.v b/test_regress/t/t_const_slicesel.v index a4fec28f4..c62da7db3 100644 --- a/test_regress/t/t_const_slicesel.v +++ b/test_regress/t/t_const_slicesel.v @@ -13,7 +13,7 @@ localparam int unsigned A3 [2:0] = '{4,5,6}; localparam int unsigned B22 [1:0] = A2[1:0]; localparam int unsigned B33 [2:0] = A3[2:0]; -// bug #3186 +// See issue #3186 localparam int unsigned B32_B [1:0] = A3[1:0]; localparam int unsigned B32_T [1:0] = A3[2:1]; diff --git a/test_regress/t/t_delay.v b/test_regress/t/t_delay.v index 628bc3c32..4b01e9eb8 100644 --- a/test_regress/t/t_delay.v +++ b/test_regress/t/t_delay.v @@ -42,7 +42,7 @@ module t (/*AUTOARG*/ else if (cyc == 4) begin dly_s.dly = 55; dly0 <= #(dly_s.dly) 32'h55; - //dly0 <= # dly_s.dly 32'h55; // Unsupported, issue-2410 + //dly0 <= # dly_s.dly 32'h55; // Unsupported, issue #2410 end else if (cyc == 99) begin if (dly3 !== 32'h57) $stop; diff --git a/test_regress/t/t_fork_initial.pl b/test_regress/t/t_fork_initial.pl index fccceb96e..c78ec8a58 100755 --- a/test_regress/t/t_fork_initial.pl +++ b/test_regress/t/t_fork_initial.pl @@ -13,11 +13,11 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], make_main => 0, - # bug#4471 - remove this + # issue #4471 - remove this verilator_make_gmake => 0, ); -#bug#4471 - add this +# issue #4471 - add this #execute( # check_finished => 1, # ); diff --git a/test_regress/t/t_gen_index.v b/test_regress/t/t_gen_index.v index 97d143c11..47e5cd994 100644 --- a/test_regress/t/t_gen_index.v +++ b/test_regress/t/t_gen_index.v @@ -3,7 +3,7 @@ // The code illustrates a problem in Verilator's handling of constant // expressions inside generate indexes. // -// This is a regression test against issue 517. +// This is a regression test against issue #517. // // **If you do not wish for your code to be released to the public // please note it here, otherwise:** diff --git a/test_regress/t/t_lint_latch_1.v b/test_regress/t/t_lint_latch_1.v index 99987cfbc..a6a5640e1 100644 --- a/test_regress/t/t_lint_latch_1.v +++ b/test_regress/t/t_lint_latch_1.v @@ -1,4 +1,4 @@ -// DESCRIPTION: Verilator: Verilog Test module for Issue#1609 +// DESCRIPTION: Verilator: Verilog Test module for issue #1609 // // This file ONLY is placed into the Public Domain, for any use, // without warranty, 2020 by Julien Margetts. diff --git a/test_regress/t/t_lint_latch_2.v b/test_regress/t/t_lint_latch_2.v index 5ce9ec5e5..e447f3216 100644 --- a/test_regress/t/t_lint_latch_2.v +++ b/test_regress/t/t_lint_latch_2.v @@ -1,4 +1,4 @@ -// DESCRIPTION: Verilator: Verilog Test module for Issue#1609 +// DESCRIPTION: Verilator: Verilog Test module for issue #1609 // // This file ONLY is placed into the Public Domain, for any use, // without warranty, 2020 by Julien Margetts. diff --git a/test_regress/t/t_lint_latch_3.v b/test_regress/t/t_lint_latch_3.v index b38862ece..cfc3461c9 100644 --- a/test_regress/t/t_lint_latch_3.v +++ b/test_regress/t/t_lint_latch_3.v @@ -1,4 +1,4 @@ -// DESCRIPTION: Verilator: Verilog Test module for Issue#1609 +// DESCRIPTION: Verilator: Verilog Test module for issue #1609 // // This file ONLY is placed into the Public Domain, for any use, // without warranty, 2020 by Julien Margetts. diff --git a/test_regress/t/t_lint_latch_4.v b/test_regress/t/t_lint_latch_4.v index 628af7315..c91093ea1 100644 --- a/test_regress/t/t_lint_latch_4.v +++ b/test_regress/t/t_lint_latch_4.v @@ -1,4 +1,4 @@ -// DESCRIPTION: Verilator: Verilog Test module for Issue#2938 +// DESCRIPTION: Verilator: Verilog Test module for issue #2938 // // This file ONLY is placed into the Public Domain, for any use, // without warranty, 2021 by Julien Margetts (Originally provided by YanJiun) diff --git a/test_regress/t/t_lint_latch_5.v b/test_regress/t/t_lint_latch_5.v index c8d5697e8..e1d276789 100644 --- a/test_regress/t/t_lint_latch_5.v +++ b/test_regress/t/t_lint_latch_5.v @@ -1,4 +1,4 @@ -// DESCRIPTION: Verilator: Verilog Test module for Issue#2863 +// DESCRIPTION: Verilator: Verilog Test module for issue #2863 // // This file ONLY is placed into the Public Domain, for any use, // without warranty, 2021 by Julien Margetts (Originally provided by Thomas Sailer) diff --git a/test_regress/t/t_lint_latch_6.v b/test_regress/t/t_lint_latch_6.v index 9f55fb831..9383231ff 100644 --- a/test_regress/t/t_lint_latch_6.v +++ b/test_regress/t/t_lint_latch_6.v @@ -1,4 +1,4 @@ -// DESCRIPTION: Verilator: Verilog Test module for Issue#221 +// DESCRIPTION: Verilator: Verilog Test module for issue #221 // // This file ONLY is placed into the Public Domain, for any use, // without warranty, 2023 by Julien Margetts (Originally provided by Adrien Le Masle) diff --git a/test_regress/t/t_lint_latch_bad_2.v b/test_regress/t/t_lint_latch_bad_2.v index 531995874..75ef49a6d 100644 --- a/test_regress/t/t_lint_latch_bad_2.v +++ b/test_regress/t/t_lint_latch_bad_2.v @@ -1,4 +1,4 @@ -// DESCRIPTION: Verilator: Verilog Test module for Issue#1609 +// DESCRIPTION: Verilator: Verilog Test module for issue #1609 // // This file ONLY is placed into the Public Domain, for any use, // without warranty, 2020 by Julien Margetts. diff --git a/test_regress/t/t_lint_latch_bad_3.v b/test_regress/t/t_lint_latch_bad_3.v index 4f1ba7c9c..386a9d460 100644 --- a/test_regress/t/t_lint_latch_bad_3.v +++ b/test_regress/t/t_lint_latch_bad_3.v @@ -1,4 +1,4 @@ -// DESCRIPTION: Verilator: Verilog Test module for Issue#1609 +// DESCRIPTION: Verilator: Verilog Test module for issue #1609 // // This file ONLY is placed into the Public Domain, for any use, // without warranty, 2020 by Julien Margetts. diff --git a/test_regress/t/t_lint_nolatch_bad.v b/test_regress/t/t_lint_nolatch_bad.v index 0119646b1..715c5884b 100644 --- a/test_regress/t/t_lint_nolatch_bad.v +++ b/test_regress/t/t_lint_nolatch_bad.v @@ -1,4 +1,4 @@ -// DESCRIPTION: Verilator: Verilog Test module for Issue#1609 +// DESCRIPTION: Verilator: Verilog Test module for issue #1609 // // This file ONLY is placed into the Public Domain, for any use, // without warranty, 2020 by Julien Margetts. diff --git a/test_regress/t/t_merge_cond_bug_3409.v b/test_regress/t/t_merge_cond_bug_3409.v index 71e0ccf48..938e1fa9f 100644 --- a/test_regress/t/t_merge_cond_bug_3409.v +++ b/test_regress/t/t_merge_cond_bug_3409.v @@ -82,7 +82,7 @@ module Test(/*AUTOARG*/ integer x; row_idx = {2{1'b0}}; row_found = 1'b0; - // Bug #3409: After unrolling, these conditionals should not be merged + // Issue #3409: After unrolling, these conditionals should not be merged // as row_found is assigned. for (x = 0; $unsigned(x) < 4; x = x + 1) begin row_idx = !row_found ? x[1:0] : row_idx; diff --git a/test_regress/t/t_mod_nomod.v b/test_regress/t/t_mod_nomod.v index e19757ef6..7046313bb 100644 --- a/test_regress/t/t_mod_nomod.v +++ b/test_regress/t/t_mod_nomod.v @@ -4,7 +4,7 @@ // any use, without warranty, 2019 by Wilson Snyder. // SPDX-License-Identifier: CC0-1.0 -//bug 1381 +// See issue #1381 logic root_var; diff --git a/test_regress/t/t_order_loop_bad.v b/test_regress/t/t_order_loop_bad.v index 9b4c0175e..2372d90a0 100644 --- a/test_regress/t/t_order_loop_bad.v +++ b/test_regress/t/t_order_loop_bad.v @@ -4,7 +4,7 @@ // the use of ready in the first two always blocks. However it should // trivially trigger the $write on the first clk posedge. // -// This is a regression test against issue 513. +// This is a regression test against issue #513. // // This file ONLY is placed into the Public Domain, for any use, // without warranty, 2012 by Jeremy Bennett. diff --git a/test_regress/t/t_order_quad.v b/test_regress/t/t_order_quad.v index 02a873239..f33d48478 100644 --- a/test_regress/t/t_order_quad.v +++ b/test_regress/t/t_order_quad.v @@ -4,7 +4,7 @@ // any use, without warranty, 2014 by Wilson Snyder. // SPDX-License-Identifier: CC0-1.0 -//bug 762 +// See issue #762 module t(a0, y); input [3:0] a0; output [44:0] y; diff --git a/test_regress/t/t_package_ddecl.v b/test_regress/t/t_package_ddecl.v index e6b4ab541..57e057c50 100644 --- a/test_regress/t/t_package_ddecl.v +++ b/test_regress/t/t_package_ddecl.v @@ -4,7 +4,7 @@ // any use, without warranty, 2012 by Wilson Snyder. // SPDX-License-Identifier: CC0-1.0 -// see bug 474 +// See issue #474 package functions; localparam LP_PACK = 512; localparam LP_PACK_AND_MOD = 19; diff --git a/test_regress/t/t_package_export.v b/test_regress/t/t_package_export.v index 320261f3f..a0c297915 100644 --- a/test_regress/t/t_package_export.v +++ b/test_regress/t/t_package_export.v @@ -4,7 +4,7 @@ // without warranty, 2012 by Jeremy Bennett. // SPDX-License-Identifier: CC0-1.0 -// see bug 591 +// See issue #591 package pkg1; parameter PARAM2 = 16; diff --git a/test_regress/t/t_package_twodeep.v b/test_regress/t/t_package_twodeep.v index 1f11482de..ff88ff992 100644 --- a/test_regress/t/t_package_twodeep.v +++ b/test_regress/t/t_package_twodeep.v @@ -4,7 +4,7 @@ // without warranty, 2012 by Jeremy Bennett // SPDX-License-Identifier: CC0-1.0 -// see bug 591 +// See issue #591 package pkg2; parameter PARAM2 = 16; diff --git a/test_regress/t/t_param.v b/test_regress/t/t_param.v index abcc6e402..3d0c68bea 100644 --- a/test_regress/t/t_param.v +++ b/test_regress/t/t_param.v @@ -48,7 +48,7 @@ module m1; initial if (PACKED_PARAM != 8'h36) $stop; endmodule -// bug 810 +// See issue #810 module m2 #(/*parameter*/ integer PAR2 = 10); initial begin $display("%x",PAR2); diff --git a/test_regress/t/t_param_wide_io.v b/test_regress/t/t_param_wide_io.v index 4dd8f1cc5..12fdc58f8 100644 --- a/test_regress/t/t_param_wide_io.v +++ b/test_regress/t/t_param_wide_io.v @@ -4,7 +4,7 @@ // any use, without warranty, 2016 by Wilson Snyder. // SPDX-License-Identifier: CC0-1.0 -// issue 1991 +// See issue #1991 module t #( diff --git a/test_regress/t/t_param_width.v b/test_regress/t/t_param_width.v index bc41be394..ec0cce8bc 100644 --- a/test_regress/t/t_param_width.v +++ b/test_regress/t/t_param_width.v @@ -4,7 +4,7 @@ // any use, without warranty, 2016 by Wilson Snyder. // SPDX-License-Identifier: CC0-1.0 -// issue 1991 +// See issue #1991 module t (/*AUTOARG*/ diff --git a/test_regress/t/t_randcase_bad.v b/test_regress/t/t_randcase_bad.v index 4704bf681..d6bba0df1 100644 --- a/test_regress/t/t_randcase_bad.v +++ b/test_regress/t/t_randcase_bad.v @@ -1,6 +1,6 @@ // DESCRIPTION: Verilator: Test of select from constant // -// This tests issue 508, bit select of constant fails +// This tests issue #508, bit select of constant fails // // This file ONLY is placed into the Public Domain, for any use, // without warranty, 2022 by Wilson Snyder. diff --git a/test_regress/t/t_struct_unaligned.v b/test_regress/t/t_struct_unaligned.v index b28fe866a..642d4af86 100644 --- a/test_regress/t/t_struct_unaligned.v +++ b/test_regress/t/t_struct_unaligned.v @@ -1,6 +1,6 @@ // DESCRIPTION: Verilator: // Test an error where a shift amount was out of bounds and the compiler treats the -// value as undefined (Issue #803) +// value as undefined (issue #803) // // This file ONLY is placed into the Public Domain, for any use, // without warranty, 2014 by Jeff Bush. diff --git a/test_regress/t/t_sys_plusargs.v b/test_regress/t/t_sys_plusargs.v index 4aef6e33c..148cc00f1 100644 --- a/test_regress/t/t_sys_plusargs.v +++ b/test_regress/t/t_sys_plusargs.v @@ -50,17 +50,17 @@ module t; if (!$value$plusargs("INT=%o", p_i)) $stop; if (p_i !== 32'o1234) $stop; - // Check handling of 'SData' type signals (Issue #1592) + // Check handling of 'SData' type signals (issue #1592) p_s = 0; if (!$value$plusargs("INT=%d", p_s)) $stop; if (p_s !== 16'd1234) $stop; - // Check handling of 'CData' type signals (Issue #1592) + // Check handling of 'CData' type signals (issue #1592) p_c = 0; if (!$value$plusargs("INT=%d", p_c)) $stop; if (p_c !== 8'd210) $stop; - // Check handling of 'double' type signals (Issue #1619) + // Check handling of 'double' type signals (issue #1619) p_r = 0; if (!$value$plusargs("REAL=%e", p_r)) $stop; $display("r='%e'", p_r); diff --git a/test_regress/t/t_tri_select_unsized.v b/test_regress/t/t_tri_select_unsized.v index 6c9430780..87a250039 100644 --- a/test_regress/t/t_tri_select_unsized.v +++ b/test_regress/t/t_tri_select_unsized.v @@ -14,12 +14,12 @@ module t (/*AUTOARG*/ wire [1:0] b; wire [1:0] c; - wire [0:0] d; // Explicit width due to issue 508 + wire [0:0] d; // Explicit width due to issue #508 wire [0:0] e; // This works if we use 1'bz, or 1'bx, but not with just 'bz or 'bx. It // does require the tri-state Z. Since we get the same effect if b is - // dimensioned [0:0], this may be connected to issue 508. + // dimensioned [0:0], this may be connected to issue #508. assign b[1:0] = clk ? 2'bx : 'bz; assign c[1:0] = clk ? 2'bz : 'bx; assign d = clk ? 1'bx : 'bz; diff --git a/test_regress/t/t_vpi_get.cpp b/test_regress/t/t_vpi_get.cpp index 41f3df6b4..1d63845b4 100644 --- a/test_regress/t/t_vpi_get.cpp +++ b/test_regress/t/t_vpi_get.cpp @@ -121,7 +121,7 @@ static int _mon_check_props(TestVpiHandle& handle, int size, int direction, int // check direction of object int vpidir = vpi_get(vpiDirection, handle); // Don't check port directions in verilator - // see #681 + // See issue #681 if (!TestSimulator::is_verilator()) CHECK_RESULT(vpidir, direction); } @@ -129,7 +129,7 @@ static int _mon_check_props(TestVpiHandle& handle, int size, int direction, int int vpitype = vpi_get(vpiType, handle); if (!(TestSimulator::is_verilator() && type == vpiPort)) { // Don't check for ports in verilator - // see #681 + // See issue #681 CHECK_RESULT(vpitype, type); } From 188cf85b3f271b855a95e34af4eb5991aefe60ec Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 15 Sep 2023 18:33:02 -0400 Subject: [PATCH 099/111] Suppress some debug unknown hash/simulate warnings in UVM. --- src/V3Hasher.cpp | 6 ++++++ src/V3Simulate.h | 21 +++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/V3Hasher.cpp b/src/V3Hasher.cpp index 2ecfaaa69..9169d06bd 100644 --- a/src/V3Hasher.cpp +++ b/src/V3Hasher.cpp @@ -174,6 +174,9 @@ private: iterateConstNull(nodep->refDTypep()); }); } + void visit(AstStreamDType* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() {}); + } void visit(AstVoidDType* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() {}); } @@ -269,6 +272,9 @@ private: iterateConstNull(nodep->sensesp()); }); } + void visit(AstCLocalScope* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); + } void visit(AstCoverInc* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // iterateConstNull(nodep->declp()); diff --git a/src/V3Simulate.h b/src/V3Simulate.h index e73f111f7..a3f1be13a 100644 --- a/src/V3Simulate.h +++ b/src/V3Simulate.h @@ -355,6 +355,13 @@ private: if (nodep->isOutputter()) m_isOutputter = true; } + void knownBadNodeType(AstNode* nodep) { + // Call for node types we know we can't handle + checkNodeInfo(nodep); + if (optimizable()) { + clearOptimizable(nodep, std::string{"Known unhandled node type "} + nodep->typeName()); + } + } void badNodeType(AstNode* nodep) { // Call for default node types, or other node types we don't know how to handle checkNodeInfo(nodep); @@ -1163,6 +1170,20 @@ private: } } + // ==== + // Known Bad + void visit(AstCMethodHard* nodep) override { + // Some CMethods such as size() on queues could be supported, but + // instead we should change those methods to new Ast types so we can + // properly dispatch them + if (jumpingOver(nodep)) return; + knownBadNodeType(nodep); + } + void visit(AstMemberSel* nodep) override { + if (jumpingOver(nodep)) return; + knownBadNodeType(nodep); + } + // ==== // default // These types are definitely not reducible // AstCoverInc, AstFinish, From d840c612d487ca7e0d677f3f0c6440b2785118a9 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 15 Sep 2023 19:01:11 -0400 Subject: [PATCH 100/111] Fix IGNOREDRETURN to not warn on void-cast static function calls. --- Changes | 1 + src/verilog.y | 6 ++++-- test_regress/t/t_func_void.v | 8 ++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Changes b/Changes index f1d8d0b3d..5f835040b 100644 --- a/Changes +++ b/Changes @@ -35,6 +35,7 @@ Verilator 5.015 devel * Fix reference to extended class in parameterized class (#4466). * Fix display %x formatting of real. * Fix mis-warning on #() in classes' own functions. +* Fix IGNOREDRETURN to not warn on void-cast static function calls. * Fix ZERODLY to not warn on 'wait(0)'. diff --git a/src/verilog.y b/src/verilog.y index 34410ffdc..65d92bc6b 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -3558,9 +3558,11 @@ statement_item: // IEEE: statement_item // // Alternative would be shim with new AstVoidStmt. | yVOID yP_TICK '(' task_subroutine_callNoMethod ')' ';' { $$ = $4; - FileLine* const newfl = new FileLine{$$->fileline()}; + AstNode* callp = $$; + while (AstDot* const dotp = VN_CAST(callp, Dot)) callp = dotp->rhsp(); + FileLine* const newfl = new FileLine{callp->fileline()}; newfl->warnOff(V3ErrorCode::IGNOREDRETURN, true); - $$->fileline(newfl); + callp->fileline(newfl); $$ = VN_AS($$, NodeExpr)->makeStmt(); } | yVOID yP_TICK '(' expr '.' task_subroutine_callNoMethod ')' ';' { $$ = new AstDot{$5, false, $4, $6}; diff --git a/test_regress/t/t_func_void.v b/test_regress/t/t_func_void.v index ca357d7ce..5d013b936 100644 --- a/test_regress/t/t_func_void.v +++ b/test_regress/t/t_func_void.v @@ -15,6 +15,12 @@ module t (clk); side_effect += in + 1; endfunction + class Cls; + static function int initialize(); + return 6; + endfunction + endclass + initial begin int got; side_effect = 1; @@ -30,6 +36,8 @@ module t (clk); void'(f1(30)); if (side_effect != 64) $stop; // + void'(Cls::initialize()); + // $write("*-* All Finished *-*\n"); $finish; end From 07013da13d744a2b00db5f6ee1f4313ee58a3fd5 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 15 Sep 2023 19:56:05 -0400 Subject: [PATCH 101/111] Tests: Disabled test (#4493) --- test_regress/t/t_fork_none_var.pl | 25 ++++++++++++++++ test_regress/t/t_fork_none_var.v | 47 +++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100755 test_regress/t/t_fork_none_var.pl create mode 100644 test_regress/t/t_fork_none_var.v diff --git a/test_regress/t/t_fork_none_var.pl b/test_regress/t/t_fork_none_var.pl new file mode 100755 index 000000000..3407291f9 --- /dev/null +++ b/test_regress/t/t_fork_none_var.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 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(simulator => 1); + +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + fails => $Self->{vlt_all}, # issue #4493 + ); + +# issue #4493 +#execute( +# check_finished => 1, +# ); + +ok(1); +1; diff --git a/test_regress/t/t_fork_none_var.v b/test_regress/t/t_fork_none_var.v new file mode 100644 index 000000000..3b568b085 --- /dev/null +++ b/test_regress/t/t_fork_none_var.v @@ -0,0 +1,47 @@ +// 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 + +module t(/*AUTOARG*/); + + logic [3:0] m_mask; + + initial begin + int i; + int n = 4; + m_mask = 0; + fork + begin + fork + begin + fork + begin + for(i = 0; i < n; i++) begin + fork + automatic int k = i; + begin + // issue #4493 + $display("[%0t] start %0d", $time, k); + // UVM's arb_sequence_q[is_relevant_entries[k]].wait_for_relevant(); + m_mask[k] = 1; + #1; + end + join_none + wait (m_mask[i]); + end + end + join_any + end + join_any + end + join + + if (m_mask != {4{1'b1}}) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule From 26ed2a06a0a45f15a6372d5a598f910145930ef2 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 15 Sep 2023 20:26:46 -0400 Subject: [PATCH 102/111] Tests: Add UVM test that generates ok with known issues commented out. (#1538) (#3267) (#4125) (#4323) (#4349) (#4465) (#4467) (#4468) (#4470) (#4493) (#4494) (#4495) (#4496) (#4497) --- test_regress/t/t_dist_copyright.pl | 1 + test_regress/t/t_uvm_all.pl | 5 +- test_regress/t/t_uvm_pkg_todo.vh | 34254 +++++++++++++++++++++++++++ test_regress/t/t_uvm_todo.pl | 30 + test_regress/t/t_uvm_todo.v | 16 + 5 files changed, 34304 insertions(+), 2 deletions(-) create mode 100644 test_regress/t/t_uvm_pkg_todo.vh create mode 100755 test_regress/t/t_uvm_todo.pl create mode 100644 test_regress/t/t_uvm_todo.v diff --git a/test_regress/t/t_dist_copyright.pl b/test_regress/t/t_dist_copyright.pl index a44cb1e21..18338c290 100755 --- a/test_regress/t/t_dist_copyright.pl +++ b/test_regress/t/t_dist_copyright.pl @@ -42,6 +42,7 @@ our @Exempt_Files_List = qw( test_regress/t/t_incr_void.v test_regress/t/t_timing_trace_fst.pl test_regress/t/t_uvm_pkg_all.vh + test_regress/t/t_uvm_pkg_todo.vh test_regress/t/t_wrapper_context.pl test_regress/t/t_wrapper_context_fst.pl test_regress/t/t_wrapper_context_seq.pl diff --git a/test_regress/t/t_uvm_all.pl b/test_regress/t/t_uvm_all.pl index f61c40c4f..23cc4f82d 100755 --- a/test_regress/t/t_uvm_all.pl +++ b/test_regress/t/t_uvm_all.pl @@ -10,11 +10,12 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -lint( +compile( v_flags2 => ["--timing", - "-Wno-PKGNODECL -Wno-UNPACKED -Wno-RANDC -Wno-IMPLICITSTATIC -Wno-CONSTRAINTIGN -Wno-MISINDENT", + "-Wno-PKGNODECL -Wno-RANDC -Wno-IMPLICITSTATIC -Wno-CONSTRAINTIGN -Wno-MISINDENT", "-Wno-WIDTHEXPAND -Wno-WIDTHTRUNC -Wno-CASTCONST -Wno-REALCVT", "--error-limit 200 --debug-exit-uvm"], + verilator_make_gmake => 0, ); #execute( diff --git a/test_regress/t/t_uvm_pkg_todo.vh b/test_regress/t/t_uvm_pkg_todo.vh new file mode 100644 index 000000000..be8852449 --- /dev/null +++ b/test_regress/t/t_uvm_pkg_todo.vh @@ -0,0 +1,34254 @@ +// DESCRIPTION: Verilator: Concatenated UVM header for internal testing +// SPDX-License-Identifier: Apache-2.0 +//------------------------------------------------------------------------------ +// To recreate: +// Using verilator_ext_tests +// t/t_uvm_parse.pl --debug --no-dump-tree +// Copy to here t/obj_vlt/Vt_uvm_parse/Vt_uvm_parse__inputs.vpp +// M-x untabify +// (global-replace-regexp "[ ]+$" "") +// (global-replace-regexp ", +" ", ") +// Add this header +//------------------------------------------------------------------------------ +// Copyright 2007-2011 Mentor Graphics Corporation +// Copyright 2010 Synopsys, Inc. +// Copyright 2007-2018 Cadence Design Systems, Inc. +// Copyright 2010 AMD +// Copyright 2017 NVIDIA Corporation +// All Rights Reserved Worldwide +// +// Licensed under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of +// the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in +// writing, software distributed under the License is +// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See +// the License for the specific language governing +// permissions and limitations under the License. +//------------------------------------------------------------------------------ + +package uvm_pkg; +parameter int UVM_HDL_MAX_WIDTH = 1024; +typedef logic [UVM_HDL_MAX_WIDTH-1:0] uvm_hdl_data_t; + import "DPI-C" context function int uvm_hdl_check_path(string path); + import "DPI-C" context function int uvm_hdl_deposit(string path, uvm_hdl_data_t value); + import "DPI-C" context function int uvm_hdl_force(string path, uvm_hdl_data_t value); + task uvm_hdl_force_time(string path, uvm_hdl_data_t value, time force_time = 0); + if (force_time == 0) begin + void'(uvm_hdl_deposit(path, value)); + return; + end + if (!uvm_hdl_force(path, value)) + return; + #force_time; + void'(uvm_hdl_release_and_read(path, value)); + endtask + import "DPI-C" context function int uvm_hdl_release_and_read(string path, inout uvm_hdl_data_t value); + import "DPI-C" context function int uvm_hdl_release(string path); + import "DPI-C" context function int uvm_hdl_read(string path, output uvm_hdl_data_t value); +import "DPI-C" function string uvm_dpi_get_next_arg_c (int init); +import "DPI-C" function string uvm_dpi_get_tool_name_c (); +import "DPI-C" function string uvm_dpi_get_tool_version_c (); +function string uvm_dpi_get_next_arg(int init=0); + return uvm_dpi_get_next_arg_c(init); +endfunction +function string uvm_dpi_get_tool_name(); + return uvm_dpi_get_tool_name_c(); +endfunction +function string uvm_dpi_get_tool_version(); + return uvm_dpi_get_tool_version_c(); +endfunction +import "DPI-C" function chandle uvm_dpi_regcomp(string regex); +import "DPI-C" function int uvm_dpi_regexec(chandle preg, string str); +import "DPI-C" function void uvm_dpi_regfree(chandle preg); +import "DPI-C" context function int uvm_re_match(string re, string str); +import "DPI-C" context function string uvm_glob_to_re(string glob); + typedef class uvm_cmdline_processor; +parameter string UVM_VERSION_STRING = "Accellera:1800.2-2017:UVM:1.0"; +function string uvm_revision_string(); + return UVM_VERSION_STRING; +endfunction +parameter UVM_STREAMBITS = 4096; +typedef logic signed [UVM_STREAMBITS-1:0] uvm_bitstream_t; +typedef logic signed [63:0] uvm_integral_t; +parameter UVM_FIELD_FLAG_RESERVED_BITS = 28; +typedef bit [UVM_FIELD_FLAG_RESERVED_BITS-1 : 0] uvm_field_flag_t; +typedef enum uvm_field_flag_t { + UVM_BIN = 'h1000000, + UVM_DEC = 'h2000000, + UVM_UNSIGNED = 'h3000000, + UVM_UNFORMAT2 = 'h4000000, + UVM_UNFORMAT4 = 'h5000000, + UVM_OCT = 'h6000000, + UVM_HEX = 'h7000000, + UVM_STRING = 'h8000000, + UVM_TIME = 'h9000000, + UVM_ENUM = 'ha000000, + UVM_REAL = 'hb000000, + UVM_REAL_DEC = 'hc000000, + UVM_REAL_EXP = 'hd000000, + UVM_NORADIX = 0 +} uvm_radix_enum; +parameter UVM_RADIX = 'hf000000; +function string uvm_radix_to_string(uvm_radix_enum radix); + case(radix) + UVM_BIN: return "b"; + UVM_OCT: return "o"; + UVM_DEC: return "d"; + UVM_HEX: return "h"; + UVM_UNSIGNED: return "u"; + UVM_UNFORMAT2: return "u"; + UVM_UNFORMAT4: return "z"; + UVM_STRING: return "s"; + UVM_TIME: return "t"; + UVM_ENUM: return "s"; + UVM_REAL: return "g"; + UVM_REAL_DEC: return "f"; + UVM_REAL_EXP: return "e"; + default: return "x"; + endcase +endfunction +typedef enum uvm_field_flag_t { + UVM_DEFAULT_POLICY = 0, + UVM_DEEP = (1<<16), + UVM_SHALLOW = (1<<17), + UVM_REFERENCE = (1<<18) + } uvm_recursion_policy_enum; +parameter UVM_RECURSION = (UVM_DEEP|UVM_SHALLOW|UVM_REFERENCE); +typedef enum bit { UVM_PASSIVE=0, UVM_ACTIVE=1 } uvm_active_passive_enum; +parameter uvm_field_flag_t UVM_MACRO_NUMFLAGS = 19; +parameter uvm_field_flag_t UVM_DEFAULT = 'b000010101010101; +parameter uvm_field_flag_t UVM_ALL_ON = 'b000000101010101; +parameter uvm_field_flag_t UVM_FLAGS_ON = 'b000000101010101; +parameter uvm_field_flag_t UVM_FLAGS_OFF = 0; +parameter uvm_field_flag_t UVM_COPY = (1<<0); +parameter uvm_field_flag_t UVM_NOCOPY = (1<<1); +parameter uvm_field_flag_t UVM_COMPARE = (1<<2); +parameter uvm_field_flag_t UVM_NOCOMPARE = (1<<3); +parameter uvm_field_flag_t UVM_PRINT = (1<<4); +parameter uvm_field_flag_t UVM_NOPRINT = (1<<5); +parameter uvm_field_flag_t UVM_RECORD = (1<<6); +parameter uvm_field_flag_t UVM_NORECORD = (1<<7); +parameter uvm_field_flag_t UVM_PACK = (1<<8); +parameter uvm_field_flag_t UVM_NOPACK = (1<<9); +parameter uvm_field_flag_t UVM_UNPACK = (1<<10); +parameter uvm_field_flag_t UVM_NOUNPACK = UVM_NOPACK; +parameter uvm_field_flag_t UVM_SET = (1<<11); +parameter uvm_field_flag_t UVM_NOSET = (1<<12); +parameter uvm_field_flag_t UVM_NODEFPRINT = (1<<15); +parameter uvm_field_flag_t UVM_MACRO_EXTRAS = (1<"; + uvm_object_value_str.itoa(v.get_inst_id()); + uvm_object_value_str = {"@",uvm_object_value_str}; +endfunction +function string uvm_leaf_scope (string full_name, byte scope_separator = "."); + byte bracket_match; + int pos; + int bmatches; + bmatches = 0; + case(scope_separator) + "[": bracket_match = "]"; + "(": bracket_match = ")"; + "<": bracket_match = ">"; + "{": bracket_match = "}"; + default: bracket_match = ""; + endcase + if(bracket_match != "" && bracket_match != full_name[full_name.len()-1]) + bracket_match = ""; + for(pos=full_name.len()-1; pos>0; --pos) begin + if(full_name[pos] == bracket_match) bmatches++; + else if(full_name[pos] == scope_separator) begin + bmatches--; + if(!bmatches || (bracket_match == "")) break; + end + end + if(pos) begin + if(scope_separator != ".") pos--; + uvm_leaf_scope = full_name.substr(pos+1,full_name.len()-1); + end + else begin + uvm_leaf_scope = full_name; + end +endfunction +function string uvm_bitstream_to_string (uvm_bitstream_t value, int size, + uvm_radix_enum radix=UVM_NORADIX, + string radix_str=""); + if (radix == UVM_DEC && value[size-1] === 1) + return $sformatf("%0d", value); + if($isunknown(value)) begin + uvm_bitstream_t _t; + _t=0; + for(int idx=0;idx 0 && (arg[i] != "[")) begin + --i; + if((arg[i] == "*") || (arg[i] == "?")) i=0; + else if((arg[i] < "0") || (arg[i] > "9") && (arg[i] != "[")) begin + uvm_get_array_index_int = -1; + i=0; + end + end + else begin + is_wildcard = 0; + return 0; + end + if(i>0) begin + arg = arg.substr(i+1, arg.len()-2); + uvm_get_array_index_int = arg.atoi(); + is_wildcard = 0; + end +endfunction +function string uvm_get_array_index_string(string arg, output bit is_wildcard); + int i; + uvm_get_array_index_string = ""; + is_wildcard = 1; + i = arg.len() - 1; + if(arg[i] == "]") + while(i > 0 && (arg[i] != "[")) begin + if((arg[i] == "*") || (arg[i] == "?")) i=0; + --i; + end + if(i>0) begin + uvm_get_array_index_string = arg.substr(i+1, arg.len()-2); + is_wildcard = 0; + end +endfunction +function bit uvm_is_array(string arg); + return arg[arg.len()-1] == "]"; +endfunction +function automatic bit uvm_has_wildcard (string arg); + uvm_has_wildcard = 0; + if( (arg.len() > 1) && (arg[0] == "/") && (arg[arg.len()-1] == "/") ) + return 1; + foreach(arg[i]) + if( (arg[i] == "*") || (arg[i] == "+") || (arg[i] == "?") ) + uvm_has_wildcard = 1; +endfunction +typedef class uvm_component; +typedef class uvm_root; +typedef class uvm_report_object; +function automatic string m_uvm_string_queue_join(ref string i[$]); + m_uvm_string_queue_join = {>>{i}}; +endfunction +typedef class uvm_factory; +typedef class uvm_default_factory; +typedef class uvm_report_server; +typedef class uvm_default_report_server; +typedef class uvm_root; +typedef class uvm_visitor; +typedef class uvm_component_name_check_visitor; +typedef class uvm_component; +typedef class uvm_comparer; +typedef class uvm_copier; +typedef class uvm_packer; +typedef class uvm_printer; +typedef class uvm_table_printer; +typedef class uvm_tr_database; +typedef class uvm_text_tr_database; +typedef class uvm_resource_pool; +typedef class uvm_default_coreservice_t; +virtual class uvm_coreservice_t; + pure virtual function uvm_factory get_factory(); + pure virtual function void set_factory(uvm_factory f); + pure virtual function uvm_report_server get_report_server(); + pure virtual function void set_report_server(uvm_report_server server); + pure virtual function uvm_tr_database get_default_tr_database(); + pure virtual function void set_default_tr_database(uvm_tr_database db); + pure virtual function void set_component_visitor(uvm_visitor#(uvm_component) v); + pure virtual function uvm_visitor#(uvm_component) get_component_visitor(); + pure virtual function uvm_root get_root(); + pure virtual function void set_phase_max_ready_to_end(int max); + pure virtual function int get_phase_max_ready_to_end(); + pure virtual function void set_default_printer(uvm_printer printer); + pure virtual function uvm_printer get_default_printer(); + pure virtual function void set_default_packer(uvm_packer packer); + pure virtual function uvm_packer get_default_packer(); + pure virtual function void set_default_comparer(uvm_comparer comparer); + pure virtual function uvm_comparer get_default_comparer(); + pure virtual function int unsigned get_global_seed(); + pure virtual function void set_default_copier(uvm_copier copier); + pure virtual function uvm_copier get_default_copier(); + pure virtual function bit get_uvm_seeding(); + pure virtual function void set_uvm_seeding(bit enable); + pure virtual function void set_resource_pool (uvm_resource_pool pool); + pure virtual function uvm_resource_pool get_resource_pool(); + pure virtual function void set_resource_pool_default_precedence(int unsigned precedence); + pure virtual function int unsigned get_resource_pool_default_precedence(); + static uvm_coreservice_t inst; + static function uvm_coreservice_t get(); + if(inst==null) + uvm_init(null); + return inst; + endfunction + static function void set(uvm_coreservice_t cs); + inst=cs; + endfunction +endclass +class uvm_default_coreservice_t extends uvm_coreservice_t; + local uvm_factory factory; + virtual function uvm_factory get_factory(); + if(factory==null) begin + uvm_default_factory f; + f=new; + factory=f; + end + return factory; + endfunction + virtual function void set_factory(uvm_factory f); + factory = f; + endfunction + local uvm_tr_database tr_database; + virtual function uvm_tr_database get_default_tr_database(); + if (tr_database == null) begin + process p = process::self(); + uvm_text_tr_database tx_db; + string s; + if(p != null) + s = p.get_randstate(); + tx_db = new("default_tr_database"); + tr_database = tx_db; + if(p != null) + p.set_randstate(s); + end + return tr_database; + endfunction : get_default_tr_database + virtual function void set_default_tr_database(uvm_tr_database db); + tr_database = db; + endfunction : set_default_tr_database + local uvm_report_server report_server; + virtual function uvm_report_server get_report_server(); + if(report_server==null) begin + uvm_default_report_server f; + f=new; + report_server=f; + end + return report_server; + endfunction + virtual function void set_report_server(uvm_report_server server); + report_server=server; + endfunction + virtual function uvm_root get_root(); + return uvm_root::m_uvm_get_root(); + endfunction + local uvm_visitor#(uvm_component) _visitor; + virtual function void set_component_visitor(uvm_visitor#(uvm_component) v); + _visitor=v; + endfunction + virtual function uvm_visitor#(uvm_component) get_component_visitor(); + if(_visitor==null) begin + uvm_component_name_check_visitor v = new("name-check-visitor"); + _visitor=v; + end + return _visitor; + endfunction + local uvm_printer m_printer ; + virtual function void set_default_printer(uvm_printer printer); + m_printer = printer ; + endfunction + virtual function uvm_printer get_default_printer(); + if (m_printer == null) begin + m_printer = uvm_table_printer::get_default() ; + end + return m_printer ; + endfunction + local uvm_packer m_packer ; + virtual function void set_default_packer(uvm_packer packer); + m_packer = packer ; + endfunction + virtual function uvm_packer get_default_packer(); + if (m_packer == null) begin + m_packer = new("uvm_default_packer") ; + end + return m_packer ; + endfunction + local uvm_comparer m_comparer ; + virtual function void set_default_comparer(uvm_comparer comparer); + m_comparer = comparer ; + endfunction + virtual function uvm_comparer get_default_comparer(); + if (m_comparer == null) begin + m_comparer = new("uvm_default_comparer") ; + end + return m_comparer ; + endfunction + local int m_default_max_ready_to_end_iters = 20; + virtual function void set_phase_max_ready_to_end(int max); + m_default_max_ready_to_end_iters = max; + endfunction + virtual function int get_phase_max_ready_to_end(); + return m_default_max_ready_to_end_iters; + endfunction + local uvm_resource_pool m_rp ; + virtual function void set_resource_pool (uvm_resource_pool pool); + m_rp = pool; + endfunction + virtual function uvm_resource_pool get_resource_pool(); + if(m_rp == null) + m_rp = new(); + return m_rp; + endfunction + local int unsigned m_default_precedence = 1000; + virtual function void set_resource_pool_default_precedence(int unsigned precedence); + m_default_precedence = precedence; + endfunction + virtual function int unsigned get_resource_pool_default_precedence(); + return m_default_precedence; + endfunction + local int unsigned m_uvm_global_seed = $urandom; + virtual function int unsigned get_global_seed(); + return m_uvm_global_seed; + endfunction + local bit m_use_uvm_seeding = 1; + virtual function bit get_uvm_seeding(); + return m_use_uvm_seeding; + endfunction : get_uvm_seeding + virtual function void set_uvm_seeding(bit enable); + m_use_uvm_seeding = enable; + endfunction : set_uvm_seeding + local uvm_copier m_copier ; + virtual function void set_default_copier(uvm_copier copier); + m_copier = copier ; + endfunction + virtual function uvm_copier get_default_copier(); + if (m_copier == null) begin + m_copier = new("uvm_default_copier") ; + end + return m_copier ; + endfunction +endclass +typedef class uvm_root; +typedef class uvm_report_object; +typedef class uvm_report_message; +task run_test (string test_name=""); + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + top.run_test(test_name); +endtask +function uvm_report_object uvm_get_report_object(); + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + return top; +endfunction +function int uvm_report_enabled (int verbosity, + uvm_severity severity=UVM_INFO, string id=""); + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + return top.uvm_report_enabled(verbosity,severity,id); +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, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + top.uvm_report(severity, id, message, verbosity, filename, line, context_name, report_enabled_checked); +endfunction +export "DPI-C" function m__uvm_report_dpi; +function void m__uvm_report_dpi(int severity, + string id, + string message, + int verbosity, + string filename, + int line); + uvm_report(uvm_severity'(severity), id, message, verbosity, filename, line); +endfunction : m__uvm_report_dpi +function void uvm_report_info(string id, + string message, + int verbosity = UVM_MEDIUM, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + top.uvm_report_info(id, message, verbosity, filename, line, context_name, + report_enabled_checked); +endfunction +function void uvm_report_warning(string id, + string message, + int verbosity = UVM_MEDIUM, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + top.uvm_report_warning(id, message, verbosity, filename, line, context_name, + report_enabled_checked); +endfunction +function void uvm_report_error(string id, + string message, + int verbosity = UVM_NONE, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + top.uvm_report_error(id, message, verbosity, filename, line, context_name, + report_enabled_checked); +endfunction +function void uvm_report_fatal(string id, + string message, + int verbosity = UVM_NONE, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); +//TODO issue #3267 - Support recursive functions +//TODO %Error-UNSUPPORTED: t/t_uvm_pkg_todo.vh:753:15: Unsupported: Recursive function or task call: 'uvm_report_fatal' +//TODO top.uvm_report_fatal(id, message, verbosity, filename, line, context_name, +//TODO report_enabled_checked); +endfunction +function void uvm_process_report_message(uvm_report_message report_message); + uvm_root top; + uvm_coreservice_t cs; + process p; + p = process::self(); + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + top.uvm_process_report_message(report_message); +endfunction +function bit uvm_string_to_severity (string sev_str, output uvm_severity sev); + case (sev_str) + "UVM_INFO": sev = UVM_INFO; + "UVM_WARNING": sev = UVM_WARNING; + "UVM_ERROR": sev = UVM_ERROR; + "UVM_FATAL": sev = UVM_FATAL; + default: return 0; + endcase + return 1; +endfunction +function automatic bit uvm_string_to_action (string action_str, output uvm_action action); + string actions[$]; + uvm_split_string(action_str,"|",actions); + uvm_string_to_action = 1; + action = 0; + foreach(actions[i]) begin + case (actions[i]) + "UVM_NO_ACTION": action |= UVM_NO_ACTION; + "UVM_DISPLAY": action |= UVM_DISPLAY; + "UVM_LOG": action |= UVM_LOG; + "UVM_COUNT": action |= UVM_COUNT; + "UVM_EXIT": action |= UVM_EXIT; + "UVM_CALL_HOOK": action |= UVM_CALL_HOOK; + "UVM_STOP": action |= UVM_STOP; + "UVM_RM_RECORD": action |= UVM_RM_RECORD; + default: uvm_string_to_action = 0; + endcase + end +endfunction +function bit uvm_is_match (string expr, string str); + string s; + s = uvm_glob_to_re(expr); + return (uvm_re_match(s, str) == 0); +endfunction +parameter UVM_LINE_WIDTH = 120; +parameter UVM_NUM_LINES = 120; +parameter UVM_SMALL_STRING = UVM_LINE_WIDTH*8-1; +parameter UVM_LARGE_STRING = UVM_LINE_WIDTH*UVM_NUM_LINES*8-1; +function logic[UVM_LARGE_STRING:0] uvm_string_to_bits(string str); + $swrite(uvm_string_to_bits, "%0s", str); +endfunction +function uvm_core_state get_core_state(); + return m_uvm_core_state; +endfunction +function void uvm_init(uvm_coreservice_t cs=null); + uvm_default_coreservice_t dcs; + if(get_core_state()!=UVM_CORE_UNINITIALIZED) begin + if (get_core_state() == UVM_CORE_PRE_INIT) begin + dcs = new(); + uvm_coreservice_t::set(dcs); + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"UVM/INIT/MULTI")) + uvm_report_fatal ("UVM/INIT/MULTI", "Non-recoverable race during uvm_init", UVM_NONE, "t/uvm/src/base/uvm_globals.svh", 335, "", 1); + end + end + else begin + uvm_coreservice_t actual; + actual = uvm_coreservice_t::inst; + if ((cs != actual) && (cs != null)) + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/INIT/MULTI")) + uvm_report_warning ("UVM/INIT/MULTI", "uvm_init() called after library has already completed initialization, subsequent calls are ignored!", UVM_NONE, "t/uvm/src/base/uvm_globals.svh", 349, "", 1); + end + end + return; + end + m_uvm_core_state=UVM_CORE_PRE_INIT; + if(cs == null) begin + dcs = new(); + cs = dcs; + end + uvm_coreservice_t::set(cs); + m_uvm_core_state=UVM_CORE_INITIALIZING; + foreach(uvm_deferred_init[idx]) begin + uvm_deferred_init[idx].initialize(); + end + uvm_deferred_init.delete(); + begin + uvm_root top; + top = uvm_root::get(); + top.report_header(); + top.m_check_uvm_field_flag_size(); + top.m_check_verbosity(); + end + m_uvm_core_state=UVM_CORE_INITIALIZED; +endfunction +function string uvm_bits_to_string(logic [UVM_LARGE_STRING:0] str); + $swrite(uvm_bits_to_string, "%0s", str); +endfunction +task uvm_wait_for_nba_region; + int nba; + int next_nba; + next_nba++; +//TODO issue #4496 - Delayed assignment inside public function/task +//TODO %Error-UNSUPPORTED: t/t_uvm_pkg_todo.vh:875:7: Unsupported: Delayed assignment inside public function/task +//TODO nba <= next_nba; + @(nba); +endtask +function automatic void uvm_split_string (string str, byte sep, ref string values[$]); + int s = 0, e = 0; + values.delete(); + while(e < str.len()) begin + for(s=e; e"; endfunction + virtual function uvm_object create (string name=""); return null; endfunction + extern virtual function uvm_object clone (); + extern function void print (uvm_printer printer=null); + extern function string sprint (uvm_printer printer=null); + extern virtual function void do_print (uvm_printer printer); + extern virtual function string convert2string(); + extern function void record (uvm_recorder recorder=null); + extern virtual function void do_record (uvm_recorder recorder); + extern function void copy (uvm_object rhs, uvm_copier copier=null); + extern virtual function void do_copy (uvm_object rhs); + extern function bit compare (uvm_object rhs, uvm_comparer comparer=null); + extern virtual function bit do_compare (uvm_object rhs, + uvm_comparer comparer); + extern function int pack (ref bit bitstream[], + input uvm_packer packer=null); + extern function int pack_bytes (ref byte unsigned bytestream[], + input uvm_packer packer=null); + extern function int pack_ints (ref int unsigned intstream[], + input uvm_packer packer=null); + extern function int pack_longints (ref longint unsigned longintstream[], + input uvm_packer packer=null); + extern virtual function void do_pack (uvm_packer packer); + extern function int unpack (ref bit bitstream[], + input uvm_packer packer=null); + extern function int unpack_bytes (ref byte unsigned bytestream[], + input uvm_packer packer=null); + extern function int unpack_ints (ref int unsigned intstream[], + input uvm_packer packer=null); + extern function int unpack_longints (ref longint unsigned longintstream[], + input uvm_packer packer=null); + extern virtual function void do_unpack (uvm_packer packer); + extern virtual function void do_execute_op ( uvm_field_op op); + extern virtual function void set_local(uvm_resource_base rsrc) ; + extern local function void m_pack (inout uvm_packer packer); + extern local function void m_unpack_pre (inout uvm_packer packer); + extern local function int m_unpack_post (uvm_packer packer); + extern virtual function void m_unsupported_set_local(uvm_resource_base rsrc); + local string m_leaf_name; + local int m_inst_id; + static protected int m_inst_count; + extern virtual function void __m_uvm_field_automation (uvm_object tmp_data__, + uvm_field_flag_t what__, + string str__); + extern protected virtual function uvm_report_object m_get_report_object(); +endclass +function uvm_object::new (string name=""); + m_inst_id = m_inst_count++; + m_leaf_name = name; +endfunction +function bit uvm_object::get_uvm_seeding(); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + return cs.get_uvm_seeding(); +endfunction +function void uvm_object::set_uvm_seeding(bit enable); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + cs.set_uvm_seeding(enable); +endfunction +function void uvm_object::reseed (); + if(get_uvm_seeding()) + this.srandom(uvm_create_random_seed(get_type_name(), get_full_name())); +endfunction +function uvm_object_wrapper uvm_object::get_type(); + uvm_report_error("NOTYPID", "get_type not implemented in derived class.", UVM_NONE); + return null; +endfunction +function int uvm_object::get_inst_id(); + return m_inst_id; +endfunction +function uvm_object_wrapper uvm_object::get_object_type(); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory=cs.get_factory(); + if(get_type_name() == "") return null; + return factory.find_wrapper_by_name(get_type_name()); +endfunction +function int uvm_object::get_inst_count(); + return m_inst_count; +endfunction +function string uvm_object::get_name (); + return m_leaf_name; +endfunction +function string uvm_object::get_full_name (); + return get_name(); +endfunction +function void uvm_object::set_name (string name); + m_leaf_name = name; +endfunction +function void uvm_object::print(uvm_printer printer=null); + if (printer==null) printer = uvm_printer::get_default(); + $fwrite(printer.get_file(),sprint(printer)); +endfunction +function string uvm_object::sprint(uvm_printer printer=null); + string name; + if(printer==null) printer = uvm_printer::get_default(); + if (printer.get_active_object_depth() == 0) begin + printer.flush() ; + name = printer.get_root_enabled() ? get_full_name() : get_name(); + end + else begin + name = get_name(); + end + printer.print_object(name,this); + return printer.emit(); +endfunction +function string uvm_object::convert2string(); + return ""; +endfunction +function void uvm_object::set_local(uvm_resource_base rsrc) ; + if(rsrc==null) begin + return ; + end + else begin + begin + uvm_field_op op; + op = uvm_field_op::m_get_available_op(); + op.set(UVM_SET,null,rsrc); + this.do_execute_op(op); + op.m_recycle(); + end + end +endfunction +function void uvm_object::m_unsupported_set_local(uvm_resource_base rsrc); + return; +endfunction +function uvm_object uvm_object::clone(); + uvm_object tmp; + tmp = this.create(get_name()); + if(tmp == null) + uvm_report_warning("CRFLD", $sformatf("The create method failed for %s, object cannot be cloned", get_name()), UVM_NONE); + else + tmp.copy(this); + return(tmp); +endfunction +function void uvm_object::copy (uvm_object rhs, uvm_copier copier=null); +uvm_coreservice_t coreservice ; +uvm_copier m_copier; + if(rhs == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"OBJ/COPY")) + uvm_report_error ("OBJ/COPY", "Passing a null object to be copied", UVM_NONE, "t/uvm/src/base/uvm_object.svh", 1138, "", 1); + end + return; + end + if(copier == null) begin + coreservice = uvm_coreservice_t::get() ; + m_copier = coreservice.get_default_copier() ; + end + else + m_copier = copier; + if(m_copier.get_active_object_depth() == 0) + m_copier.flush(); + m_copier.copy_object(this,rhs); +endfunction +function void uvm_object::do_copy (uvm_object rhs); + return; +endfunction +function bit uvm_object::compare (uvm_object rhs, + uvm_comparer comparer=null); + if (comparer == null) comparer = uvm_comparer::get_default(); + if (comparer.get_active_object_depth() == 0) + comparer.flush() ; + compare = comparer.compare_object(get_name(),this,rhs); +endfunction +function bit uvm_object::do_compare (uvm_object rhs, + uvm_comparer comparer); + return 1; +endfunction +function void uvm_object::__m_uvm_field_automation (uvm_object tmp_data__, + uvm_field_flag_t what__, + string str__ ); + return; +endfunction +function void uvm_object::do_print(uvm_printer printer); + return; +endfunction +function void uvm_object::m_pack (inout uvm_packer packer); + if (packer == null) + packer = uvm_packer::get_default(); + if(packer.get_active_object_depth() == 0) + packer.flush(); + packer.pack_object(this); +endfunction +function int uvm_object::pack (ref bit bitstream [], + input uvm_packer packer =null ); + m_pack(packer); + packer.get_packed_bits(bitstream); + return packer.get_packed_size(); +endfunction +function int uvm_object::pack_bytes (ref byte unsigned bytestream [], + input uvm_packer packer=null ); + m_pack(packer); + packer.get_packed_bytes(bytestream); + return packer.get_packed_size(); +endfunction +function int uvm_object::pack_ints (ref int unsigned intstream [], + input uvm_packer packer=null ); + m_pack(packer); + packer.get_packed_ints(intstream); + return packer.get_packed_size(); +endfunction +function int uvm_object::pack_longints (ref longint unsigned longintstream [], + input uvm_packer packer=null ); + m_pack(packer); + packer.get_packed_longints(longintstream); + return packer.get_packed_size(); +endfunction +function void uvm_object::do_pack (uvm_packer packer ); + if (packer == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/OBJ/PACK/NULL")) + uvm_report_error ("UVM/OBJ/PACK/NULL", "uvm_object::do_pack called with null packer!", UVM_NONE, "t/uvm/src/base/uvm_object.svh", 1265, "", 1); + end + return; +endfunction +function void uvm_object::m_unpack_pre (inout uvm_packer packer); + if (packer == null) + packer = uvm_packer::get_default(); + if(packer.get_active_object_depth() == 0) + packer.flush(); +endfunction +function int uvm_object::m_unpack_post (uvm_packer packer); + int size_before_unpack = packer.get_packed_size(); + packer.unpack_object(this); + return size_before_unpack - packer.get_packed_size(); +endfunction +function int uvm_object::unpack (ref bit bitstream [], + input uvm_packer packer=null); + m_unpack_pre(packer); + packer.set_packed_bits(bitstream); + return m_unpack_post(packer); +endfunction +function int uvm_object::unpack_bytes (ref byte unsigned bytestream [], + input uvm_packer packer=null); + m_unpack_pre(packer); + packer.set_packed_bytes(bytestream); + return m_unpack_post(packer); +endfunction +function int uvm_object::unpack_ints (ref int unsigned intstream [], + input uvm_packer packer=null); + m_unpack_pre(packer); + packer.set_packed_ints(intstream); + return m_unpack_post(packer); +endfunction +function int uvm_object::unpack_longints (ref longint unsigned longintstream [], + input uvm_packer packer=null); + m_unpack_pre(packer); + packer.set_packed_longints(longintstream); + return m_unpack_post(packer); +endfunction +function void uvm_object::do_execute_op ( uvm_field_op op); +endfunction +function void uvm_object::do_unpack (uvm_packer packer); + if (packer == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/OBJ/UNPACK/NULL")) + uvm_report_error ("UVM/OBJ/UNPACK/NULL", "uvm_object::do_unpack called with null packer!", UVM_NONE, "t/uvm/src/base/uvm_object.svh", 1345, "", 1); + end + return; +endfunction +function void uvm_object::record (uvm_recorder recorder=null); + if(recorder == null) + return; + recorder.record_object(get_name(), this); +endfunction +function void uvm_object::do_record (uvm_recorder recorder); + return; +endfunction +function uvm_report_object uvm_object::m_get_report_object(); + return null; +endfunction +typedef class uvm_object; +typedef class uvm_component; +typedef class uvm_object_wrapper; +typedef class uvm_factory_override; +typedef struct {uvm_object_wrapper m_type; + string m_type_name;} m_uvm_factory_type_pair_t; +class uvm_factory_queue_class; + uvm_factory_override queue[$]; +endclass +virtual class uvm_factory; + static function uvm_factory get(); + uvm_coreservice_t s; + s = uvm_coreservice_t::get(); + return s.get_factory(); + endfunction + static function void set(uvm_factory f); + uvm_coreservice_t s; + s = uvm_coreservice_t::get(); + s.set_factory(f); + endfunction + pure virtual function void register (uvm_object_wrapper obj); + pure virtual function + void set_inst_override_by_type (uvm_object_wrapper original_type, + uvm_object_wrapper override_type, + string full_inst_path); + pure virtual function + void set_inst_override_by_name (string original_type_name, + string override_type_name, + string full_inst_path); + pure virtual function + void set_type_override_by_type (uvm_object_wrapper original_type, + uvm_object_wrapper override_type, + bit replace=1); + pure virtual function + void set_type_override_by_name (string original_type_name, + string override_type_name, + bit replace=1); + pure virtual function + uvm_object create_object_by_type (uvm_object_wrapper requested_type, + string parent_inst_path="", + string name=""); + pure virtual function + uvm_component create_component_by_type (uvm_object_wrapper requested_type, + string parent_inst_path="", + string name, + uvm_component parent); + pure virtual function + uvm_object create_object_by_name (string requested_type_name, + string parent_inst_path="", + string name=""); + pure virtual + function bit is_type_name_registered (string type_name); + pure virtual + function bit is_type_registered (uvm_object_wrapper obj); + pure virtual function + uvm_component create_component_by_name (string requested_type_name, + string parent_inst_path="", + string name, + uvm_component parent); + pure virtual function + void set_type_alias(string alias_type_name, + uvm_object_wrapper original_type); + pure virtual function + void set_inst_alias(string alias_type_name, + uvm_object_wrapper original_type, string full_inst_path); + pure virtual function + void debug_create_by_type (uvm_object_wrapper requested_type, + string parent_inst_path="", + string name=""); + pure virtual function + void debug_create_by_name (string requested_type_name, + string parent_inst_path="", + string name=""); + pure virtual function + uvm_object_wrapper find_override_by_type (uvm_object_wrapper requested_type, + string full_inst_path); + pure virtual function + uvm_object_wrapper find_override_by_name (string requested_type_name, + string full_inst_path); + pure virtual + function uvm_object_wrapper find_wrapper_by_name (string type_name); + pure virtual function void print (int all_types=1); +endclass +class uvm_default_factory extends uvm_factory; + extern virtual function void register (uvm_object_wrapper obj); + extern virtual function + void set_inst_override_by_type (uvm_object_wrapper original_type, + uvm_object_wrapper override_type, + string full_inst_path); + extern virtual function + void set_inst_override_by_name (string original_type_name, + string override_type_name, + string full_inst_path); + extern virtual function + void set_type_override_by_type (uvm_object_wrapper original_type, + uvm_object_wrapper override_type, + bit replace=1); + extern virtual function + void set_type_override_by_name (string original_type_name, + string override_type_name, + bit replace=1); + extern virtual function + void set_type_alias(string alias_type_name, + uvm_object_wrapper original_type); + extern virtual function + void set_inst_alias(string alias_type_name, + uvm_object_wrapper original_type, string full_inst_path); + extern virtual function + uvm_object create_object_by_type (uvm_object_wrapper requested_type, + string parent_inst_path="", + string name=""); + extern virtual function + uvm_component create_component_by_type (uvm_object_wrapper requested_type, + string parent_inst_path="", + string name, + uvm_component parent); + extern virtual function + uvm_object create_object_by_name (string requested_type_name, + string parent_inst_path="", + string name=""); + extern virtual function + uvm_component create_component_by_name (string requested_type_name, + string parent_inst_path="", + string name, + uvm_component parent); + extern virtual + function bit is_type_name_registered (string type_name); + extern virtual + function bit is_type_registered (uvm_object_wrapper obj); + extern virtual function + void debug_create_by_type (uvm_object_wrapper requested_type, + string parent_inst_path="", + string name=""); + extern virtual function + void debug_create_by_name (string requested_type_name, + string parent_inst_path="", + string name=""); + extern virtual function + uvm_object_wrapper find_override_by_type (uvm_object_wrapper requested_type, + string full_inst_path); + extern virtual function + uvm_object_wrapper find_override_by_name (string requested_type_name, + string full_inst_path); + extern virtual + function uvm_object_wrapper find_wrapper_by_name (string type_name); + extern virtual function void print (int all_types=1); + extern protected + function void m_debug_create (string requested_type_name, + uvm_object_wrapper requested_type, + string parent_inst_path, + string name); + extern protected + function void m_debug_display(string requested_type_name, + uvm_object_wrapper result, + string full_inst_path); + extern + function uvm_object_wrapper m_resolve_type_name(string requested_type_name); + extern + function uvm_object_wrapper m_resolve_type_name_by_inst(string requested_type_name, + string full_inst_path); + extern + function bit m_matches_type_pair(m_uvm_factory_type_pair_t match_type_pair, + uvm_object_wrapper requested_type, + string requested_type_name); + extern + function bit m_matches_type_override(uvm_factory_override override, + uvm_object_wrapper requested_type, + string requested_type_name, + string full_inst_path="", + bit match_original_type = 1, + bit resolve_null_type_by_inst=0); + extern + function bit m_matches_inst_override(uvm_factory_override override, + uvm_object_wrapper requested_type, + string requested_type_name, + string full_inst_path=""); + typedef struct { + m_uvm_factory_type_pair_t orig; + string alias_type_name; + string full_inst_path; + } m_inst_typename_alias_t; + protected bit m_types[uvm_object_wrapper]; + protected bit m_lookup_strs[string]; + protected uvm_object_wrapper m_type_names[string]; + protected m_inst_typename_alias_t m_inst_aliases[$]; + protected uvm_factory_override m_type_overrides[$]; + protected uvm_factory_override m_inst_overrides[$]; + local uvm_factory_override m_override_info[$]; + local static bit m_debug_pass; + extern function bit check_inst_override_exists + (uvm_object_wrapper original_type, + string original_type_name, + uvm_object_wrapper override_type, + string override_type_name, + string full_inst_path); +endclass +virtual class uvm_object_wrapper; + virtual function uvm_object create_object (string name=""); + return null; + endfunction + virtual function uvm_component create_component (string name, + uvm_component parent); + return null; + endfunction + pure virtual function string get_type_name(); + virtual function void initialize(); endfunction +endclass +class uvm_factory_override; + string full_inst_path; + m_uvm_factory_type_pair_t orig; + m_uvm_factory_type_pair_t ovrd; + bit replace; + bit selected; + int unsigned used; + bit has_wildcard; + function new (string full_inst_path="", + string orig_type_name="", + uvm_object_wrapper orig_type=null, + uvm_object_wrapper ovrd_type, + string ovrd_type_name="", + bit replace=0); + this.full_inst_path= full_inst_path; + this.orig.m_type_name = orig_type_name; + this.orig.m_type = orig_type; + this.ovrd.m_type_name = ovrd_type_name; + this.ovrd.m_type = ovrd_type; + this.replace = replace; + this.has_wildcard = m_has_wildcard(full_inst_path); + endfunction + function bit m_has_wildcard(string nm); + foreach (nm[i]) + if(nm[i] == "*" || nm[i] == "?") return 1; + return 0; + endfunction +endclass +function void uvm_default_factory::register (uvm_object_wrapper obj); + if (obj == null) begin + uvm_report_fatal ("NULLWR", "Attempting to register a null object with the factory", UVM_NONE); + end + if (obj.get_type_name() != "" && obj.get_type_name() != "") begin + if (m_type_names.exists(obj.get_type_name())) + uvm_report_warning("TPRGED", {"Type name '",obj.get_type_name(), + "' already registered with factory. No string-based lookup ", + "support for multiple types with the same type name."}, UVM_NONE); + else + m_type_names[obj.get_type_name()] = obj; + end + if (m_types.exists(obj)) begin + if (obj.get_type_name() != "" && obj.get_type_name() != "") + uvm_report_warning("TPRGED", {"Object type '",obj.get_type_name(), + "' already registered with factory. "}, UVM_NONE); + end + else begin + uvm_factory_override overrides[$]; + m_types[obj] = 1; + overrides = {m_type_overrides, m_inst_overrides}; + foreach (overrides[index]) begin + if(m_matches_type_pair(.match_type_pair(overrides[index].orig), + .requested_type(null), + .requested_type_name(obj.get_type_name()))) begin + overrides[index].orig.m_type = obj; + end + if(m_matches_type_pair(.match_type_pair(overrides[index].ovrd), + .requested_type(null), + .requested_type_name(obj.get_type_name()))) begin + overrides[index].ovrd.m_type = obj; + end + end + end +endfunction +function void uvm_default_factory::set_type_override_by_type (uvm_object_wrapper original_type, + uvm_object_wrapper override_type, + bit replace=1); + bit replaced; + if (original_type == override_type) begin + if (original_type.get_type_name() == "" || original_type.get_type_name() == "") + uvm_report_warning("TYPDUP", {"Original and override type ", + "arguments are identical"}, UVM_NONE); + else + uvm_report_warning("TYPDUP", {"Original and override type ", + "arguments are identical: ", + original_type.get_type_name()}, UVM_NONE); + end + if (!m_types.exists(original_type)) + register(original_type); + if (!m_types.exists(override_type)) + register(override_type); + foreach (m_type_overrides[index]) begin + if(m_matches_type_override(.override(m_type_overrides[index]), + .requested_type(original_type), + .requested_type_name(original_type.get_type_name()))) begin + string msg; + msg = {"Original object type '",original_type.get_type_name(), + "' already registered to produce '", + m_type_overrides[index].ovrd.m_type_name,"'"}; + if (!replace) begin + msg = {msg, ". Set 'replace' argument to replace the existing entry."}; + uvm_report_info("TPREGD", msg, UVM_MEDIUM); + return; + end + msg = {msg, ". Replacing with override to produce type '", + override_type.get_type_name(),"'."}; + uvm_report_info("TPREGR", msg, UVM_MEDIUM); + replaced = 1; + m_type_overrides[index].orig.m_type = original_type; + m_type_overrides[index].orig.m_type_name = original_type.get_type_name(); + m_type_overrides[index].ovrd.m_type = override_type; + m_type_overrides[index].ovrd.m_type_name = override_type.get_type_name(); + m_type_overrides[index].replace = replace; + end + else if (m_type_overrides[index].orig.m_type == null) begin + break; + end + end + if (!replaced) begin + uvm_factory_override override; + override = new(.orig_type(original_type), + .orig_type_name(original_type.get_type_name()), + .ovrd_type(override_type), + .ovrd_type_name(override_type.get_type_name()), + .replace(replace)); + m_type_overrides.push_front(override); + end +endfunction +function void uvm_default_factory::set_type_override_by_name (string original_type_name, + string override_type_name, + bit replace=1); + bit replaced; + uvm_object_wrapper original_type; + uvm_object_wrapper override_type; + if(m_type_names.exists(original_type_name)) + original_type = m_type_names[original_type_name]; + if(m_type_names.exists(override_type_name)) + override_type = m_type_names[override_type_name]; + if (original_type_name == override_type_name) begin + uvm_report_warning("TYPDUP", {"Requested and actual type name ", + " arguments are identical: ",original_type_name,". Ignoring this override."}, UVM_NONE); + return; + end + foreach (m_type_overrides[index]) begin + if(m_matches_type_override(.override(m_type_overrides[index]), + .requested_type(original_type), + .requested_type_name(original_type_name))) begin + if (!replace) begin + uvm_report_info("TPREGD", {"Original type '",original_type_name, "'/'",m_type_overrides[index].orig.m_type_name, + "' already registered to produce '",m_type_overrides[index].ovrd.m_type_name, + "'. Set 'replace' argument to replace the existing entry."}, UVM_MEDIUM); + return; + end + uvm_report_info("TPREGR", {"Original object type '",original_type_name, "'/'",m_type_overrides[index].orig.m_type_name, + "' already registered to produce '",m_type_overrides[index].ovrd.m_type_name, + "'. Replacing with override to produce type '",override_type_name,"'."}, UVM_MEDIUM); + replaced = 1; + m_type_overrides[index].ovrd.m_type = override_type; + m_type_overrides[index].ovrd.m_type_name = override_type_name; + m_type_overrides[index].replace = replace; + end + else if ((m_type_overrides[index].orig.m_type == null) || (original_type == null)) begin + break; + end + end + if (original_type == null) + m_lookup_strs[original_type_name] = 1; + if (!replaced) begin + uvm_factory_override override; + override = new(.orig_type(original_type), + .orig_type_name(original_type_name), + .ovrd_type(override_type), + .ovrd_type_name(override_type_name), + .replace(replace) + ); + m_type_overrides.push_front(override); + end +endfunction +function bit uvm_default_factory::check_inst_override_exists (uvm_object_wrapper original_type, + string original_type_name, + uvm_object_wrapper override_type, + string override_type_name, + string full_inst_path); + uvm_factory_override override; + foreach (m_inst_overrides[i]) begin + override = m_inst_overrides[i]; + if (override.full_inst_path == full_inst_path && + override.orig.m_type == original_type && + override.orig.m_type_name == original_type_name && + override.ovrd.m_type == override_type && + override.ovrd.m_type_name == override_type_name) begin + uvm_report_info("DUPOVRD",{"Instance override for '", + original_type_name,"' already exists: override type '", + override_type_name,"' with full_inst_path '", + full_inst_path,"'"},UVM_HIGH); + return 1; + end + end + return 0; +endfunction +function void uvm_default_factory::set_inst_override_by_type (uvm_object_wrapper original_type, + uvm_object_wrapper override_type, + string full_inst_path); + uvm_factory_override override; + if (!m_types.exists(original_type)) + register(original_type); + if (!m_types.exists(override_type)) + register(override_type); + if (check_inst_override_exists(original_type, + original_type.get_type_name(), + override_type, + override_type.get_type_name(), + full_inst_path)) + return; + override = new(.full_inst_path(full_inst_path), + .orig_type(original_type), + .orig_type_name(original_type.get_type_name()), + .ovrd_type(override_type), + .ovrd_type_name(override_type.get_type_name())); + m_inst_overrides.push_back(override); +endfunction +function void uvm_default_factory::set_inst_override_by_name (string original_type_name, + string override_type_name, + string full_inst_path); + uvm_factory_override override; + uvm_object_wrapper original_type; + uvm_object_wrapper override_type; + if(m_type_names.exists(original_type_name)) + original_type = m_type_names[original_type_name]; + if(m_type_names.exists(override_type_name)) + override_type = m_type_names[override_type_name]; + if (original_type == null) + m_lookup_strs[original_type_name] = 1; + override = new(.full_inst_path(full_inst_path), + .orig_type(original_type), + .orig_type_name(original_type_name), + .ovrd_type(override_type), + .ovrd_type_name(override_type_name)); + if (check_inst_override_exists(original_type, + original_type_name, + override_type, + override_type_name, + full_inst_path)) + return; + m_inst_overrides.push_back(override); +endfunction +function void uvm_default_factory::set_type_alias(string alias_type_name, + uvm_object_wrapper original_type); + if (!is_type_registered(original_type)) + uvm_report_warning("BDTYP",{"Cannot define alias of type '", + original_type.get_type_name(),"' because it is not registered with the factory."}, UVM_NONE); + else begin + if (!m_type_names.exists(alias_type_name)) begin + uvm_factory_override overrides[$]; + m_type_names[alias_type_name] = original_type; + overrides = {m_type_overrides, m_inst_overrides}; + foreach (overrides[index]) begin + if(m_matches_type_pair(.match_type_pair(overrides[index].orig), + .requested_type(null), + .requested_type_name(alias_type_name))) begin + overrides[index].orig.m_type = original_type; + end + if(m_matches_type_pair(.match_type_pair(overrides[index].ovrd), + .requested_type(null), + .requested_type_name(alias_type_name))) begin + overrides[index].ovrd.m_type = original_type; + end + end + end + end +endfunction +function void uvm_default_factory::set_inst_alias(string alias_type_name, + uvm_object_wrapper original_type, string full_inst_path); + string original_type_name; + m_inst_typename_alias_t orig_type_alias_per_inst; + original_type_name = original_type.get_type_name(); + if (!is_type_registered(original_type)) + uvm_report_warning("BDTYP",{"Cannot define alias of type '", + original_type_name,"' because it is not registered with the factory."}, UVM_NONE); + else begin + orig_type_alias_per_inst.alias_type_name = alias_type_name; + orig_type_alias_per_inst.full_inst_path = full_inst_path; + orig_type_alias_per_inst.orig.m_type_name = original_type_name; + orig_type_alias_per_inst.orig.m_type = original_type; + m_inst_aliases.push_back(orig_type_alias_per_inst); + end +endfunction +function uvm_object uvm_default_factory::create_object_by_name (string requested_type_name, + string parent_inst_path="", + string name=""); + uvm_object_wrapper wrapper; + string inst_path; + if (parent_inst_path == "") + inst_path = name; + else if (name != "") + inst_path = {parent_inst_path,".",name}; + else + inst_path = parent_inst_path; + m_override_info.delete(); + wrapper = find_override_by_name(requested_type_name, inst_path); + if (wrapper==null) begin + wrapper = m_resolve_type_name_by_inst(requested_type_name,inst_path); + if(wrapper == null) begin + uvm_report_warning("BDTYP",{"Cannot create an object of type '", + requested_type_name,"' because it is not registered with the factory."}, UVM_NONE); + return null; + end + end + return wrapper.create_object(name); +endfunction +function uvm_object uvm_default_factory::create_object_by_type (uvm_object_wrapper requested_type, + string parent_inst_path="", + string name=""); + string full_inst_path; + if (parent_inst_path == "") + full_inst_path = name; + else if (name != "") + full_inst_path = {parent_inst_path,".",name}; + else + full_inst_path = parent_inst_path; + m_override_info.delete(); + requested_type = find_override_by_type(requested_type, full_inst_path); + return requested_type.create_object(name); +endfunction +function bit uvm_default_factory::is_type_name_registered (string type_name); + return (m_type_names.exists(type_name)); +endfunction +function bit uvm_default_factory::is_type_registered (uvm_object_wrapper obj); + return (m_types.exists(obj)); +endfunction +function uvm_component uvm_default_factory::create_component_by_name (string requested_type_name, + string parent_inst_path="", + string name, + uvm_component parent); + uvm_object_wrapper wrapper; + string inst_path; + if (parent_inst_path == "") + inst_path = name; + else if (name != "") + inst_path = {parent_inst_path,".",name}; + else + inst_path = parent_inst_path; + m_override_info.delete(); + wrapper = find_override_by_name(requested_type_name, inst_path); + if (wrapper == null) begin + if(!m_type_names.exists(requested_type_name)) begin + uvm_report_warning("BDTYP",{"Cannot create a component of type '", + requested_type_name,"' because it is not registered with the factory."}, UVM_NONE); + return null; + end + wrapper = m_type_names[requested_type_name]; + end + return wrapper.create_component(name, parent); +endfunction +function uvm_component uvm_default_factory::create_component_by_type (uvm_object_wrapper requested_type, + string parent_inst_path="", + string name, + uvm_component parent); + string full_inst_path; + if (parent_inst_path == "") + full_inst_path = name; + else if (name != "") + full_inst_path = {parent_inst_path,".",name}; + else + full_inst_path = parent_inst_path; + m_override_info.delete(); + requested_type = find_override_by_type(requested_type, full_inst_path); + return requested_type.create_component(name, parent); +endfunction +function uvm_object_wrapper uvm_default_factory::find_wrapper_by_name(string type_name); + uvm_object_wrapper wrapper = m_resolve_type_name(type_name); + if (wrapper != null) + return wrapper; + uvm_report_warning("UnknownTypeName", {"find_wrapper_by_name: Type name '",type_name, + "' not registered with the factory."}, UVM_NONE); +endfunction +function uvm_object_wrapper uvm_default_factory::find_override_by_name (string requested_type_name, + string full_inst_path); + uvm_object_wrapper rtype; + uvm_factory_override lindex; + rtype = m_resolve_type_name_by_inst(requested_type_name,full_inst_path); + if(full_inst_path != "") + begin + foreach(m_inst_overrides[i]) begin + if(m_matches_inst_override(.override(m_inst_overrides[i]), + .requested_type(rtype), + .requested_type_name(requested_type_name), + .full_inst_path(full_inst_path))) begin + m_override_info.push_back(m_inst_overrides[i]); + if (lindex == null) begin + lindex = m_inst_overrides[i]; + if (!m_debug_pass) begin + break; + end + end + end + end + end + if ((lindex == null) || m_debug_pass) begin + uvm_factory_override matched_overrides[$]; + foreach (m_type_overrides[index]) begin + if(m_matches_type_override(.override(m_type_overrides[index]), + .requested_type(rtype), + .requested_type_name(requested_type_name), + .full_inst_path(full_inst_path), + .resolve_null_type_by_inst(1))) begin + matched_overrides.push_back(m_type_overrides[index]); + if ((lindex == null) || (lindex.replace == 0)) begin + lindex = m_type_overrides[index]; + if (!m_debug_pass && lindex.replace) begin + break; + end + end + end + end + if(matched_overrides.size() != 0) begin + if (m_debug_pass) begin + m_override_info = {m_override_info,matched_overrides}; + end + else begin + m_override_info.push_back(matched_overrides[$]); + end + end + end + if (lindex != null) begin + uvm_object_wrapper override = lindex.ovrd.m_type; + lindex.used++; + if (m_debug_pass) begin + lindex.selected = 1; + end + if(!m_matches_type_override(.override(lindex), + .requested_type(rtype), + .requested_type_name(requested_type_name), + .full_inst_path(full_inst_path), + .match_original_type(0), + .resolve_null_type_by_inst(1))) begin + if(override == null) begin + override = find_override_by_name(lindex.ovrd.m_type_name,full_inst_path); + end + else begin + override = find_override_by_type(override,full_inst_path); + end + end + else if(override == null) begin + override = m_resolve_type_name_by_inst(lindex.ovrd.m_type_name,full_inst_path); + end + if(override == null) begin + uvm_report_error("TYPNTF", {"Cannot resolve override for original type '", + lindex.orig.m_type_name,"' because the override type '", + lindex.ovrd.m_type_name, "' is not registered with the factory."}, UVM_NONE); + end + return override; + end + return null; +endfunction +function uvm_object_wrapper uvm_default_factory::find_override_by_type(uvm_object_wrapper requested_type, + string full_inst_path); + uvm_object_wrapper override; + uvm_factory_override lindex; + uvm_factory_queue_class qc; + foreach (m_override_info[index]) begin + if ( + m_override_info[index].orig.m_type == requested_type) begin + uvm_report_error("OVRDLOOP", "Recursive loop detected while finding override.", UVM_NONE); + m_override_info[index].used++; + if (!m_debug_pass) + debug_create_by_type (requested_type, full_inst_path); + return requested_type; + end + end + if(full_inst_path != "") + begin + foreach(m_inst_overrides[i]) begin + if(m_matches_inst_override(.override(m_inst_overrides[i]), + .requested_type(requested_type), + .requested_type_name(requested_type.get_type_name()), + .full_inst_path(full_inst_path))) begin + m_override_info.push_back(m_inst_overrides[i]); + if (lindex == null) begin + lindex = m_inst_overrides[i]; + if (!m_debug_pass) begin + break; + end + end + end + end + end + if ((lindex == null) || m_debug_pass) begin + uvm_factory_override matched_overrides[$]; + foreach (m_type_overrides[index]) begin + if(m_matches_type_override(.override(m_type_overrides[index]), + .requested_type(requested_type), + .requested_type_name(requested_type.get_type_name()), + .full_inst_path(full_inst_path), + .resolve_null_type_by_inst(1))) begin + matched_overrides.push_back(m_type_overrides[index]); + if ((lindex == null) || (lindex.replace == 0)) begin + lindex = m_type_overrides[index]; + if (!m_debug_pass && lindex.replace) begin + break; + end + end + end + end + if(matched_overrides.size() != 0) begin + if (m_debug_pass) begin + m_override_info = {m_override_info,matched_overrides}; + end + else begin + m_override_info.push_back(matched_overrides[$]); + end + end + end + if (lindex != null) begin + uvm_object_wrapper override = lindex.ovrd.m_type; + lindex.used++; + if (m_debug_pass) begin + lindex.selected = 1; + end + if(!m_matches_type_override(.override(lindex), + .requested_type(requested_type), + .requested_type_name(requested_type.get_type_name()), + .full_inst_path(full_inst_path), + .match_original_type(0), + .resolve_null_type_by_inst(1))) begin + if(override == null) begin + override = find_override_by_name(lindex.ovrd.m_type_name,full_inst_path); + end + else begin + override = find_override_by_type(override,full_inst_path); + end + end + else if(override == null) begin + override = m_resolve_type_name_by_inst(lindex.ovrd.m_type_name,full_inst_path); + end + if(override == null) begin + uvm_report_error("TYPNTF", {"Cannot resolve override for original type '", + lindex.orig.m_type_name,"' because the override type '", + lindex.ovrd.m_type_name, "' is not registered with the factory."}, UVM_NONE); + end + return override; + end + return requested_type; +endfunction +function void uvm_default_factory::print (int all_types=1); + string key; + string qs[$]; + qs.push_back("\n#### Factory Configuration (*)\n\n"); + if(!m_type_overrides.size() && !m_inst_overrides.size()) + qs.push_back(" No instance or type overrides are registered with this factory\n"); + else begin + int max1,max2,max3; + string dash = "---------------------------------------------------------------------------------------------------"; + string space= " "; + if(!m_inst_overrides.size()) + qs.push_back("No instance overrides are registered with this factory\n"); + else begin + foreach(m_inst_overrides[j]) begin + if (m_inst_overrides[j].orig.m_type_name.len() > max1) + max1=m_inst_overrides[j].orig.m_type_name.len(); + if (m_inst_overrides[j].full_inst_path.len() > max2) + max2=m_inst_overrides[j].full_inst_path.len(); + if (m_inst_overrides[j].ovrd.m_type_name.len() > max3) + max3=m_inst_overrides[j].ovrd.m_type_name.len(); + end + if (max1 < 14) max1 = 14; + if (max2 < 13) max2 = 13; + if (max3 < 13) max3 = 13; + qs.push_back("Instance Overrides:\n\n"); + qs.push_back($sformatf(" %0s%0s %0s%0s %0s%0s\n","Requested Type",space.substr(1,max1-14), + "Override Path", space.substr(1,max2-13), + "Override Type", space.substr(1,max3-13))); + qs.push_back($sformatf(" %0s %0s %0s\n",dash.substr(1,max1), + dash.substr(1,max2), + dash.substr(1,max3))); + foreach(m_inst_overrides[j]) begin + qs.push_back($sformatf(" %0s%0s %0s%0s",m_inst_overrides[j].orig.m_type_name, + space.substr(1,max1-m_inst_overrides[j].orig.m_type_name.len()), + m_inst_overrides[j].full_inst_path, + space.substr(1,max2-m_inst_overrides[j].full_inst_path.len()))); + qs.push_back($sformatf(" %0s\n", m_inst_overrides[j].ovrd.m_type_name)); + end + end + if (!m_type_overrides.size()) + qs.push_back("\nNo type overrides are registered with this factory\n"); + else begin + if (max1 < 14) max1 = 14; + if (max2 < 13) max2 = 13; + if (max3 < 13) max3 = 13; + foreach (m_type_overrides[i]) begin + if (m_type_overrides[i].orig.m_type_name.len() > max1) + max1=m_type_overrides[i].orig.m_type_name.len(); + if (m_type_overrides[i].ovrd.m_type_name.len() > max2) + max2=m_type_overrides[i].ovrd.m_type_name.len(); + end + if (max1 < 14) max1 = 14; + if (max2 < 13) max2 = 13; + qs.push_back("\nType Overrides:\n\n"); + qs.push_back($sformatf(" %0s%0s %0s%0s\n","Requested Type",space.substr(1,max1-14), + "Override Type", space.substr(1,max2-13))); + qs.push_back($sformatf(" %0s %0s\n",dash.substr(1,max1), + dash.substr(1,max2))); + for (int index=m_type_overrides.size()-1; index>=0; index--) + qs.push_back($sformatf(" %0s%0s %0s\n", + m_type_overrides[index].orig.m_type_name, + space.substr(1,max1-m_type_overrides[index].orig.m_type_name.len()), + m_type_overrides[index].ovrd.m_type_name)); + end + end + if (all_types >= 1 && m_type_names.first(key)) begin + bit banner; + qs.push_back($sformatf("\nAll types registered with the factory: %0d total\n",m_types.num())); + do begin + if (!(all_types < 2 && uvm_is_match("uvm_*", + m_type_names[key].get_type_name())) && + key == m_type_names[key].get_type_name()) begin + if (!banner) begin + qs.push_back(" Type Name\n"); + qs.push_back(" ---------\n"); + banner=1; + end + qs.push_back($sformatf(" %s\n", m_type_names[key].get_type_name())); + end + end while(m_type_names.next(key)); + end + qs.push_back("(*) Types with no associated type name will be printed as \n\n####\n\n"); + begin + if (uvm_report_enabled(UVM_NONE,UVM_INFO,"UVM/FACTORY/PRINT")) + uvm_report_info ("UVM/FACTORY/PRINT", uvm_pkg::m_uvm_string_queue_join(qs), UVM_NONE, "t/uvm/src/base/uvm_factory.svh", 1875, "", 1); + end +endfunction +function void uvm_default_factory::debug_create_by_name (string requested_type_name, + string parent_inst_path="", + string name=""); + m_debug_create(requested_type_name, null, parent_inst_path, name); +endfunction +function void uvm_default_factory::debug_create_by_type (uvm_object_wrapper requested_type, + string parent_inst_path="", + string name=""); + m_debug_create("", requested_type, parent_inst_path, name); +endfunction +function void uvm_default_factory::m_debug_create (string requested_type_name, + uvm_object_wrapper requested_type, + string parent_inst_path, + string name); + string full_inst_path; + uvm_object_wrapper result; + if (parent_inst_path == "") + full_inst_path = name; + else if (name != "") + full_inst_path = {parent_inst_path,".",name}; + else + full_inst_path = parent_inst_path; + m_override_info.delete(); + if (requested_type == null) begin + if (!m_type_names.exists(requested_type_name) && + !m_lookup_strs.exists(requested_type_name)) begin + uvm_report_warning("Factory Warning", {"The factory does not recognize '", + requested_type_name,"' as a registered type."}, UVM_NONE); + return; + end + m_debug_pass = 1; + result = find_override_by_name(requested_type_name,full_inst_path); + end + else begin + m_debug_pass = 1; + if (!m_types.exists(requested_type)) + register(requested_type); + result = find_override_by_type(requested_type,full_inst_path); + if (requested_type_name == "") + requested_type_name = requested_type.get_type_name(); + end + m_debug_display(requested_type_name, result, full_inst_path); + m_debug_pass = 0; + foreach (m_override_info[index]) + m_override_info[index].selected = 0; +endfunction +function void uvm_default_factory::m_debug_display (string requested_type_name, + uvm_object_wrapper result, + string full_inst_path); + int max1,max2,max3; + string dash = "---------------------------------------------------------------------------------------------------"; + string space= " "; + string qs[$]; + qs.push_back("\n#### Factory Override Information (*)\n\n"); + qs.push_back( + $sformatf("Given a request for an object of type '%s' with an instance\npath of '%s' the factory encountered\n\n", + requested_type_name,full_inst_path)); + if (m_override_info.size() == 0) + qs.push_back("no relevant overrides.\n\n"); + else begin + qs.push_back("the following relevant overrides. An 'x' next to a match indicates a\nmatch that was ignored.\n\n"); + foreach (m_override_info[i]) begin + if (m_override_info[i].orig.m_type_name.len() > max1) + max1=m_override_info[i].orig.m_type_name.len(); + if (m_override_info[i].full_inst_path.len() > max2) + max2=m_override_info[i].full_inst_path.len(); + if (m_override_info[i].ovrd.m_type_name.len() > max3) + max3=m_override_info[i].ovrd.m_type_name.len(); + end + if (max1 < 13) max1 = 13; + if (max2 < 13) max2 = 13; + if (max3 < 13) max3 = 13; + qs.push_back($sformatf("Original Type%0s Instance Path%0s Override Type%0s\n", + space.substr(1,max1-13),space.substr(1,max2-13),space.substr(1,max3-13))); + qs.push_back($sformatf(" %0s %0s %0s\n",dash.substr(1,max1), + dash.substr(1,max2), + dash.substr(1,max3))); + foreach (m_override_info[i]) begin + qs.push_back($sformatf("%s%0s%0s\n", + m_override_info[i].selected ? " " : "x ", + m_override_info[i].orig.m_type_name, + space.substr(1,max1-m_override_info[i].orig.m_type_name.len()))); + qs.push_back($sformatf(" %0s%0s", m_override_info[i].full_inst_path, + space.substr(1,max2-m_override_info[i].full_inst_path.len()))); + qs.push_back($sformatf(" %0s%0s", m_override_info[i].ovrd.m_type_name, + space.substr(1,max3-m_override_info[i].ovrd.m_type_name.len()))); + if (m_override_info[i].full_inst_path == "*") + qs.push_back(" "); + else + qs.push_back("\n"); + end + qs.push_back("\n"); + end + qs.push_back("Result:\n\n"); + qs.push_back($sformatf(" The factory will produce an object of type '%0s'\n", + result == null ? requested_type_name : result.get_type_name())); + qs.push_back("\n(*) Types with no associated type name will be printed as \n\n####\n\n"); + begin + if (uvm_report_enabled(UVM_NONE,UVM_INFO,"UVM/FACTORY/DUMP")) + uvm_report_info ("UVM/FACTORY/DUMP", uvm_pkg::m_uvm_string_queue_join(qs), UVM_NONE, "t/uvm/src/base/uvm_factory.svh", 2015, "", 1); + end +endfunction +function uvm_object_wrapper uvm_default_factory::m_resolve_type_name(string requested_type_name); + uvm_object_wrapper wrapper=null; + if(m_type_names.exists(requested_type_name)) + wrapper = m_type_names[requested_type_name]; + return wrapper; +endfunction +function uvm_object_wrapper uvm_default_factory::m_resolve_type_name_by_inst(string requested_type_name, + string full_inst_path); + uvm_object_wrapper wrapper=null; + m_inst_typename_alias_t type_alias_inst[$]; + type_alias_inst = m_inst_aliases.find(i) with ((i.alias_type_name == requested_type_name) && uvm_is_match(i.full_inst_path,full_inst_path)); + if (type_alias_inst.size() > 0) begin + wrapper = type_alias_inst[0].orig.m_type; + end + else begin + wrapper = m_resolve_type_name(requested_type_name); + end + return wrapper; +endfunction +function bit uvm_default_factory::m_matches_type_pair(m_uvm_factory_type_pair_t match_type_pair, + uvm_object_wrapper requested_type, + string requested_type_name); + return ((match_type_pair.m_type != null) && + (match_type_pair.m_type == requested_type) || + (match_type_pair.m_type_name != "" && + match_type_pair.m_type_name != "" && + match_type_pair.m_type_name == requested_type_name)); +endfunction +function bit uvm_default_factory::m_matches_inst_override(uvm_factory_override override, + uvm_object_wrapper requested_type, + string requested_type_name, + string full_inst_path=""); + m_uvm_factory_type_pair_t match_type_pair = override.orig ; + if(match_type_pair.m_type == null) begin + match_type_pair.m_type = m_resolve_type_name_by_inst(match_type_pair.m_type_name, full_inst_path); + end + if (m_matches_type_pair(.match_type_pair(match_type_pair), + .requested_type(requested_type), + .requested_type_name(requested_type_name))) begin + if(override.has_wildcard) begin + return (override.full_inst_path == "*" || + uvm_is_match(override.full_inst_path,full_inst_path)); + end + else begin + return (override.full_inst_path == full_inst_path); + end + end + return 0; +endfunction +function bit uvm_default_factory::m_matches_type_override(uvm_factory_override override, + uvm_object_wrapper requested_type, + string requested_type_name, + string full_inst_path="", + bit match_original_type = 1, + bit resolve_null_type_by_inst=0); + m_uvm_factory_type_pair_t match_type_pair = match_original_type ? override.orig : override.ovrd; + if(match_type_pair.m_type == null) begin + if(resolve_null_type_by_inst) begin + match_type_pair.m_type = m_resolve_type_name_by_inst(match_type_pair.m_type_name,full_inst_path); + end + else begin + match_type_pair.m_type = m_resolve_type_name(match_type_pair.m_type_name); + end + end + return m_matches_type_pair(.match_type_pair(match_type_pair), + .requested_type(requested_type), + .requested_type_name(requested_type_name)); +endfunction +typedef class uvm_registry_common; +typedef class uvm_registry_component_creator; +typedef class uvm_registry_object_creator; +class uvm_component_registry #(type T=uvm_component, string Tname="") + extends uvm_object_wrapper; + typedef uvm_component_registry #(T,Tname) this_type; + typedef uvm_registry_common#( this_type, uvm_registry_component_creator, T, Tname ) common_type; + virtual function uvm_component create_component (string name, + uvm_component parent); + T obj; + obj = new(name, parent); + return obj; + endfunction + static function string type_name(); + return common_type::type_name(); + endfunction : type_name + virtual function string get_type_name(); + common_type common = common_type::get(); + return common.get_type_name(); + endfunction + static function this_type get(); + static this_type m_inst; + if (m_inst == null) + m_inst = new(); + return m_inst; + endfunction + virtual function void initialize(); + common_type common = common_type::get(); + common.initialize(); + endfunction + static function T create(string name, uvm_component parent, string contxt=""); + return common_type::create( name, parent, contxt ); + endfunction + static function void set_type_override (uvm_object_wrapper override_type, + bit replace=1); + common_type::set_type_override( override_type, replace ); + endfunction + static function void set_inst_override(uvm_object_wrapper override_type, + string inst_path, + uvm_component parent=null); + common_type::set_inst_override( override_type, inst_path, parent ); + endfunction + static function bit set_type_alias(string alias_name); + common_type::set_type_alias( alias_name ); + return 1; + endfunction +endclass +class uvm_object_registry #(type T=uvm_object, string Tname="") + extends uvm_object_wrapper; + typedef uvm_object_registry #(T,Tname) this_type; + typedef uvm_registry_common#( this_type, uvm_registry_object_creator, T, Tname ) common_type; + virtual function uvm_object create_object(string name=""); + T obj; + if (name=="") obj = new(); + else obj = new(name); + return obj; + endfunction + static function string type_name(); + return common_type::type_name(); + endfunction : type_name + virtual function string get_type_name(); + common_type common = common_type::get(); + return common.get_type_name(); + endfunction + static function this_type get(); + static this_type m_inst; + if (m_inst == null) + m_inst = new(); + return m_inst; + endfunction + static function T create (string name="", uvm_component parent=null, + string contxt=""); + return common_type::create( name, parent, contxt ); + endfunction + static function void set_type_override (uvm_object_wrapper override_type, + bit replace=1); + common_type::set_type_override( override_type, replace ); + endfunction + static function void set_inst_override(uvm_object_wrapper override_type, + string inst_path, + uvm_component parent=null); + common_type::set_inst_override( override_type, inst_path, parent ); + endfunction + static function bit set_type_alias(string alias_name); + common_type::set_type_alias( alias_name ); + return 1; + endfunction + virtual function void initialize(); + common_type common = common_type::get(); + common.initialize(); + endfunction +endclass +class uvm_abstract_component_registry #(type T=uvm_component, string Tname="") + extends uvm_object_wrapper; + typedef uvm_abstract_component_registry #(T,Tname) this_type; + typedef uvm_registry_common#( this_type, uvm_registry_component_creator, T, Tname ) common_type; + virtual function uvm_component create_component (string name, + uvm_component parent); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/ABST_RGTRY/CREATE_ABSTRACT_CMPNT")) + uvm_report_error ("UVM/ABST_RGTRY/CREATE_ABSTRACT_CMPNT", $sformatf( "Cannot create an instance of abstract class %s (with name %s and parent %s). Check for missing factory overrides for %s.", this.get_type_name(), name, parent.get_full_name(), this.get_type_name() ), UVM_NONE, "t/uvm/src/base/uvm_registry.svh", 308, "", 1); + end + return null; + endfunction + static function string type_name(); + return common_type::type_name(); + endfunction : type_name + virtual function string get_type_name(); + common_type common = common_type::get(); + return common.get_type_name(); + endfunction + static function this_type get(); + static this_type m_inst; + if (m_inst == null) + m_inst = new(); + return m_inst; + endfunction + static function T create(string name, uvm_component parent, string contxt=""); + return common_type::create( name, parent, contxt ); + endfunction + static function void set_type_override (uvm_object_wrapper override_type, + bit replace=1); + common_type::set_type_override( override_type, replace ); + endfunction + static function void set_inst_override(uvm_object_wrapper override_type, + string inst_path, + uvm_component parent=null); + common_type::set_inst_override( override_type, inst_path, parent ); + endfunction + static function bit set_type_alias(string alias_name); + common_type::set_type_alias( alias_name ); + return 1; + endfunction + virtual function void initialize(); + common_type common = common_type::get(); + common.initialize(); + endfunction +endclass +class uvm_abstract_object_registry #(type T=uvm_object, string Tname="") + extends uvm_object_wrapper; + typedef uvm_abstract_object_registry #(T,Tname) this_type; + typedef uvm_registry_common#( this_type, uvm_registry_object_creator, T, Tname ) common_type; + virtual function uvm_object create_object(string name=""); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/ABST_RGTRY/CREATE_ABSTRACT_OBJ")) + uvm_report_error ("UVM/ABST_RGTRY/CREATE_ABSTRACT_OBJ", $sformatf( "Cannot create an instance of abstract class %s (with name %s). Check for missing factory overrides for %s.", this.get_type_name(), name, this.get_type_name() ), UVM_NONE, "t/uvm/src/base/uvm_registry.svh", 428, "", 1); + end + return null; + endfunction + static function string type_name(); + return common_type::type_name(); + endfunction : type_name + virtual function string get_type_name(); + common_type common = common_type::get(); + return common.get_type_name(); + endfunction + static function this_type get(); + static this_type m_inst; + if (m_inst == null) + m_inst = new(); + return m_inst; + endfunction + static function T create (string name="", uvm_component parent=null, + string contxt=""); + return common_type::create( name, parent, contxt ); + endfunction + static function void set_type_override (uvm_object_wrapper override_type, + bit replace=1); + common_type::set_type_override( override_type, replace ); + endfunction + static function void set_inst_override(uvm_object_wrapper override_type, + string inst_path, + uvm_component parent=null); + common_type::set_inst_override( override_type, inst_path, parent ); + endfunction + static function bit set_type_alias(string alias_name); + common_type::set_type_alias( alias_name ); + return 1; + endfunction + virtual function void initialize(); + common_type common = common_type::get(); + common.initialize(); + endfunction +endclass +class uvm_registry_common #( type Tregistry=int, type Tcreator=int, type Tcreated=int, string Tname="" ); + typedef uvm_registry_common#(Tregistry,Tcreator,Tcreated,Tname) this_type; + local static string m__type_aliases[$]; + static function string type_name(); + if((Tname == "") && (m__type_aliases.size() != 0)) begin + return m__type_aliases[0]; + end + return Tname; + endfunction : type_name + virtual function string get_type_name(); + return type_name(); + endfunction + static function this_type get(); + static this_type m_inst; + if (m_inst == null) + m_inst = new(); + return m_inst; + endfunction : get + static function Tcreated create(string name, uvm_component parent, string contxt); + uvm_object obj; + if (contxt == "" && parent != null) + contxt = parent.get_full_name(); + obj = Tcreator::create_by_type( Tregistry::get(), contxt, name, parent ); + if (!$cast(create, obj)) begin + string msg; + msg = {"Factory did not return a ", Tcreator::base_type_name(), " of type '",Tregistry::type_name, + "'. A component of type '",obj == null ? "null" : obj.get_type_name(), + "' was returned instead. Name=",name," Parent=", + parent==null?"null":parent.get_type_name()," contxt=",contxt}; + uvm_report_fatal("FCTTYP", msg, UVM_NONE); + end + endfunction + static function void set_type_override (uvm_object_wrapper override_type, + bit replace); + uvm_factory factory=uvm_factory::get(); + factory.set_type_override_by_type(Tregistry::get(),override_type,replace); + endfunction + static function void set_inst_override(uvm_object_wrapper override_type, + string inst_path, + uvm_component parent); + string full_inst_path; + uvm_factory factory=uvm_factory::get(); + if (parent != null) begin + if (inst_path == "") + inst_path = parent.get_full_name(); + else + inst_path = {parent.get_full_name(),".",inst_path}; + end + factory.set_inst_override_by_type(Tregistry::get(),override_type,inst_path); + endfunction + static function void set_type_alias(string alias_name); + m__type_aliases.push_back(alias_name); + m__type_aliases.sort(); + if (uvm_pkg::get_core_state() != UVM_CORE_UNINITIALIZED) begin + uvm_factory factory = uvm_factory::get(); + Tregistry rgtry = Tregistry::get(); + if (factory.is_type_registered(rgtry)) begin + factory.set_type_alias(alias_name,rgtry); + end + end + endfunction + static function bit __deferred_init(); + Tregistry rgtry = Tregistry::get(); + if (uvm_pkg::get_core_state() == UVM_CORE_UNINITIALIZED) begin + uvm_pkg::uvm_deferred_init.push_back(rgtry); + end + else begin + rgtry.initialize(); + end + return 1; + endfunction + local static bit m__initialized=__deferred_init(); + virtual function void initialize(); + uvm_factory factory =uvm_factory::get(); + Tregistry rgtry = Tregistry::get(); + factory.register(rgtry); + foreach(m__type_aliases[i]) begin + factory.set_type_alias(m__type_aliases[i],rgtry); + end + endfunction +endclass +virtual class uvm_registry_component_creator; + static function uvm_component create_by_type( + uvm_object_wrapper obj_wrpr, + string contxt, + string name, + uvm_component parent + ); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory = cs.get_factory(); + return factory.create_component_by_type( obj_wrpr, contxt, name, parent ); + endfunction + static function string base_type_name(); return "component"; endfunction +endclass +virtual class uvm_registry_object_creator; + static function uvm_object create_by_type( + uvm_object_wrapper obj_wrpr, + string contxt, + string name, + uvm_object unused + ); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory = cs.get_factory(); + unused = unused; + return factory.create_object_by_type( obj_wrpr, contxt, name ); + endfunction + static function string base_type_name(); return "object"; endfunction +endclass +class uvm_pool #(type KEY=int, T=uvm_void) extends uvm_object; + typedef uvm_pool #(KEY,T) this_type; + static protected this_type m_global_pool; + protected T pool[KEY]; + typedef uvm_object_registry #(uvm_pool #(KEY,T)) type_id; + static function uvm_pool #(KEY,T) type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_pool #(KEY,T) tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_pool"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_pool"; + endfunction : get_type_name + function new (string name=""); + super.new(name); + endfunction + static function this_type get_global_pool (); + if (m_global_pool==null) + m_global_pool = new("pool"); + return m_global_pool; + endfunction + static function T get_global (KEY key); + this_type gpool; + gpool = get_global_pool(); + return gpool.get(key); + endfunction + virtual function T get (KEY key); + if (!pool.exists(key)) begin + T default_value; + pool[key] = default_value; + end + return pool[key]; + endfunction + virtual function void add (KEY key, T item); + pool[key] = item; + endfunction + virtual function int num (); + return pool.num(); + endfunction + virtual function void delete (KEY key); + if (!exists(key)) begin + uvm_report_warning("POOLDEL", + $sformatf("delete: pool key doesn't exist. Ignoring delete request")); + return; + end + pool.delete(key); + endfunction + virtual function int exists (KEY key); + return pool.exists(key); + endfunction + virtual function int first (ref KEY key); + return pool.first(key); + endfunction + virtual function int last (ref KEY key); + return pool.last(key); + endfunction + virtual function int next (ref KEY key); + return pool.next(key); + endfunction + virtual function int prev (ref KEY key); + return pool.prev(key); + endfunction + virtual function void do_copy (uvm_object rhs); + this_type p; + KEY key; + super.do_copy(rhs); + if (rhs==null || !$cast(p, rhs)) + return; + pool = p.pool; + endfunction + virtual function void do_print (uvm_printer printer); + string v; + int cnt; + string item; + KEY key; + printer.print_array_header("pool",pool.num(),"aa_object_string"); + if (pool.first(key)) + do begin + item.itoa(cnt); + item = {"[-key",item,"--]"}; + $swrite(v,pool[key]); + printer.print_generic(item,"",-1,v,"["); + end + while (pool.next(key)); + printer.print_array_footer(); + endfunction +endclass +class uvm_object_string_pool #(type T=uvm_object) extends uvm_pool #(string,T); + typedef uvm_object_string_pool #(T) this_type; + static protected this_type m_global_pool; + typedef uvm_object_registry #(uvm_object_string_pool#(T)) type_id; + static function uvm_object_string_pool#(T) type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_object_string_pool#(T) tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_obj_str_pool"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_obj_str_pool"; + endfunction : get_type_name + function new (string name=""); + super.new(name); + endfunction + static function this_type get_global_pool (); + if (m_global_pool==null) + m_global_pool = new("global_pool"); + return m_global_pool; + endfunction + static function T get_global (string key); + this_type gpool; + gpool = get_global_pool(); + return gpool.get(key); + endfunction + virtual function T get (string key); + if (!pool.exists(key)) + pool[key] = new (key); + return pool[key]; + endfunction + virtual function void delete (string key); + if (!exists(key)) begin + uvm_report_warning("POOLDEL", + $sformatf("delete: key '%s' doesn't exist", key)); + return; + end + pool.delete(key); + endfunction + virtual function void do_print (uvm_printer printer); + string key; + printer.print_array_header("pool",pool.num(),"aa_object_string"); + if (pool.first(key)) + do + printer.print_object({"[",key,"]"}, pool[key],"["); + while (pool.next(key)); + printer.print_array_footer(); + endfunction +endclass +typedef class uvm_barrier; +typedef class uvm_event; +typedef uvm_object_string_pool #(uvm_barrier) uvm_barrier_pool ; +typedef uvm_object_string_pool #(uvm_event#(uvm_object)) uvm_event_pool ; +class uvm_queue #(type T=int) extends uvm_object; + typedef uvm_queue #(T) this_type; + typedef uvm_object_registry #(uvm_queue#(T)) type_id; + static function uvm_queue#(T) type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_queue#(T) tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_queue"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_queue"; + endfunction : get_type_name + static local this_type m_global_queue; + protected T queue[$]; + function new (string name=""); + super.new(name); + endfunction + static function this_type get_global_queue (); + if (m_global_queue==null) + m_global_queue = new("global_queue"); + return m_global_queue; + endfunction + static function T get_global (int index); + this_type gqueue; + gqueue = get_global_queue(); + return gqueue.get(index); + endfunction + virtual function T get (int index); + T default_value; + if (index >= size() || index < 0) begin + uvm_report_warning("QUEUEGET", + $sformatf("get: given index out of range for queue of size %0d. Ignoring get request",size())); + return default_value; + end + return queue[index]; + endfunction + virtual function int size (); + return queue.size(); + endfunction + virtual function void insert (int index, T item); + if (index >= size() || index < 0) begin + uvm_report_warning("QUEUEINS", + $sformatf("insert: given index out of range for queue of size %0d. Ignoring insert request",size())); + return; + end + queue.insert(index,item); + endfunction + virtual function void delete (int index=-1); + if (index >= size() || index < -1) begin + uvm_report_warning("QUEUEDEL", + $sformatf("delete: given index out of range for queue of size %0d. Ignoring delete request",size())); + return; + end + if (index == -1) + queue.delete(); + else + queue.delete(index); + endfunction + virtual function T pop_front(); + return queue.pop_front(); + endfunction + virtual function T pop_back(); + return queue.pop_back(); + endfunction + virtual function void push_front(T item); + queue.push_front(item); + endfunction + virtual function void push_back(T item); + queue.push_back(item); + endfunction + virtual task wait_until_not_empty(); + wait(queue.size() > 0); + endtask + virtual function void do_copy (uvm_object rhs); + this_type p; + super.do_copy(rhs); + if (rhs == null || !$cast(p, rhs)) + return; + queue = p.queue; + endfunction + virtual function string convert2string(); + return $sformatf("%p",queue); + endfunction +endclass +class uvm_spell_chkr #(type T=int); + typedef T tab_t[string]; + static const int unsigned max = '1; + static function bit check ( ref tab_t strtab, input string s); + string key; + int distance; + int unsigned min; + string min_key[$]; + if(strtab.exists(s)) begin + return 1; + end + min = max; + foreach(strtab[key]) begin + distance = levenshtein_distance(key, s); + if(distance < 0) + continue; + if(distance < min) begin + min = distance; + min_key.delete(); + min_key.push_back(key); + continue; + end + if(distance == min) begin + min_key.push_back(key); + end + end + if(min == max) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_INFO,"UVM/CONFIGDB/SPELLCHK")) + uvm_report_info ("UVM/CONFIGDB/SPELLCHK", $sformatf("%s not located, no alternatives to suggest", s), UVM_NONE, "t/uvm/src/base/uvm_spell_chkr.svh", 110, "", 1); + end + end + else + begin + string q[$]; + foreach(min_key[i]) begin + q.push_back(min_key[i]); + q.push_back("|"); + end + if(q.size()) + void'(q.pop_back()); + begin + if (uvm_report_enabled(UVM_NONE,UVM_INFO,"UVM/CONFIGDB/SPELLCHK")) + uvm_report_info ("UVM/CONFIGDB/SPELLCHK", $sformatf("%s not located, did you mean %s", s, uvm_pkg::m_uvm_string_queue_join(q)), UVM_NONE, "t/uvm/src/base/uvm_spell_chkr.svh", 124, "", 1); + end + end + return 0; + endfunction + static local function int levenshtein_distance(string s, string t); + int k, i, j, n, m, cost, distance; + int d[]; + n = s.len() + 1; + m = t.len() + 1; + if(n == 1 || m == 1) + return -1; + d = new[m*n]; + for(k = 0; k < n; k++) + d[k] = k; + for(k = 0; k < m; k++) + d[k*n] = k; + for(i = 1; i < n; i++) begin + for(j = 1; j < m; j++) begin + cost = !(s[i-1] == t[j-1]); + d[j*n+i] = minimum(d[(j-1)*n+i]+1, d[j*n+i-1]+1, d[(j-1)*n+i-1]+cost); + end + end + distance = d[n*m-1]; + return distance; + endfunction + static local function int minimum(int a, int b, int c); + int min = a; + if(b < min) + min = b; + if(c < min) + min = c; + return min; + endfunction +endclass +typedef class uvm_resource_base; +class uvm_resource_types; + typedef bit[1:0] override_t; + typedef enum override_t { TYPE_OVERRIDE = 2'b01, + NAME_OVERRIDE = 2'b10 } override_e; + typedef uvm_queue#(uvm_resource_base) rsrc_q_t; + typedef enum { PRI_HIGH, PRI_LOW } priority_e; + typedef struct + { + time read_time; + time write_time; + int unsigned read_count; + int unsigned write_count; + } access_t; +endclass +class uvm_resource_options; + static local bit auditing = 1; + static function void turn_on_auditing(); + auditing = 1; + endfunction + static function void turn_off_auditing(); + auditing = 0; + endfunction + static function bit is_auditing(); + return auditing; + endfunction +endclass +virtual class uvm_resource_base extends uvm_object; + protected bit modified; + protected bit read_only; + uvm_resource_types::access_t access[string]; + function new(string name = ""); + super.new(name); + modified = 0; + read_only = 0; + endfunction + pure virtual function uvm_resource_base get_type_handle(); + function void set_read_only(); + read_only = 1; + endfunction + function void set_read_write(); + read_only = 0; + endfunction + function bit is_read_only(); + return read_only; + endfunction + task wait_modified(); + wait (modified == 1); + modified = 0; + endtask + function string convert2string(); + return $sformatf("(%s) %s", m_value_type_name(), m_value_as_string()); + endfunction + pure virtual function string m_value_type_name(); + pure virtual function string m_value_as_string(); + function void do_print(uvm_printer printer); + super.do_print(printer); + printer.print_generic_element("val", m_value_type_name(), "", m_value_as_string()); + endfunction : do_print + function void record_read_access(uvm_object accessor = null); + string str; + uvm_resource_types::access_t access_record; + if(!uvm_resource_options::is_auditing()) + return; + if(accessor != null) + str = accessor.get_full_name(); + else + str = ""; + if(access.exists(str)) + access_record = access[str]; + else + init_access_record(access_record); + access_record.read_count++; + access_record.read_time = $realtime; + access[str] = access_record; + endfunction + function void record_write_access(uvm_object accessor = null); + string str; + if(uvm_resource_options::is_auditing()) begin + if(accessor != null) begin + uvm_resource_types::access_t access_record; + string str; + str = accessor.get_full_name(); + if(access.exists(str)) + access_record = access[str]; + else + init_access_record(access_record); + access_record.write_count++; + access_record.write_time = $realtime; + access[str] = access_record; + end + end + endfunction + virtual function void print_accessors(); + string str; + uvm_component comp; + uvm_resource_types::access_t access_record; + string qs[$]; + if(access.num() == 0) + return; + foreach (access[i]) begin + str = i; + access_record = access[str]; + qs.push_back($sformatf("%s reads: %0d @ %0t writes: %0d @ %0t\n",str, + access_record.read_count, + access_record.read_time, + access_record.write_count, + access_record.write_time)); + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_INFO,"UVM/RESOURCE/ACCESSOR")) + uvm_report_info ("UVM/RESOURCE/ACCESSOR", uvm_pkg::m_uvm_string_queue_join(qs), UVM_NONE, "t/uvm/src/base/uvm_resource_base.svh", 532, "", 1); + end + endfunction + function void init_access_record (inout uvm_resource_types::access_t access_record); + access_record.read_time = 0; + access_record.write_time = 0; + access_record.read_count = 0; + access_record.write_count = 0; + endfunction +endclass +class get_t; + string name; + string scope; + uvm_resource_base rsrc; + time t; +endclass +typedef class uvm_tree_printer ; +class uvm_resource_pool; + uvm_resource_types::rsrc_q_t rtab [string]; + uvm_resource_types::rsrc_q_t ttab [uvm_resource_base]; + typedef struct { + string scope ; + int unsigned precedence; + } rsrc_info_t ; + static rsrc_info_t ri_tab [uvm_resource_base]; + get_t get_record [$]; + function new(); + endfunction + static function uvm_resource_pool get(); + uvm_resource_pool t_rp; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + t_rp = cs.get_resource_pool(); + return t_rp; + endfunction + function bit spell_check(string s); + return uvm_spell_chkr#(uvm_resource_types::rsrc_q_t)::check(rtab, s); + endfunction + function void set_scope (uvm_resource_base rsrc, string scope); + uvm_resource_types::rsrc_q_t rq; + string name; + uvm_resource_base type_handle; + uvm_resource_base r; + int unsigned i; + if(rsrc == null) begin + uvm_report_warning("NULLRASRC", "attempting to set scope of a null resource"); + return; + end + name = rsrc.get_name(); + if ((name != "") && rtab.exists(name)) begin + rq = rtab[name]; + for(i = 0; i < rq.size(); i++) begin + r = rq.get(i); + if(r == rsrc) begin + ri_tab[rsrc].scope = uvm_glob_to_re(scope); + return ; + end + end + end + if (rq == null) + rq = new(name); + rq.push_back(rsrc); + rtab[name] = rq; + type_handle = rsrc.get_type_handle(); + if(ttab.exists(type_handle)) + rq = ttab[type_handle]; + else + rq = new(); + rq.push_back(rsrc); + ttab[type_handle] = rq; + ri_tab[rsrc].scope = uvm_glob_to_re(scope); + ri_tab[rsrc].precedence = get_default_precedence(); + endfunction + function void set_override(uvm_resource_base rsrc, string scope = ""); + string s = scope; + set_scope(rsrc, s); + set_priority(rsrc, uvm_resource_types::PRI_HIGH); + endfunction + function void set_name_override(uvm_resource_base rsrc, string scope = ""); + string s = scope; + set_scope(rsrc, s); + set_priority_name(rsrc, uvm_resource_types::PRI_HIGH); + endfunction + function void set_type_override(uvm_resource_base rsrc, string scope = ""); + string s = scope; + set_scope(rsrc, s); + set_priority_type(rsrc, uvm_resource_types::PRI_HIGH); + endfunction + virtual function bit get_scope(uvm_resource_base rsrc, + output string scope); + uvm_resource_types::rsrc_q_t rq; + string name; + uvm_resource_base r; + int unsigned i; + if(rsrc == null) + return 0; + name = rsrc.get_name(); + if((name != "") && rtab.exists(name)) begin + rq = rtab[name]; + for(i = 0; i < rq.size(); i++) begin + r = rq.get(i); + if(r == rsrc) begin + scope = ri_tab[rsrc].scope; + return 1; + end + end + end + scope = ""; + return 0; + endfunction + virtual function void delete ( uvm_resource_base rsrc ); + string name; + uvm_resource_base type_handle; + if (rsrc != null) begin + name = rsrc.get_name(); + if(name != "") begin + if(rtab.exists(name)) + rtab.delete(name); + end + type_handle = rsrc.get_type_handle(); + if(ttab.exists(type_handle)) begin + int q_size = ttab[type_handle].size(); + if (q_size == 1) + ttab.delete(type_handle); + else begin + int i; + for (i=0; i prec) begin + rsrc = r; + prec = c_prec; + end + end + return rsrc; + endfunction + static function void sort_by_precedence(ref uvm_resource_types::rsrc_q_t q); + uvm_resource_types::rsrc_q_t all[int]; + uvm_resource_base r; + int unsigned prec; + for(int i=0; i", scope, null); + return null; + end + rsrc = q.get(0); + push_get_record("", scope, rsrc); + return rsrc; + endfunction + function uvm_resource_types::rsrc_q_t lookup_regex_names(string scope, + string name, + uvm_resource_base type_handle = null); + return lookup_name(scope, name, type_handle, 0); + endfunction + function uvm_resource_types::rsrc_q_t lookup_regex(string re, scope); + uvm_resource_types::rsrc_q_t rq; + uvm_resource_types::rsrc_q_t result_q; + int unsigned i; + uvm_resource_base r; + string s; + result_q = new(); + foreach (rtab[name]) begin + if ( ! uvm_is_match(re, name) ) + continue; + rq = rtab[name]; + for(i = 0; i < rq.size(); i++) begin + r = rq.get(i); + if(ri_tab.exists(r) && uvm_is_match(ri_tab[r].scope, scope)) + result_q.push_back(r); + end + end + return result_q; + endfunction + function uvm_resource_types::rsrc_q_t lookup_scope(string scope); + uvm_resource_types::rsrc_q_t rq; + uvm_resource_base r; + int unsigned i; + int unsigned err; + uvm_resource_types::rsrc_q_t q = new(); + string name; + if(rtab.last(name)) begin + do begin + rq = rtab[name]; + for(int i = 0; i < rq.size(); ++i) begin + r = rq.get(i); + if(ri_tab.exists(r) && uvm_is_match(ri_tab[r].scope, scope)) begin + q.push_back(r); + end + end + end while(rtab.prev(name)); + end + return q; + endfunction + local function void set_priority_queue(uvm_resource_base rsrc, + ref uvm_resource_types::rsrc_q_t q, + uvm_resource_types::priority_e pri); + uvm_resource_base r; + int unsigned i; + string msg; + string name = rsrc.get_name(); + for(i = 0; i < q.size(); i++) begin + r = q.get(i); + if(r == rsrc) break; + end + if(r != rsrc) begin + $sformat(msg, "Handle for resource named %s is not in the name name; cannot change its priority", name); + uvm_report_error("NORSRC", msg); + return; + end + q.delete(i); + case(pri) + uvm_resource_types::PRI_HIGH: q.push_front(rsrc); + uvm_resource_types::PRI_LOW: q.push_back(rsrc); + endcase + endfunction + function void set_priority_type(uvm_resource_base rsrc, + uvm_resource_types::priority_e pri); + uvm_resource_base type_handle; + string msg; + uvm_resource_types::rsrc_q_t q; + if(rsrc == null) begin + uvm_report_warning("NULLRASRC", "attempting to change the serach priority of a null resource"); + return; + end + type_handle = rsrc.get_type_handle(); + if(!ttab.exists(type_handle)) begin + $sformat(msg, "Type handle for resrouce named %s not found in type map; cannot change its search priority", rsrc.get_name()); + uvm_report_error("RNFTYPE", msg); + return; + end + q = ttab[type_handle]; + set_priority_queue(rsrc, q, pri); + endfunction + function void set_priority_name(uvm_resource_base rsrc, + uvm_resource_types::priority_e pri); + string name; + string msg; + uvm_resource_types::rsrc_q_t q; + if(rsrc == null) begin + uvm_report_warning("NULLRASRC", "attempting to change the serach priority of a null resource"); + return; + end + name = rsrc.get_name(); + if(!rtab.exists(name)) begin + $sformat(msg, "Resrouce named %s not found in name map; cannot change its search priority", name); + uvm_report_error("RNFNAME", msg); + return; + end + q = rtab[name]; + set_priority_queue(rsrc, q, pri); + endfunction + function void set_priority (uvm_resource_base rsrc, + uvm_resource_types::priority_e pri); + set_priority_type(rsrc, pri); + set_priority_name(rsrc, pri); + endfunction + static function void set_default_precedence( int unsigned precedence); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + cs.set_resource_pool_default_precedence(precedence); + endfunction + static function int unsigned get_default_precedence(); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + return cs.get_resource_pool_default_precedence(); + endfunction + virtual function void set_precedence(uvm_resource_base r, + int unsigned p=uvm_resource_pool::get_default_precedence()); + uvm_resource_types::rsrc_q_t q; + string name; + int unsigned i; + uvm_resource_base rsrc; + if(r == null) begin + uvm_report_warning("NULLRASRC", "attempting to set precedence of a null resource"); + return; + end + name = r.get_name(); + if(rtab.exists(name)) begin + q = rtab[name]; + for(i = 0; i < q.size(); i++) begin + rsrc = q.get(i); + if(rsrc == r) break; + end + end + if(r != rsrc) begin + uvm_report_warning("NORSRC", $sformatf("resource named %s is not placed within the pool", name)); + return; + end + ri_tab[r].precedence = p; + endfunction + virtual function int unsigned get_precedence(uvm_resource_base r); + uvm_resource_types::rsrc_q_t q; + string name; + int unsigned i; + uvm_resource_base rsrc; + if(r == null) begin + uvm_report_warning("NULLRASRC", "attempting to get precedence of a null resource"); + return uvm_resource_pool::get_default_precedence(); + end + name = r.get_name(); + if(rtab.exists(name)) begin + q = rtab[name]; + for(i = 0; i < q.size(); i++) begin + rsrc = q.get(i); + if(rsrc == r) break; + end + end + if(r != rsrc) begin + uvm_report_warning("NORSRC", $sformatf("resource named %s is not placed within the pool", name)); + return uvm_resource_pool::get_default_precedence(); + end + return ri_tab[r].precedence; + endfunction + function void m_print_resources(uvm_printer printer, + uvm_resource_types::rsrc_q_t rq, + bit audit = 0); + printer.push_element(rq.get_name(), + "uvm_queue#(uvm_resource_base)", + $sformatf("%0d",rq.size()), + uvm_object_value_str(rq)); + for(int i=0; i"); + else + m_print_resources(printer, rq, audit); + begin + if (uvm_report_enabled(UVM_NONE,UVM_INFO,"UVM/RESOURCE_POOL/PRINT_QUEUE")) + uvm_report_info ("UVM/RESOURCE_POOL/PRINT_QUEUE", printer.emit(), UVM_NONE, "t/uvm/src/base/uvm_resource.svh", 1071, "", 1); + end + endfunction + function void dump(bit audit = 0, uvm_printer printer = null); + string name; + static uvm_tree_printer m_printer; + if (m_printer == null) begin + m_printer = new(); + m_printer.set_type_name_enabled(1); + end + if (printer == null) + printer = m_printer; + printer.flush(); + printer.push_element("uvm_resource_pool", + "", + $sformatf("%0d",rtab.size()), + ""); + foreach (rtab[name]) begin + m_print_resources(printer, rtab[name], audit); + end + printer.pop_element(); + begin + if (uvm_report_enabled(UVM_NONE,UVM_INFO,"UVM/RESOURCE/DUMP")) + uvm_report_info ("UVM/RESOURCE/DUMP", printer.emit(), UVM_NONE, "t/uvm/src/base/uvm_resource.svh", 1108, "", 1); + end + endfunction +endclass +class uvm_resource #(type T=int) extends uvm_resource_base; + typedef uvm_resource#(T) this_type; + static this_type my_type = get_type(); + protected T val; + typedef uvm_object_registry#(this_type) type_id; + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction : get_object_type + virtual function uvm_object create (string name=""); + this_type tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction : create + static function string type_name(); + return $sformatf("uvm_resource#(%s)", $typename(T)); + endfunction : type_name + virtual function string get_type_name(); + return $sformatf("uvm_resource#(%s)", $typename(T)); + endfunction : get_type_name + function new(string name=""); + super.new(name); + endfunction + virtual function string m_value_type_name(); + return $typename(T); + endfunction : m_value_type_name + virtual function string m_value_as_string(); + return $sformatf("%0p", val); + endfunction : m_value_as_string + static function this_type get_type(); + if(my_type == null) + my_type = new(); + return my_type; + endfunction + function uvm_resource_base get_type_handle(); + return get_type(); + endfunction + function T read(uvm_object accessor = null); + record_read_access(accessor); + return val; + endfunction + function void write(T t, uvm_object accessor = null); + if(is_read_only()) begin + uvm_report_error("resource", $sformatf("resource %s is read only -- cannot modify", get_name())); + return; + end + if(val == t) + return; + record_write_access(accessor); + val = t; + modified = 1; + endfunction + static function this_type get_highest_precedence(ref uvm_resource_types::rsrc_q_t q); + this_type rsrc; + this_type r; + uvm_resource_types::rsrc_q_t tq; + uvm_resource_base rb; + uvm_resource_pool rp = uvm_resource_pool::get(); + if(q.size() == 0) + return null; + tq = new(); + rsrc = null; + for(int i = 0; i < q.size(); ++i) begin + if($cast(r, q.get(i))) begin + tq.push_back(r) ; + end + end + rb = rp.get_highest_precedence(tq); + if (!$cast(rsrc, rb)) + return null; + return rsrc; + endfunction +endclass +class uvm_int_rsrc extends uvm_resource #(int); + typedef uvm_int_rsrc this_subtype; + function new(string name, string s = "*"); + uvm_resource_pool rp; + super.new(name); + rp = uvm_resource_pool::get(); + rp.set_scope(this, s); + endfunction + function string convert2string(); + string s; + $sformat(s, "%0d", read()); + return s; + endfunction +endclass +class uvm_string_rsrc extends uvm_resource #(string); + typedef uvm_string_rsrc this_subtype; + function new(string name, string s = "*"); + uvm_resource_pool rp; + super.new(name); + rp = uvm_resource_pool::get(); + rp.set_scope(this, s); + endfunction + function string convert2string(); + return read(); + endfunction +endclass +class uvm_obj_rsrc extends uvm_resource #(uvm_object); + typedef uvm_obj_rsrc this_subtype; + function new(string name, string s = "*"); + uvm_resource_pool rp; + super.new(name); + rp = uvm_resource_pool::get(); + rp.set_scope(this, s); + endfunction +endclass +class uvm_bit_rsrc #(int unsigned N=1) extends uvm_resource #(bit[N-1:0]); + typedef uvm_bit_rsrc#(N) this_subtype; + function new(string name, string s = "*"); + uvm_resource_pool rp; + super.new(name); + rp = uvm_resource_pool::get(); + rp.set_scope(this, s); + endfunction + function string convert2string(); + string s; + $sformat(s, "%0b", read()); + return s; + endfunction +endclass +class uvm_byte_rsrc #(int unsigned N=1) extends uvm_resource #(bit[7:0][N-1:0]); + typedef uvm_byte_rsrc#(N) this_subtype; + function new(string name, string s = "*"); + uvm_resource_pool rp; + super.new(name); + rp = uvm_resource_pool::get(); + rp.set_scope(this, s); + endfunction + function string convert2string(); + string s; + $sformat(s, "%0x", read()); + return s; + endfunction +endclass +typedef class uvm_resource_db_options; +typedef class uvm_cmdline_processor; +class uvm_resource_db #(type T=uvm_object); + typedef uvm_resource #(T) rsrc_t; + protected function new(); + endfunction + static function rsrc_t get_by_type(string scope); + uvm_resource_pool rp = uvm_resource_pool::get(); + uvm_resource_base rsrc_base; + rsrc_t rsrc; + string msg; + uvm_resource_base type_handle = rsrc_t::get_type(); + if(type_handle == null) + return null; + rsrc_base = rp.get_by_type(scope, type_handle); + if(!$cast(rsrc, rsrc_base)) begin + $sformat(msg, "Resource with specified type handle in scope %s was not located", scope); + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RSRCNF")) + uvm_report_warning ("RSRCNF", msg, UVM_NONE, "t/uvm/src/base/uvm_resource_db.svh", 84, "", 1); + end + return null; + end + return rsrc; + endfunction + static function rsrc_t get_by_name(string scope, + string name, + bit rpterr=1); + uvm_resource_pool rp = uvm_resource_pool::get(); + uvm_resource_base rsrc_base; + rsrc_t rsrc; + string msg; + rsrc_base = rp.get_by_name(scope, name, rsrc_t::get_type(), rpterr); + if(rsrc_base == null) + return null; + if(!$cast(rsrc, rsrc_base)) begin + if(rpterr) begin + $sformat(msg, "Resource with name %s in scope %s has incorrect type", name, scope); + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RSRCTYPE")) + uvm_report_warning ("RSRCTYPE", msg, UVM_NONE, "t/uvm/src/base/uvm_resource_db.svh", 115, "", 1); + end + end + return null; + end + return rsrc; + endfunction + static function rsrc_t set_default(string scope, string name); + rsrc_t r; + uvm_resource_pool rp = uvm_resource_pool::get(); + r = new(name); + rp.set_scope(r, scope); + return r; + endfunction + protected static function void m_show_msg( + input string id, + input string rtype, + input string action, + input string scope, + input string name, + input uvm_object accessor, + input rsrc_t rsrc); + T foo; + string msg=$typename(foo); + $sformat(msg, "%s scope='%s' name='%s' (type %s) %s accessor=%s = %s", + rtype,scope,name, msg,action, + (accessor != null) ? accessor.get_full_name() : "", + rsrc==null?"null (failed lookup)":rsrc.convert2string()); + begin + if (uvm_report_enabled(UVM_LOW,UVM_INFO,id)) + uvm_report_info (id, msg, UVM_LOW, "t/uvm/src/base/uvm_resource_db.svh", 161, "", 1); + end + endfunction + static function void set(input string scope, input string name, + T val, input uvm_object accessor = null); + uvm_resource_pool rp = uvm_resource_pool::get(); + rsrc_t rsrc = new(name); + rsrc.write(val, accessor); + rp.set_scope(rsrc, scope); + if(uvm_resource_db_options::is_tracing()) + m_show_msg("RSRCDB/SET", "Resource","set", scope, name, accessor, rsrc); + endfunction + static function void set_anonymous(input string scope, + T val, input uvm_object accessor = null); + uvm_resource_pool rp = uvm_resource_pool::get(); + rsrc_t rsrc = new(""); + rsrc.write(val, accessor); + rp.set_scope(rsrc, scope); + if(uvm_resource_db_options::is_tracing()) + m_show_msg("RSRCDB/SETANON","Resource", "set", scope, "", accessor, rsrc); + endfunction + static function void set_override(input string scope, input string name, + T val, uvm_object accessor = null); + uvm_resource_pool rp = uvm_resource_pool::get(); + rsrc_t rsrc = new(name); + rsrc.write(val, accessor); + rp.set_override(rsrc, scope); + if(uvm_resource_db_options::is_tracing()) + m_show_msg("RSRCDB/SETOVRD", "Resource","set", scope, name, accessor, rsrc); + endfunction + static function void set_override_type(input string scope, input string name, + T val, uvm_object accessor = null); + uvm_resource_pool rp = uvm_resource_pool::get(); + rsrc_t rsrc = new(name); + rsrc.write(val, accessor); + rp.set_type_override(rsrc, scope); + if(uvm_resource_db_options::is_tracing()) + m_show_msg("RSRCDB/SETOVRDTYP","Resource", "set", scope, name, accessor, rsrc); + endfunction + static function void set_override_name(input string scope, input string name, + T val, uvm_object accessor = null); + uvm_resource_pool rp = uvm_resource_pool::get(); + rsrc_t rsrc = new(name); + rsrc.write(val, accessor); + rp.set_name_override(rsrc, scope); + if(uvm_resource_db_options::is_tracing()) + m_show_msg("RSRCDB/SETOVRDNAM","Resource", "set", scope, name, accessor, rsrc); + endfunction + static function bit read_by_name(input string scope, + input string name, + inout T val, input uvm_object accessor = null); + rsrc_t rsrc = get_by_name(scope, name); + if(uvm_resource_db_options::is_tracing()) + m_show_msg("RSRCDB/RDBYNAM","Resource", "read", scope, name, accessor, rsrc); + if(rsrc == null) + return 0; + val = rsrc.read(accessor); + return 1; + endfunction + static function bit read_by_type(input string scope, + inout T val, + input uvm_object accessor = null); + rsrc_t rsrc = get_by_type(scope); + if(uvm_resource_db_options::is_tracing()) + m_show_msg("RSRCDB/RDBYTYP", "Resource","read", scope, "", accessor, rsrc); + if(rsrc == null) + return 0; + val = rsrc.read(accessor); + return 1; + endfunction + static function bit write_by_name(input string scope, input string name, + input T val, input uvm_object accessor = null); + rsrc_t rsrc = get_by_name(scope, name); + if(uvm_resource_db_options::is_tracing()) + m_show_msg("RSRCDB/WR","Resource", "written", scope, name, accessor, rsrc); + if(rsrc == null) + return 0; + rsrc.write(val, accessor); + return 1; + endfunction + static function bit write_by_type(input string scope, + input T val, input uvm_object accessor = null); + rsrc_t rsrc = get_by_type(scope); + if(uvm_resource_db_options::is_tracing()) + m_show_msg("RSRCDB/WRTYP", "Resource","written", scope, "", accessor, rsrc); + if(rsrc == null) + return 0; + rsrc.write(val, accessor); + return 1; + endfunction + static function void dump(); + uvm_resource_pool rp = uvm_resource_pool::get(); + rp.dump(); + endfunction +endclass +class uvm_resource_db_options; + static local bit ready; + static local bit tracing; + static function void turn_on_tracing(); + if (!ready) init(); + tracing = 1; + endfunction + static function void turn_off_tracing(); + if (!ready) init(); + tracing = 0; + endfunction + static function bit is_tracing(); + if (!ready) init(); + return tracing; + endfunction + static local function void init(); + uvm_cmdline_processor clp; + string trace_args[$]; + clp = uvm_cmdline_processor::get_inst(); + if (clp.get_arg_matches("+UVM_RESOURCE_DB_TRACE", trace_args)) begin + tracing = 1; + end + ready = 1; + endfunction +endclass +typedef class uvm_phase; +class m_uvm_waiter; + string inst_name; + string field_name; + event trigger; + function new (string inst_name, string field_name); + this.inst_name = inst_name; + this.field_name = field_name; + endfunction +endclass +typedef class uvm_root; +typedef class uvm_config_db_options; +class uvm_config_db#(type T=int) extends uvm_resource_db#(T); + static uvm_pool#(string,uvm_resource#(T)) m_rsc[uvm_component]; + static local uvm_queue#(m_uvm_waiter) m_waiters[string]; + static function bit get(uvm_component cntxt, + string inst_name, + string field_name, + inout T value); + uvm_resource#(T) r; + uvm_resource_pool rp = uvm_resource_pool::get(); + uvm_resource_types::rsrc_q_t rq; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + if(cntxt == null) + cntxt = cs.get_root(); + if(inst_name == "") + inst_name = cntxt.get_full_name(); + else if(cntxt.get_full_name() != "") + inst_name = {cntxt.get_full_name(), ".", inst_name}; + rq = rp.lookup_regex_names(inst_name, field_name, uvm_resource#(T)::get_type()); + r = uvm_resource#(T)::get_highest_precedence(rq); + if(uvm_config_db_options::is_tracing()) + m_show_msg("CFGDB/GET", "Configuration","read", inst_name, field_name, cntxt, r); + if(r == null) + return 0; + value = r.read(cntxt); + return 1; + endfunction + static function void set(uvm_component cntxt, + string inst_name, + string field_name, + T value); + uvm_root top; + uvm_phase curr_phase; + uvm_resource#(T) r; + bit exists; + string lookup; + uvm_pool#(string,uvm_resource#(T)) pool; + string rstate; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_resource_pool rp = cs.get_resource_pool(); + int unsigned precedence; + process p = process::self(); + if(p != null) + rstate = p.get_randstate(); + top = cs.get_root(); + curr_phase = top.m_current_phase; + if(cntxt == null) + cntxt = top; + if(inst_name == "") + inst_name = cntxt.get_full_name(); + else if(cntxt.get_full_name() != "") + inst_name = {cntxt.get_full_name(), ".", inst_name}; + if(!m_rsc.exists(cntxt)) begin + m_rsc[cntxt] = new; + end + pool = m_rsc[cntxt]; + lookup = {inst_name, "__M_UVM__", field_name}; + if(!pool.exists(lookup)) begin + r = new(field_name); + rp.set_scope(r, inst_name); + pool.add(lookup, r); + end + else begin + r = pool.get(lookup); + exists = 1; + end + if(curr_phase != null && curr_phase.get_name() == "build") + precedence = cs.get_resource_pool_default_precedence() - (cntxt.get_depth()); + else + precedence = cs.get_resource_pool_default_precedence(); + rp.set_precedence(r, precedence); + r.write(value, cntxt); + rp.set_priority_name(r, uvm_resource_types::PRI_HIGH); + if(m_waiters.exists(field_name)) begin + m_uvm_waiter w; + for(int i=0; iw.trigger; + end + end + if(p != null) + p.set_randstate(rstate); + if(uvm_config_db_options::is_tracing()) + m_show_msg("CFGDB/SET", "Configuration","set", inst_name, field_name, cntxt, r); + endfunction + static function bit exists(uvm_component cntxt, string inst_name, + string field_name, bit spell_chk=0); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + if(cntxt == null) + cntxt = cs.get_root(); + if(inst_name == "") + inst_name = cntxt.get_full_name(); + else if(cntxt.get_full_name() != "") + inst_name = {cntxt.get_full_name(), ".", inst_name}; + return (uvm_resource_db#(T)::get_by_name(inst_name,field_name,spell_chk) != null); + endfunction + static task wait_modified(uvm_component cntxt, string inst_name, + string field_name); + process p = process::self(); + string rstate = p.get_randstate(); + m_uvm_waiter waiter; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + if(cntxt == null) + cntxt = cs.get_root(); + if(cntxt != cs.get_root()) begin + if(inst_name != "") + inst_name = {cntxt.get_full_name(),".",inst_name}; + else + inst_name = cntxt.get_full_name(); + end + waiter = new(inst_name, field_name); + if(!m_waiters.exists(field_name)) + m_waiters[field_name] = new; + m_waiters[field_name].push_back(waiter); + p.set_randstate(rstate); + @waiter.trigger; + for(int i=0; i 1) begin + string msg_queue[$]; + msg_queue.push_back("("); + foreach (matching_ops[i]) begin + msg_queue.push_back(matching_ops[i]); + if (i != matching_ops.size() - 1) + msg_queue.push_back(","); + end + msg_queue.push_back(")"); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/FIELD_OP/SET_BAD_OP_TYPE")) + uvm_report_error ("UVM/FIELD_OP/SET_BAD_OP_TYPE", {"set() was passed op_type matching multiple operations: ", uvm_pkg::m_uvm_string_queue_join(msg_queue)}, UVM_NONE, "t/uvm/src/base/uvm_field_op.svh", 88, "", 1); + end + end + if(m_is_set == 0) begin + m_op_type = op_type; + m_policy = policy; + m_object = rhs; + m_is_set = 1'b1; + end + else + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/FIELD_OP/SET")) + uvm_report_error ("UVM/FIELD_OP/SET", "Attempting to set values in policy without flushing", UVM_NONE, "t/uvm/src/base/uvm_field_op.svh", 98, "", 1); + end + endfunction + virtual function string get_op_name(); + case(m_op_type) + UVM_COPY : return "copy"; + UVM_COMPARE : return "compare"; + UVM_PRINT : return "print"; + UVM_RECORD : return "record"; + UVM_PACK : return "pack"; + UVM_UNPACK : return "unpack"; + UVM_SET : return "set"; + default: return ""; + endcase + endfunction + virtual function uvm_field_flag_t get_op_type(); + if(m_is_set == 1'b1) + return m_op_type; + else + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/FIELD_OP/GET_OP_TYPE")) + uvm_report_error ("UVM/FIELD_OP/GET_OP_TYPE", "Calling get_op_type() before calling set() is not allowed", UVM_NONE, "t/uvm/src/base/uvm_field_op.svh", 120, "", 1); + end + endfunction + virtual function uvm_policy get_policy(); + if(m_is_set == 1'b1) + return m_policy; + else + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/FIELD_OP/GET_POLICY")) + uvm_report_error ("UVM/FIELD_OP/GET_POLICY", "Attempting to call get_policy() before calling set() is not allowed", UVM_NONE, "t/uvm/src/base/uvm_field_op.svh", 129, "", 1); + end + endfunction + virtual function uvm_object get_rhs(); + if(m_is_set == 1'b1) + return m_object; + else + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/FIELD_OP/GET_RHS")) + uvm_report_error ("UVM/FIELD_OP/GET_RHS", "Calling get_rhs() before calling set() is not allowed", UVM_NONE, "t/uvm/src/base/uvm_field_op.svh", 137, "", 1); + end + endfunction + function bit user_hook_enabled(); + if(m_is_set == 1'b1) + return m_user_hook; + else + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/FIELD_OP/GET_USER_HOOK")) + uvm_report_error ("UVM/FIELD_OP/GET_USER_HOOK", "Attempting to get_user_hook before calling set() is not allowed", UVM_NONE, "t/uvm/src/base/uvm_field_op.svh", 145, "", 1); + end + endfunction + function void disable_user_hook(); + m_user_hook = 1'b0; + endfunction + static uvm_field_op m_recycled_op[$] ; + virtual function void flush(); + m_policy = null; + m_object = null; + m_user_hook = 1'b1; + m_is_set = 0; + endfunction + function void m_recycle(); + this.flush(); + m_recycled_op.push_back(this); + endfunction : m_recycle + static function uvm_field_op m_get_available_op() ; + uvm_field_op field_op ; + if (m_recycled_op.size() > 0) field_op = m_recycled_op.pop_back() ; + else field_op = uvm_field_op::type_id_create("field_op"); + return field_op ; + endfunction +endclass +class uvm_copier extends uvm_policy; + typedef uvm_object_registry#(uvm_copier,"uvm_copier") type_id; + static function uvm_copier type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_copier tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_copier"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_copier"; + endfunction : get_type_name + uvm_recursion_policy_enum policy = UVM_DEFAULT_POLICY; + function new(string name="uvm_copier") ; + super.new(name); + endfunction + recursion_state_e m_recur_states[uvm_object ][uvm_object ][uvm_recursion_policy_enum ]; + virtual function void copy_object ( + uvm_object lhs, + uvm_object rhs); + uvm_field_op field_op; + if (get_recursion_policy() == UVM_REFERENCE) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM_COPY_POLICY")) + uvm_report_error ("UVM_COPY_POLICY", "Attempting to make a copy of a object which is a reference", UVM_NONE, "t/uvm/src/base/uvm_copier.svh", 82, "", 1); + end + return; + end + if (rhs == null || lhs == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM_COPY_NULL_OBJ")) + uvm_report_error ("UVM_COPY_NULL_OBJ", "Attempting to make a copy of a object with null src/target", UVM_NONE, "t/uvm/src/base/uvm_copier.svh", 87, "", 1); + end + return; + end + push_active_object(lhs); + m_recur_states[rhs][lhs][get_recursion_policy()] = uvm_policy::STARTED; + field_op = uvm_field_op::m_get_available_op() ; + field_op.set(UVM_COPY,this,rhs); + lhs.do_execute_op(field_op); + if (field_op.user_hook_enabled()) begin + lhs.do_copy(rhs); + end + field_op.m_recycle(); + m_recur_states[rhs][lhs][get_recursion_policy()] = uvm_policy::FINISHED; + void'(pop_active_object()); + endfunction + virtual function recursion_state_e object_copied( + uvm_object lhs, + uvm_object rhs, + uvm_recursion_policy_enum recursion + ); + if (!m_recur_states.exists(rhs)) return NEVER ; + else if (!m_recur_states[rhs].exists(lhs)) return NEVER ; + else if (!m_recur_states[rhs][lhs].exists(recursion)) return NEVER ; + else begin + return m_recur_states[rhs][lhs][recursion]; + end +endfunction +function void flush(); + m_recur_states.delete(); +endfunction +virtual function void set_recursion_policy (uvm_recursion_policy_enum policy); + this.policy = policy; +endfunction +virtual function uvm_recursion_policy_enum get_recursion_policy(); + return policy; +endfunction +function int unsigned get_num_copies(uvm_object rhs); + if (m_recur_states.exists(rhs)) + return m_recur_states[rhs].size(); + return 0; +endfunction : get_num_copies +function int get_first_copy(uvm_object rhs, ref uvm_object lhs); + if (m_recur_states.exists(rhs)) + return m_recur_states[rhs].first(lhs); + return 0; +endfunction : get_first_copy +function int get_next_copy(uvm_object rhs, ref uvm_object lhs); + if (m_recur_states.exists(rhs)) + return m_recur_states[rhs].next(lhs); + return 0; +endfunction : get_next_copy +function int get_last_copy(uvm_object rhs, ref uvm_object lhs); + if (m_recur_states.exists(rhs)) + return m_recur_states[rhs].last(lhs); + return 0; +endfunction : get_last_copy +function int get_prev_copy(uvm_object rhs, ref uvm_object lhs); + if (m_recur_states.exists(rhs)) + return m_recur_states[rhs].prev(lhs); + return 0; +endfunction : get_prev_copy +static function void set_default (uvm_copier copier) ; + uvm_coreservice_t coreservice ; + coreservice = uvm_coreservice_t::get() ; + coreservice.set_default_copier(copier) ; +endfunction +static function uvm_copier get_default () ; + uvm_coreservice_t coreservice ; + coreservice = uvm_coreservice_t::get() ; + return coreservice.get_default_copier() ; +endfunction +endclass +typedef class m_uvm_printer_knobs; +typedef class uvm_printer_element; +typedef class uvm_structure_proxy; +virtual class uvm_printer extends uvm_policy; + typedef uvm_abstract_object_registry#(uvm_printer,"uvm_printer") type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_printer"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_printer"; + endfunction : get_type_name + extern function new(string name="") ; + bit m_flushed ; + local m_uvm_printer_knobs knobs ; +protected function m_uvm_printer_knobs get_knobs() ; return knobs; endfunction + extern static function void set_default(uvm_printer printer) ; + extern static function uvm_printer get_default() ; + extern virtual function void print_field (string name, + uvm_bitstream_t value, + int size, + uvm_radix_enum radix=UVM_NORADIX, + byte scope_separator=".", + string type_name=""); + extern virtual function void print_field_int (string name, + uvm_integral_t value, + int size, + uvm_radix_enum radix=UVM_NORADIX, + byte scope_separator=".", + string type_name=""); + extern virtual function void print_object (string name, + uvm_object value, + byte scope_separator="."); + extern virtual function void print_object_header (string name, + uvm_object value, + byte scope_separator="."); + extern virtual function void print_string (string name, + string value, + byte scope_separator="."); + uvm_policy::recursion_state_e m_recur_states[uvm_object][uvm_recursion_policy_enum ] ; + extern virtual function uvm_policy::recursion_state_e object_printed ( uvm_object value, + uvm_recursion_policy_enum recursion); + extern virtual function void print_time (string name, + time value, + byte scope_separator="."); + extern virtual function void print_real (string name, + real value, + byte scope_separator="."); + extern virtual function void print_generic (string name, + string type_name, + int size, + string value, + byte scope_separator="."); + extern virtual function void print_generic_element (string name, + string type_name, + string size, + string value); + extern virtual function string emit (); + extern virtual function void flush (); + extern virtual function void set_name_enabled (bit enabled); + extern virtual function bit get_name_enabled (); + extern virtual function void set_type_name_enabled (bit enabled); + extern virtual function bit get_type_name_enabled (); + extern virtual function void set_size_enabled (bit enabled); + extern virtual function bit get_size_enabled (); + extern virtual function void set_id_enabled (bit enabled); + extern virtual function bit get_id_enabled (); + extern virtual function void set_radix_enabled (bit enabled); + extern virtual function bit get_radix_enabled (); + extern virtual function void set_radix_string (uvm_radix_enum radix, string prefix); + extern virtual function string get_radix_string (uvm_radix_enum radix); + extern virtual function void set_default_radix (uvm_radix_enum radix); + extern virtual function uvm_radix_enum get_default_radix (); + extern virtual function void set_root_enabled (bit enabled); + extern virtual function bit get_root_enabled (); + extern virtual function void set_recursion_policy (uvm_recursion_policy_enum policy); + extern virtual function uvm_recursion_policy_enum get_recursion_policy (); + extern virtual function void set_max_depth (int depth); + extern virtual function int get_max_depth (); + extern virtual function void set_file (UVM_FILE fl); + extern virtual function UVM_FILE get_file (); + extern virtual function void set_line_prefix (string prefix); + extern virtual function string get_line_prefix (); + extern virtual function void set_begin_elements (int elements = 5); + extern virtual function int get_begin_elements (); + extern virtual function void set_end_elements (int elements = 5); + extern virtual function int get_end_elements (); + local uvm_printer_element m_element_stack[$] ; + protected function int m_get_stack_size(); return m_element_stack.size(); endfunction + extern protected virtual function uvm_printer_element get_bottom_element (); + extern protected virtual function uvm_printer_element get_top_element (); + extern virtual function void push_element ( string name, + string type_name, + string size, + string value="" + ); + extern virtual function void pop_element (); + extern function uvm_printer_element get_unused_element() ; + uvm_printer_element m_recycled_elements[$]; + extern virtual function void print_array_header(string name, + int size, + string arraytype="array", + byte scope_separator="."); + extern virtual function void print_array_range (int min, int max); + extern virtual function void print_array_footer (int size = 0); + extern function bit istop (); + extern function string index_string (int index, string name=""); + string m_string; +endclass +class uvm_printer_element extends uvm_object; + extern function new (string name=""); + extern virtual function void set (string element_name = "", + string element_type_name = "", + string element_size = "", + string element_value = "" + ); + extern virtual function void set_element_name (string element_name); + extern virtual function string get_element_name (); + extern virtual function void set_element_type_name (string element_type_name); + extern virtual function string get_element_type_name (); + extern virtual function void set_element_size (string element_size); + extern virtual function string get_element_size (); + extern virtual function void set_element_value (string element_value); + extern virtual function string get_element_value (); + extern function void add_child(uvm_printer_element child) ; + extern function void get_children(ref uvm_printer_element children[$], input bit recurse) ; + extern function void clear_children() ; + local string m_name ; + local string m_type_name ; + local string m_size ; + local string m_value ; + local uvm_printer_element m_children[$] ; +endclass +class uvm_printer_element_proxy extends uvm_structure_proxy#(uvm_printer_element); + extern function new (string name=""); + extern virtual function void get_immediate_children(uvm_printer_element s, ref uvm_printer_element children[$]); +endclass : uvm_printer_element_proxy +class uvm_table_printer extends uvm_printer; + typedef uvm_object_registry#(uvm_table_printer,"uvm_table_printer") type_id; + static function uvm_table_printer type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_table_printer tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_table_printer"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_table_printer"; + endfunction : get_type_name + extern function new(string name=""); + extern virtual function string emit(); + extern virtual function string m_emit_element(uvm_printer_element element, int unsigned level); + local static uvm_table_printer m_default_table_printer ; + local static string m_space ; + extern static function void set_default(uvm_table_printer printer) ; + extern static function uvm_table_printer get_default() ; + extern virtual function void set_indent(int indent) ; + extern virtual function int get_indent() ; + extern virtual function void flush() ; + protected int m_max_name=4; + protected int m_max_type=4; + protected int m_max_size=4; + protected int m_max_value=5; + extern virtual function void pop_element(); +endclass +class uvm_tree_printer extends uvm_printer; + protected string m_newline = "\n"; + protected string m_linefeed ; + typedef uvm_object_registry#(uvm_tree_printer,"uvm_tree_printer") type_id; + static function uvm_tree_printer type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_tree_printer tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_tree_printer"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_tree_printer"; + endfunction : get_type_name + extern function new(string name=""); + local static uvm_tree_printer m_default_tree_printer ; + extern static function void set_default(uvm_tree_printer printer) ; + extern static function uvm_tree_printer get_default() ; + extern virtual function void set_indent(int indent) ; + extern virtual function int get_indent() ; + extern virtual function void set_separators(string separators) ; + extern virtual function string get_separators() ; + extern virtual function void flush() ; + extern virtual function string emit(); + extern virtual function string m_emit_element(uvm_printer_element element, int unsigned level); +endclass +class uvm_line_printer extends uvm_tree_printer; + typedef uvm_object_registry#(uvm_line_printer,"uvm_line_printer") type_id; + static function uvm_line_printer type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_line_printer tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_line_printer"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_line_printer"; + endfunction : get_type_name + extern function new(string name=""); + local static uvm_line_printer m_default_line_printer ; + extern static function void set_default(uvm_line_printer printer) ; + extern static function uvm_line_printer get_default() ; + extern virtual function void set_separators(string separators) ; + extern virtual function string get_separators() ; + extern virtual function void flush() ; +endclass +class m_uvm_printer_knobs; + bit identifier = 1; + bit type_name = 1; + bit size = 1; + int depth = -1; + bit reference = 1; + int begin_elements = 5; + int end_elements = 5; + string prefix = ""; + int indent = 2; + bit show_root = 0; + int mcd = UVM_STDOUT; + string separator = "{}"; + bit show_radix = 1; + uvm_radix_enum default_radix = UVM_HEX; + string dec_radix = "'d"; + string bin_radix = "'b"; + string oct_radix = "'o"; + string unsigned_radix = "'d"; + string hex_radix = "'h"; + uvm_recursion_policy_enum recursion_policy ; +endclass +function uvm_printer::new(string name=""); + super.new(name); + knobs = new ; + flush(); +endfunction +function void uvm_printer::set_default(uvm_printer printer) ; + uvm_coreservice_t coreservice ; + coreservice = uvm_coreservice_t::get() ; + coreservice.set_default_printer(printer) ; +endfunction +function uvm_printer uvm_printer::get_default() ; + uvm_coreservice_t coreservice ; + coreservice = uvm_coreservice_t::get() ; + return coreservice.get_default_printer() ; +endfunction +function void uvm_printer::print_field (string name, + uvm_bitstream_t value, + int size, + uvm_radix_enum radix=UVM_NORADIX, + byte scope_separator=".", + string type_name=""); + string sz_str, val_str; + if(type_name == "") begin + if(radix == UVM_TIME) + type_name ="time"; + else if(radix == UVM_STRING) + type_name ="string"; + else + type_name ="integral"; + end + sz_str.itoa(size); + if(radix == UVM_NORADIX) + radix = get_default_radix(); + val_str = uvm_bitstream_to_string (value, size, radix, + get_radix_string(radix)); + name = uvm_leaf_scope(name,scope_separator); + push_element(name,type_name,sz_str,val_str); + pop_element() ; +endfunction +function void uvm_printer::print_field_int (string name, + uvm_integral_t value, + int size, + uvm_radix_enum radix=UVM_NORADIX, + byte scope_separator=".", + string type_name=""); + string sz_str, val_str; + if(type_name == "") begin + if(radix == UVM_TIME) + type_name ="time"; + else if(radix == UVM_STRING) + type_name ="string"; + else + type_name ="integral"; + end + sz_str.itoa(size); + if(radix == UVM_NORADIX) + radix = get_default_radix(); + val_str = uvm_integral_to_string (value, size, radix, + get_radix_string(radix)); + name = uvm_leaf_scope(name,scope_separator); + push_element(name,type_name,sz_str,val_str); + pop_element() ; +endfunction +function string uvm_printer::emit (); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"NO_OVERRIDE")) + uvm_report_error ("NO_OVERRIDE", "emit() method not overridden in printer subtype", UVM_NONE, "t/uvm/src/base/uvm_printer.svh", 999, "", 1); + end + return ""; +endfunction +function void uvm_printer::flush (); + uvm_printer_element element = get_bottom_element() ; + uvm_printer_element all_descendent_elements[$] ; + element = get_bottom_element() ; + if (element != null) begin + element.get_children(all_descendent_elements,1) ; + foreach (all_descendent_elements[i]) begin + m_recycled_elements.push_back(all_descendent_elements[i]) ; + all_descendent_elements[i].clear_children() ; + end + element.clear_children(); + m_recycled_elements.push_back(element) ; + m_element_stack.delete() ; + end + m_recur_states.delete(); + m_flushed = 1 ; +endfunction +function void uvm_printer::set_name_enabled (bit enabled); + knobs.identifier = enabled ; +endfunction +function bit uvm_printer::get_name_enabled (); + return knobs.identifier ; +endfunction +function void uvm_printer::set_type_name_enabled (bit enabled); + knobs.type_name = enabled ; +endfunction +function bit uvm_printer::get_type_name_enabled (); + return knobs.type_name ; +endfunction +function void uvm_printer::set_size_enabled (bit enabled); + knobs.size = enabled ; +endfunction +function bit uvm_printer::get_size_enabled (); + return knobs.size ; +endfunction +function void uvm_printer::set_id_enabled (bit enabled); + knobs.reference = enabled ; +endfunction +function bit uvm_printer::get_id_enabled (); + return knobs.reference ; +endfunction +function void uvm_printer::set_radix_enabled (bit enabled); + knobs.show_radix = enabled ; +endfunction +function bit uvm_printer::get_radix_enabled (); + return knobs.show_radix ; +endfunction +function void uvm_printer::set_radix_string (uvm_radix_enum radix, string prefix); + if (radix == UVM_DEC) knobs.dec_radix = prefix ; + else if (radix == UVM_BIN) knobs.bin_radix = prefix ; + else if (radix == UVM_OCT) knobs.oct_radix = prefix ; + else if (radix == UVM_UNSIGNED) knobs.unsigned_radix = prefix ; + else if (radix == UVM_HEX) knobs.hex_radix = prefix ; + else + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"PRINTER_UNKNOWN_RADIX")) + uvm_report_warning ("PRINTER_UNKNOWN_RADIX", $sformatf("set_radix_string called with unsupported radix %s",radix), UVM_NONE, "t/uvm/src/base/uvm_printer.svh", 1065, "", 1); + end +endfunction +function string uvm_printer::get_radix_string (uvm_radix_enum radix); + if (radix == UVM_DEC) return knobs.dec_radix ; + else if (radix == UVM_BIN) return knobs.bin_radix ; + else if (radix == UVM_OCT) return knobs.oct_radix ; + else if (radix == UVM_UNSIGNED) return knobs.unsigned_radix ; + else if (radix == UVM_HEX) return knobs.hex_radix ; + else return ""; +endfunction +function void uvm_printer::set_default_radix (uvm_radix_enum radix); + knobs.default_radix = radix ; +endfunction +function uvm_radix_enum uvm_printer::get_default_radix (); + return knobs.default_radix ; +endfunction +function void uvm_printer::set_root_enabled (bit enabled); + knobs.show_root = enabled ; +endfunction +function bit uvm_printer::get_root_enabled (); + return knobs.show_root ; +endfunction +function void uvm_printer::set_recursion_policy (uvm_recursion_policy_enum policy); + knobs.recursion_policy = policy ; +endfunction +function uvm_recursion_policy_enum uvm_printer::get_recursion_policy (); + return knobs.recursion_policy ; +endfunction +function void uvm_printer::set_max_depth (int depth); + knobs.depth = depth ; +endfunction +function int uvm_printer::get_max_depth (); + return knobs.depth ; +endfunction +function void uvm_printer::set_file (UVM_FILE fl); + knobs.mcd = fl ; +endfunction +function UVM_FILE uvm_printer::get_file (); + return knobs.mcd ; +endfunction +function void uvm_printer::set_line_prefix (string prefix); + knobs.prefix = prefix ; +endfunction +function string uvm_printer::get_line_prefix (); + return knobs.prefix ; +endfunction +function void uvm_printer::set_begin_elements (int elements = 5); + knobs.begin_elements = elements ; +endfunction +function int uvm_printer::get_begin_elements (); + return knobs.begin_elements ; +endfunction +function void uvm_printer::set_end_elements (int elements = 5); + knobs.end_elements = elements ; +endfunction +function int uvm_printer::get_end_elements (); + return knobs.end_elements ; +endfunction +function uvm_printer_element uvm_printer::get_bottom_element (); + if (m_element_stack.size() > 0) return m_element_stack[0] ; + else return null ; +endfunction +function uvm_printer_element uvm_printer::get_top_element (); + if (m_element_stack.size() > 0) return m_element_stack[$] ; + else return null ; +endfunction +function uvm_printer_element_proxy::new (string name=""); + super.new(name) ; +endfunction +function void uvm_printer_element_proxy::get_immediate_children(uvm_printer_element s, + ref uvm_printer_element children[$]); + s.get_children(children,0) ; +endfunction +function void uvm_printer::push_element ( string name, + string type_name, + string size, + string value=""); + uvm_printer_element element ; + uvm_printer_element parent ; + element = get_unused_element() ; + parent = get_top_element() ; + element.set(name,type_name,size,value); + if (parent != null) parent.add_child(element) ; + m_element_stack.push_back(element) ; +endfunction +function void uvm_printer::pop_element (); + if (m_element_stack.size() > 1) begin + void'(m_element_stack.pop_back()); + end +endfunction +function uvm_printer_element uvm_printer::get_unused_element() ; + uvm_printer_element element ; + if (m_recycled_elements.size() > 0) begin + element = m_recycled_elements.pop_back() ; + end + else begin + element = new() ; + end + return element ; +endfunction +function void uvm_printer::print_array_header (string name, + int size, + string arraytype="array", + byte scope_separator="."); + push_element(name,arraytype,$sformatf("%0d",size),"-"); +endfunction +function void uvm_printer::print_array_footer (int size=0); + pop_element() ; +endfunction +function void uvm_printer::print_array_range(int min, int max); + string tmpstr; + if(min == -1 && max == -1) + return; + if(min == -1) + min = max; + if(max == -1) + max = min; + if(max < min) + return; + print_generic_element("...", "...", "...", "..."); +endfunction +function void uvm_printer::print_object_header (string name, + uvm_object value, + byte scope_separator="."); + if(name == "") + name = ""; + push_element(name, + (value != null) ? value.get_type_name() : "object", + "-", + get_id_enabled() ? uvm_object_value_str(value) : "-"); +endfunction +function void uvm_printer::print_object (string name, uvm_object value, + byte scope_separator="."); + uvm_component comp, child_comp; + uvm_field_op field_op ; + uvm_recursion_policy_enum recursion_policy; + recursion_policy = get_recursion_policy(); + if ((value == null) || + (recursion_policy == UVM_REFERENCE) || + (get_max_depth() == get_active_object_depth())) begin + print_object_header(name,value,scope_separator); + pop_element(); + end + else begin + push_active_object(value); + m_recur_states[value][recursion_policy] = uvm_policy::STARTED ; + print_object_header(name,value,scope_separator); + if($cast(comp, value)) begin + string name; + if (comp.get_first_child(name)) + do begin + child_comp = comp.get_child(name); + if(child_comp.print_enabled) + this.print_object(name,child_comp); + end while (comp.get_next_child(name)); + end + field_op = uvm_field_op::m_get_available_op() ; + field_op.set(UVM_PRINT,this,null); + value.do_execute_op(field_op); + if (field_op.user_hook_enabled()) + value.do_print(this); + field_op.m_recycle(); + pop_element() ; + m_recur_states[value][recursion_policy] = uvm_policy::FINISHED ; + void'(pop_active_object()); + end +endfunction +function bit uvm_printer::istop (); + return (get_active_object_depth() == 0); +endfunction +function void uvm_printer::print_generic (string name, + string type_name, + int size, + string value, + byte scope_separator="."); + push_element(name, + type_name, + (size == -2 ? "..." : $sformatf("%0d",size)), + value); + pop_element(); +endfunction +function void uvm_printer::print_generic_element (string name, + string type_name, + string size, + string value); + push_element(name,type_name,size,value); + pop_element() ; +endfunction +function void uvm_printer::print_time (string name, + time value, + byte scope_separator="."); + print_field_int(name, value, 64, UVM_TIME, scope_separator); +endfunction +function void uvm_printer::print_string (string name, + string value, + byte scope_separator="."); + push_element(name, + "string", + $sformatf("%0d",value.len()), + (value == "" ? "\"\"" : value)); + pop_element() ; +endfunction +function uvm_policy::recursion_state_e uvm_printer::object_printed (uvm_object value, + uvm_recursion_policy_enum recursion); + if (!m_recur_states.exists(value)) return NEVER ; + if (!m_recur_states[value].exists(recursion)) return NEVER ; + else return m_recur_states[value][recursion] ; +endfunction +function void uvm_printer::print_real (string name, + real value, + byte scope_separator="."); + push_element(name,"real","64",$sformatf("%f",value)); + pop_element() ; +endfunction +function string uvm_printer::index_string(int index, string name=""); + index_string.itoa(index); + index_string = { name, "[", index_string, "]" }; +endfunction +function uvm_printer_element::new (string name = ""); + super.new(name) ; +endfunction +function void uvm_printer_element::set (string element_name = "", + string element_type_name = "", + string element_size = "", + string element_value = "" + ); + m_name = element_name ; + m_type_name = element_type_name ; + m_size = element_size ; + m_value = element_value ; +endfunction +function void uvm_printer_element::set_element_name (string element_name); + m_name = element_name ; +endfunction +function string uvm_printer_element::get_element_name (); + return m_name ; +endfunction +function void uvm_printer_element::set_element_type_name (string element_type_name); + m_type_name = element_type_name ; +endfunction +function string uvm_printer_element::get_element_type_name (); + return m_type_name ; +endfunction +function void uvm_printer_element::set_element_size (string element_size); + m_size = element_size ; +endfunction +function string uvm_printer_element::get_element_size (); + return m_size ; +endfunction +function void uvm_printer_element::set_element_value (string element_value); + m_value = element_value ; +endfunction +function string uvm_printer_element::get_element_value (); + return m_value ; +endfunction +function void uvm_printer_element::add_child(uvm_printer_element child) ; + m_children.push_back(child) ; +endfunction +function void uvm_printer_element::get_children(ref uvm_printer_element children[$], input bit recurse) ; + foreach (m_children[i]) begin + children.push_back(m_children[i]) ; + if (recurse) begin + m_children[i].get_children(children,1) ; + end + end +endfunction +function void uvm_printer_element::clear_children() ; + m_children.delete() ; +endfunction +function uvm_table_printer::new(string name=""); + super.new(name); +endfunction +function void uvm_table_printer::pop_element(); + int name_len; + int level ; + uvm_printer_element popped ; + string name_str ; + string type_name_str ; + string size_str ; + string value_str ; + popped = get_top_element() ; + level = m_get_stack_size() - 1 ; + name_str = popped.get_element_name() ; + type_name_str = popped.get_element_type_name() ; + size_str = popped.get_element_size() ; + value_str = popped.get_element_value() ; + if ((name_str.len() + (get_indent() * level)) > m_max_name) m_max_name = (name_str.len() + (get_indent() * level)); + if (type_name_str.len() > m_max_type) m_max_type = type_name_str.len(); + if (size_str.len() > m_max_size) m_max_size = size_str.len(); + if (value_str.len() > m_max_value) m_max_value = value_str.len(); + super.pop_element() ; +endfunction +function string uvm_table_printer::emit(); + string s; + string user_format; + static string dash; + string dashes; + string linefeed; + if (!m_flushed) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/PRINT/NO_FLUSH")) + uvm_report_error ("UVM/PRINT/NO_FLUSH", "printer emit() method called twice without intervening uvm_printer::flush()", UVM_NONE, "t/uvm/src/base/uvm_printer.svh", 1516, "", 1); + end + end + else m_flushed = 0 ; + linefeed = {"\n", get_line_prefix()}; + begin + int q[5]; + int m; + int qq[$]; + q = '{m_max_name,m_max_type,m_max_size,m_max_value,100}; + qq = q.max; + m = qq[0]; + if(dash.len() 0) && (value_str[0] == "@")) + result = {result,"(",element.get_element_type_name(),value_str,") "}; + else + if (get_type_name_enabled() && + (element.get_element_type_name() != "" || + element.get_element_type_name() != "-" || + element.get_element_type_name() != "...")) + result = {result,"(",element.get_element_type_name(),") "}; + if (get_size_enabled()) begin + if (element.get_element_size() != "" || element.get_element_size() != "-") + result = {result,"(",element.get_element_size(),") "}; + end + if (element_children.size() > 0) begin + result = {result, string'(separators[0]), m_linefeed}; + end + else result = {result, value_str, " ", m_linefeed}; + foreach (element_children[i]) begin + result = {result, m_emit_element(element_children[i],level+1)} ; + end + if (element_children.size() > 0) begin + result = {result, indent_str, string'(separators[1]), m_linefeed}; + end + end + return result ; +endfunction : m_emit_element +function void uvm_table_printer::set_default(uvm_table_printer printer) ; + m_default_table_printer = printer ; +endfunction +function uvm_table_printer uvm_table_printer::get_default() ; + if (m_default_table_printer == null) begin + m_default_table_printer = new("uvm_default_table_printer") ; + end + return m_default_table_printer ; +endfunction +function void uvm_table_printer::set_indent(int indent) ; + m_uvm_printer_knobs _knobs = get_knobs(); + _knobs.indent = indent ; +endfunction +function int uvm_table_printer::get_indent() ; + m_uvm_printer_knobs _knobs = get_knobs(); + return _knobs.indent ; +endfunction +function void uvm_table_printer::flush() ; + super.flush() ; + m_max_name=4; + m_max_type=4; + m_max_size=4; + m_max_value=5; +endfunction +function void uvm_tree_printer::set_default(uvm_tree_printer printer) ; + m_default_tree_printer = printer ; +endfunction +function uvm_tree_printer uvm_tree_printer::get_default() ; + if (m_default_tree_printer == null) begin + m_default_tree_printer = new("uvm_default_tree_printer") ; + end + return m_default_tree_printer ; +endfunction +function uvm_line_printer::new(string name="") ; + super.new(name); + m_newline = " "; + set_indent(0); +endfunction +function void uvm_line_printer::set_default(uvm_line_printer printer) ; + m_default_line_printer = printer ; +endfunction +function uvm_line_printer uvm_line_printer::get_default() ; + if (m_default_line_printer == null) begin + m_default_line_printer = new("uvm_default_line_printer") ; + end + return m_default_line_printer ; +endfunction +function void uvm_line_printer::set_separators(string separators) ; + m_uvm_printer_knobs _knobs = get_knobs(); + if (separators.len() < 2) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/PRINT/SHORT_SEP")) + uvm_report_error ("UVM/PRINT/SHORT_SEP", $sformatf("Bad call: set_separators(%s) (Argument must have at least 2 characters)",separators), UVM_NONE, "t/uvm/src/base/uvm_printer.svh", 1888, "", 1); + end + end + _knobs.separator = separators ; +endfunction +function string uvm_line_printer::get_separators() ; + m_uvm_printer_knobs _knobs = get_knobs(); + return _knobs.separator ; +endfunction +function void uvm_line_printer::flush() ; + super.flush() ; +endfunction +class uvm_comparer extends uvm_policy; + typedef uvm_object_registry#(uvm_comparer,"uvm_comparer") type_id; + static function uvm_comparer type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_comparer tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_comparer"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_comparer"; + endfunction : get_type_name + extern virtual function void flush(); + extern virtual function uvm_policy::recursion_state_e object_compared( + uvm_object lhs, + uvm_object rhs, + uvm_recursion_policy_enum recursion, + output bit ret_val + ); + extern virtual function string get_miscompares(); + extern virtual function int unsigned get_result(); + extern virtual function void set_result(int unsigned result) ; + extern virtual function void set_recursion_policy( uvm_recursion_policy_enum policy); + extern virtual function uvm_recursion_policy_enum get_recursion_policy(); + extern virtual function void set_check_type( bit enabled ); + extern virtual function bit get_check_type(); + extern virtual function void set_show_max (int unsigned show_max); + extern virtual function int unsigned get_show_max (); + extern virtual function void set_verbosity (int unsigned verbosity); + extern virtual function int unsigned get_verbosity (); + extern virtual function void set_severity (uvm_severity severity); + extern virtual function uvm_severity get_severity (); + extern virtual function void set_threshold (int unsigned threshold); + extern virtual function int unsigned get_threshold (); + typedef struct { + recursion_state_e state; + bit ret_val; + } state_info_t ; + state_info_t m_recur_states[uvm_object ][uvm_object ][uvm_recursion_policy_enum ]; + local uvm_recursion_policy_enum policy = UVM_DEFAULT_POLICY; + local int unsigned show_max = 1; + local int unsigned verbosity = UVM_LOW; + local uvm_severity sev = UVM_INFO; + local string miscompares = ""; + local bit check_type = 1; + local int unsigned result = 0; + local int unsigned m_threshold; + function new(string name=""); + super.new(name); + m_threshold = 1; + endfunction + static function void set_default (uvm_comparer comparer) ; + uvm_coreservice_t coreservice ; + coreservice = uvm_coreservice_t::get() ; + coreservice.set_default_comparer(comparer) ; + endfunction + static function uvm_comparer get_default () ; + uvm_coreservice_t coreservice ; + coreservice = uvm_coreservice_t::get() ; + return coreservice.get_default_comparer() ; + endfunction + virtual function bit compare_field (string name, + uvm_bitstream_t lhs, + uvm_bitstream_t rhs, + int size, + uvm_radix_enum radix=UVM_NORADIX); + uvm_bitstream_t mask; + string msg; + if(size <= 64) + return compare_field_int(name, lhs, rhs, size, radix); + mask = -1; + mask >>= (UVM_STREAMBITS-size); + if((lhs & mask) !== (rhs & mask)) begin + case (radix) + UVM_BIN: begin + $swrite(msg, "%s: lhs = 'b%0b : rhs = 'b%0b", + name, lhs&mask, rhs&mask); + end + UVM_OCT: begin + $swrite(msg, "%s: lhs = 'o%0o : rhs = 'o%0o", + name, lhs&mask, rhs&mask); + end + UVM_DEC: begin + $swrite(msg, "%s: lhs = %0d : rhs = %0d", + name, lhs&mask, rhs&mask); + end + UVM_TIME: begin + $swrite(msg, "%s: lhs = %0t : rhs = %0t", + name, lhs&mask, rhs&mask); + end + UVM_STRING: begin + $swrite(msg, "%s: lhs = %0s : rhs = %0s", + name, lhs&mask, rhs&mask); + end + UVM_ENUM: begin + $swrite(msg, "%s: lhs = %0d : rhs = %0d", + name, lhs&mask, rhs&mask); + end + default: begin + $swrite(msg, "%s: lhs = 'h%0x : rhs = 'h%0x", + name, lhs&mask, rhs&mask); + end + endcase + print_msg(msg); + return 0; + end + return 1; + endfunction + virtual function bit compare_field_int (string name, + uvm_integral_t lhs, + uvm_integral_t rhs, + int size, + uvm_radix_enum radix=UVM_NORADIX); + logic [63:0] mask; + string msg; + mask = -1; + mask >>= (64-size); + if((lhs & mask) !== (rhs & mask)) begin + case (radix) + UVM_BIN: begin + $swrite(msg, "%s: lhs = 'b%0b : rhs = 'b%0b", + name, lhs&mask, rhs&mask); + end + UVM_OCT: begin + $swrite(msg, "%s: lhs = 'o%0o : rhs = 'o%0o", + name, lhs&mask, rhs&mask); + end + UVM_DEC: begin + $swrite(msg, "%s: lhs = %0d : rhs = %0d", + name, lhs&mask, rhs&mask); + end + UVM_TIME: begin + $swrite(msg, "%s: lhs = %0t : rhs = %0t", + name, lhs&mask, rhs&mask); + end + UVM_STRING: begin + $swrite(msg, "%s: lhs = %0s : rhs = %0s", + name, lhs&mask, rhs&mask); + end + UVM_ENUM: begin + $swrite(msg, "%s: lhs = %0d : rhs = %0d", + name, lhs&mask, rhs&mask); + end + default: begin + $swrite(msg, "%s: lhs = 'h%0x : rhs = 'h%0x", + name, lhs&mask, rhs&mask); + end + endcase + print_msg(msg); + return 0; + end + return 1; + endfunction + virtual function bit compare_field_real (string name, + real lhs, + real rhs); + string msg; + if(lhs != rhs) begin + $swrite(msg, name, ": lhs = ", lhs, " : rhs = ", rhs); + print_msg(msg); + return 0; + end + return 1; + endfunction + local string m_object_names[$]; + local function string m_current_context(string name=""); + if (m_object_names.size() == 0) + return name; + else if ((m_object_names.size() == 1) && (name=="")) + return m_object_names[0]; + else begin + string full_name; + foreach(m_object_names[i]) begin + if (i == m_object_names.size() - 1) + full_name = {full_name, m_object_names[i]}; + else + full_name = {full_name, m_object_names[i], "."}; + end + if (name != "") + return {full_name, ".", name}; + else + return full_name; + end + endfunction : m_current_context + virtual function bit compare_object (string name, + uvm_object lhs, + uvm_object rhs); + int old_result ; + uvm_field_op field_op ; + uvm_policy::recursion_state_e prev_state; + bit ret_val = 1; + if (rhs == lhs) + return ret_val; + m_object_names.push_back(name); + if (policy == UVM_REFERENCE && lhs != rhs) begin + print_msg_object(lhs, rhs); + ret_val = 0; + end + if (ret_val && (rhs == null || lhs == null)) begin + print_msg_object(lhs, rhs); + ret_val = 0; + end + if (ret_val) begin + prev_state = object_compared(lhs,rhs,get_recursion_policy(),ret_val); + if (prev_state != uvm_policy::NEVER) + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/COPIER/LOOP")) + uvm_report_warning ("UVM/COPIER/LOOP", {"Possible loop when comparing '", lhs.get_full_name(), "' to '", rhs.get_full_name(), "'"}, UVM_NONE, "t/uvm/src/base/uvm_comparer.svh", 465, "", 1); + end + push_active_object(lhs); + m_recur_states[lhs][rhs][get_recursion_policy()] = '{uvm_policy::STARTED,0}; + old_result = get_result(); + if (get_check_type() && (lhs.get_object_type() != rhs.get_object_type())) begin + if(lhs.get_type_name() != rhs.get_type_name()) begin + print_msg({"type: lhs = \"", lhs.get_type_name(), "\" : rhs = \"", rhs.get_type_name(), "\""}); + end + else begin + print_msg({"get_object_type() for ",lhs.get_name()," does not match get_object_type() for ",rhs.get_name()}); + end + end + field_op = uvm_field_op::m_get_available_op(); + field_op.set(UVM_COMPARE,this,rhs); + lhs.do_execute_op(field_op); + if (field_op.user_hook_enabled()) begin + ret_val = lhs.do_compare(rhs,this); + end + field_op.m_recycle(); + if (ret_val && (get_result() > old_result)) + ret_val = 0; + m_recur_states[lhs][rhs][get_recursion_policy()] = '{uvm_policy::FINISHED,ret_val}; + void'(pop_active_object()); + end + void'(m_object_names.pop_back()); + if (!ret_val && (get_active_object_depth() == 0)) begin + string msg ; + if(get_result()) begin + if (get_show_max() && (get_show_max() < get_result())) + $swrite(msg, "%0d Miscompare(s) (%0d shown) for object ", + result, show_max); + else + $swrite(msg, "%0d Miscompare(s) for object ", result); + end + uvm_pkg::uvm_report(sev, "MISCMP", $sformatf("%s%s@%0d vs. %s@%0d", msg, + (lhs == null) ? "" : lhs.get_name(), + (lhs == null) ? 0 : lhs.get_inst_id(), + (rhs == null) ? "" : rhs.get_name(), + (rhs == null) ? 0 : rhs.get_inst_id()), + get_verbosity(), "t/uvm/src/base/uvm_comparer.svh", 525); + end + return ret_val; + endfunction + virtual function bit compare_string (string name, + string lhs, + string rhs); + string msg; + if(lhs != rhs) begin + msg = { name, ": lhs = \"", lhs, "\" : rhs = \"", rhs, "\""}; + print_msg(msg); + return 0; + end + return 1; + endfunction + function void print_msg (string msg); + string tmp = m_current_context(msg); + result++; + if((get_show_max() == 0) || + (get_result() <= get_show_max())) begin + msg = {"Miscompare for ", tmp}; + uvm_pkg::uvm_report(sev, "MISCMP", msg, get_verbosity(), "t/uvm/src/base/uvm_comparer.svh", 573); + end + miscompares = { miscompares, tmp, "\n" }; + endfunction + function void print_msg_object(uvm_object lhs, uvm_object rhs); + string tmp = $sformatf("%s: lhs = @%0d : rhs = @%0d", + m_current_context(), + (lhs != null ? lhs.get_inst_id() : 0), + (rhs != null ? rhs.get_inst_id() : 0)); + result++; + if((get_show_max() == 0) || + (get_result() <= get_show_max())) begin + uvm_pkg::uvm_report(sev, + "MISCMP", + {"Miscompare for ", tmp}, + get_verbosity(), + "t/uvm/src/base/uvm_comparer.svh", + 599); + end + miscompares = { miscompares, tmp, "\n" }; + endfunction + int depth; + bit compare_map[uvm_object][uvm_object]; +endclass +function void uvm_comparer::flush(); + miscompares = "" ; + check_type = 1 ; + result = 0 ; + m_recur_states.delete(); +endfunction +function uvm_policy::recursion_state_e uvm_comparer::object_compared( + uvm_object lhs, + uvm_object rhs, + uvm_recursion_policy_enum recursion, + output bit ret_val +); + if (!m_recur_states.exists(lhs)) return NEVER ; + else if (!m_recur_states[lhs].exists(rhs)) return NEVER ; + else if (!m_recur_states[lhs][rhs].exists(recursion)) return NEVER ; + else begin + if (m_recur_states[lhs][rhs][recursion].state == FINISHED) + ret_val = m_recur_states[lhs][rhs][recursion].ret_val; + return m_recur_states[lhs][rhs][recursion].state ; + end +endfunction +function string uvm_comparer::get_miscompares(); + return miscompares ; +endfunction +function int unsigned uvm_comparer::get_result(); + return result ; +endfunction +function void uvm_comparer::set_result(int unsigned result); + this.result = result ; +endfunction +function void uvm_comparer::set_recursion_policy( uvm_recursion_policy_enum policy); + this.policy = policy ; +endfunction +function uvm_recursion_policy_enum uvm_comparer::get_recursion_policy(); + return policy ; +endfunction +function void uvm_comparer::set_check_type( bit enabled ); + check_type = enabled ; +endfunction +function bit uvm_comparer::get_check_type(); + return check_type ; +endfunction +function void uvm_comparer::set_show_max (int unsigned show_max); + this.show_max = show_max ; +endfunction +function int unsigned uvm_comparer::get_show_max(); + return show_max ; +endfunction +function void uvm_comparer::set_verbosity (int unsigned verbosity); + this.verbosity = verbosity ; +endfunction +function int unsigned uvm_comparer::get_verbosity(); + return verbosity ; +endfunction +function void uvm_comparer::set_severity (uvm_severity severity); + sev = severity ; +endfunction +function uvm_severity uvm_comparer::get_severity(); + return sev ; +endfunction +function void uvm_comparer::set_threshold (int unsigned threshold); + m_threshold = threshold; +endfunction +function int unsigned uvm_comparer::get_threshold(); + return m_threshold; +endfunction +typedef bit signed [(4096*8)-1:0] uvm_pack_bitstream_t; +class uvm_packer extends uvm_policy; + typedef uvm_object_registry#(uvm_packer,"uvm_packer") type_id; + static function uvm_packer type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_packer tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_packer"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_packer"; + endfunction : get_type_name + uvm_factory m_factory; + local uvm_object m_object_references[int]; + extern virtual function void set_packed_bits (ref bit unsigned stream[]); + extern virtual function void set_packed_bytes (ref byte unsigned stream[]); + extern virtual function void set_packed_ints (ref int unsigned stream[]); + extern virtual function void set_packed_longints (ref longint unsigned stream[]); + extern virtual function void get_packed_bits (ref bit unsigned stream[]); + extern virtual function void get_packed_bytes (ref byte unsigned stream[]); + extern virtual function void get_packed_ints (ref int unsigned stream[]); + extern virtual function void get_packed_longints (ref longint unsigned stream[]); + static function void set_default (uvm_packer packer) ; + uvm_coreservice_t coreservice ; + coreservice = uvm_coreservice_t::get() ; + coreservice.set_default_packer(packer) ; + endfunction + static function uvm_packer get_default () ; + uvm_coreservice_t coreservice ; + coreservice = uvm_coreservice_t::get() ; + return coreservice.get_default_packer() ; + endfunction + extern virtual function void flush (); + extern virtual function void pack_field (uvm_bitstream_t value, int size); + extern function new(string name=""); + extern virtual function void pack_field_int (uvm_integral_t value, int size); + extern virtual function void pack_bits(ref bit value[], input int size = -1); + extern virtual function void pack_bytes(ref byte value[], input int size = -1); + extern virtual function void pack_ints(ref int value[], input int size = -1); + extern virtual function void pack_string (string value); + extern virtual function void pack_time (time value); + extern virtual function void pack_real (real value); + extern virtual function void pack_object (uvm_object value); + extern virtual function void pack_object_with_meta (uvm_object value); + extern virtual function void pack_object_wrapper (uvm_object_wrapper value); + extern virtual function bit is_null (); + extern virtual function bit is_object_wrapper(); + extern virtual function uvm_bitstream_t unpack_field (int size); + extern virtual function uvm_integral_t unpack_field_int (int size); + extern virtual function void unpack_bits(ref bit value[], input int size = -1); + extern virtual function void unpack_bytes(ref byte value[], input int size = -1); + extern virtual function void unpack_ints(ref int value[], input int size = -1); + extern virtual function string unpack_string (); + extern virtual function time unpack_time (); + extern virtual function real unpack_real (); + extern virtual function void unpack_object (uvm_object value); + extern virtual function void unpack_object_with_meta (inout uvm_object value); + extern virtual function uvm_object_wrapper unpack_object_wrapper(); + extern virtual function int get_packed_size(); + static bit bitstream[]; + static bit fabitstream[]; + int m_pack_iter; + int m_unpack_iter; + bit reverse_order; + byte byte_size = 8; + int word_size = 16; + bit nopack; + uvm_pack_bitstream_t m_bits; + extern function void index_error(int index, string id, int sz); + extern function bit enough_bits(int needed, string id); +endclass +function void uvm_packer::index_error(int index, string id, int sz); + uvm_report_error("PCKIDX", + $sformatf("index %0d for get_%0s too large; valid index range is 0-%0d.", + index,id,((m_pack_iter+sz-1)/sz)-1), UVM_NONE); +endfunction +function bit uvm_packer::enough_bits(int needed, string id); + if ((m_pack_iter - m_unpack_iter) < needed) begin + uvm_report_error("PCKSZ", + $sformatf("%0d bits needed to unpack %0s, yet only %0d available.", + needed, id, (m_pack_iter - m_unpack_iter)), UVM_NONE); + return 0; + end + return 1; +endfunction +function int uvm_packer::get_packed_size(); + return m_pack_iter - m_unpack_iter; +endfunction +function void uvm_packer::flush(); + m_pack_iter = 64; + m_unpack_iter = 64; + m_bits = 0; + m_object_references.delete(); + m_object_references[0] = null; + m_factory = null; + super.flush(); +endfunction : flush +function void uvm_packer::get_packed_bits(ref bit unsigned stream[]); + stream = new[m_pack_iter]; + m_bits[31:0] = m_pack_iter; + m_bits[63:32] = m_unpack_iter; + for (int i=0;i> ($bits(byte)-(m_pack_iter%$bits(byte)))); + stream[i] = v; + end +endfunction +function void uvm_packer::get_packed_ints (ref int unsigned stream[] ); + int sz; + int v; + sz = (m_pack_iter + $high(v)) / $bits(int); + m_bits[31:0] = m_pack_iter; + m_bits[63:32] = m_unpack_iter; + stream = new[sz]; + foreach (stream[i]) begin + if (i != sz-1 || (m_pack_iter % $bits(int)) == 0) + v = m_bits[ i* $bits(int) +: $bits(int) ]; + else + v = m_bits[ i* $bits(int) +: $bits(int) ] & ({$bits(int){1'b1}} >> ($bits(int)-(m_pack_iter%$bits(int)))); + stream[i] = v; + end +endfunction +function void uvm_packer::get_packed_longints (ref longint unsigned stream[] ); + int sz; + longint v; + sz = (m_pack_iter + $high(v)) / $bits(longint); + m_bits[31:0] = m_pack_iter; + m_bits[63:32] = m_unpack_iter; + stream = new[sz]; + foreach (stream[i]) begin + if (i != sz-1 || (m_pack_iter % $bits(longint)) == 0) + v = m_bits[ i* $bits(longint) +: $bits(longint) ]; + else + v = m_bits[ i* $bits(longint) +: $bits(longint) ] & ({$bits(longint){1'b1}} >> ($bits(longint)-(m_pack_iter%$bits(longint)))); + stream[i] = v; + end +endfunction +function void uvm_packer::set_packed_bits (ref bit stream []); + int bit_size; + bit_size = stream.size(); + for (int i=0;i value.size()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/BASE/PACKER/BAD_SIZE")) + uvm_report_error ("UVM/BASE/PACKER/BAD_SIZE", $sformatf("pack_bits called with size '%0d', which exceeds value.size() of '%0d'", size, value.size()), UVM_NONE, "t/uvm/src/base/uvm_packer.svh", 797, "", 1); + end + return; + end + for (int i=0; i max_size) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/BASE/PACKER/BAD_SIZE")) + uvm_report_error ("UVM/BASE/PACKER/BAD_SIZE", $sformatf("pack_bytes called with size '%0d', which exceeds value size of '%0d'", size, max_size), UVM_NONE, "t/uvm/src/base/uvm_packer.svh", 824, "", 1); + end + return; + end + else begin + int idx_select; + for (int i=0; i max_size) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/BASE/PACKER/BAD_SIZE")) + uvm_report_error ("UVM/BASE/PACKER/BAD_SIZE", $sformatf("pack_ints called with size '%0d', which exceeds value size of '%0d'", size, max_size), UVM_NONE, "t/uvm/src/base/uvm_packer.svh", 858, "", 1); + end + return; + end + else begin + int idx_select; + for (int i=0; i value.size()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/BASE/PACKER/BAD_SIZE")) + uvm_report_error ("UVM/BASE/PACKER/BAD_SIZE", $sformatf("unpack_bits called with size '%0d', which exceeds value.size() of '%0d'", size, value.size()), UVM_NONE, "t/uvm/src/base/uvm_packer.svh", 1076, "", 1); + end + return; + end + if (enough_bits(size, "integral")) begin + m_unpack_iter += size; + for (int i=0; i max_size) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/BASE/PACKER/BAD_SIZE")) + uvm_report_error ("UVM/BASE/PACKER/BAD_SIZE", $sformatf("unpack_bytes called with size '%0d', which exceeds value size of '%0d'", size, value.size()), UVM_NONE, "t/uvm/src/base/uvm_packer.svh", 1104, "", 1); + end + return; + end + else begin + if (enough_bits(size, "integral")) begin + m_unpack_iter += size; + for (int i=0; i max_size) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/BASE/PACKER/BAD_SIZE")) + uvm_report_error ("UVM/BASE/PACKER/BAD_SIZE", $sformatf("unpack_ints called with size '%0d', which exceeds value size of '%0d'", size, value.size()), UVM_NONE, "t/uvm/src/base/uvm_packer.svh", 1136, "", 1); + end + return; + end + else begin + if (enough_bits(size, "integral")) begin + m_unpack_iter += size; + for (int i=0; i' is not supported in links for 'uvm_tr_database'", UVM_NONE, "t/uvm/src/base/uvm_tr_database.svh", 158, "", 1); + end + return; + end + if (rhs == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/TR_DB/BAD_LINK")) + uvm_report_warning ("UVM/TR_DB/BAD_LINK", "right hand side '' is not supported in links for 'uvm_tr_database'", UVM_NONE, "t/uvm/src/base/uvm_tr_database.svh", 163, "", 1); + end + return; + end + if (!$cast(s_lhs, lhs) && + !$cast(r_lhs, lhs)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/TR_DB/BAD_LINK")) + uvm_report_warning ("UVM/TR_DB/BAD_LINK", $sformatf("left hand side of type '%s' not supported in links for 'uvm_tr_database'", lhs.get_type_name()), UVM_NONE, "t/uvm/src/base/uvm_tr_database.svh", 171, "", 1); + end + return; + end + if (!$cast(s_rhs, rhs) && + !$cast(r_rhs, rhs)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/TR_DB/BAD_LINK")) + uvm_report_warning ("UVM/TR_DB/BAD_LINK", $sformatf("right hand side of type '%s' not supported in links for 'uvm_record_datbasae'", rhs.get_type_name()), UVM_NONE, "t/uvm/src/base/uvm_tr_database.svh", 178, "", 1); + end + return; + end + if (r_lhs != null) begin + s_lhs = r_lhs.get_stream(); + end + if (r_rhs != null) begin + s_rhs = r_rhs.get_stream(); + end + if ((s_lhs != null) && (s_lhs.get_db() != this)) begin + db = s_lhs.get_db(); + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/TR_DB/BAD_LINK")) + uvm_report_warning ("UVM/TR_DB/BAD_LINK", $sformatf("attempt to link stream from '%s' into '%s'", db.get_name(), this.get_name()), UVM_NONE, "t/uvm/src/base/uvm_tr_database.svh", 193, "", 1); + end + return; + end + if ((s_rhs != null) && (s_rhs.get_db() != this)) begin + db = s_rhs.get_db(); + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/TR_DB/BAD_LINK")) + uvm_report_warning ("UVM/TR_DB/BAD_LINK", $sformatf("attempt to link stream from '%s' into '%s'", db.get_name(), this.get_name()), UVM_NONE, "t/uvm/src/base/uvm_tr_database.svh", 200, "", 1); + end + return; + end + do_establish_link(link); + endfunction : establish_link + pure virtual protected function bit do_open_db(); + pure virtual protected function bit do_close_db(); + pure virtual protected function uvm_tr_stream do_open_stream(string name, + string scope, + string type_name); + pure virtual protected function void do_establish_link(uvm_link_base link); +endclass : uvm_tr_database +typedef class uvm_recorder; +typedef class uvm_tr_stream; +typedef class uvm_link_base; +typedef class uvm_simple_lock_dap; +typedef class uvm_text_tr_stream; +class uvm_text_tr_database extends uvm_tr_database; + local uvm_simple_lock_dap#(string) m_filename_dap; + UVM_FILE m_file; + typedef uvm_object_registry#(uvm_text_tr_database,"uvm_text_tr_database") type_id; + static function uvm_text_tr_database type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_text_tr_database tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_text_tr_database"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_text_tr_database"; + endfunction : get_type_name + function new(string name="unnamed-uvm_text_tr_database"); + super.new(name); + m_filename_dap = new("filename_dap"); + m_filename_dap.set("tr_db.log"); + endfunction : new + protected virtual function bit do_open_db(); + if (m_file == 0) begin + m_file = $fopen(m_filename_dap.get(), "a+"); + if (m_file != 0) + m_filename_dap.lock(); + end + return (m_file != 0); + endfunction : do_open_db + protected virtual function bit do_close_db(); + if (m_file != 0) begin + fork + $fclose(m_file); + join_none + m_filename_dap.unlock(); + end + return 1; + endfunction : do_close_db + protected virtual function uvm_tr_stream do_open_stream(string name, + string scope, + string type_name); + uvm_text_tr_stream m_stream = uvm_text_tr_stream::type_id_create(name); + return m_stream; + endfunction : do_open_stream + protected virtual function void do_establish_link(uvm_link_base link); + uvm_recorder r_lhs, r_rhs; + uvm_object lhs = link.get_lhs(); + uvm_object rhs = link.get_rhs(); + void'($cast(r_lhs, lhs)); + void'($cast(r_rhs, rhs)); + if ((r_lhs == null) || + (r_rhs == null)) + return; + else begin + uvm_parent_child_link pc_link; + uvm_related_link re_link; + if ($cast(pc_link, link)) begin + $fdisplay(m_file," LINK @%0t {TXH1:%0d TXH2:%0d RELATION=%0s}", + $time, + r_lhs.get_handle(), + r_rhs.get_handle(), + "child"); + end + else if ($cast(re_link, link)) begin + $fdisplay(m_file," LINK @%0t {TXH1:%0d TXH2:%0d RELATION=%0s}", + $time, + r_lhs.get_handle(), + r_rhs.get_handle(), + ""); + end + end + endfunction : do_establish_link + function void set_file_name(string filename); + if (filename == "") begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/TXT_DB/EMPTY_NAME")) + uvm_report_warning ("UVM/TXT_DB/EMPTY_NAME", "Ignoring attempt to set file name to ''!", UVM_NONE, "t/uvm/src/base/uvm_text_tr_database.svh", 195, "", 1); + end + return; + end + if (!m_filename_dap.try_set(filename)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/TXT_DB/SET_AFTER_OPEN")) + uvm_report_warning ("UVM/TXT_DB/SET_AFTER_OPEN", "Ignoring attempt to change file name after opening the db!", UVM_NONE, "t/uvm/src/base/uvm_text_tr_database.svh", 201, "", 1); + end + return; + end + endfunction : set_file_name +endclass : uvm_text_tr_database +class m_uvm_tr_stream_cfg; + uvm_tr_database db; + string scope; + string stream_type_name; +endclass : m_uvm_tr_stream_cfg +typedef class uvm_set_before_get_dap; +typedef class uvm_text_recorder; +virtual class uvm_tr_stream extends uvm_object; + local uvm_set_before_get_dap#(m_uvm_tr_stream_cfg) m_cfg_dap; + local bit m_records[uvm_recorder]; + local bit m_warn_null_cfg; + local bit m_is_opened; + local bit m_is_closed; + function new(string name="unnamed-uvm_tr_stream"); + super.new(name); + m_cfg_dap = new("cfg_dap"); + endfunction : new + local static int m_ids_by_stream[uvm_tr_stream]; + function uvm_tr_database get_db(); + m_uvm_tr_stream_cfg m_cfg; + if (!m_cfg_dap.try_get(m_cfg)) begin + if (m_warn_null_cfg == 1) + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/REC_STR/NO_CFG")) + uvm_report_warning ("UVM/REC_STR/NO_CFG", $sformatf("attempt to retrieve DB from '%s' before it was set!", get_name()), UVM_NONE, "t/uvm/src/base/uvm_tr_stream.svh", 94, "", 1); + end + m_warn_null_cfg = 0; + return null; + end + return m_cfg.db; + endfunction : get_db + function string get_scope(); + m_uvm_tr_stream_cfg m_cfg; + if (!m_cfg_dap.try_get(m_cfg)) begin + if (m_warn_null_cfg == 1) + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/REC_STR/NO_CFG")) + uvm_report_warning ("UVM/REC_STR/NO_CFG", $sformatf("attempt to retrieve scope from '%s' before it was set!", get_name()), UVM_NONE, "t/uvm/src/base/uvm_tr_stream.svh", 109, "", 1); + end + m_warn_null_cfg = 0; + return ""; + end + return m_cfg.scope; + endfunction : get_scope + function string get_stream_type_name(); + m_uvm_tr_stream_cfg m_cfg; + if (!m_cfg_dap.try_get(m_cfg)) begin + if (m_warn_null_cfg == 1) + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/REC_STR/NO_CFG")) + uvm_report_warning ("UVM/REC_STR/NO_CFG", $sformatf("attempt to retrieve STREAM_TYPE_NAME from '%s' before it was set!", get_name()), UVM_NONE, "t/uvm/src/base/uvm_tr_stream.svh", 124, "", 1); + end + m_warn_null_cfg = 0; + return ""; + end + return m_cfg.stream_type_name; + endfunction : get_stream_type_name + function void close(); + if (!is_open()) + return; + do_close(); + foreach (m_records[idx]) + if (idx.is_open()) + idx.close(); + m_is_opened = 0; + m_is_closed = 1; + endfunction : close + function void free(); + process p; + string s; + uvm_tr_database db; + if (!is_open() && !is_closed()) + return; + if (is_open()) + close(); + do_free(); + foreach (m_records[idx]) + idx.free(); + db = get_db(); + m_is_closed = 0; + p = process::self(); + if(p != null) + s = p.get_randstate(); + m_cfg_dap = new("cfg_dap"); + if(p != null) + p.set_randstate(s); + m_warn_null_cfg = 1; + if (m_ids_by_stream.exists(this)) + m_free_id(m_ids_by_stream[this]); + if (db != null) + db.m_free_stream(this); + endfunction : free + function void m_do_open(uvm_tr_database db, + string scope="", + string stream_type_name=""); + m_uvm_tr_stream_cfg m_cfg; + uvm_tr_database m_db; + if (db == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/REC_STR/NULL_DB")) + uvm_report_error ("UVM/REC_STR/NULL_DB", $sformatf("Illegal attempt to set DB for '%s' to ''", this.get_full_name()), UVM_NONE, "t/uvm/src/base/uvm_tr_stream.svh", 217, "", 1); + end + return; + end + if (m_cfg_dap.try_get(m_cfg)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/REC_STR/RE_CFG")) + uvm_report_error ("UVM/REC_STR/RE_CFG", $sformatf("Illegal attempt to re-open '%s'", this.get_full_name()), UVM_NONE, "t/uvm/src/base/uvm_tr_stream.svh", 224, "", 1); + end + end + else begin + m_cfg = new(); + m_cfg.db = db; + m_cfg.scope = scope; + m_cfg.stream_type_name = stream_type_name; + m_cfg_dap.set(m_cfg); + m_is_opened = 1; + do_open(db, scope, stream_type_name); + end + endfunction : m_do_open + function bit is_open(); + return m_is_opened; + endfunction : is_open + function bit is_closed(); + return m_is_closed; + endfunction : is_closed + function uvm_recorder open_recorder(string name, + time open_time = 0, + string type_name=""); + time m_time = (open_time == 0) ? $time : open_time; + if (!is_open()) + return null; + else begin + process p = process::self(); + string s; + if (p != null) + s = p.get_randstate(); + open_recorder = do_open_recorder(name, + m_time, + type_name); + if (open_recorder != null) begin + m_records[open_recorder] = 1; + open_recorder.m_do_open(this, m_time, type_name); + end + if (p != null) + p.set_randstate(s); + end + endfunction : open_recorder + function void m_free_recorder(uvm_recorder recorder); + if (m_records.exists(recorder)) + m_records.delete(recorder); + endfunction : m_free_recorder + function unsigned get_recorders(ref uvm_recorder q[$]); + q.delete(); + foreach (m_records[idx]) + q.push_back(idx); + return q.size(); + endfunction : get_recorders + local static uvm_tr_stream m_streams_by_id[int]; + function int get_handle(); + if (!is_open() && !is_closed()) begin + return 0; + end + else begin + int handle = get_inst_id(); + if (m_ids_by_stream.exists(this) && m_ids_by_stream[this] != handle) + m_streams_by_id.delete(m_ids_by_stream[this]); + m_streams_by_id[handle] = this; + m_ids_by_stream[this] = handle; + return handle; + end + endfunction : get_handle + static function uvm_tr_stream get_stream_from_handle(int id); + if (id == 0) + return null; + if ($isunknown(id) || !m_streams_by_id.exists(id)) + return null; + return m_streams_by_id[id]; + endfunction : get_stream_from_handle + static function void m_free_id(int id); + uvm_tr_stream stream; + if (!$isunknown(id) && m_streams_by_id.exists(id)) + stream = m_streams_by_id[id]; + if (stream != null) begin + m_streams_by_id.delete(id); + m_ids_by_stream.delete(stream); + end + endfunction : m_free_id + protected virtual function void do_open(uvm_tr_database db, + string scope, + string stream_type_name); + endfunction : do_open + protected virtual function void do_close(); + endfunction : do_close + protected virtual function void do_free(); + endfunction : do_free + protected virtual function uvm_recorder do_open_recorder(string name, + time open_time, + string type_name); + return null; + endfunction : do_open_recorder +endclass : uvm_tr_stream +class uvm_text_tr_stream extends uvm_tr_stream; + local uvm_text_tr_database m_text_db; + typedef uvm_object_registry#(uvm_text_tr_stream,"uvm_text_tr_stream") type_id; + static function uvm_text_tr_stream type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_text_tr_stream tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_text_tr_stream"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_text_tr_stream"; + endfunction : get_type_name +function void do_execute_op( uvm_field_op op ); + super.do_execute_op(op); + __m_uvm_execute_field_op(op); +endfunction : do_execute_op +local function void __m_uvm_execute_field_op( uvm_field_op __local_op__ ); + uvm_field_flag_t local_op_type__; + uvm_text_tr_stream local_rhs__; + uvm_resource_base local_rsrc__; + string local_rsrc_name__; + uvm_object local_obj__; + bit local_success__; + typedef uvm_text_tr_stream __local_type__; + int local_size__; + uvm_printer __local_printer__; + uvm_comparer __local_comparer__; + uvm_recorder __local_recorder__; + uvm_packer __local_packer__; + uvm_copier __local_copier__; + void'($cast(local_rhs__, __local_op__.get_rhs())); + if (($cast(local_rsrc__, __local_op__.get_rhs())) && + (local_rsrc__ != null)) + local_rsrc_name__ = local_rsrc__.get_name(); + local_op_type__ = __local_op__.get_op_type(); + case (local_op_type__) + UVM_PRINT: begin + $cast(__local_printer__, __local_op__.get_policy()); + end + UVM_COMPARE: begin + if (local_rhs__ == null) return; + $cast(__local_comparer__, __local_op__.get_policy()); + end + UVM_RECORD: begin + $cast(__local_recorder__, __local_op__.get_policy()); + end + UVM_PACK, UVM_UNPACK: begin + $cast(__local_packer__, __local_op__.get_policy()); + end + UVM_COPY: begin + if (local_rhs__ == null) return; + $cast(__local_copier__, __local_op__.get_policy()); + end + UVM_SET: begin + if (local_rsrc__ == null) return; + end + default: + return; + endcase +endfunction : __m_uvm_execute_field_op + function new(string name="unnamed-uvm_text_tr_stream"); + super.new(name); + endfunction : new + protected virtual function void do_open(uvm_tr_database db, + string scope, + string stream_type_name); + $cast(m_text_db, db); + if (m_text_db.open_db()) + $fdisplay(m_text_db.m_file, + " CREATE_STREAM @%0t {NAME:%s T:%s SCOPE:%s STREAM:%0d}", + $time, + this.get_name(), + stream_type_name, + scope, + this.get_handle()); + endfunction : do_open + protected virtual function void do_close(); + if (m_text_db.open_db()) + $fdisplay(m_text_db.m_file, + " CLOSE_STREAM @%0t {NAME:%s T:%s SCOPE:%s STREAM:%0d}", + $time, + this.get_name(), + this.get_stream_type_name(), + this.get_scope(), + this.get_handle()); + endfunction : do_close + protected virtual function void do_free(); + if (m_text_db.open_db()) + $fdisplay(m_text_db.m_file, + " FREE_STREAM @%0t {NAME:%s T:%s SCOPE:%s STREAM:%0d}", + $time, + this.get_name(), + this.get_stream_type_name(), + this.get_scope(), + this.get_handle()); + m_text_db = null; + return; + endfunction : do_free + protected virtual function uvm_recorder do_open_recorder(string name, + time open_time, + string type_name); + if (m_text_db.open_db()) begin + return uvm_text_recorder::type_id_create(name); + end + return null; + endfunction : do_open_recorder +endclass : uvm_text_tr_stream +typedef class uvm_report_message; +virtual class uvm_recorder extends uvm_policy; + typedef uvm_abstract_object_registry#(uvm_recorder,"uvm_recorder") type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_recorder"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_recorder"; + endfunction : get_type_name + local uvm_set_before_get_dap#(uvm_tr_stream) m_stream_dap; + local bit m_warn_null_stream; + local bit m_is_opened; + local bit m_is_closed; + local time m_open_time; + local time m_close_time; + int recording_depth; + uvm_radix_enum default_radix = UVM_HEX; + bit identifier = 1; + local + uvm_recursion_policy_enum policy = UVM_DEFAULT_POLICY; + virtual function void set_recursion_policy(uvm_recursion_policy_enum policy); + this.policy = policy; + endfunction : set_recursion_policy + virtual function uvm_recursion_policy_enum get_recursion_policy(); + return this.policy; + endfunction : get_recursion_policy + virtual function void flush(); + policy = UVM_DEFAULT_POLICY; + identifier = 1; + free(); + endfunction : flush + local static int m_ids_by_recorder[uvm_recorder]; + function new(string name = "uvm_recorder"); + super.new(name); + m_stream_dap = new("stream_dap"); + m_warn_null_stream = 1; + endfunction + function uvm_tr_stream get_stream(); + if (!m_stream_dap.try_get(get_stream)) begin + if (m_warn_null_stream == 1) + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/REC/NO_CFG")) + uvm_report_warning ("UVM/REC/NO_CFG", $sformatf("attempt to retrieve STREAM from '%s' before it was set!", get_name()), UVM_NONE, "t/uvm/src/base/uvm_recorder.svh", 178, "", 1); + end + m_warn_null_stream = 0; + end + endfunction : get_stream + function void close(time close_time = 0); + if (close_time == 0) + close_time = $realtime; + if (!is_open()) + return; + do_close(close_time); + m_is_opened = 0; + m_is_closed = 1; + m_close_time = close_time; + endfunction : close + function void free(time close_time = 0); + process p=process::self(); + string s; + uvm_tr_stream stream; + if (!is_open() && !is_closed()) + return; + if (is_open()) begin + close(close_time); + end + do_free(); + stream = get_stream(); + m_is_closed = 0; + if(p != null) + s=p.get_randstate(); + m_stream_dap = new("stream_dap"); + if(p != null) + p.set_randstate(s); + m_warn_null_stream = 1; + if (m_ids_by_recorder.exists(this)) + m_free_id(m_ids_by_recorder[this]); + if (stream != null) + stream.m_free_recorder(this); + endfunction : free + function bit is_open(); + return m_is_opened; + endfunction : is_open + function time get_open_time(); + return m_open_time; + endfunction : get_open_time + function bit is_closed(); + return m_is_closed; + endfunction : is_closed + function time get_close_time(); + return m_close_time; + endfunction : get_close_time + function void m_do_open(uvm_tr_stream stream, time open_time, string type_name); + uvm_tr_stream m_stream; + if (stream == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/REC/NULL_STREAM")) + uvm_report_error ("UVM/REC/NULL_STREAM", $sformatf("Illegal attempt to set STREAM for '%s' to ''", this.get_name()), UVM_NONE, "t/uvm/src/base/uvm_recorder.svh", 287, "", 1); + end + return; + end + if (m_stream_dap.try_get(m_stream)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/REC/RE_INIT")) + uvm_report_error ("UVM/REC/RE_INIT", $sformatf("Illegal attempt to re-initialize '%s'", this.get_name()), UVM_NONE, "t/uvm/src/base/uvm_recorder.svh", 294, "", 1); + end + return; + end + m_stream_dap.set(stream); + m_open_time = open_time; + m_is_opened = 1; + do_open(stream, open_time, type_name); + endfunction : m_do_open + local static uvm_recorder m_recorders_by_id[int]; + local static int m_id; + static function void m_free_id(int id); + uvm_recorder recorder; + if ((!$isunknown(id)) && (m_recorders_by_id.exists(id))) + recorder = m_recorders_by_id[id]; + if (recorder != null) begin + m_recorders_by_id.delete(id); + m_ids_by_recorder.delete(recorder); + end + endfunction : m_free_id + function int get_handle(); + if (!is_open() && !is_closed()) begin + return 0; + end + else begin + int handle = get_inst_id(); + if (m_ids_by_recorder.exists(this) && m_ids_by_recorder[this] != handle) + m_recorders_by_id.delete(m_ids_by_recorder[this]); + m_recorders_by_id[handle] = this; + m_ids_by_recorder[this] = handle; + return handle; + end + endfunction : get_handle + static function uvm_recorder get_recorder_from_handle(int id); + if (id == 0) + return null; + if (($isunknown(id)) || (!m_recorders_by_id.exists(id))) + return null; + return m_recorders_by_id[id]; + endfunction : get_recorder_from_handle + function void record_field(string name, + uvm_bitstream_t value, + int size, + uvm_radix_enum radix=UVM_NORADIX); + if (get_stream() == null) begin + return; + end + do_record_field(name, value, size, radix); + endfunction : record_field + function void record_field_int(string name, + uvm_integral_t value, + int size, + uvm_radix_enum radix=UVM_NORADIX); + if (get_stream() == null) begin + return; + end + do_record_field_int(name, value, size, radix); + endfunction : record_field_int + function void record_field_real(string name, + real value); + if (get_stream() == null) begin + return; + end + do_record_field_real(name, value); + endfunction : record_field_real + function void record_object(string name, + uvm_object value); + if (get_stream() == null) begin + return; + end + if (value == null) + do_record_object(name, value); + else begin + push_active_object(value); + do_record_object(name, value); + void'(pop_active_object()); + end + endfunction : record_object + function void record_string(string name, + string value); + if (get_stream() == null) begin + return; + end + do_record_string(name, value); + endfunction : record_string + function void record_time(string name, + time value); + if (get_stream() == null) begin + return; + end + do_record_time(name, value); + endfunction : record_time + function void record_generic(string name, + string value, + string type_name=""); + if (get_stream() == null) begin + return; + end + do_record_generic(name, value, type_name); + endfunction : record_generic + virtual function bit use_record_attribute(); + return 0; + endfunction : use_record_attribute + virtual function int get_record_attribute_handle(); + return get_handle(); + endfunction : get_record_attribute_handle + protected virtual function void do_open(uvm_tr_stream stream, + time open_time, + string type_name); + endfunction : do_open + protected virtual function void do_close(time close_time); + endfunction : do_close + protected virtual function void do_free(); + endfunction : do_free + pure virtual protected function void do_record_field(string name, + uvm_bitstream_t value, + int size, + uvm_radix_enum radix); + pure virtual protected function void do_record_field_int(string name, + uvm_integral_t value, + int size, + uvm_radix_enum radix); + pure virtual protected function void do_record_field_real(string name, + real value); + virtual protected function void do_record_object(string name, + uvm_object value); + if ((get_recursion_policy() != UVM_REFERENCE) && + (value != null)) begin + uvm_field_op field_op = uvm_field_op::m_get_available_op(); + field_op.set(UVM_RECORD, this, null); + value.do_execute_op(field_op); + if (field_op.user_hook_enabled()) + value.do_record(this); + field_op.m_recycle(); + end + endfunction : do_record_object + pure virtual protected function void do_record_string(string name, + string value); + pure virtual protected function void do_record_time(string name, + time value); + pure virtual protected function void do_record_generic(string name, + string value, + string type_name); + virtual function bit open_file(); + return 0; + endfunction + virtual function int create_stream (string name, + string t, + string scope); + return -1; + endfunction + virtual function void m_set_attribute (int txh, + string nm, + string value); + endfunction + virtual function void set_attribute (int txh, + string nm, + logic [1023:0] value, + uvm_radix_enum radix, + int numbits=1024); + endfunction + virtual function int check_handle_kind (string htype, int handle); + return 0; + endfunction + virtual function int begin_tr(string txtype, + int stream, + string nm, + string label="", + string desc="", + time begin_time=0); + return -1; + endfunction + virtual function void end_tr (int handle, time end_time=0); + endfunction + virtual function void link_tr(int h1, + int h2, + string relation=""); + endfunction + virtual function void free_tr(int handle); + endfunction +endclass +class uvm_text_recorder extends uvm_recorder; + typedef uvm_object_registry#(uvm_text_recorder,"uvm_text_recorder") type_id; + static function uvm_text_recorder type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_text_recorder tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_text_recorder"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_text_recorder"; + endfunction : get_type_name + uvm_text_tr_database m_text_db; + function new(string name="unnamed-uvm_text_recorder"); + super.new(name); + endfunction : new + protected virtual function void do_open(uvm_tr_stream stream, + time open_time, + string type_name); + $cast(m_text_db, stream.get_db()); + if (m_text_db.open_db()) + $fdisplay(m_text_db.m_file, + " OPEN_RECORDER @%0t {TXH:%0d STREAM:%0d NAME:%s TIME:%0t TYPE=\"%0s\"}", + $realtime, + this.get_handle(), + stream.get_handle(), + this.get_name(), + open_time, + type_name); + endfunction : do_open + protected virtual function void do_close(time close_time); + if (m_text_db.open_db()) begin + $fdisplay(m_text_db.m_file, + " CLOSE_RECORDER @%0t {TXH:%0d TIME=%0t}", + $realtime, + this.get_handle(), + close_time); + end + endfunction : do_close + protected virtual function void do_free(); + if (m_text_db.open_db()) begin + $fdisplay(m_text_db.m_file, + " FREE_RECORDER @%0t {TXH:%0d}", + $realtime, + this.get_handle()); + end + m_text_db = null; + endfunction : do_free + protected virtual function void do_record_field(string name, + uvm_bitstream_t value, + int size, + uvm_radix_enum radix); + if (!radix) + radix = default_radix; + write_attribute(m_current_context(name), + value, + radix, + size); + endfunction : do_record_field + protected virtual function void do_record_field_int(string name, + uvm_integral_t value, + int size, + uvm_radix_enum radix); + if (!radix) + radix = default_radix; + write_attribute_int(m_current_context(name), + value, + radix, + size); + endfunction : do_record_field_int + protected virtual function void do_record_field_real(string name, + real value); + bit [63:0] ival = $realtobits(value); + write_attribute_int(m_current_context(name), + ival, + UVM_REAL, + 64); + endfunction : do_record_field_real + local string m_object_names[$]; + local function string m_current_context(string name=""); + if (m_object_names.size() == 0) + return name; + else if ((m_object_names.size() == 1) && (name=="")) + return m_object_names[0]; + else begin + string full_name; + foreach(m_object_names[i]) begin + if (i == m_object_names.size() - 1) + full_name = {full_name, m_object_names[i]}; + else + full_name = {full_name, m_object_names[i], "."}; + end + if (name != "") + return {full_name, ".", name}; + else + return full_name; + end + endfunction : m_current_context + protected virtual function void do_record_object(string name, + uvm_object value); + int v; + string str; + if(identifier) begin + if(value != null) begin + v = value.get_inst_id(); + end + write_attribute_int("inst_id", + v, + UVM_DEC, + 32); + end + if (get_active_object_depth() > 1) + m_object_names.push_back(name); + super.do_record_object(name, value); + if (get_active_object_depth() > 1) + void'(m_object_names.pop_back()); + endfunction : do_record_object + protected virtual function void do_record_string(string name, + string value); + if (m_text_db.open_db()) begin + $fdisplay(m_text_db.m_file, + " SET_ATTR @%0t {TXH:%0d NAME:%s VALUE:%s RADIX:%s BITS=%0d}", + $realtime, + this.get_handle(), + m_current_context(name), + value, + "UVM_STRING", + 8+value.len()); + end + endfunction : do_record_string + protected virtual function void do_record_time(string name, + time value); + write_attribute_int(m_current_context(name), + value, + UVM_TIME, + 64); + endfunction : do_record_time + protected virtual function void do_record_generic(string name, + string value, + string type_name); + write_attribute(m_current_context(name), + uvm_string_to_bits(value), + UVM_STRING, + 8+value.len()); + endfunction : do_record_generic + function void write_attribute(string nm, + uvm_bitstream_t value, + uvm_radix_enum radix, + int numbits=$bits(uvm_bitstream_t)); + if (m_text_db.open_db()) begin + $fdisplay(m_text_db.m_file, + " SET_ATTR @%0t {TXH:%0d NAME:%s VALUE:%s RADIX:%s BITS=%0d}", + $realtime, + this.get_handle(), + nm, + uvm_bitstream_to_string(value, numbits, radix), + radix.name(), + numbits); + end + endfunction : write_attribute + function void write_attribute_int(string nm, + uvm_integral_t value, + uvm_radix_enum radix, + int numbits=$bits(uvm_bitstream_t)); + if (m_text_db.open_db()) begin + $fdisplay(m_text_db.m_file, + " SET_ATTR @%0t {TXH:%0d NAME:%s VALUE:%s RADIX:%s BITS=%0d}", + $realtime, + this.get_handle(), + nm, + uvm_integral_to_string(value, numbits, radix), + radix.name(), + numbits); + end + endfunction : write_attribute_int + string filename; + bit filename_set; + virtual function bit open_file(); + if (!filename_set) begin + m_text_db.set_file_name(filename); + end + return m_text_db.open_db(); + endfunction + virtual function int create_stream (string name, + string t, + string scope); + uvm_text_tr_stream stream; + if (open_file()) begin + $cast(stream,m_text_db.open_stream(name, scope, t)); + return stream.get_handle(); + end + return 0; + endfunction + virtual function void m_set_attribute (int txh, + string nm, + string value); + if (open_file()) begin + UVM_FILE file = m_text_db.m_file; + $fdisplay(file," SET_ATTR @%0t {TXH:%0d NAME:%s VALUE:%s}", $realtime,txh,nm,value); + end + endfunction + virtual function void set_attribute (int txh, + string nm, + logic [1023:0] value, + uvm_radix_enum radix, + int numbits=1024); + if (open_file()) begin + UVM_FILE file = m_text_db.m_file; + $fdisplay(file, + " SET_ATTR @%0t {TXH:%0d NAME:%s VALUE:%s RADIX:%s BITS=%0d}", + $realtime, + txh, + nm, + uvm_bitstream_to_string(value, numbits, radix), + radix.name(), + numbits); + end + endfunction + virtual function int check_handle_kind (string htype, int handle); + return ((uvm_recorder::get_recorder_from_handle(handle) != null) || + (uvm_tr_stream::get_stream_from_handle(handle) != null)); + endfunction + virtual function int begin_tr(string txtype, + int stream, + string nm, + string label="", + string desc="", + time begin_time=0); + if (open_file()) begin + uvm_tr_stream stream_obj = uvm_tr_stream::get_stream_from_handle(stream); + uvm_recorder recorder; + if (stream_obj == null) + return -1; + recorder = stream_obj.open_recorder(nm, begin_time, txtype); + return recorder.get_handle(); + end + return -1; + endfunction + virtual function void end_tr (int handle, time end_time=0); + if (open_file()) begin + uvm_recorder record = uvm_recorder::get_recorder_from_handle(handle); + if (record != null) begin + record.close(end_time); + end + end + endfunction + virtual function void link_tr(int h1, + int h2, + string relation=""); + if (open_file()) + $fdisplay(m_text_db.m_file," LINK @%0t {TXH1:%0d TXH2:%0d RELATION=%0s}", $realtime,h1,h2,relation); + endfunction + virtual function void free_tr(int handle); + if (open_file()) begin + uvm_recorder record = uvm_recorder::get_recorder_from_handle(handle); + if (record != null) begin + record.free(); + end + end + endfunction +endclass : uvm_text_recorder +typedef class uvm_object; +typedef class uvm_event; +typedef class uvm_callback; +typedef class uvm_callbacks; +virtual class uvm_event_callback#(type T=uvm_object) extends uvm_callback; + function new (string name=""); + super.new(name); + endfunction + virtual function bit pre_trigger (uvm_event#(T) e, T data); + return 0; + endfunction + virtual function void post_trigger (uvm_event#(T) e, T data); + return; + endfunction + virtual function uvm_object create (string name=""); + return null; + endfunction +endclass +virtual class uvm_event_base extends uvm_object; + typedef uvm_abstract_object_registry#(uvm_event_base,"uvm_event_base") type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_event_base"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_event_base"; + endfunction : get_type_name + protected event m_event; + protected int num_waiters; + protected bit on; + protected time trigger_time=0; + function new (string name=""); + super.new(name); + endfunction + virtual task wait_on (bit delta = 0); + if (on) begin + if (delta) + #0; + return; + end + num_waiters++; + @on; + endtask + virtual task wait_off (bit delta = 0); + if (!on) begin + if (delta) + #0; + return; + end + num_waiters++; + @on; + endtask + virtual task wait_trigger (); + num_waiters++; + @m_event; + endtask + virtual task wait_ptrigger (); + if (m_event.triggered) + return; + num_waiters++; + @m_event; + endtask + virtual function time get_trigger_time (); + return trigger_time; + endfunction + virtual function bit is_on (); + return (on == 1); + endfunction + virtual function bit is_off (); + return (on == 0); + endfunction + virtual function void reset (bit wakeup = 0); + event e; + if (wakeup) + ->m_event; +//TODO issue #4468 - Fix UVM assignment of event data types +//TODO %Error-UNSUPPORTED: t/t_uvm_pkg_todo.vh:7477:25: Unsupported: assignment of event data type +//TODO m_event = e; + num_waiters = 0; + on = 0; + trigger_time = 0; + endfunction + virtual function void cancel (); + if (num_waiters > 0) + num_waiters--; + endfunction + virtual function int get_num_waiters (); + return num_waiters; + endfunction + virtual function void do_print (uvm_printer printer); + printer.print_field_int("num_waiters", num_waiters, $bits(num_waiters), UVM_DEC, ".", "int"); + printer.print_field_int("on", on, $bits(on), UVM_BIN, ".", "bit"); + printer.print_time("trigger_time", trigger_time); + endfunction + virtual function void do_copy (uvm_object rhs); + uvm_event_base e; + super.do_copy(rhs); + if(!$cast(e, rhs) || (e==null)) return; +//TODO issue #4468 - Fix UVM assignment of event data types +//TODO %Error-UNSUPPORTED: t/t_uvm_pkg_todo.vh:7498:25: Unsupported: assignment of event data type +//TODO m_event = e.m_event; + num_waiters = e.num_waiters; + on = e.on; + trigger_time = e.trigger_time; + endfunction +endclass +class uvm_event#(type T=uvm_object) extends uvm_event_base; + typedef uvm_event#(T) this_type; + typedef uvm_event_callback#(T) cb_type; + typedef uvm_callbacks#(this_type, cb_type) cbs_type; + static local function bit m_register_cb(); + return uvm_callbacks#(this_type,cb_type)::m_register_pair( + "uvm_pkg::uvm_event#(T)", + "uvm_pkg::uvm_event_callback#(T)" + ); + endfunction : m_register_cb + static local bit m_cb_registered = m_register_cb(); + typedef uvm_object_registry #(this_type) type_id; + static function this_type type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + this_type tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + virtual function string get_type_name(); + return "uvm_pkg::uvm_event#(T)"; + endfunction : get_type_name + local T trigger_data; + local T default_data; + function new (string name=""); + super.new(name); + endfunction + virtual task wait_trigger_data (output T data); + wait_trigger(); + data = get_trigger_data(); + endtask + virtual task wait_ptrigger_data (output T data); + 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); + int skip; + cb_type cb_q[$]; + skip=0; + cbs_type::get_all(cb_q, this); + foreach (cb_q[i]) + skip += cb_q[i].pre_trigger(this, data); + if (skip==0) begin + ->m_event; + foreach (cb_q[i]) + cb_q[i].post_trigger(this, data); + num_waiters = 0; + on = 1; + trigger_time = $realtime; + trigger_data = data; + end + endfunction + virtual function T get_trigger_data (); + return trigger_data; + endfunction + virtual function T get_default_data(); + return default_data; + endfunction : get_default_data + virtual function void set_default_data(T data); + default_data = data; + endfunction : set_default_data + virtual function void do_print (uvm_printer printer); + uvm_event#(uvm_object) oe; + cb_type cb_q[$]; + super.do_print(printer); + cbs_type::get_all(cb_q, this); + printer.print_array_header("callbacks", cb_q.size(), "queue"); + foreach(cb_q[e]) + printer.print_object($sformatf("[%0d]", e), cb_q[e], "["); + printer.print_array_footer(cb_q.size()); + if ($cast(oe, this)) begin + printer.print_object("trigger_data", oe.get_trigger_data()); + end + else begin + uvm_event#(string) se; + if ($cast(se, this)) + printer.print_string("trigger_data", se.get_trigger_data()); + end + endfunction + virtual function void do_copy (uvm_object rhs); + this_type e; + cb_type cb_q[$]; + super.do_copy(rhs); + if(!$cast(e, rhs) || (e==null)) return; + trigger_data = e.trigger_data; + begin + cbs_type::get_all(cb_q, this); + foreach(cb_q[i]) + cbs_type::delete(this, cb_q[i]); + cb_q.delete(); + cbs_type::get_all(cb_q, e); + foreach(cb_q[i]) + cbs_type::add(this, cb_q[i]); + end + endfunction +endclass +class uvm_barrier extends uvm_object; + local int threshold; + local int num_waiters; + local bit at_threshold; + local bit auto_reset; + local uvm_event#(uvm_object) m_event; + typedef uvm_object_registry#(uvm_barrier,"uvm_barrier") type_id; + static function uvm_barrier type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_barrier tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_barrier"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_barrier"; + endfunction : get_type_name + function new (string name="", int threshold=0); + super.new(name); + m_event = new({"barrier_",name}); + this.threshold = threshold; + num_waiters = 0; + auto_reset = 1; + at_threshold = 0; + endfunction + virtual task wait_for(); + if (at_threshold) + return; + num_waiters++; + if (num_waiters >= threshold) begin + if (!auto_reset) + at_threshold=1; + m_trigger(); + return; + end + m_event.wait_trigger(); + endtask + virtual function void reset (bit wakeup=1); + at_threshold = 0; + if (num_waiters) begin + if (wakeup) + m_event.trigger(); + else + m_event.reset(); + end + num_waiters = 0; + endfunction + virtual function void set_auto_reset (bit value=1); + at_threshold = 0; + auto_reset = value; + endfunction + virtual function void set_threshold (int threshold); + this.threshold = threshold; + if (threshold <= num_waiters) + reset(1); + endfunction + virtual function int get_threshold (); + return threshold; + endfunction + virtual function int get_num_waiters (); + return num_waiters; + endfunction + virtual function void cancel (); + m_event.cancel(); + num_waiters = m_event.get_num_waiters(); + endfunction + local task m_trigger(); + m_event.trigger(); + num_waiters=0; + #0; + endtask + virtual function void do_print (uvm_printer printer); + printer.print_field_int("threshold", threshold, $bits(threshold), UVM_DEC, ".", "int"); + printer.print_field_int("num_waiters", num_waiters, $bits(num_waiters), UVM_DEC, ".", "int"); + printer.print_field_int("at_threshold", at_threshold, $bits(at_threshold), UVM_BIN, ".", "bit"); + printer.print_field_int("auto_reset", auto_reset, $bits(auto_reset), UVM_BIN, ".", "bit"); + endfunction + virtual function void do_copy (uvm_object rhs); + uvm_barrier b; + super.do_copy(rhs); + if(!$cast(b, rhs) || (b==null)) return; + threshold = b.threshold; + num_waiters = b.num_waiters; + at_threshold = b.at_threshold; + auto_reset = b.auto_reset; + m_event = b.m_event; + endfunction +endclass +typedef class uvm_root; +typedef class uvm_callback; +typedef class uvm_callbacks_base; +class uvm_typeid_base; + static string typename; + static uvm_callbacks_base typeid_map[uvm_typeid_base]; + static uvm_typeid_base type_map[uvm_callbacks_base]; +endclass +class uvm_typeid#(type T=uvm_object) extends uvm_typeid_base; + static uvm_typeid#(T) m_b_inst; + static function uvm_typeid#(T) get(); + if(m_b_inst == null) + m_b_inst = new; + return m_b_inst; + endfunction +endclass +class uvm_callbacks_base extends uvm_object; + typedef uvm_callbacks_base this_type; + static bit m_tracing = 1; + static this_type m_b_inst; + static uvm_pool#(uvm_object,uvm_queue#(uvm_callback)) m_pool; + static function this_type m_initialize(); + if(m_b_inst == null) begin + m_b_inst = new; + m_pool = new; + end + return m_b_inst; + endfunction + this_type m_this_type[$]; + uvm_typeid_base m_super_type; + uvm_typeid_base m_derived_types[$]; + virtual function bit m_am_i_a(uvm_object obj); + return 0; + endfunction + virtual function bit m_is_for_me(uvm_callback cb); + return 0; + endfunction + virtual function bit m_is_registered(uvm_object obj, uvm_callback cb); + return 0; + endfunction + virtual function uvm_queue#(uvm_callback) m_get_tw_cb_q(uvm_object obj); + return null; + endfunction + virtual function void m_add_tw_cbs(uvm_callback cb, uvm_apprepend ordering); + endfunction + virtual function bit m_delete_tw_cbs(uvm_callback cb); + return 0; + endfunction + function bit check_registration(uvm_object obj, uvm_callback cb); + this_type dt; + if (m_is_registered(obj,cb)) + return 1; + foreach(m_this_type[i]) + if(m_b_inst != m_this_type[i] && m_this_type[i].m_is_registered(obj,cb)) + return 1; + if(obj == null) begin + foreach(m_derived_types[i]) begin + dt = uvm_typeid_base::typeid_map[m_derived_types[i] ]; + if(dt != null && dt.check_registration(null,cb)) + return 1; + end + end + return 0; + endfunction +endclass +class uvm_typed_callbacks#(type T=uvm_object) extends uvm_callbacks_base; + static uvm_queue#(uvm_callback) m_tw_cb_q; + static string m_typename; + typedef uvm_typed_callbacks#(T) this_type; + typedef uvm_callbacks_base super_type; + static this_type m_t_inst; + static function this_type m_initialize(); + if(m_t_inst == null) begin + void'(super_type::m_initialize()); + m_t_inst = new; + m_t_inst.m_tw_cb_q = new("typewide_queue"); + end + return m_t_inst; + endfunction + virtual function bit m_am_i_a(uvm_object obj); + T casted_obj; + if (obj == null) + return 1; + return($cast(casted_obj,obj)); + endfunction + virtual function uvm_queue#(uvm_callback) m_get_tw_cb_q(uvm_object obj); + if(m_am_i_a(obj)) begin + foreach(m_derived_types[i]) begin + super_type dt; + dt = uvm_typeid_base::typeid_map[m_derived_types[i] ]; + if(dt != null && dt != this) begin + m_get_tw_cb_q = dt.m_get_tw_cb_q(obj); + if(m_get_tw_cb_q != null) + return m_get_tw_cb_q; + end + end + return m_t_inst.m_tw_cb_q; + end + else + return null; + endfunction + static function int m_cb_find(uvm_queue#(uvm_callback) q, uvm_callback cb); + for(int i=0; i str.len() ? max_cb_name : str.len(); + str = "(*)"; + max_inst_name = max_inst_name > str.len() ? max_inst_name : str.len(); + end + if(obj ==null) begin + if(m_t_inst.m_pool.first(bobj)) begin + do + if($cast(me,bobj)) break; + while(m_t_inst.m_pool.next(bobj)); + end + if(me != null || m_t_inst.m_tw_cb_q.size()) begin + qs.push_back($sformatf("Registered callbacks for all instances of %s\n", tname)); + qs.push_back("---------------------------------------------------------------\n"); + end + if(me != null) begin + do begin + if($cast(me,bobj)) begin + q = m_t_inst.m_pool.get(bobj); + if (q==null) begin + q=new; + m_t_inst.m_pool.add(bobj,q); + end + for(int i=0; i str.len() ? max_cb_name : str.len(); + str = bobj.get_full_name(); + max_inst_name = max_inst_name > str.len() ? max_inst_name : str.len(); + end + end + end while (m_t_inst.m_pool.next(bobj)); + end + else begin + qs.push_back($sformatf("No callbacks registered for any instances of type %s\n", tname)); + end + end + else begin + if(m_t_inst.m_pool.exists(bobj) || m_t_inst.m_tw_cb_q.size()) begin + qs.push_back($sformatf("Registered callbacks for instance %s of %s\n", obj.get_full_name(), tname)); + qs.push_back("---------------------------------------------------------------\n"); + end + if(m_t_inst.m_pool.exists(bobj)) begin + q = m_t_inst.m_pool.get(bobj); + if(q==null) begin + q=new; + m_t_inst.m_pool.add(bobj,q); + end + for(int i=0; i str.len() ? max_cb_name : str.len(); + str = bobj.get_full_name(); + max_inst_name = max_inst_name > str.len() ? max_inst_name : str.len(); + end + end + end + if(!cbq.size()) begin + if(obj == null) str = "*"; + else str = obj.get_full_name(); + qs.push_back($sformatf("No callbacks registered for instance %s of type %s\n", str, tname)); + end + foreach (cbq[i]) begin + qs.push_back($sformatf("%s %s %s on %s %s\n", cbq[i], blanks.substr(0,max_cb_name-cbq[i].len()-1), inst_q[i], blanks.substr(0,max_inst_name - inst_q[i].len()-1), mode_q[i])); + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_INFO,"UVM/CB/DISPLAY")) + uvm_report_info ("UVM/CB/DISPLAY", uvm_pkg::m_uvm_string_queue_join(qs), UVM_NONE, "t/uvm/src/base/uvm_callback.svh", 435, "", 1); + end + m_tracing = 1; + endfunction +endclass +class uvm_callbacks #(type T=uvm_object, type CB=uvm_callback) + extends uvm_typed_callbacks#(T); + typedef uvm_typed_callbacks#(T) super_type; + typedef uvm_callbacks#(T,CB) this_type; + local static this_type m_inst; + static uvm_typeid_base m_typeid; + static uvm_typeid_base m_cb_typeid; + static string m_typename; + static string m_cb_typename; + static uvm_callbacks#(T,uvm_callback) m_base_inst; + bit m_registered; + static function this_type get(); + if (m_inst == null) begin + uvm_typeid_base cb_base_type; + void'(super_type::m_initialize()); + cb_base_type = uvm_typeid#(uvm_callback)::get(); + m_cb_typeid = uvm_typeid#(CB)::get(); + m_typeid = uvm_typeid#(T)::get(); + m_inst = new; + if (cb_base_type == m_cb_typeid) begin + $cast(m_base_inst, m_inst); + m_t_inst = m_base_inst; + uvm_typeid_base::typeid_map[m_typeid] = m_inst; + uvm_typeid_base::type_map[m_b_inst] = m_typeid; + end + else begin + m_base_inst = uvm_callbacks#(T,uvm_callback)::get(); + m_base_inst.m_this_type.push_back(m_inst); + end + if (m_inst == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"CB/INTERNAL")) + uvm_report_fatal ("CB/INTERNAL", "get(): m_inst is null", UVM_NONE, "t/uvm/src/base/uvm_callback.svh", 547, "", 1); + end + end + return m_inst; + endfunction + static function bit m_register_pair(string tname="", cbname=""); + this_type inst = get(); + m_typename = tname; + super_type::m_typename = tname; + m_typeid.typename = tname; + m_cb_typename = cbname; + m_cb_typeid.typename = cbname; + inst.m_registered = 1; + return 1; + endfunction + virtual function bit m_is_registered(uvm_object obj, uvm_callback cb); + if(m_is_for_me(cb) && m_am_i_a(obj)) begin + return m_registered; + end + endfunction + virtual function bit m_is_for_me(uvm_callback cb); + CB this_cb; + return($cast(this_cb,cb)); + endfunction + static function void add(T obj, uvm_callback cb, uvm_apprepend ordering=UVM_APPEND); + uvm_queue#(uvm_callback) q; + string nm,tnm; + void'(get()); + if (cb==null) begin + if (obj==null) + nm = "(*)"; + else + nm = obj.get_full_name(); + if (m_base_inst.m_typename!="") + tnm = m_base_inst.m_typename; + else if (obj != null) + tnm = obj.get_type_name(); + else + tnm = "uvm_object"; + uvm_report_error("CBUNREG", + {"Null callback object cannot be registered with object ", + nm, " (", tnm, ")"}, UVM_NONE); + return; + end + if (!m_base_inst.check_registration(obj,cb)) begin + if (obj==null) + nm = "(*)"; + else + nm = obj.get_full_name(); + if (m_base_inst.m_typename!="") + tnm = m_base_inst.m_typename; + else if(obj != null) + tnm = obj.get_type_name(); + else + tnm = "uvm_object"; + uvm_report_warning("CBUNREG", + {"Callback ", cb.get_name(), " cannot be registered with object ", + nm, " because callback type ", cb.get_type_name(), + " is not registered with object type ", tnm }, UVM_NONE); + end + if(obj == null) begin + if (m_cb_find(m_t_inst.m_tw_cb_q,cb) != -1) begin + if (m_base_inst.m_typename!="") + tnm = m_base_inst.m_typename; + else tnm = "uvm_object"; + uvm_report_warning("CBPREG", + {"Callback object ", cb.get_name(), + " is already registered with type ", tnm }, UVM_NONE); + end + else begin + m_t_inst.m_add_tw_cbs(cb,ordering); + end + end + else begin + q = m_base_inst.m_pool.get(obj); + if (q==null) begin + q=new; + m_base_inst.m_pool.add(obj,q); + end + if(q.size() == 0) begin + uvm_report_object o; + if($cast(o,obj)) begin + uvm_queue#(uvm_callback) qr; + void'(uvm_callbacks#(uvm_report_object, uvm_callback)::get()); + qr = uvm_callbacks#(uvm_report_object,uvm_callback)::m_t_inst.m_tw_cb_q; + for(int i=0; i=0; --itr) + if ($cast(cb, q.get(itr)) && cb.callback_mode()) + return cb; + return null; + endfunction + static function CB get_next (ref int itr, input T obj); + uvm_queue#(uvm_callback) q; + CB cb; + void'(get()); + m_get_q(q,obj); + for(itr = itr+1; itr= 0; --itr) + if($cast(cb, q.get(itr)) && cb.callback_mode()) + return cb; + return null; + endfunction + static function void get_all ( ref CB all_callbacks[$], input T obj=null ); + uvm_queue#(uvm_callback) q; + CB cb; + CB callbacks_to_append[$]; + CB unique_callbacks_to_append[$]; + void'( get() ); + if ((obj == null) || (!m_pool.exists(obj))) begin + for (int qi=0; qi= m_max_quit_count); + endfunction + function int get_severity_count(uvm_severity severity); + return m_severity_count[severity]; + endfunction + function void set_severity_count(uvm_severity severity, int count); + m_severity_count[severity] = count < 0 ? 0 : count; + endfunction + function void incr_severity_count(uvm_severity severity); + m_severity_count[severity]++; + endfunction + function void reset_severity_counts(); + uvm_severity s; + s = s.first(); + forever begin + m_severity_count[s] = 0; + if(s == s.last()) break; + s = s.next(); + end + endfunction + function int get_id_count(string id); + if(m_id_count.exists(id)) + return m_id_count[id]; + return 0; + endfunction + function void set_id_count(string id, int count); + m_id_count[id] = count < 0 ? 0 : count; + endfunction + function void incr_id_count(string id); + if(m_id_count.exists(id)) + m_id_count[id]++; + else + m_id_count[id] = 1; + endfunction + virtual function void set_message_database(uvm_tr_database database); + m_message_db = database; + endfunction : set_message_database + virtual function uvm_tr_database get_message_database(); + return m_message_db; + endfunction : get_message_database + virtual function void get_severity_set(output uvm_severity q[$]); + foreach(m_severity_count[idx]) + q.push_back(idx); + endfunction + virtual function void get_id_set(output string q[$]); + foreach(m_id_count[idx]) + q.push_back(idx); + endfunction + function void f_display(UVM_FILE file, string str); + if (file == 0) + $display("%s", str); + else + $fdisplay(file, "%s", str); + endfunction + virtual function void process_report_message(uvm_report_message report_message); + uvm_report_handler l_report_handler = report_message.get_report_handler(); + process p = process::self(); + bit report_ok = 1; + report_message.set_report_server(this); + if(report_ok) + report_ok = uvm_report_catcher::process_all_report_catchers(report_message); + if(uvm_action_type'(report_message.get_action()) == UVM_NO_ACTION) + report_ok = 0; + if(report_ok) begin + string m; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_report_server svr = cs.get_report_server(); + if (report_message.get_action() & (UVM_LOG|UVM_DISPLAY)) + m = svr.compose_report_message(report_message); + svr.execute_report_message(report_message, m); + end + endfunction + virtual function void execute_report_message(uvm_report_message report_message, + string composed_message); + process p = process::self(); + incr_severity_count(report_message.get_severity()); + incr_id_count(report_message.get_id()); + if (record_all_messages) + report_message.set_action(report_message.get_action() | UVM_RM_RECORD); + if(report_message.get_action() & UVM_RM_RECORD) begin + uvm_tr_stream stream; + uvm_report_object ro = report_message.get_report_object(); + uvm_report_handler rh = report_message.get_report_handler(); + if (m_streams.exists(ro.get_name()) && (m_streams[ro.get_name()].exists(rh.get_name()))) + stream = m_streams[ro.get_name()][rh.get_name()]; + if (stream == null) begin + uvm_tr_database db; + db = get_message_database(); + if (db == null) begin + uvm_coreservice_t cs = uvm_coreservice_t::get(); + db = cs.get_default_tr_database(); + end + if (db != null) begin + stream = db.open_stream(ro.get_name(), rh.get_name(), "MESSAGES"); + m_streams[ro.get_name()][rh.get_name()] = stream; + end + end + if (stream != null) begin + uvm_recorder recorder = stream.open_recorder(report_message.get_name(),,report_message.get_type_name()); + if (recorder != null) begin + report_message.record(recorder); + recorder.free(); + end + end + end + if(report_message.get_action() & UVM_DISPLAY) + $display("%s", composed_message); + if(report_message.get_action() & UVM_LOG) + if( (report_message.get_file() == 0) || + (report_message.get_file() != 32'h8000_0001) ) begin + UVM_FILE tmp_file = report_message.get_file(); + if((report_message.get_file() & 32'h8000_0000) == 0) begin + tmp_file = report_message.get_file() & 32'hffff_fffe; + end + f_display(tmp_file, composed_message); + end + if(report_message.get_action() & UVM_COUNT) begin + if(get_max_quit_count() != 0) begin + incr_quit_count(); + if(is_quit_count_reached()) begin + report_message.set_action(report_message.get_action() | UVM_EXIT); + end + end + end + if(report_message.get_action() & UVM_EXIT) begin + uvm_root l_root; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + l_root = cs.get_root(); + l_root.die(); + end + if (report_message.get_action() & UVM_STOP) + $stop; + endfunction + virtual function string compose_report_message(uvm_report_message report_message, + string report_object_name = ""); + string sev_string; + uvm_severity l_severity; + uvm_verbosity l_verbosity; + string filename_line_string; + string time_str; + string line_str; + string context_str; + string verbosity_str; + string terminator_str; + string msg_body_str; + uvm_report_message_element_container el_container; + string prefix; + uvm_report_handler l_report_handler; + l_severity = report_message.get_severity(); + sev_string = l_severity.name(); + if (report_message.get_filename() != "") begin + line_str.itoa(report_message.get_line()); + filename_line_string = {report_message.get_filename(), "(", line_str, ") "}; + end + $swrite(time_str, "%0t", $time); + if (report_message.get_context() != "") + context_str = {"@@", report_message.get_context()}; + if (show_verbosity) begin + if ($cast(l_verbosity, report_message.get_verbosity())) + verbosity_str = l_verbosity.name(); + else + verbosity_str.itoa(report_message.get_verbosity()); + verbosity_str = {"(", verbosity_str, ")"}; + end + if (show_terminator) + terminator_str = {" -",sev_string}; + el_container = report_message.get_element_container(); + if (el_container.size() == 0) + msg_body_str = report_message.get_message(); + else begin + uvm_printer uvm_default_printer = uvm_printer::get_default() ; + prefix = uvm_default_printer.get_line_prefix(); + uvm_default_printer.set_line_prefix(" +"); + msg_body_str = {report_message.get_message(), "\n", el_container.sprint()}; + uvm_default_printer.set_line_prefix(prefix); + end + if (report_object_name == "") begin + l_report_handler = report_message.get_report_handler(); + report_object_name = l_report_handler.get_full_name(); + end + compose_report_message = {sev_string, verbosity_str, " ", filename_line_string, "@ ", + time_str, ": ", report_object_name, context_str, + " [", report_message.get_id(), "] ", msg_body_str, terminator_str}; + endfunction + virtual function void report_summarize(UVM_FILE file = UVM_STDOUT); + string id; + string name; + string output_str; + string q[$]; + uvm_report_catcher::summarize(); + q.push_back("\n--- UVM Report Summary ---\n\n"); + if(m_max_quit_count != 0) begin + if ( m_quit_count >= m_max_quit_count ) + q.push_back("Quit count reached!\n"); + q.push_back($sformatf("Quit count : %5d of %5d\n",m_quit_count, m_max_quit_count)); + end + q.push_back("** Report counts by severity\n"); + foreach(m_severity_count[s]) begin + q.push_back($sformatf("%s :%5d\n", s.name(), m_severity_count[s])); + end + if (enable_report_id_count_summary) begin + q.push_back("** Report counts by id\n"); + foreach(m_id_count[id]) + q.push_back($sformatf("[%s] %5d\n", id, m_id_count[id])); + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_INFO,"UVM/REPORT/SERVER")) + uvm_report_info ("UVM/REPORT/SERVER", uvm_pkg::m_uvm_string_queue_join(q), UVM_NONE, "t/uvm/src/base/uvm_report_server.svh", 864, "", 1); + end + endfunction +endclass +typedef class uvm_report_object; +typedef class uvm_report_server; +typedef uvm_pool#(string, uvm_action) uvm_id_actions_array; +typedef uvm_pool#(string, UVM_FILE) uvm_id_file_array; +typedef uvm_pool#(string, int) uvm_id_verbosities_array; +typedef uvm_pool#(uvm_severity, uvm_severity) uvm_sev_override_array; +class uvm_report_handler extends uvm_object; + int m_max_verbosity_level; + uvm_id_verbosities_array id_verbosities; + uvm_id_verbosities_array severity_id_verbosities[uvm_severity]; + uvm_id_actions_array id_actions; + uvm_action severity_actions[uvm_severity]; + uvm_id_actions_array severity_id_actions[uvm_severity]; + uvm_sev_override_array sev_overrides; + uvm_sev_override_array sev_id_overrides [string]; + UVM_FILE default_file_handle; + uvm_id_file_array id_file_handles; + UVM_FILE severity_file_handles[uvm_severity]; + uvm_id_file_array severity_id_file_handles[uvm_severity]; + typedef uvm_object_registry#(uvm_report_handler,"uvm_report_handler") type_id; + static function uvm_report_handler type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_report_handler tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_report_handler"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_report_handler"; + endfunction : get_type_name + function new(string name = "uvm_report_handler"); + super.new(name); + initialize(); + endfunction + virtual function void do_print (uvm_printer printer); + uvm_verbosity l_verbosity; + uvm_severity l_severity; + string idx; + int l_int; + if ($cast(l_verbosity, m_max_verbosity_level)) + printer.print_generic("max_verbosity_level", "uvm_verbosity", 32, + l_verbosity.name()); + else + printer.print_field("max_verbosity_level", m_max_verbosity_level, 32, UVM_DEC, + ".", "int"); + if(id_verbosities.first(idx)) begin + printer.print_array_header("id_verbosities",id_verbosities.num(), + "uvm_pool"); + do begin + l_int = id_verbosities.get(idx); + if ($cast(l_verbosity, l_int)) + printer.print_generic($sformatf("[%s]", idx), "uvm_verbosity", 32, + l_verbosity.name()); + else begin + string l_str; + l_str.itoa(l_int); + printer.print_generic($sformatf("[%s]", idx), "int", 32, + l_str); + end + end while(id_verbosities.next(idx)); + printer.print_array_footer(); + end + if(severity_id_verbosities.size() != 0) begin + int _total_cnt; + foreach (severity_id_verbosities[l_severity]) + _total_cnt += severity_id_verbosities[l_severity].num(); + printer.print_array_header("severity_id_verbosities", _total_cnt, + "array"); + if(severity_id_verbosities.first(l_severity)) begin + do begin + uvm_id_verbosities_array id_v_ary = severity_id_verbosities[l_severity]; + if(id_v_ary.first(idx)) + do begin + l_int = id_v_ary.get(idx); + if ($cast(l_verbosity, l_int)) + printer.print_generic($sformatf("[%s:%s]", l_severity.name(), idx), + "uvm_verbosity", 32, l_verbosity.name()); + else begin + string l_str; + l_str.itoa(l_int); + printer.print_generic($sformatf("[%s:%s]", l_severity.name(), idx), + "int", 32, l_str); + end + end while(id_v_ary.next(idx)); + end while(severity_id_verbosities.next(l_severity)); + end + printer.print_array_footer(); + end + if(id_actions.first(idx)) begin + printer.print_array_header("id_actions",id_actions.num(), + "uvm_pool"); + do begin + l_int = id_actions.get(idx); + printer.print_generic($sformatf("[%s]", idx), "uvm_action", 32, + format_action(l_int)); + end while(id_actions.next(idx)); + printer.print_array_footer(); + end + if(severity_actions.first(l_severity)) begin + printer.print_array_header("severity_actions",4,"array"); + do begin + printer.print_generic($sformatf("[%s]", l_severity.name()), "uvm_action", 32, + format_action(severity_actions[l_severity])); + end while(severity_actions.next(l_severity)); + printer.print_array_footer(); + end + if(severity_id_actions.size() != 0) begin + int _total_cnt; + foreach (severity_id_actions[l_severity]) + _total_cnt += severity_id_actions[l_severity].num(); + printer.print_array_header("severity_id_actions", _total_cnt, + "array"); + if(severity_id_actions.first(l_severity)) begin + do begin + uvm_id_actions_array id_a_ary = severity_id_actions[l_severity]; + if(id_a_ary.first(idx)) + do begin + printer.print_generic($sformatf("[%s:%s]", l_severity.name(), idx), + "uvm_action", 32, format_action(id_a_ary.get(idx))); + end while(id_a_ary.next(idx)); + end while(severity_id_actions.next(l_severity)); + end + printer.print_array_footer(); + end + if(sev_overrides.first(l_severity)) begin + printer.print_array_header("sev_overrides",sev_overrides.num(), + "uvm_pool"); + do begin + uvm_severity l_severity_new = sev_overrides.get(l_severity); + printer.print_generic($sformatf("[%s]", l_severity.name()), + "uvm_severity", 32, l_severity_new.name()); + end while(sev_overrides.next(l_severity)); + printer.print_array_footer(); + end + if(sev_id_overrides.size() != 0) begin + int _total_cnt; + foreach (sev_id_overrides[idx]) + _total_cnt += sev_id_overrides[idx].num(); + printer.print_array_header("sev_id_overrides", _total_cnt, + "array"); + if(sev_id_overrides.first(idx)) begin + do begin + uvm_sev_override_array sev_o_ary = sev_id_overrides[idx]; + if(sev_o_ary.first(l_severity)) + do begin + uvm_severity new_sev = sev_o_ary.get(l_severity); + printer.print_generic($sformatf("[%s:%s]", l_severity.name(), idx), + "uvm_severity", 32, new_sev.name()); + end while(sev_o_ary.next(l_severity)); + end while(sev_id_overrides.next(idx)); + end + printer.print_array_footer(); + end + printer.print_field("default_file_handle", default_file_handle, 32, UVM_HEX, + ".", "int"); + if(id_file_handles.first(idx)) begin + printer.print_array_header("id_file_handles",id_file_handles.num(), + "uvm_pool"); + do begin + printer.print_field($sformatf("[%s]", idx), id_file_handles.get(idx), 32, + UVM_HEX, ".", "UVM_FILE"); + end while(id_file_handles.next(idx)); + printer.print_array_footer(); + end + if(severity_file_handles.first(l_severity)) begin + printer.print_array_header("severity_file_handles",4,"array"); + do begin + printer.print_field($sformatf("[%s]", l_severity.name()), + severity_file_handles[l_severity], 32, UVM_HEX, ".", "UVM_FILE"); + end while(severity_file_handles.next(l_severity)); + printer.print_array_footer(); + end + if(severity_id_file_handles.size() != 0) begin + int _total_cnt; + foreach (severity_id_file_handles[l_severity]) + _total_cnt += severity_id_file_handles[l_severity].num(); + printer.print_array_header("severity_id_file_handles", _total_cnt, + "array"); + if(severity_id_file_handles.first(l_severity)) begin + do begin + uvm_id_file_array id_f_ary = severity_id_file_handles[l_severity]; + if(id_f_ary.first(idx)) + do begin + printer.print_field($sformatf("[%s:%s]", l_severity.name(), idx), + id_f_ary.get(idx), 32, UVM_HEX, ".", "UVM_FILE"); + end while(id_f_ary.next(idx)); + end while(severity_id_file_handles.next(l_severity)); + end + printer.print_array_footer(); + end + endfunction + virtual function void process_report_message(uvm_report_message report_message); + process p = process::self(); + uvm_report_server srvr = uvm_report_server::get_server(); + string id = report_message.get_id(); + uvm_severity severity = report_message.get_severity(); + if(sev_id_overrides.exists(id)) begin + if(sev_id_overrides[id].exists(uvm_severity'(severity))) begin + severity = sev_id_overrides[id].get(severity); + report_message.set_severity(severity); + end + end + else begin + if(sev_overrides.exists(severity)) begin + severity = sev_overrides.get(severity); + report_message.set_severity(severity); + end + end + report_message.set_file(get_file_handle(severity, id)); + report_message.set_report_handler(this); + report_message.set_action(get_action(severity, id)); + srvr.process_report_message(report_message); + endfunction + static function string format_action(uvm_action action); + string s; + if(uvm_action_type'(action) == UVM_NO_ACTION) begin + s = "NO ACTION"; + end + else begin + s = ""; + if(action & UVM_DISPLAY) s = {s, "DISPLAY "}; + if(action & UVM_LOG) s = {s, "LOG "}; + if(action & UVM_RM_RECORD) s = {s, "RM_RECORD "}; + if(action & UVM_COUNT) s = {s, "COUNT "}; + if(action & UVM_CALL_HOOK) s = {s, "CALL_HOOK "}; + if(action & UVM_EXIT) s = {s, "EXIT "}; + if(action & UVM_STOP) s = {s, "STOP "}; + end + return s; + endfunction + function void initialize(); + set_default_file(0); + m_max_verbosity_level = UVM_MEDIUM; + id_actions=new(); + id_verbosities=new(); + id_file_handles=new(); + sev_overrides=new(); + set_severity_action(UVM_INFO, UVM_DISPLAY); + set_severity_action(UVM_WARNING, UVM_DISPLAY); + set_severity_action(UVM_ERROR, UVM_DISPLAY | UVM_COUNT); + set_severity_action(UVM_FATAL, UVM_DISPLAY | UVM_EXIT); + set_severity_file(UVM_INFO, default_file_handle); + set_severity_file(UVM_WARNING, default_file_handle); + set_severity_file(UVM_ERROR, default_file_handle); + set_severity_file(UVM_FATAL, default_file_handle); + endfunction + local function UVM_FILE get_severity_id_file(uvm_severity severity, string id); + uvm_id_file_array array; + if(severity_id_file_handles.exists(severity)) begin + array = severity_id_file_handles[severity]; + if(array.exists(id)) + return array.get(id); + end + if(id_file_handles.exists(id)) + return id_file_handles.get(id); + if(severity_file_handles.exists(severity)) + return severity_file_handles[severity]; + return default_file_handle; + endfunction + function void set_verbosity_level(int verbosity_level); + m_max_verbosity_level = verbosity_level; + endfunction + function int get_verbosity_level(uvm_severity severity=UVM_INFO, string id="" ); + uvm_id_verbosities_array array; + if(severity_id_verbosities.exists(severity)) begin + array = severity_id_verbosities[severity]; + if(array.exists(id)) begin + return array.get(id); + end + end + if(id_verbosities.exists(id)) begin + return id_verbosities.get(id); + end + return m_max_verbosity_level; + endfunction + function uvm_action get_action(uvm_severity severity, string id); + uvm_id_actions_array array; + if(severity_id_actions.exists(severity)) begin + array = severity_id_actions[severity]; + if(array.exists(id)) + return array.get(id); + end + if(id_actions.exists(id)) + return id_actions.get(id); + return severity_actions[severity]; + endfunction + function UVM_FILE get_file_handle(uvm_severity severity, string id); + UVM_FILE file; + file = get_severity_id_file(severity, id); + if (file != 0) + return file; + if (id_file_handles.exists(id)) begin + file = id_file_handles.get(id); + if (file != 0) + return file; + end + if (severity_file_handles.exists(severity)) begin + file = severity_file_handles[severity]; + if(file != 0) + return file; + end + return default_file_handle; + endfunction + function void set_severity_action(input uvm_severity severity, + input uvm_action action); + severity_actions[severity] = action; + endfunction + function void set_id_action(input string id, input uvm_action action); + id_actions.add(id, action); + endfunction + function void set_severity_id_action(uvm_severity severity, + string id, + uvm_action action); + if(!severity_id_actions.exists(severity)) + severity_id_actions[severity] = new; + severity_id_actions[severity].add(id,action); + endfunction + function void set_id_verbosity(input string id, input int verbosity); + id_verbosities.add(id, verbosity); + endfunction + function void set_severity_id_verbosity(uvm_severity severity, + string id, + int verbosity); + if(!severity_id_verbosities.exists(severity)) + severity_id_verbosities[severity] = new; + severity_id_verbosities[severity].add(id,verbosity); + endfunction + function void set_default_file (UVM_FILE file); + default_file_handle = file; + endfunction + function void set_severity_file (uvm_severity severity, UVM_FILE file); + severity_file_handles[severity] = file; + endfunction + function void set_id_file (string id, UVM_FILE file); + id_file_handles.add(id, file); + endfunction + function void set_severity_id_file(uvm_severity severity, + string id, UVM_FILE file); + if(!severity_id_file_handles.exists(severity)) + severity_id_file_handles[severity] = new; + severity_id_file_handles[severity].add(id, file); + endfunction + function void set_severity_override(uvm_severity cur_severity, + uvm_severity new_severity); + sev_overrides.add(cur_severity, new_severity); + endfunction + function void set_severity_id_override(uvm_severity cur_severity, + string id, + uvm_severity new_severity); + uvm_sev_override_array arr; + if(!sev_id_overrides.exists(id)) + sev_id_overrides[id] = new; + sev_id_overrides[id].add(cur_severity, new_severity); + endfunction + virtual function void report( + uvm_severity severity, + string name, + string id, + string message, + int verbosity_level=UVM_MEDIUM, + string filename="", + int line=0, + uvm_report_object client=null + ); + bit l_report_enabled = 0; + uvm_report_message l_report_message; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + if (!uvm_report_enabled(verbosity_level, UVM_INFO, id)) + return; + if (client==null) + client = cs.get_root(); + l_report_message = uvm_report_message::new_report_message(); + l_report_message.set_report_message(severity, id, message, + verbosity_level, filename, line, name); + l_report_message.set_report_object(client); + l_report_message.set_action(get_action(severity,id)); + process_report_message(l_report_message); + endfunction +endclass : uvm_report_handler +typedef class uvm_component; +typedef class uvm_env; +typedef class uvm_root; +class uvm_report_object extends uvm_object; + uvm_report_handler m_rh; + local bit m_rh_set; + local function void m_rh_init(); + if (!m_rh_set) + set_report_handler(uvm_report_handler::type_id_create(get_name())); + endfunction : m_rh_init + function new(string name = ""); + super.new(name); + endfunction + function uvm_report_object uvm_get_report_object(); + return this; + endfunction + function int uvm_report_enabled(int verbosity, + uvm_severity severity = UVM_INFO, string id = ""); + if (get_report_verbosity_level(severity, id) < verbosity) + return 0; + return 1; + endfunction + 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, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked =0); + uvm_report_message l_report_message; + if ((severity == UVM_INFO) && (report_enabled_checked == 0)) begin + if (!uvm_report_enabled(verbosity, severity, id)) + return; + end + l_report_message = uvm_report_message::new_report_message(); + l_report_message.set_report_message(severity, id, message, + verbosity, filename, line, context_name); + uvm_process_report_message(l_report_message); + endfunction + virtual function void uvm_report_info( string id, + string message, + int verbosity = UVM_MEDIUM, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + uvm_report (UVM_INFO, id, message, verbosity, + filename, line, context_name, report_enabled_checked); + endfunction + virtual function void uvm_report_warning( string id, + string message, + int verbosity = UVM_MEDIUM, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + uvm_report (UVM_WARNING, id, message, verbosity, + filename, line, context_name, report_enabled_checked); + endfunction + virtual function void uvm_report_error( string id, + string message, + int verbosity = UVM_NONE, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + uvm_report (UVM_ERROR, id, message, verbosity, + filename, line, context_name, report_enabled_checked); + endfunction + virtual function void uvm_report_fatal( string id, + string message, + int verbosity = UVM_NONE, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + uvm_report (UVM_FATAL, id, message, verbosity, + filename, line, context_name, report_enabled_checked); + endfunction + virtual function void uvm_process_report_message(uvm_report_message report_message); + m_rh_init(); + report_message.set_report_object(this); + m_rh.process_report_message(report_message); + endfunction + function int get_report_verbosity_level(uvm_severity severity=UVM_INFO, string id=""); + m_rh_init(); + return m_rh.get_verbosity_level(severity, id); + endfunction + function int get_report_max_verbosity_level(); + m_rh_init(); + return m_rh.m_max_verbosity_level; + endfunction + function void set_report_verbosity_level (int verbosity_level); + m_rh_init(); + m_rh.set_verbosity_level(verbosity_level); + endfunction + function void set_report_id_verbosity (string id, int verbosity); + m_rh_init(); + m_rh.set_id_verbosity(id, verbosity); + endfunction + function void set_report_severity_id_verbosity (uvm_severity severity, + string id, int verbosity); + m_rh_init(); + m_rh.set_severity_id_verbosity(severity, id, verbosity); + endfunction + function int get_report_action(uvm_severity severity, string id); + m_rh_init(); + return m_rh.get_action(severity,id); + endfunction + function void set_report_severity_action (uvm_severity severity, + uvm_action action); + m_rh_init(); + m_rh.set_severity_action(severity, action); + endfunction + function void set_report_id_action (string id, uvm_action action); + m_rh_init(); + m_rh.set_id_action(id, action); + endfunction + function void set_report_severity_id_action (uvm_severity severity, + string id, uvm_action action); + m_rh_init(); + m_rh.set_severity_id_action(severity, id, action); + endfunction + function int get_report_file_handle(uvm_severity severity, string id); + m_rh_init(); + return m_rh.get_file_handle(severity,id); + endfunction + function void set_report_default_file (UVM_FILE file); + m_rh_init(); + m_rh.set_default_file(file); + endfunction + function void set_report_id_file (string id, UVM_FILE file); + m_rh_init(); + m_rh.set_id_file(id, file); + endfunction + function void set_report_severity_file (uvm_severity severity, UVM_FILE file); + m_rh_init(); + m_rh.set_severity_file(severity, file); + endfunction + function void set_report_severity_id_file (uvm_severity severity, string id, + UVM_FILE file); + m_rh_init(); + m_rh.set_severity_id_file(severity, id, file); + endfunction + function void set_report_severity_override(uvm_severity cur_severity, + uvm_severity new_severity); + m_rh_init(); + m_rh.set_severity_override(cur_severity, new_severity); + endfunction + function void set_report_severity_id_override(uvm_severity cur_severity, + string id, + uvm_severity new_severity); + m_rh_init(); + m_rh.set_severity_id_override(cur_severity, id, new_severity); + endfunction + function void set_report_handler(uvm_report_handler handler); + m_rh = handler; + m_rh_set = 1; + endfunction + function uvm_report_handler get_report_handler(); + m_rh_init(); + return m_rh; + endfunction + function void reset_report_handler; + m_rh_init(); + m_rh.initialize(); + endfunction +endclass +typedef class uvm_event; +typedef class uvm_event_pool; +typedef class uvm_component; +typedef class uvm_parent_child_link; +virtual class uvm_transaction extends uvm_object; + extern function new (string name="", uvm_component initiator=null); + extern function void accept_tr (time accept_time = 0); + extern virtual protected function void do_accept_tr (); + extern function int begin_tr (time begin_time = 0); + extern function int begin_child_tr (time begin_time = 0, + int parent_handle = 0); + extern virtual protected function void do_begin_tr (); + extern function void end_tr (time end_time=0, bit free_handle=1); + extern virtual protected function void do_end_tr (); + extern function int get_tr_handle (); + extern function void disable_recording (); + extern function void enable_recording (uvm_tr_stream stream); + extern function bit is_recording_enabled(); + extern function bit is_active (); + extern function uvm_event_pool get_event_pool (); + extern function void set_initiator (uvm_component initiator); + extern function uvm_component get_initiator (); + extern function time get_accept_time (); + extern function time get_begin_time (); + extern function time get_end_time (); + extern function void set_transaction_id(int id); + extern function int get_transaction_id(); + const local uvm_event_pool events = new("events"); + extern virtual function void do_print (uvm_printer printer); + extern virtual function void do_record (uvm_recorder recorder); + extern virtual function void do_copy (uvm_object rhs); + extern protected function int m_begin_tr (time begin_time=0, + int parent_handle=0); + local int m_transaction_id = -1; + local time begin_time=-1; + local time end_time=-1; + local time accept_time=-1; + local uvm_component initiator; + local uvm_tr_stream stream_handle; + local uvm_recorder tr_recorder; +endclass +function uvm_transaction::new (string name="", + uvm_component initiator = null); + super.new(name); + this.initiator = initiator; + m_transaction_id = -1; +endfunction +function void uvm_transaction::set_transaction_id(int id); + m_transaction_id = id; +endfunction +function int uvm_transaction::get_transaction_id(); + return (m_transaction_id); +endfunction +function void uvm_transaction::set_initiator(uvm_component initiator); + this.initiator = initiator; +endfunction +function uvm_component uvm_transaction::get_initiator(); + return initiator; +endfunction +function uvm_event_pool uvm_transaction::get_event_pool(); + return events; +endfunction +function bit uvm_transaction::is_active(); + return (end_time == -1); +endfunction +function time uvm_transaction::get_begin_time (); + return begin_time; +endfunction +function time uvm_transaction::get_end_time (); + return end_time; +endfunction +function time uvm_transaction::get_accept_time (); + return accept_time; +endfunction +function void uvm_transaction::do_accept_tr(); + return; +endfunction +function void uvm_transaction::do_begin_tr(); + return; +endfunction +function void uvm_transaction::do_end_tr(); + return; +endfunction +function void uvm_transaction::do_print (uvm_printer printer); + string str; + uvm_component tmp_initiator; + super.do_print(printer); + if(accept_time != -1) + printer.print_time("accept_time", accept_time); + if(begin_time != -1) + printer.print_time("begin_time", begin_time); + if(end_time != -1) + printer.print_time("end_time", end_time); + if(initiator != null) begin + tmp_initiator = initiator; + $swrite(str,"@%0d", tmp_initiator.get_inst_id()); + printer.print_generic("initiator", initiator.get_type_name(), -1, str); + end +endfunction +function void uvm_transaction::do_copy (uvm_object rhs); + uvm_transaction txn; + super.do_copy(rhs); + if(rhs == null) return; + if(!$cast(txn, rhs) ) return; + accept_time = txn.accept_time; + begin_time = txn.begin_time; + end_time = txn.end_time; + initiator = txn.initiator; + stream_handle = txn.stream_handle; + tr_recorder = txn.tr_recorder; +endfunction +function void uvm_transaction::do_record (uvm_recorder recorder); + string s; + super.do_record(recorder); + if(accept_time != -1) + recorder.record_field("accept_time", accept_time, $bits(accept_time), UVM_TIME); + if(initiator != null) begin + uvm_recursion_policy_enum p = recorder.get_recursion_policy(); + recorder.set_recursion_policy(UVM_REFERENCE); + recorder.record_object("initiator", initiator); + recorder.set_recursion_policy(p); + end +endfunction +function int uvm_transaction::get_tr_handle (); + if (tr_recorder != null) + return tr_recorder.get_handle(); + else + return 0; +endfunction +function void uvm_transaction::disable_recording (); + this.stream_handle = null; +endfunction +function void uvm_transaction::enable_recording (uvm_tr_stream stream); + this.stream_handle = stream; +endfunction : enable_recording +function bit uvm_transaction::is_recording_enabled (); + return (this.stream_handle != null); +endfunction +function void uvm_transaction::accept_tr (time accept_time = 0); + uvm_event#(uvm_object) e; + if(accept_time != 0) + this.accept_time = accept_time; + else + this.accept_time = $realtime; + do_accept_tr(); + e = events.get("accept"); + if(e!=null) + e.trigger(); +endfunction +function int uvm_transaction::begin_tr (time begin_time=0); + return m_begin_tr(begin_time); +endfunction +function int uvm_transaction::begin_child_tr (time begin_time=0, + int parent_handle=0); + return m_begin_tr(begin_time, parent_handle); +endfunction +function int uvm_transaction::m_begin_tr (time begin_time=0, + int parent_handle=0); + time tmp_time = (begin_time == 0) ? $realtime : begin_time; + uvm_recorder parent_recorder; + if (parent_handle != 0) + parent_recorder = uvm_recorder::get_recorder_from_handle(parent_handle); + if (tr_recorder != null) + end_tr(tmp_time); + if(is_recording_enabled()) begin + uvm_tr_database db = stream_handle.get_db(); + this.end_time = -1; + this.begin_time = tmp_time; + if(parent_recorder == null) + tr_recorder = stream_handle.open_recorder(get_type_name(), + this.begin_time, + "Begin_No_Parent, Link"); + else begin + tr_recorder = stream_handle.open_recorder(get_type_name(), + this.begin_time, + "Begin_End, Link"); + if (tr_recorder != null) + db.establish_link(uvm_parent_child_link::get_link(parent_recorder, tr_recorder)); + end + if (tr_recorder != null) + m_begin_tr = tr_recorder.get_handle(); + else + m_begin_tr = 0; + end + else begin + tr_recorder = null; + this.end_time = -1; + this.begin_time = tmp_time; + m_begin_tr = 0; + end + do_begin_tr(); + begin + uvm_event#(uvm_object) begin_event ; + begin_event = events.get("begin"); + begin_event.trigger(); + end +endfunction +function void uvm_transaction::end_tr (time end_time=0, bit free_handle=1); + this.end_time = (end_time == 0) ? $realtime : end_time; + do_end_tr(); + if(is_recording_enabled() && (tr_recorder != null)) begin + record(tr_recorder); + tr_recorder.close(this.end_time); + if(free_handle) + begin + tr_recorder.free(); + end + end + tr_recorder = null; + begin + uvm_event#(uvm_object) end_event ; + end_event = events.get("end") ; + end_event.trigger(); + end +endfunction +typedef class uvm_sequencer_base; +typedef class uvm_domain; +typedef class uvm_task_phase; +typedef class uvm_phase_cb; +class uvm_phase extends uvm_object; + static local bit m_register_cb_uvm_phase_cb = uvm_callbacks#(uvm_phase,uvm_phase_cb)::m_register_pair("uvm_phase","uvm_phase_cb"); + extern function new(string name="uvm_phase", + uvm_phase_type phase_type=UVM_PHASE_SCHEDULE, + uvm_phase parent=null); + extern function uvm_phase_type get_phase_type(); + extern virtual function void set_max_ready_to_end_iterations(int max); + extern virtual function int get_max_ready_to_end_iterations(); + extern static function void set_default_max_ready_to_end_iterations(int max); + extern static function int get_default_max_ready_to_end_iterations(); + extern function uvm_phase_state get_state(); + extern function int get_run_count(); + extern function uvm_phase find_by_name(string name, bit stay_in_scope=1); + extern function uvm_phase find(uvm_phase phase, bit stay_in_scope=1); + extern function bit is(uvm_phase phase); + extern function bit is_before(uvm_phase phase); + extern function bit is_after(uvm_phase phase); + virtual function void exec_func(uvm_component comp, uvm_phase phase); endfunction + virtual task exec_task(uvm_component comp, uvm_phase phase); endtask + extern function void add(uvm_phase phase, + uvm_phase with_phase=null, + uvm_phase after_phase=null, + uvm_phase before_phase=null, + uvm_phase start_with_phase=null, + uvm_phase end_with_phase=null + ); + extern function uvm_phase get_parent(); + extern virtual function string get_full_name(); + extern function uvm_phase get_schedule(bit hier = 0); + extern function string get_schedule_name(bit hier = 0); + extern function uvm_domain get_domain(); + extern function uvm_phase get_imp(); + extern function string get_domain_name(); + extern function void get_adjacent_predecessor_nodes(ref uvm_phase pred[]); + extern function void get_adjacent_successor_nodes(ref uvm_phase succ[]); + extern function void m_report_null_objection(uvm_object obj, + string description, + int count, + string action); + extern virtual function void raise_objection (uvm_object obj, + string description="", + int count=1); + extern virtual function void drop_objection (uvm_object obj, + string description="", + int count=1); + extern virtual function int get_objection_count( uvm_object obj=null ); + extern function void sync(uvm_domain target, + uvm_phase phase=null, + uvm_phase with_phase=null); + extern function void unsync(uvm_domain target, + uvm_phase phase=null, + uvm_phase with_phase=null); + extern task wait_for_state(uvm_phase_state state, uvm_wait_op op=UVM_EQ); + extern function void jump(uvm_phase phase); + extern function void set_jump_phase(uvm_phase phase) ; + extern function void end_prematurely() ; + extern static function void jump_all(uvm_phase phase); + extern function uvm_phase get_jump_target(); + protected uvm_phase_type m_phase_type; + protected uvm_phase m_parent; + uvm_phase m_imp; + local uvm_phase_state m_state; + local int m_run_count; + local process m_phase_proc; + local static int m_default_max_ready_to_end_iters = 20; + local + int max_ready_to_end_iters = get_default_max_ready_to_end_iterations(); + int m_num_procs_not_yet_returned; + extern function uvm_phase m_find_predecessor(uvm_phase phase, bit stay_in_scope=1, uvm_phase orig_phase=null); + extern function uvm_phase m_find_successor(uvm_phase phase, bit stay_in_scope=1, uvm_phase orig_phase=null); + extern function uvm_phase m_find_predecessor_by_name(string name, bit stay_in_scope=1, uvm_phase orig_phase=null); + extern function uvm_phase m_find_successor_by_name(string name, bit stay_in_scope=1, uvm_phase orig_phase=null); + extern function void m_print_successors(); + virtual function void traverse(uvm_component comp, + uvm_phase phase, + uvm_phase_state state); + endfunction + virtual function void execute(uvm_component comp, + uvm_phase phase); + endfunction + protected bit m_predecessors[uvm_phase]; + protected bit m_successors[uvm_phase]; + protected uvm_phase m_end_node; + static protected bit m_executing_phases[uvm_phase]; + function uvm_phase get_begin_node(); if (m_imp != null) return this; return null; endfunction + function uvm_phase get_end_node(); return m_end_node; endfunction + local uvm_phase m_sync[$]; + local uvm_objection phase_done; + local int unsigned m_ready_to_end_count; + function int unsigned get_ready_to_end_count(); + return m_ready_to_end_count; + endfunction + extern local function void get_predecessors_for_successors(output bit pred_of_succ[uvm_phase]); + extern local task m_wait_for_pred(); + local bit m_jump_bkwd; + local bit m_jump_fwd; + local uvm_phase m_jump_phase; + local bit m_premature_end; + extern function void clear(uvm_phase_state state = UVM_PHASE_DORMANT); + extern function void clear_successors( + uvm_phase_state state = UVM_PHASE_DORMANT, + uvm_phase end_state=null); + local static mailbox #(uvm_phase) m_phase_hopper = new(); + extern static task m_run_phases(); + extern local task execute_phase(); + extern local function void m_terminate_phase(); + extern local function void m_print_termination_state(); + extern local task wait_for_self_and_siblings_to_drop(); + extern function void kill(); + extern function void kill_successors(); + protected static bit m_phase_trace; + local static bit m_use_ovm_run_semantic; + function string convert2string(); + string s; + s = $sformatf("phase: %s parent=%s pred=%s succ=%s",get_name(), + (m_parent==null) ? "null" : get_schedule_name(), + m_aa2string(m_predecessors), + m_aa2string(m_successors)); + return s; + endfunction + local function string m_aa2string(bit aa[uvm_phase]); + string s; + int i; + s = "'{ "; + foreach (aa[ph]) begin + uvm_phase n = ph; + s = {s, (n == null) ? "null" : n.get_name(), + (i == aa.num()-1) ? "" : ", "}; + i++; + end + s = {s, " }"}; + return s; + endfunction + function bit is_domain(); + return (m_phase_type == UVM_PHASE_DOMAIN); + endfunction + virtual function void m_get_transitive_children(ref uvm_phase phases[$]); + foreach (m_successors[succ]) + begin + phases.push_back(succ); + succ.m_get_transitive_children(phases); + end + endfunction + function uvm_objection get_objection(); + uvm_phase imp; + uvm_task_phase tp; + imp = get_imp(); + if ((get_phase_type() != UVM_PHASE_NODE) || (imp == null) || !$cast(tp, imp)) begin + return null; + end + if (phase_done == null) begin + phase_done = uvm_objection::type_id_create({get_name(), "_objection"}); + end + return phase_done; + endfunction +endclass +class uvm_phase_state_change extends uvm_object; + typedef uvm_object_registry#(uvm_phase_state_change,"uvm_phase_state_change") type_id; + static function uvm_phase_state_change type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_phase_state_change tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_phase_state_change"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_phase_state_change"; + endfunction : get_type_name + uvm_phase m_phase; + uvm_phase_state m_prev_state; + uvm_phase m_jump_to; + function new(string name = "uvm_phase_state_change"); + super.new(name); + endfunction + virtual function uvm_phase_state get_state(); + return m_phase.get_state(); + endfunction + virtual function uvm_phase_state get_prev_state(); + return m_prev_state; + endfunction + function uvm_phase jump_to(); + return m_jump_to; + endfunction +endclass +class uvm_phase_cb extends uvm_callback; + function new(string name="unnamed-uvm_phase_cb"); + super.new(name); + endfunction : new + virtual function void phase_state_change(uvm_phase phase, + uvm_phase_state_change change); + endfunction +endclass +typedef uvm_callbacks#(uvm_phase, uvm_phase_cb) uvm_phase_cb_pool ; +typedef class uvm_cmdline_processor; +function uvm_phase::new(string name="uvm_phase", + uvm_phase_type phase_type=UVM_PHASE_SCHEDULE, + uvm_phase parent=null); + super.new(name); + m_phase_type = phase_type; + if ((name == "common") && + (phase_type == UVM_PHASE_DOMAIN)) + m_state = UVM_PHASE_DORMANT; + m_run_count = 0; + m_parent = parent; + begin + uvm_cmdline_processor clp = uvm_cmdline_processor::get_inst(); + string val; + if (clp.get_arg_value("+UVM_PHASE_TRACE", val)) + m_phase_trace = 1; + else + m_phase_trace = 0; + if (clp.get_arg_value("+UVM_USE_OVM_RUN_SEMANTIC", val)) + m_use_ovm_run_semantic = 1; + else + m_use_ovm_run_semantic = 0; + end + if (parent == null && (phase_type == UVM_PHASE_SCHEDULE || + phase_type == UVM_PHASE_DOMAIN )) begin + m_end_node = new({name,"_end"}, UVM_PHASE_TERMINAL, this); + this.m_successors[m_end_node] = 1; + m_end_node.m_predecessors[this] = 1; + end +endfunction +function void uvm_phase::add(uvm_phase phase, + uvm_phase with_phase=null, + uvm_phase after_phase=null, + uvm_phase before_phase=null, + uvm_phase start_with_phase=null, + uvm_phase end_with_phase=null + ); + uvm_phase new_node, begin_node, end_node, tmp_node; + uvm_phase_state_change state_chg; + if (phase == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH/NULL")) + uvm_report_fatal ("PH/NULL", "add: phase argument is null", UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 762, "", 1); + end + if (with_phase != null && with_phase.get_phase_type() == UVM_PHASE_IMP) begin + string nm = with_phase.get_name(); + with_phase = find(with_phase); + if (with_phase == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BAD_ADD")) + uvm_report_fatal ("PH_BAD_ADD", {"cannot find with_phase '",nm,"' within node '",get_name(),"'"}, UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 769, "", 1); + end + end + if (before_phase != null && before_phase.get_phase_type() == UVM_PHASE_IMP) begin + string nm = before_phase.get_name(); + before_phase = find(before_phase); + if (before_phase == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BAD_ADD")) + uvm_report_fatal ("PH_BAD_ADD", {"cannot find before_phase '",nm,"' within node '",get_name(),"'"}, UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 777, "", 1); + end + end + if (after_phase != null && after_phase.get_phase_type() == UVM_PHASE_IMP) begin + string nm = after_phase.get_name(); + after_phase = find(after_phase); + if (after_phase == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BAD_ADD")) + uvm_report_fatal ("PH_BAD_ADD", {"cannot find after_phase '",nm,"' within node '",get_name(),"'"}, UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 785, "", 1); + end + end + if (start_with_phase != null && start_with_phase.get_phase_type() == UVM_PHASE_IMP) begin + string nm = start_with_phase.get_name(); + start_with_phase = find(start_with_phase); + if (start_with_phase == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BAD_ADD")) + uvm_report_fatal ("PH_BAD_ADD", {"cannot find start_with_phase '",nm,"' within node '",get_name(),"'"}, UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 793, "", 1); + end + end + if (end_with_phase != null && end_with_phase.get_phase_type() == UVM_PHASE_IMP) begin + string nm = end_with_phase.get_name(); + end_with_phase = find(end_with_phase); + if (end_with_phase == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BAD_ADD")) + uvm_report_fatal ("PH_BAD_ADD", {"cannot find end_with_phase '",nm,"' within node '",get_name(),"'"}, UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 801, "", 1); + end + end + if (((with_phase != null) + (after_phase != null) + (start_with_phase != null)) > 1) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BAD_ADD")) + uvm_report_fatal ("PH_BAD_ADD", "only one of with_phase/after_phase/start_with_phase may be specified as they all specify predecessor", UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 806, "", 1); + end + if (((with_phase != null) + (before_phase != null) + (end_with_phase != null)) > 1) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BAD_ADD")) + uvm_report_fatal ("PH_BAD_ADD", "only one of with_phase/before_phase/end_with_phase may be specified as they all specify successor", UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 810, "", 1); + end + if (before_phase == this || + after_phase == m_end_node || + with_phase == m_end_node || + start_with_phase == m_end_node || + end_with_phase == m_end_node) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BAD_ADD")) + uvm_report_fatal ("PH_BAD_ADD", "cannot add before begin node, after end node, or with end nodes", UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 818, "", 1); + end + if (before_phase != null && after_phase != null) begin + if (!after_phase.is_before(before_phase)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BAD_ADD")) + uvm_report_fatal ("PH_BAD_ADD", {"Phase '",before_phase.get_name(), "' is not before phase '",after_phase.get_name(),"'"}, UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 823, "", 1); + end + end + end + if (before_phase != null && start_with_phase != null) begin + if (!start_with_phase.is_before(before_phase)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BAD_ADD")) + uvm_report_fatal ("PH_BAD_ADD", {"Phase '",before_phase.get_name(), "' is not before phase '",start_with_phase.get_name(),"'"}, UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 830, "", 1); + end + end + end + if (end_with_phase != null && after_phase != null) begin + if (!after_phase.is_before(end_with_phase)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BAD_ADD")) + uvm_report_fatal ("PH_BAD_ADD", {"Phase '",end_with_phase.get_name(), "' is not before phase '",after_phase.get_name(),"'"}, UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 837, "", 1); + end + end + end + if (phase.get_phase_type() == UVM_PHASE_IMP) begin + uvm_task_phase tp; + new_node = new(phase.get_name(),UVM_PHASE_NODE,this); + new_node.m_imp = phase; + begin_node = new_node; + end_node = new_node; + end + else begin + begin_node = phase; + end_node = phase.m_end_node; + phase.m_parent = this; + end + if (with_phase==null && after_phase==null && before_phase==null && + start_with_phase==null && end_with_phase==null) begin + before_phase = m_end_node; + end + if (m_phase_trace) begin + uvm_phase_type typ = phase.get_phase_type(); + begin + if (uvm_report_enabled(UVM_DEBUG,UVM_INFO,"PH/TRC/ADD_PH")) + uvm_report_info ("PH/TRC/ADD_PH", {get_name()," (",m_phase_type.name(),") ADD_PHASE: phase=",phase.get_full_name()," (", typ.name(),", inst_id=",$sformatf("%0d",phase.get_inst_id()),")", " with_phase=", (with_phase == null) ? "null" : with_phase.get_name(), " start_with_phase=", (start_with_phase == null) ? "null" : start_with_phase.get_name(), " end_with_phase=", (end_with_phase == null) ? "null" : end_with_phase.get_name(), " after_phase=", (after_phase == null) ? "null" : after_phase.get_name(), " before_phase=", (before_phase == null) ? "null" : before_phase.get_name(), " new_node=", (new_node == null) ? "null" : {new_node.get_name(), " inst_id=", $sformatf("%0d",new_node.get_inst_id())}, " begin_node=", (begin_node == null) ? "null" : begin_node.get_name(), " end_node=", (end_node == null) ? "null" : end_node.get_name()}, UVM_DEBUG, "t/uvm/src/base/uvm_phase.svh", 886, "", 1); + end + end + if (with_phase != null) begin + begin_node.m_predecessors = with_phase.m_predecessors; + foreach (with_phase.m_predecessors[pred]) pred.m_successors[begin_node] = 1; + end_node.m_successors = with_phase.m_successors; + foreach (with_phase.m_successors[succ]) succ.m_predecessors[end_node] = 1; + end + if (start_with_phase != null) begin + begin_node.m_predecessors = start_with_phase.m_predecessors; + foreach (start_with_phase.m_predecessors[pred]) begin + pred.m_successors[begin_node] = 1; + end + if (before_phase == null && end_with_phase == null) begin + end_node.m_successors = m_end_node.m_successors ; + foreach (m_end_node.m_successors[succ]) begin + succ.m_predecessors[end_node] = 1; + end + end + end + if (end_with_phase != null) begin + end_node.m_successors = end_with_phase.m_successors; + foreach (end_with_phase.m_successors[succ]) begin + succ.m_predecessors[end_node] = 1; + end + if (after_phase == null && start_with_phase == null) begin + begin_node.m_predecessors = this.m_predecessors ; + foreach (this.m_predecessors[pred]) begin + pred.m_successors[begin_node] = 1; + end + end + end + if (before_phase != null) begin + if (after_phase == null && start_with_phase == null) begin + foreach (before_phase.m_predecessors[pred]) begin + pred.m_successors.delete(before_phase); + pred.m_successors[begin_node] = 1; + end + begin_node.m_predecessors = before_phase.m_predecessors; + before_phase.m_predecessors.delete(); + end + else if (before_phase.m_predecessors.exists(after_phase)) begin + before_phase.m_predecessors.delete(after_phase); + end + before_phase.m_predecessors[end_node] = 1; + end_node.m_successors.delete() ; + end_node.m_successors[before_phase] = 1; + end + if (after_phase != null) begin + if (before_phase == null && end_with_phase == null) begin + foreach (after_phase.m_successors[succ]) begin + succ.m_predecessors.delete(after_phase); + succ.m_predecessors[end_node] = 1; + end + end_node.m_successors = after_phase.m_successors; + after_phase.m_successors.delete(); + end + else if (after_phase.m_successors.exists(before_phase)) begin + after_phase.m_successors.delete(before_phase); + end + after_phase.m_successors[begin_node] = 1; + begin_node.m_predecessors.delete(); + begin_node.m_predecessors[after_phase] = 1; + end + if (new_node == null) + tmp_node = phase; + else + tmp_node = new_node; + state_chg = uvm_phase_state_change::type_id_create(tmp_node.get_name()); + state_chg.m_phase = tmp_node; + state_chg.m_jump_to = null; + state_chg.m_prev_state = tmp_node.m_state; + tmp_node.m_state = UVM_PHASE_DORMANT; + begin + uvm_callback_iter#(uvm_phase,uvm_phase_cb) iter = new(this); + uvm_phase_cb cb = iter.first(); + while(cb != null) begin + cb.phase_state_change(tmp_node, state_chg); + cb = iter.next(); + end + end +endfunction +function uvm_phase uvm_phase::get_parent(); + return m_parent; +endfunction +function uvm_phase uvm_phase::get_imp(); + return m_imp; +endfunction +function uvm_phase uvm_phase::get_schedule(bit hier=0); + uvm_phase sched; + sched = this; + if (hier) + while (sched.m_parent != null && (sched.m_parent.get_phase_type() == UVM_PHASE_SCHEDULE)) + sched = sched.m_parent; + if (sched.m_phase_type == UVM_PHASE_SCHEDULE) + return sched; + if (sched.m_phase_type == UVM_PHASE_NODE) + if (m_parent != null && m_parent.m_phase_type != UVM_PHASE_DOMAIN) + return m_parent; + return null; +endfunction +function uvm_domain uvm_phase::get_domain(); + uvm_phase phase; + phase = this; + while (phase != null && phase.m_phase_type != UVM_PHASE_DOMAIN) + phase = phase.m_parent; + if (phase == null) + return null; + if(!$cast(get_domain,phase)) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH/INTERNAL")) + uvm_report_fatal ("PH/INTERNAL", "get_domain: m_phase_type is DOMAIN but $cast to uvm_domain fails", UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 1047, "", 1); + end +endfunction +function string uvm_phase::get_domain_name(); + uvm_domain domain; + domain = get_domain(); + if (domain == null) + return "unknown"; + return domain.get_name(); +endfunction +function string uvm_phase::get_schedule_name(bit hier=0); + uvm_phase sched; + string s; + sched = get_schedule(hier); + if (sched == null) + return ""; + s = sched.get_name(); + while (sched.m_parent != null && sched.m_parent != sched && + (sched.m_parent.get_phase_type() == UVM_PHASE_SCHEDULE)) begin + sched = sched.m_parent; + s = {sched.get_name(),(s.len()>0?".":""),s}; + end + return s; +endfunction +function string uvm_phase::get_full_name(); + string dom, sch; + if (m_phase_type == UVM_PHASE_IMP) + return get_name(); + get_full_name = get_domain_name(); + sch = get_schedule_name(); + if (sch != "") + get_full_name = {get_full_name, ".", sch}; + if (m_phase_type != UVM_PHASE_DOMAIN && m_phase_type != UVM_PHASE_SCHEDULE) + get_full_name = {get_full_name, ".", get_name()}; +endfunction +function uvm_phase_type uvm_phase::get_phase_type(); + return m_phase_type; +endfunction +function void uvm_phase::set_max_ready_to_end_iterations(int max); + max_ready_to_end_iters = max; +endfunction +function int uvm_phase::get_max_ready_to_end_iterations(); + return max_ready_to_end_iters; +endfunction +function void uvm_phase::set_default_max_ready_to_end_iterations(int max); + m_default_max_ready_to_end_iters = max; +endfunction +function int uvm_phase::get_default_max_ready_to_end_iterations(); + return m_default_max_ready_to_end_iters; +endfunction +function uvm_phase_state uvm_phase::get_state(); + return m_state; +endfunction +function int uvm_phase::get_run_count(); + return m_run_count; +endfunction +function void uvm_phase::m_print_successors(); + uvm_phase found; + static string spaces = " "; + static int level; + if (m_phase_type == UVM_PHASE_DOMAIN) + level = 0; + begin + if (uvm_report_enabled(UVM_NONE,UVM_INFO,"UVM/PHASE/SUCC")) + uvm_report_info ("UVM/PHASE/SUCC", $sformatf("%s%s (%s) id=%0d",spaces.substr(0,level*2),get_name(), m_phase_type.name(),get_inst_id()), UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 1162, "", 1); + end + level++; + foreach (m_successors[succ]) begin + succ.m_print_successors(); + end + level--; +endfunction +function uvm_phase uvm_phase::m_find_predecessor(uvm_phase phase, bit stay_in_scope=1, uvm_phase orig_phase=null); + uvm_phase found; + if (phase == null) begin + return null ; + end + if (phase == m_imp || phase == this) + return this; + foreach (m_predecessors[pred]) begin + uvm_phase orig; + orig = (orig_phase==null) ? this : orig_phase; + if (!stay_in_scope || + (pred.get_schedule() == orig.get_schedule()) || + (pred.get_domain() == orig.get_domain())) begin + found = pred.m_find_predecessor(phase,stay_in_scope,orig); + if (found != null) + return found; + end + end + return null; +endfunction +function uvm_phase uvm_phase::m_find_predecessor_by_name(string name, bit stay_in_scope=1, uvm_phase orig_phase=null); + uvm_phase found; + if (get_name() == name) + return this; + foreach (m_predecessors[pred]) begin + uvm_phase orig; + orig = (orig_phase==null) ? this : orig_phase; + if (!stay_in_scope || + (pred.get_schedule() == orig.get_schedule()) || + (pred.get_domain() == orig.get_domain())) begin + found = pred.m_find_predecessor_by_name(name,stay_in_scope,orig); + if (found != null) + return found; + end + end + return null; +endfunction +function uvm_phase uvm_phase::m_find_successor(uvm_phase phase, bit stay_in_scope=1, uvm_phase orig_phase=null); + uvm_phase found; + if (phase == null) begin + return null ; + end + if (phase == m_imp || phase == this) begin + return this; + end + foreach (m_successors[succ]) begin + uvm_phase orig; + orig = (orig_phase==null) ? this : orig_phase; + if (!stay_in_scope || + (succ.get_schedule() == orig.get_schedule()) || + (succ.get_domain() == orig.get_domain())) begin + found = succ.m_find_successor(phase,stay_in_scope,orig); + if (found != null) begin + return found; + end + end + end + return null; +endfunction +function uvm_phase uvm_phase::m_find_successor_by_name(string name, bit stay_in_scope=1, uvm_phase orig_phase=null); + uvm_phase found; + if (get_name() == name) + return this; + foreach (m_successors[succ]) begin + uvm_phase orig; + orig = (orig_phase==null) ? this : orig_phase; + if (!stay_in_scope || + (succ.get_schedule() == orig.get_schedule()) || + (succ.get_domain() == orig.get_domain())) begin + found = succ.m_find_successor_by_name(name,stay_in_scope,orig); + if (found != null) + return found; + end + end + return null; +endfunction +function uvm_phase uvm_phase::find(uvm_phase phase, bit stay_in_scope=1); + if (phase == m_imp || phase == this) + return phase; + find = m_find_predecessor(phase,stay_in_scope,this); + if (find == null) + find = m_find_successor(phase,stay_in_scope,this); +endfunction +function uvm_phase uvm_phase::find_by_name(string name, bit stay_in_scope=1); + if (get_name() == name) + return this; + find_by_name = m_find_predecessor_by_name(name,stay_in_scope,this); + if (find_by_name == null) + find_by_name = m_find_successor_by_name(name,stay_in_scope,this); +endfunction +function bit uvm_phase::is(uvm_phase phase); + return (m_imp == phase || this == phase); +endfunction +function bit uvm_phase::is_before(uvm_phase phase); + return (!is(phase) && m_find_successor(phase,0,this) != null); +endfunction +function bit uvm_phase::is_after(uvm_phase phase); + return (!is(phase) && m_find_predecessor(phase,0,this) != null); +endfunction +task uvm_phase::execute_phase(); + uvm_task_phase task_phase; + uvm_root top; + uvm_phase_state_change state_chg; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + foreach (m_predecessors[pred]) + wait (pred.m_state == UVM_PHASE_DONE); + if (m_state == UVM_PHASE_DONE) + return; + state_chg = uvm_phase_state_change::type_id_create(get_name()); + state_chg.m_phase = this; + state_chg.m_jump_to = null; + state_chg.m_prev_state = m_state; + m_state = UVM_PHASE_SYNCING; + begin + uvm_callback_iter#(uvm_phase,uvm_phase_cb) iter = new(this); + uvm_phase_cb cb = iter.first(); + while(cb != null) begin + cb.phase_state_change(this, state_chg); + cb = iter.next(); + end + end + #0; + if (m_sync.size()) begin + foreach (m_sync[i]) begin + wait (m_sync[i].m_state >= UVM_PHASE_SYNCING); + end + end + m_run_count++; + if (m_phase_trace) begin + begin + if (uvm_report_enabled(UVM_LOW,UVM_INFO,"PH/TRC/STRT")) + uvm_report_info ("PH/TRC/STRT", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),"Starting phase"}, UVM_LOW, "t/uvm/src/base/uvm_phase.svh", 1382, "", 1); + end + end + if (m_phase_type != UVM_PHASE_NODE) begin + state_chg.m_prev_state = m_state; + m_state = UVM_PHASE_STARTED; + begin + uvm_callback_iter#(uvm_phase,uvm_phase_cb) iter = new(this); + uvm_phase_cb cb = iter.first(); + while(cb != null) begin + cb.phase_state_change(this, state_chg); + cb = iter.next(); + end + end + #0; + state_chg.m_prev_state = m_state; + m_state = UVM_PHASE_EXECUTING; + begin + uvm_callback_iter#(uvm_phase,uvm_phase_cb) iter = new(this); + uvm_phase_cb cb = iter.first(); + while(cb != null) begin + cb.phase_state_change(this, state_chg); + cb = iter.next(); + end + end + #0; + end + else begin + state_chg.m_prev_state = m_state; + m_state = UVM_PHASE_STARTED; + begin + uvm_callback_iter#(uvm_phase,uvm_phase_cb) iter = new(this); + uvm_phase_cb cb = iter.first(); + while(cb != null) begin + cb.phase_state_change(this, state_chg); + cb = iter.next(); + end + end + m_imp.traverse(top,this,UVM_PHASE_STARTED); + m_ready_to_end_count = 0 ; + #0; + if (!$cast(task_phase,m_imp)) begin + state_chg.m_prev_state = m_state; + m_state = UVM_PHASE_EXECUTING; + begin + uvm_callback_iter#(uvm_phase,uvm_phase_cb) iter = new(this); + uvm_phase_cb cb = iter.first(); + while(cb != null) begin + cb.phase_state_change(this, state_chg); + cb = iter.next(); + end + end + #0; + m_imp.traverse(top,this,UVM_PHASE_EXECUTING); + end + else begin + m_executing_phases[this] = 1; + state_chg.m_prev_state = m_state; + m_state = UVM_PHASE_EXECUTING; + begin + uvm_callback_iter#(uvm_phase,uvm_phase_cb) iter = new(this); + uvm_phase_cb cb = iter.first(); + while(cb != null) begin + cb.phase_state_change(this, state_chg); + cb = iter.next(); + end + end + fork : master_phase_process + begin + m_phase_proc = process::self(); + task_phase.traverse(top,this,UVM_PHASE_EXECUTING); + wait(0); + end + join_none + uvm_wait_for_nba_region(); + fork + begin + fork + begin + wait (m_premature_end); + begin + if (uvm_report_enabled(UVM_DEBUG,UVM_INFO,"PH/TRC/EXE/JUMP")) + uvm_report_info ("PH/TRC/EXE/JUMP", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),"PHASE EXIT ON JUMP REQUEST"}, UVM_DEBUG, "t/uvm/src/base/uvm_phase.svh", 1462, "", 1); + end + end + begin + bit do_ready_to_end ; + uvm_objection phase_done; + phase_done = get_objection(); + if (phase_done.get_objection_total(top) || + m_use_ovm_run_semantic && m_imp.get_name() == "run") begin + if (!phase_done.m_top_all_dropped) + phase_done.wait_for(UVM_ALL_DROPPED, top); + begin + if (uvm_report_enabled(UVM_DEBUG,UVM_INFO,"PH/TRC/EXE/ALLDROP")) + uvm_report_info ("PH/TRC/EXE/ALLDROP", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),"PHASE EXIT ALL_DROPPED"}, UVM_DEBUG, "t/uvm/src/base/uvm_phase.svh", 1475, "", 1); + end + end + else begin + if (m_phase_trace) + begin + if (uvm_report_enabled(UVM_LOW,UVM_INFO,"PH/TRC/SKIP")) + uvm_report_info ("PH/TRC/SKIP", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),"No objections raised, skipping phase"}, UVM_LOW, "t/uvm/src/base/uvm_phase.svh", 1478, "", 1); + end + end + wait_for_self_and_siblings_to_drop() ; + do_ready_to_end = 1; + while (do_ready_to_end) begin + uvm_wait_for_nba_region(); + begin + if (uvm_report_enabled(UVM_DEBUG,UVM_INFO,"PH_READY_TO_END")) + uvm_report_info ("PH_READY_TO_END", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),"PHASE READY TO END"}, UVM_DEBUG, "t/uvm/src/base/uvm_phase.svh", 1490, "", 1); + end + m_ready_to_end_count++; + if (m_phase_trace) + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"PH_READY_TO_END_CB")) + uvm_report_info ("PH_READY_TO_END_CB", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),"CALLING READY_TO_END CB"}, UVM_HIGH, "t/uvm/src/base/uvm_phase.svh", 1493, "", 1); + end + state_chg.m_prev_state = m_state; + m_state = UVM_PHASE_READY_TO_END; + begin + uvm_callback_iter#(uvm_phase,uvm_phase_cb) iter = new(this); + uvm_phase_cb cb = iter.first(); + while(cb != null) begin + cb.phase_state_change(this, state_chg); + cb = iter.next(); + end + end + if (m_imp != null) + m_imp.traverse(top,this,UVM_PHASE_READY_TO_END); + uvm_wait_for_nba_region(); + wait_for_self_and_siblings_to_drop(); + do_ready_to_end = (m_state == UVM_PHASE_EXECUTING) && (m_ready_to_end_count < get_max_ready_to_end_iterations()) ; + end + end + begin + if (this.get_name() == "run") begin + if (top.phase_timeout == 0) + wait(top.phase_timeout != 0); + if (m_phase_trace) + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"PH/TRC/TO_WAIT")) + uvm_report_info ("PH/TRC/TO_WAIT", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),$sformatf("STARTING PHASE TIMEOUT WATCHDOG (timeout == %t)", top.phase_timeout)}, UVM_HIGH, "t/uvm/src/base/uvm_phase.svh", 1513, "", 1); + end + #(top.phase_timeout); + if ($time == 9200s) begin + if (m_phase_trace) + begin + if (uvm_report_enabled(UVM_LOW,UVM_INFO,"PH/TRC/TIMEOUT")) + uvm_report_info ("PH/TRC/TIMEOUT", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),"PHASE TIMEOUT WATCHDOG EXPIRED"}, UVM_LOW, "t/uvm/src/base/uvm_phase.svh", 1517, "", 1); + end + foreach (m_executing_phases[p]) begin + uvm_objection p_phase_done; + p_phase_done = p.get_objection(); + if ((p_phase_done != null) && (p_phase_done.get_objection_total() > 0)) begin + if (m_phase_trace) + begin + if (uvm_report_enabled(UVM_LOW,UVM_INFO,"PH/TRC/TIMEOUT/OBJCTN")) + uvm_report_info ("PH/TRC/TIMEOUT/OBJCTN", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),$sformatf("Phase '%s' has outstanding objections:\n%s", p.get_full_name(), p_phase_done.convert2string())}, UVM_LOW, "t/uvm/src/base/uvm_phase.svh", 1526, "", 1); + end + end + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_TIMEOUT")) + uvm_report_fatal ("PH_TIMEOUT", $sformatf("Default timeout of %0t hit, indicating a probable testbench issue", 9200s), UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 1532, "", 1); + end + end + else begin + if (m_phase_trace) + begin + if (uvm_report_enabled(UVM_LOW,UVM_INFO,"PH/TRC/TIMEOUT")) + uvm_report_info ("PH/TRC/TIMEOUT", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),"PHASE TIMEOUT WATCHDOG EXPIRED"}, UVM_LOW, "t/uvm/src/base/uvm_phase.svh", 1536, "", 1); + end + foreach (m_executing_phases[p]) begin + uvm_objection p_phase_done; + p_phase_done = p.get_objection(); + if ((p_phase_done != null) && (p_phase_done.get_objection_total() > 0)) begin + if (m_phase_trace) + begin + if (uvm_report_enabled(UVM_LOW,UVM_INFO,"PH/TRC/TIMEOUT/OBJCTN")) + uvm_report_info ("PH/TRC/TIMEOUT/OBJCTN", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),$sformatf("Phase '%s' has outstanding objections:\n%s", p.get_full_name(), p_phase_done.convert2string())}, UVM_LOW, "t/uvm/src/base/uvm_phase.svh", 1545, "", 1); + end + end + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_TIMEOUT")) + uvm_report_fatal ("PH_TIMEOUT", $sformatf("Explicit timeout of %0t hit, indicating a probable testbench issue", top.phase_timeout), UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 1551, "", 1); + end + end + if (m_phase_trace) + begin + if (uvm_report_enabled(UVM_DEBUG,UVM_INFO,"PH/TRC/EXE/3")) + uvm_report_info ("PH/TRC/EXE/3", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),"PHASE EXIT TIMEOUT"}, UVM_DEBUG, "t/uvm/src/base/uvm_phase.svh", 1554, "", 1); + end + end + else begin + wait (0); + end + end + join_any +//TODO issue #4125 - Support disable fork +//TODO %Error-UNSUPPORTED: t/t_uvm_pkg_todo.vh:11187:12: Unsupported: disable fork statements +//TODO disable fork; + end + join + end + end + m_executing_phases.delete(this); + if (m_phase_type == UVM_PHASE_NODE) begin + if(m_premature_end) begin + if(m_jump_phase != null) begin + state_chg.m_jump_to = m_jump_phase; + begin + if (uvm_report_enabled(UVM_MEDIUM,UVM_INFO,"PH_JUMP")) + uvm_report_info ("PH_JUMP", $sformatf("phase %s (schedule %s, domain %s) is jumping to phase %s", get_name(), get_schedule_name(), get_domain_name(), m_jump_phase.get_name()), UVM_MEDIUM, "t/uvm/src/base/uvm_phase.svh", 1598, "", 1); + end + end + else begin + begin + if (uvm_report_enabled(UVM_MEDIUM,UVM_INFO,"PH_JUMP")) + uvm_report_info ("PH_JUMP", $sformatf("phase %s (schedule %s, domain %s) is ending prematurely", get_name(), get_schedule_name(), get_domain_name()), UVM_MEDIUM, "t/uvm/src/base/uvm_phase.svh", 1604, "", 1); + end + end + #0; + if (m_phase_trace) + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"PH_END")) + uvm_report_info ("PH_END", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),"ENDING PHASE PREMATURELY"}, UVM_HIGH, "t/uvm/src/base/uvm_phase.svh", 1610, "", 1); + end + end + else begin + if (task_phase == null) + m_wait_for_pred(); + end + if (m_phase_trace) + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"PH_END")) + uvm_report_info ("PH_END", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),"ENDING PHASE"}, UVM_HIGH, "t/uvm/src/base/uvm_phase.svh", 1624, "", 1); + end + state_chg.m_prev_state = m_state; + m_state = UVM_PHASE_ENDED; + begin + uvm_callback_iter#(uvm_phase,uvm_phase_cb) iter = new(this); + uvm_phase_cb cb = iter.first(); + while(cb != null) begin + cb.phase_state_change(this, state_chg); + cb = iter.next(); + end + end + if (m_imp != null) + m_imp.traverse(top,this,UVM_PHASE_ENDED); + #0; + state_chg.m_prev_state = m_state; + if(m_premature_end) m_state = UVM_PHASE_JUMPING; + else m_state = UVM_PHASE_CLEANUP ; + begin + uvm_callback_iter#(uvm_phase,uvm_phase_cb) iter = new(this); + uvm_phase_cb cb = iter.first(); + while(cb != null) begin + cb.phase_state_change(this, state_chg); + cb = iter.next(); + end + end + if (m_phase_proc != null) begin + m_phase_proc.kill(); + m_phase_proc = null; + end + #0; + begin + uvm_objection objection = get_objection(); + if (objection != null) + objection.clear(); + end + end + m_premature_end = 0 ; + if(m_jump_fwd || m_jump_bkwd) begin + if(m_jump_fwd) begin + clear_successors(UVM_PHASE_DONE,m_jump_phase); + end + m_jump_phase.clear_successors(); + end + else begin + if (m_phase_trace) + begin + if (uvm_report_enabled(UVM_LOW,UVM_INFO,"PH/TRC/DONE")) + uvm_report_info ("PH/TRC/DONE", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),"Completed phase"}, UVM_LOW, "t/uvm/src/base/uvm_phase.svh", 1666, "", 1); + end + state_chg.m_prev_state = m_state; + m_state = UVM_PHASE_DONE; + begin + uvm_callback_iter#(uvm_phase,uvm_phase_cb) iter = new(this); + uvm_phase_cb cb = iter.first(); + while(cb != null) begin + cb.phase_state_change(this, state_chg); + cb = iter.next(); + end + end + m_phase_proc = null; + #0; + end + #0; + begin + uvm_objection objection; + objection = get_objection(); + if (objection != null) + objection.clear(); + end + if(m_jump_fwd || m_jump_bkwd) begin + void'(m_phase_hopper.try_put(m_jump_phase)); + m_jump_phase = null; + m_jump_fwd = 0; + m_jump_bkwd = 0; + end + else if (m_successors.size() == 0) begin + top.m_phase_all_done=1; + end + else begin + foreach (m_successors[succ]) begin + if(succ.m_state < UVM_PHASE_SCHEDULED) begin + state_chg.m_prev_state = succ.m_state; + state_chg.m_phase = succ; + succ.m_state = UVM_PHASE_SCHEDULED; + begin + uvm_callback_iter#(uvm_phase,uvm_phase_cb) iter = new(this); + uvm_phase_cb cb = iter.first(); + while(cb != null) begin + cb.phase_state_change(succ, state_chg); + cb = iter.next(); + end + end + #0; + void'(m_phase_hopper.try_put(succ)); + if (m_phase_trace) + begin + if (uvm_report_enabled(UVM_LOW,UVM_INFO,"PH/TRC/SCHEDULED")) + uvm_report_info ("PH/TRC/SCHEDULED", {$sformatf("Phase '%0s' (id=%0d) ", succ.get_full_name(), succ.get_inst_id()),{"Scheduled from phase ",get_full_name()}}, UVM_LOW, "t/uvm/src/base/uvm_phase.svh", 1705, "", 1); + end + end + end + end +endtask +function void uvm_phase::get_adjacent_predecessor_nodes(ref uvm_phase pred[]); + bit done; + bit predecessors[uvm_phase]; + int idx; + foreach (m_predecessors[p]) + predecessors[p] = 1; + do begin + done = 1; + foreach (predecessors[p]) begin + if (p.get_phase_type() != UVM_PHASE_NODE) begin + predecessors.delete(p); + foreach (p.m_predecessors[next_p]) + predecessors[next_p] = 1; + done = 0; + end + end + end while (!done); + pred = new [predecessors.size()]; + foreach (predecessors[p]) begin + pred[idx++] = p; + end +endfunction : get_adjacent_predecessor_nodes +function void uvm_phase::get_adjacent_successor_nodes(ref uvm_phase succ[]); + bit done; + bit successors[uvm_phase]; + int idx; + foreach (m_successors[s]) + successors[s] = 1; + do begin + done = 1; + foreach (successors[s]) begin + if (s.get_phase_type() != UVM_PHASE_NODE) begin + successors.delete(s); + foreach (s.m_successors[next_s]) + successors[next_s] = 1; + done = 0; + end + end + end while (!done); + succ = new [successors.size()]; + foreach (successors[s]) begin + succ[idx++] = s; + end +endfunction : get_adjacent_successor_nodes +function void uvm_phase::get_predecessors_for_successors(output bit pred_of_succ[uvm_phase]); + bit done; + uvm_phase successors[]; + get_adjacent_successor_nodes(successors); + foreach (successors[s]) + foreach (successors[s].m_predecessors[pred]) + pred_of_succ[pred] = 1; + do begin + done=1; + foreach (pred_of_succ[pred]) begin + if (pred.get_phase_type() != UVM_PHASE_NODE) begin + pred_of_succ.delete(pred); + foreach (pred.m_predecessors[next_pred]) + pred_of_succ[next_pred] = 1; + done =0; + end + end + end while (!done); + pred_of_succ.delete(this); +endfunction +task uvm_phase::m_wait_for_pred(); + bit pred_of_succ[uvm_phase]; + get_predecessors_for_successors(pred_of_succ); + foreach (pred_of_succ[sibling]) begin + if (m_phase_trace) begin + string s; + s = $sformatf("Waiting for phase '%s' (%0d) to be READY_TO_END. Current state is %s", + sibling.get_name(),sibling.get_inst_id(),sibling.m_state.name()); + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"PH/TRC/WAIT_PRED_OF_SUCC")) + uvm_report_info ("PH/TRC/WAIT_PRED_OF_SUCC", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),s}, UVM_HIGH, "t/uvm/src/base/uvm_phase.svh", 1819, "", 1); + end + end + sibling.wait_for_state(UVM_PHASE_READY_TO_END, UVM_GTE); + if (m_phase_trace) begin + string s; + s = $sformatf("Phase '%s' (%0d) is now READY_TO_END. Releasing phase", + sibling.get_name(),sibling.get_inst_id()); + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"PH/TRC/WAIT_PRED_OF_SUCC")) + uvm_report_info ("PH/TRC/WAIT_PRED_OF_SUCC", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),s}, UVM_HIGH, "t/uvm/src/base/uvm_phase.svh", 1828, "", 1); + end + end + end + if (m_phase_trace) begin + if (pred_of_succ.num()) begin + string s = "( "; + foreach (pred_of_succ[pred]) + s = {s, pred.get_full_name()," "}; + s = {s, ")"}; + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"PH/TRC/WAIT_PRED_OF_SUCC")) + uvm_report_info ("PH/TRC/WAIT_PRED_OF_SUCC", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),{"*** All pred to succ ",s," in READY_TO_END state, so ending phase ***"}}, UVM_HIGH, "t/uvm/src/base/uvm_phase.svh", 1840, "", 1); + end + end + else begin + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"PH/TRC/WAIT_PRED_OF_SUCC")) + uvm_report_info ("PH/TRC/WAIT_PRED_OF_SUCC", {$sformatf("Phase '%0s' (id=%0d) ", this.get_full_name(), this.get_inst_id()),"*** No pred to succ other than myself, so ending phase ***"}, UVM_HIGH, "t/uvm/src/base/uvm_phase.svh", 1844, "", 1); + end + end + end + #0; +endtask +function void uvm_phase::m_report_null_objection(uvm_object obj, + string description, + int count, + string action); + string m_action; + string m_addon; + string m_obj_name = (obj == null) ? "uvm_top" : obj.get_full_name(); + if ((action == "raise") || (action == "drop")) begin + if (count != 1) + m_action = $sformatf("%s %0d objections", action, count); + else + m_action = $sformatf("%s an objection", action); + end + else if (action == "get_objection_count") begin + m_action = "call get_objection_count"; + end + if (this.get_phase_type() == UVM_PHASE_IMP) begin + m_addon = " (This is a UVM_PHASE_IMP, you have to query the schedule to find the UVM_PHASE_NODE)"; + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/PH/NULL_OBJECTION")) + uvm_report_error ("UVM/PH/NULL_OBJECTION", $sformatf("'%s' attempted to %s on '%s', however '%s' is not a task-based phase node! %s", m_obj_name, m_action, get_name(), get_name(), m_addon), UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 1885, "", 1); + end +endfunction : m_report_null_objection +function void uvm_phase::raise_objection (uvm_object obj, + string description="", + int count=1); + uvm_objection phase_done; + phase_done = get_objection(); + if (phase_done != null) + phase_done.raise_objection(obj,description,count); + else + m_report_null_objection(obj, description, count, "raise"); +endfunction +function void uvm_phase::drop_objection (uvm_object obj, + string description="", + int count=1); + uvm_objection phase_done; + phase_done = get_objection(); + if (phase_done != null) + phase_done.drop_objection(obj,description,count); + else + m_report_null_objection(obj, description, count, "drop"); +endfunction +function int uvm_phase::get_objection_count (uvm_object obj=null); + uvm_objection phase_done; + phase_done = get_objection(); + if (phase_done != null) + return phase_done.get_objection_count(obj); + else begin + m_report_null_objection(obj, "" , 0, "get_objection_count"); + return 0; + end +endfunction : get_objection_count +function void uvm_phase::sync(uvm_domain target, + uvm_phase phase=null, + uvm_phase with_phase=null); + if (!this.is_domain()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BADSYNC")) + uvm_report_fatal ("PH_BADSYNC", "sync() called from a non-domain phase schedule node", UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 1939, "", 1); + end + end + else if (target == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BADSYNC")) + uvm_report_fatal ("PH_BADSYNC", "sync() called with a null target domain", UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 1942, "", 1); + end + end + else if (!target.is_domain()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BADSYNC")) + uvm_report_fatal ("PH_BADSYNC", "sync() called with a non-domain phase schedule node as target", UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 1945, "", 1); + end + end + else if (phase == null && with_phase != null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BADSYNC")) + uvm_report_fatal ("PH_BADSYNC", "sync() called with null phase and non-null with phase", UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 1948, "", 1); + end + end + else if (phase == null) begin + int visited[uvm_phase]; + uvm_phase queue[$]; + queue.push_back(this); + visited[this] = 1; + while (queue.size()) begin + uvm_phase node; + node = queue.pop_front(); + if (node.m_imp != null) begin + sync(target, node.m_imp); + end + foreach (node.m_successors[succ]) begin + if (!visited.exists(succ)) begin + queue.push_back(succ); + visited[succ] = 1; + end + end + end + end else begin + uvm_phase from_node, to_node; + int found_to[$], found_from[$]; + if(with_phase == null) with_phase = phase; + from_node = find(phase); + to_node = target.find(with_phase); + if(from_node == null || to_node == null) return; + found_to = from_node.m_sync.find_index(node) with (node == to_node); + found_from = to_node.m_sync.find_index(node) with (node == from_node); + if (found_to.size() == 0) from_node.m_sync.push_back(to_node); + if (found_from.size() == 0) to_node.m_sync.push_back(from_node); + end +endfunction +function void uvm_phase::unsync(uvm_domain target, + uvm_phase phase=null, + uvm_phase with_phase=null); + if (!this.is_domain()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BADSYNC")) + uvm_report_fatal ("PH_BADSYNC", "unsync() called from a non-domain phase schedule node", UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 1993, "", 1); + end + end else if (target == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BADSYNC")) + uvm_report_fatal ("PH_BADSYNC", "unsync() called with a null target domain", UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 1995, "", 1); + end + end else if (!target.is_domain()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BADSYNC")) + uvm_report_fatal ("PH_BADSYNC", "unsync() called with a non-domain phase schedule node as target", UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 1997, "", 1); + end + end else if (phase == null && with_phase != null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BADSYNC")) + uvm_report_fatal ("PH_BADSYNC", "unsync() called with null phase and non-null with phase", UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 1999, "", 1); + end + end else if (phase == null) begin + int visited[uvm_phase]; + uvm_phase queue[$]; + queue.push_back(this); + visited[this] = 1; + while (queue.size()) begin + uvm_phase node; + node = queue.pop_front(); + if (node.m_imp != null) unsync(target,node.m_imp); + foreach (node.m_successors[succ]) begin + if (!visited.exists(succ)) begin + queue.push_back(succ); + visited[succ] = 1; + end + end + end + end else begin + uvm_phase from_node, to_node; + int found_to[$], found_from[$]; + if(with_phase == null) with_phase = phase; + from_node = find(phase); + to_node = target.find(with_phase); + if(from_node == null || to_node == null) return; + found_to = from_node.m_sync.find_index(node) with (node == to_node); + found_from = to_node.m_sync.find_index(node) with (node == from_node); + if (found_to.size()) from_node.m_sync.delete(found_to[0]); + if (found_from.size()) to_node.m_sync.delete(found_from[0]); + end +endfunction +task uvm_phase::wait_for_state(uvm_phase_state state, uvm_wait_op op=UVM_EQ); + case (op) + UVM_EQ: wait((state&m_state) != 0); + UVM_NE: wait((state&m_state) == 0); + UVM_LT: wait(m_state < state); + UVM_LTE: wait(m_state <= state); + UVM_GT: wait(m_state > state); + UVM_GTE: wait(m_state >= state); + endcase +endtask +function void uvm_phase::set_jump_phase(uvm_phase phase) ; + uvm_phase d; + if ((m_state < UVM_PHASE_STARTED) || + (m_state > UVM_PHASE_ENDED) ) + begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"JMPPHIDL")) + uvm_report_error ("JMPPHIDL", { "Attempting to jump from phase \"", get_name(), "\" which is not currently active (current state is ", m_state.name(), "). The jump will not happen until the phase becomes ", "active."}, UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 2067, "", 1); + end + end + d = m_find_predecessor(phase,0); + if (d == null) begin + d = m_find_successor(phase,0); + if (d == null) begin + string msg; + $sformat(msg,{"phase %s is neither a predecessor or successor of ", + "phase %s or is non-existant, so we cannot jump to it. ", + "Phase control flow is now undefined so the simulation ", + "must terminate"}, phase.get_name(), get_name()); + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BADJUMP")) + uvm_report_fatal ("PH_BADJUMP", msg, UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 2093, "", 1); + end + end + else begin + m_jump_fwd = 1; + begin + if (uvm_report_enabled(UVM_DEBUG,UVM_INFO,"PH_JUMPF")) + uvm_report_info ("PH_JUMPF", $sformatf("jumping forward to phase %s", phase.get_name()), UVM_DEBUG, "t/uvm/src/base/uvm_phase.svh", 2098, "", 1); + end + end + end + else begin + m_jump_bkwd = 1; + begin + if (uvm_report_enabled(UVM_DEBUG,UVM_INFO,"PH_JUMPB")) + uvm_report_info ("PH_JUMPB", $sformatf("jumping backward to phase %s", phase.get_name()), UVM_DEBUG, "t/uvm/src/base/uvm_phase.svh", 2104, "", 1); + end + end + m_jump_phase = d; +endfunction +function void uvm_phase::end_prematurely() ; + m_premature_end = 1 ; +endfunction +function void uvm_phase::jump(uvm_phase phase); + set_jump_phase(phase) ; + end_prematurely() ; +endfunction +function void uvm_phase::jump_all(uvm_phase phase); + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"NOTIMPL")) + uvm_report_warning ("NOTIMPL", "uvm_phase::jump_all is not implemented and has been replaced by uvm_domain::jump_all", UVM_NONE, "t/uvm/src/base/uvm_phase.svh", 2136, "", 1); + end +endfunction +function uvm_phase uvm_phase::get_jump_target(); + return m_jump_phase; +endfunction +function void uvm_phase::clear(uvm_phase_state state = UVM_PHASE_DORMANT); + uvm_objection phase_done; + phase_done = get_objection(); + m_state = state; + m_phase_proc = null; + if (phase_done != null) + phase_done.clear(this); +endfunction +function void uvm_phase::clear_successors(uvm_phase_state state = UVM_PHASE_DORMANT, + uvm_phase end_state=null); + if(this == end_state) + return; + clear(state); + foreach(m_successors[succ]) begin + succ.clear_successors(state, end_state); + end +endfunction +task uvm_phase::wait_for_self_and_siblings_to_drop() ; + bit need_to_check_all = 1 ; + uvm_root top; + uvm_coreservice_t cs; + bit siblings[uvm_phase]; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + get_predecessors_for_successors(siblings); + foreach (m_sync[i]) begin + siblings[m_sync[i]] = 1; + end + while (need_to_check_all) begin + uvm_objection phase_done; + phase_done = get_objection(); + need_to_check_all = 0 ; + if ((phase_done != null) && (phase_done.get_objection_total(top) != 0)) begin + m_state = UVM_PHASE_EXECUTING ; + phase_done.wait_for(UVM_ALL_DROPPED, top); + need_to_check_all = 1 ; + end + foreach(siblings[sib]) begin + uvm_objection sib_phase_done; + sib_phase_done = sib.get_objection(); + sib.wait_for_state(UVM_PHASE_EXECUTING, UVM_GTE); + if ((sib_phase_done != null) && (sib_phase_done.get_objection_total(top) != 0)) begin + m_state = UVM_PHASE_EXECUTING ; + sib_phase_done.wait_for(UVM_ALL_DROPPED, top); + need_to_check_all = 1 ; + end + end + end +endtask +function void uvm_phase::kill(); + begin + if (uvm_report_enabled(UVM_DEBUG,UVM_INFO,"PH_KILL")) + uvm_report_info ("PH_KILL", {"killing phase '", get_name(),"'"}, UVM_DEBUG, "t/uvm/src/base/uvm_phase.svh", 2230, "", 1); + end + if (m_phase_proc != null) begin + m_phase_proc.kill(); + m_phase_proc = null; + end +endfunction +function void uvm_phase::kill_successors(); + foreach (m_successors[succ]) + succ.kill_successors(); + kill(); +endfunction +task uvm_phase::m_run_phases(); + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + begin + uvm_phase ph = uvm_domain::get_common_domain(); + void'(m_phase_hopper.try_put(ph)); + end + m_uvm_core_state=UVM_CORE_RUNNING; + forever begin + uvm_phase phase; + m_phase_hopper.get(phase); + fork + begin + phase.execute_phase(); + end + join_none + #0; + end +endtask +function void uvm_phase::m_terminate_phase(); + uvm_objection phase_done; + phase_done = get_objection(); + if (phase_done != null) + phase_done.clear(this); +endfunction +function void uvm_phase::m_print_termination_state(); + uvm_root top; + uvm_coreservice_t cs; + uvm_objection phase_done; + phase_done = get_objection(); + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + if (phase_done != null) begin + begin + if (uvm_report_enabled(UVM_DEBUG,UVM_INFO,"PH_TERMSTATE")) + uvm_report_info ("PH_TERMSTATE", $sformatf("phase %s outstanding objections = %0d", get_name(), phase_done.get_objection_total(top)), UVM_DEBUG, "t/uvm/src/base/uvm_phase.svh", 2309, "", 1); + end + end + else begin + begin + if (uvm_report_enabled(UVM_DEBUG,UVM_INFO,"PH_TERMSTATE")) + uvm_report_info ("PH_TERMSTATE", $sformatf("phase %s has no outstanding objections", get_name()), UVM_DEBUG, "t/uvm/src/base/uvm_phase.svh", 2315, "", 1); + end + end +endfunction +typedef class uvm_build_phase; +typedef class uvm_connect_phase; +typedef class uvm_end_of_elaboration_phase; +typedef class uvm_start_of_simulation_phase; +typedef class uvm_run_phase; +typedef class uvm_extract_phase; +typedef class uvm_check_phase; +typedef class uvm_report_phase; +typedef class uvm_final_phase; +typedef class uvm_pre_reset_phase; +typedef class uvm_reset_phase; +typedef class uvm_post_reset_phase; +typedef class uvm_pre_configure_phase; +typedef class uvm_configure_phase; +typedef class uvm_post_configure_phase; +typedef class uvm_pre_main_phase; +typedef class uvm_main_phase; +typedef class uvm_post_main_phase; +typedef class uvm_pre_shutdown_phase; +typedef class uvm_shutdown_phase; +typedef class uvm_post_shutdown_phase; +uvm_phase build_ph; +uvm_phase connect_ph; +uvm_phase end_of_elaboration_ph; +uvm_phase start_of_simulation_ph; +uvm_phase run_ph; +uvm_phase extract_ph; +uvm_phase check_ph; +uvm_phase report_ph; +class uvm_domain extends uvm_phase; + static local uvm_domain m_uvm_domain; + static local uvm_domain m_domains[string]; + static local uvm_phase m_uvm_schedule; + static function void get_domains(output uvm_domain domains[string]); + domains = m_domains; + endfunction + static function uvm_phase get_uvm_schedule(); + void'(get_uvm_domain()); + return m_uvm_schedule; + endfunction + static function uvm_domain get_common_domain(); + uvm_domain domain; + if(m_domains.exists("common")) + domain = m_domains["common"]; + if (domain != null) + return domain; + domain = new("common"); + domain.add(uvm_build_phase::get()); + domain.add(uvm_connect_phase::get()); + domain.add(uvm_end_of_elaboration_phase::get()); + domain.add(uvm_start_of_simulation_phase::get()); + domain.add(uvm_run_phase::get()); + domain.add(uvm_extract_phase::get()); + domain.add(uvm_check_phase::get()); + domain.add(uvm_report_phase::get()); + domain.add(uvm_final_phase::get()); + build_ph = domain.find(uvm_build_phase::get()); + connect_ph = domain.find(uvm_connect_phase::get()); + end_of_elaboration_ph = domain.find(uvm_end_of_elaboration_phase::get()); + start_of_simulation_ph = domain.find(uvm_start_of_simulation_phase::get()); + run_ph = domain.find(uvm_run_phase::get()); + extract_ph = domain.find(uvm_extract_phase::get()); + check_ph = domain.find(uvm_check_phase::get()); + report_ph = domain.find(uvm_report_phase::get()); + domain = get_uvm_domain(); + m_domains["common"].add(domain, + .with_phase(m_domains["common"].find(uvm_run_phase::get()))); + return m_domains["common"]; + endfunction + static function void add_uvm_phases(uvm_phase schedule); + schedule.add(uvm_pre_reset_phase::get()); + schedule.add(uvm_reset_phase::get()); + schedule.add(uvm_post_reset_phase::get()); + schedule.add(uvm_pre_configure_phase::get()); + schedule.add(uvm_configure_phase::get()); + schedule.add(uvm_post_configure_phase::get()); + schedule.add(uvm_pre_main_phase::get()); + schedule.add(uvm_main_phase::get()); + schedule.add(uvm_post_main_phase::get()); + schedule.add(uvm_pre_shutdown_phase::get()); + schedule.add(uvm_shutdown_phase::get()); + schedule.add(uvm_post_shutdown_phase::get()); + endfunction + static function uvm_domain get_uvm_domain(); + if (m_uvm_domain == null) begin + m_uvm_domain = new("uvm"); + m_uvm_schedule = new("uvm_sched", UVM_PHASE_SCHEDULE); + add_uvm_phases(m_uvm_schedule); + m_uvm_domain.add(m_uvm_schedule); + end + return m_uvm_domain; + endfunction + function new(string name); + super.new(name,UVM_PHASE_DOMAIN); + if (m_domains.exists(name)) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UNIQDOMNAM")) + uvm_report_error ("UNIQDOMNAM", $sformatf("Domain created with non-unique name '%s'", name), UVM_NONE, "t/uvm/src/base/uvm_domain.svh", 183, "", 1); + end + m_domains[name] = this; + endfunction + function void jump(uvm_phase phase); + uvm_phase phases[$]; + m_get_transitive_children(phases); + phases = phases.find(item) with (item.get_state() inside {[UVM_PHASE_STARTED:UVM_PHASE_CLEANUP]}); + foreach(phases[idx]) + if(phases[idx].is_before(phase) || phases[idx].is_after(phase)) + phases[idx].jump(phase); + endfunction + static function void jump_all(uvm_phase phase); + uvm_domain domains[string]; + uvm_domain::get_domains(domains); + foreach(domains[idx]) + domains[idx].jump(phase); + endfunction +endclass +virtual class uvm_bottomup_phase extends uvm_phase; + function new(string name); + super.new(name,UVM_PHASE_IMP); + endfunction + virtual function void traverse(uvm_component comp, + uvm_phase phase, + uvm_phase_state state); + string name; + uvm_domain phase_domain =phase.get_domain(); + uvm_domain comp_domain = comp.get_domain(); + if (comp.get_first_child(name)) + do + traverse(comp.get_child(name), phase, state); + while(comp.get_next_child(name)); + if (m_phase_trace) + begin + if (uvm_report_enabled(UVM_DEBUG,UVM_INFO,"PH_TRACE")) + uvm_report_info ("PH_TRACE", $sformatf("bottomup-phase phase=%s state=%s comp=%s comp.domain=%s phase.domain=%s", phase.get_name(), state.name(), comp.get_full_name(),comp_domain.get_name(),phase_domain.get_name()), UVM_DEBUG, "t/uvm/src/base/uvm_bottomup_phase.svh", 64, "", 1); + end + if (phase_domain == uvm_domain::get_common_domain() || + phase_domain == comp_domain) begin + case (state) + UVM_PHASE_STARTED: begin + comp.m_current_phase = phase; + comp.m_apply_verbosity_settings(phase); + comp.phase_started(phase); + end + UVM_PHASE_EXECUTING: begin + uvm_phase ph = this; + if (comp.m_phase_imps.exists(this)) + ph = comp.m_phase_imps[this]; + ph.execute(comp, phase); + end + UVM_PHASE_READY_TO_END: begin + comp.phase_ready_to_end(phase); + end + UVM_PHASE_ENDED: begin + comp.phase_ended(phase); + comp.m_current_phase = null; + end + default: + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BADEXEC")) + uvm_report_fatal ("PH_BADEXEC", "bottomup phase traverse internal error", UVM_NONE, "t/uvm/src/base/uvm_bottomup_phase.svh", 88, "", 1); + end + endcase + end + endfunction + virtual function void execute(uvm_component comp, + uvm_phase phase); + process proc = process::self(); + proc.srandom(uvm_create_random_seed(phase.get_type_name(), comp.get_full_name())); + comp.m_current_phase = phase; + exec_func(comp,phase); + endfunction +endclass +virtual class uvm_topdown_phase extends uvm_phase; + function new(string name); + super.new(name,UVM_PHASE_IMP); + endfunction + virtual function void traverse(uvm_component comp, + uvm_phase phase, + uvm_phase_state state); + string name; + uvm_domain phase_domain = phase.get_domain(); + uvm_domain comp_domain = comp.get_domain(); + if (m_phase_trace) + begin + if (uvm_report_enabled(UVM_DEBUG,UVM_INFO,"PH_TRACE")) + uvm_report_info ("PH_TRACE", $sformatf("topdown-phase phase=%s state=%s comp=%s comp.domain=%s phase.domain=%s", phase.get_name(), state.name(), comp.get_full_name(),comp_domain.get_name(),phase_domain.get_name()), UVM_DEBUG, "t/uvm/src/base/uvm_topdown_phase.svh", 59, "", 1); + end + if (phase_domain == uvm_domain::get_common_domain() || + phase_domain == comp_domain) begin + case (state) + UVM_PHASE_STARTED: begin + comp.m_current_phase = phase; + comp.m_apply_verbosity_settings(phase); + comp.phase_started(phase); + end + UVM_PHASE_EXECUTING: begin + if (!(phase.get_name() == "build" && comp.m_build_done)) begin + uvm_phase ph = this; + comp.m_phasing_active++; + if (comp.m_phase_imps.exists(this)) + ph = comp.m_phase_imps[this]; + ph.execute(comp, phase); + comp.m_phasing_active--; + end + end + UVM_PHASE_READY_TO_END: begin + comp.phase_ready_to_end(phase); + end + UVM_PHASE_ENDED: begin + comp.phase_ended(phase); + comp.m_current_phase = null; + end + default: + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BADEXEC")) + uvm_report_fatal ("PH_BADEXEC", "topdown phase traverse internal error", UVM_NONE, "t/uvm/src/base/uvm_topdown_phase.svh", 87, "", 1); + end + endcase + end + if(comp.get_first_child(name)) + do + traverse(comp.get_child(name), phase, state); + while(comp.get_next_child(name)); + endfunction + virtual function void execute(uvm_component comp, + uvm_phase phase); + process proc = process::self(); + proc.srandom(uvm_create_random_seed(phase.get_type_name(), comp.get_full_name())); + comp.m_current_phase = phase; + exec_func(comp,phase); + endfunction +endclass +virtual class uvm_task_phase extends uvm_phase; + function new(string name); + super.new(name,UVM_PHASE_IMP); + endfunction + virtual function void traverse(uvm_component comp, + uvm_phase phase, + uvm_phase_state state); + phase.m_num_procs_not_yet_returned = 0; + m_traverse(comp, phase, state); + endfunction + function void m_traverse(uvm_component comp, + uvm_phase phase, + uvm_phase_state state); + string name; + uvm_domain phase_domain =phase.get_domain(); + uvm_domain comp_domain = comp.get_domain(); + uvm_sequencer_base seqr; + if (comp.get_first_child(name)) + do + m_traverse(comp.get_child(name), phase, state); + while(comp.get_next_child(name)); + if (m_phase_trace) + begin + if (uvm_report_enabled(UVM_DEBUG,UVM_INFO,"PH_TRACE")) + uvm_report_info ("PH_TRACE", $sformatf("topdown-phase phase=%s state=%s comp=%s comp.domain=%s phase.domain=%s", phase.get_name(), state.name(), comp.get_full_name(),comp_domain.get_name(),phase_domain.get_name()), UVM_DEBUG, "t/uvm/src/base/uvm_task_phase.svh", 94, "", 1); + end + if (phase_domain == uvm_domain::get_common_domain() || + phase_domain == comp_domain) begin + case (state) + UVM_PHASE_STARTED: begin + comp.m_current_phase = phase; + comp.m_apply_verbosity_settings(phase); + comp.phase_started(phase); + if ($cast(seqr, comp)) + seqr.start_phase_sequence(phase); + end + UVM_PHASE_EXECUTING: begin + uvm_phase ph = this; + if (comp.m_phase_imps.exists(this)) + ph = comp.m_phase_imps[this]; + ph.execute(comp, phase); + end + UVM_PHASE_READY_TO_END: begin + comp.phase_ready_to_end(phase); + end + UVM_PHASE_ENDED: begin + if ($cast(seqr, comp)) + seqr.stop_phase_sequence(phase); + comp.phase_ended(phase); + comp.m_current_phase = null; + end + default: + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PH_BADEXEC")) + uvm_report_fatal ("PH_BADEXEC", "task phase traverse internal error", UVM_NONE, "t/uvm/src/base/uvm_task_phase.svh", 122, "", 1); + end + endcase + end + endfunction + virtual function void execute(uvm_component comp, + uvm_phase phase); + fork + begin + process proc; + proc = process::self(); + proc.srandom(uvm_create_random_seed(phase.get_type_name(), comp.get_full_name())); + phase.m_num_procs_not_yet_returned++; + exec_task(comp,phase); + phase.m_num_procs_not_yet_returned--; + end + join_none + endfunction +endclass +class uvm_build_phase extends uvm_topdown_phase; + virtual function void exec_func(uvm_component comp, uvm_phase phase); + comp.build_phase(phase); + endfunction + local static uvm_build_phase m_inst; + static function string type_name(); + return "uvm_build_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_build_phase"; + endfunction : get_type_name + static function uvm_build_phase get(); + if(m_inst == null) + m_inst = new(); + return m_inst; + endfunction + protected function new(string name="build"); + super.new(name); + endfunction +endclass +class uvm_connect_phase extends uvm_bottomup_phase; + virtual function void exec_func(uvm_component comp, uvm_phase phase); + comp.connect_phase(phase); + endfunction + local static uvm_connect_phase m_inst; + static function string type_name(); + return "uvm_connect_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_connect_phase"; + endfunction : get_type_name + static function uvm_connect_phase get(); + if(m_inst == null) + m_inst = new(); + return m_inst; + endfunction + protected function new(string name="connect"); + super.new(name); + endfunction +endclass +class uvm_end_of_elaboration_phase extends uvm_bottomup_phase; + virtual function void exec_func(uvm_component comp, uvm_phase phase); + comp.end_of_elaboration_phase(phase); + endfunction + local static uvm_end_of_elaboration_phase m_inst; + static function string type_name(); + return "uvm_end_of_elaboration_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_end_of_elaboration_phase"; + endfunction : get_type_name + static function uvm_end_of_elaboration_phase get(); + if(m_inst == null) begin + m_inst = new(); + end + return m_inst; + endfunction + protected function new(string name="end_of_elaboration"); + super.new(name); + endfunction +endclass +class uvm_start_of_simulation_phase extends uvm_bottomup_phase; + virtual function void exec_func(uvm_component comp, uvm_phase phase); + comp.start_of_simulation_phase(phase); + endfunction + local static uvm_start_of_simulation_phase m_inst; + static function string type_name(); + return "uvm_start_of_simulation_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_start_of_simulation_phase"; + endfunction : get_type_name + static function uvm_start_of_simulation_phase get(); + if(m_inst == null) + m_inst = new(); + return m_inst; + endfunction + protected function new(string name="start_of_simulation"); + super.new(name); + endfunction +endclass +class uvm_run_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.run_phase(phase); + endtask + local static uvm_run_phase m_inst; + static function string type_name(); + return "uvm_run_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_run_phase"; + endfunction : get_type_name + static function uvm_run_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="run"); + super.new(name); + endfunction +endclass +class uvm_extract_phase extends uvm_bottomup_phase; + virtual function void exec_func(uvm_component comp, uvm_phase phase); + comp.extract_phase(phase); + endfunction + local static uvm_extract_phase m_inst; + static function string type_name(); + return "uvm_extract_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_extract_phase"; + endfunction : get_type_name + static function uvm_extract_phase get(); + if(m_inst == null) + m_inst = new(); + return m_inst; + endfunction + protected function new(string name="extract"); + super.new(name); + endfunction +endclass +class uvm_check_phase extends uvm_bottomup_phase; + virtual function void exec_func(uvm_component comp, uvm_phase phase); + comp.check_phase(phase); + endfunction + local static uvm_check_phase m_inst; + static function string type_name(); + return "uvm_check_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_check_phase"; + endfunction : get_type_name + static function uvm_check_phase get(); + if(m_inst == null) + m_inst = new(); + return m_inst; + endfunction + protected function new(string name="check"); + super.new(name); + endfunction +endclass +class uvm_report_phase extends uvm_bottomup_phase; + virtual function void exec_func(uvm_component comp, uvm_phase phase); + comp.report_phase(phase); + endfunction + local static uvm_report_phase m_inst; + static function string type_name(); + return "uvm_report_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_report_phase"; + endfunction : get_type_name + static function uvm_report_phase get(); + if(m_inst == null) + m_inst = new(); + return m_inst; + endfunction + protected function new(string name="report"); + super.new(name); + endfunction +endclass +class uvm_final_phase extends uvm_topdown_phase; + virtual function void exec_func(uvm_component comp, uvm_phase phase); + comp.final_phase(phase); + endfunction + local static uvm_final_phase m_inst; + static function string type_name(); + return "uvm_final_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_final_phase"; + endfunction : get_type_name + static function uvm_final_phase get(); + if(m_inst == null) + m_inst = new(); + return m_inst; + endfunction + protected function new(string name="final"); + super.new(name); + endfunction +endclass +class uvm_pre_reset_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.pre_reset_phase(phase); + endtask + local static uvm_pre_reset_phase m_inst; + static function string type_name(); + return "uvm_pre_reset_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_pre_reset_phase"; + endfunction : get_type_name + static function uvm_pre_reset_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="pre_reset"); + super.new(name); + endfunction +endclass +class uvm_reset_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.reset_phase(phase); + endtask + local static uvm_reset_phase m_inst; + static function string type_name(); + return "uvm_reset_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_reset_phase"; + endfunction : get_type_name + static function uvm_reset_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="reset"); + super.new(name); + endfunction +endclass +class uvm_post_reset_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.post_reset_phase(phase); + endtask + local static uvm_post_reset_phase m_inst; + static function string type_name(); + return "uvm_post_reset_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_post_reset_phase"; + endfunction : get_type_name + static function uvm_post_reset_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="post_reset"); + super.new(name); + endfunction +endclass +class uvm_pre_configure_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.pre_configure_phase(phase); + endtask + local static uvm_pre_configure_phase m_inst; + static function string type_name(); + return "uvm_pre_configure_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_pre_configure_phase"; + endfunction : get_type_name + static function uvm_pre_configure_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="pre_configure"); + super.new(name); + endfunction +endclass +class uvm_configure_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.configure_phase(phase); + endtask + local static uvm_configure_phase m_inst; + static function string type_name(); + return "uvm_configure_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_configure_phase"; + endfunction : get_type_name + static function uvm_configure_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="configure"); + super.new(name); + endfunction +endclass +class uvm_post_configure_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.post_configure_phase(phase); + endtask + local static uvm_post_configure_phase m_inst; + static function string type_name(); + return "uvm_post_configure_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_post_configure_phase"; + endfunction : get_type_name + static function uvm_post_configure_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="post_configure"); + super.new(name); + endfunction +endclass +class uvm_pre_main_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.pre_main_phase(phase); + endtask + local static uvm_pre_main_phase m_inst; + static function string type_name(); + return "uvm_pre_main_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_pre_main_phase"; + endfunction : get_type_name + static function uvm_pre_main_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="pre_main"); + super.new(name); + endfunction +endclass +class uvm_main_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.main_phase(phase); + endtask + local static uvm_main_phase m_inst; + static function string type_name(); + return "uvm_main_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_main_phase"; + endfunction : get_type_name + static function uvm_main_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="main"); + super.new(name); + endfunction +endclass +class uvm_post_main_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.post_main_phase(phase); + endtask + local static uvm_post_main_phase m_inst; + static function string type_name(); + return "uvm_post_main_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_post_main_phase"; + endfunction : get_type_name + static function uvm_post_main_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="post_main"); + super.new(name); + endfunction +endclass +class uvm_pre_shutdown_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.pre_shutdown_phase(phase); + endtask + local static uvm_pre_shutdown_phase m_inst; + static function string type_name(); + return "uvm_pre_shutdown_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_pre_shutdown_phase"; + endfunction : get_type_name + static function uvm_pre_shutdown_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="pre_shutdown"); + super.new(name); + endfunction +endclass +class uvm_shutdown_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.shutdown_phase(phase); + endtask + local static uvm_shutdown_phase m_inst; + static function string type_name(); + return "uvm_shutdown_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_shutdown_phase"; + endfunction : get_type_name + static function uvm_shutdown_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="shutdown"); + super.new(name); + endfunction +endclass +class uvm_post_shutdown_phase extends uvm_task_phase; + virtual task exec_task(uvm_component comp, uvm_phase phase); + comp.post_shutdown_phase(phase); + endtask + local static uvm_post_shutdown_phase m_inst; + static function string type_name(); + return "uvm_post_shutdown_phase"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_post_shutdown_phase"; + endfunction : get_type_name + static function uvm_post_shutdown_phase get(); + if(m_inst == null) + m_inst = new; + return m_inst; + endfunction + protected function new(string name="post_shutdown"); + super.new(name); + endfunction +endclass +virtual class uvm_run_test_callback extends uvm_callback; + extern function new( string name="uvm_run_test_callback"); + virtual function void pre_run_test(); + endfunction + virtual function void post_run_test(); + endfunction + virtual function void pre_abort(); + endfunction + extern static function bit add( uvm_run_test_callback cb ); + extern static function bit delete( uvm_run_test_callback cb ); + extern static function void m_do_pre_run_test(); + extern static function void m_do_post_run_test(); + extern static function void m_do_pre_abort(); + local static uvm_run_test_callback m_registered_cbs[$]; +endclass : uvm_run_test_callback +function uvm_run_test_callback::new( string name="uvm_run_test_callback"); + super.new( name ); +endfunction +function bit uvm_run_test_callback::add( uvm_run_test_callback cb ); + bit found; + int unsigned i; + if ( cb == null ) begin + return 0; + end + found = 0; + i = 0; + while ( ! found && ( i < m_registered_cbs.size() ) ) begin + if ( m_registered_cbs[ i ] == cb ) begin + found = 1; + end + ++i; + end + if ( ! found ) begin + m_registered_cbs.push_back( cb ); + end + return ! found; +endfunction +function bit uvm_run_test_callback::delete( uvm_run_test_callback cb ); + int cb_idxs[$]; + if ( cb == null ) begin + return 0; + end + cb_idxs = m_registered_cbs.find_index( item ) with ( item == cb ); + foreach ( cb_idxs[ i ] ) begin + m_registered_cbs.delete( i ); + end + return ( cb_idxs.size() > 0 ); +endfunction +function void uvm_run_test_callback::m_do_pre_run_test(); + foreach ( m_registered_cbs[ i ] ) begin + m_registered_cbs[ i ].pre_run_test(); + end +endfunction +function void uvm_run_test_callback::m_do_post_run_test(); + foreach ( m_registered_cbs[ i ] ) begin + m_registered_cbs[ i ].post_run_test(); + end +endfunction +function void uvm_run_test_callback::m_do_pre_abort(); + foreach ( m_registered_cbs[ i ] ) begin + m_registered_cbs[ i ].pre_abort(); + end +endfunction +typedef class uvm_objection; +typedef class uvm_sequence_base; +typedef class uvm_sequence_item; +virtual class uvm_component extends uvm_report_object; + extern function new (string name, uvm_component parent); + extern virtual function uvm_component get_parent (); + extern virtual function string get_full_name (); + extern function void get_children(ref uvm_component children[$]); + extern function uvm_component get_child (string name); + extern function int get_next_child (ref string name); + extern function int get_first_child (ref string name); + extern function int get_num_children (); + extern function int has_child (string name); + extern virtual function void set_name (string name); + extern function uvm_component lookup (string name); + extern function int unsigned get_depth(); + extern virtual function void build_phase(uvm_phase phase); + extern virtual function void connect_phase(uvm_phase phase); + extern virtual function void end_of_elaboration_phase(uvm_phase phase); + extern virtual function void start_of_simulation_phase(uvm_phase phase); + extern virtual task run_phase(uvm_phase phase); + extern virtual task pre_reset_phase(uvm_phase phase); + extern virtual task reset_phase(uvm_phase phase); + extern virtual task post_reset_phase(uvm_phase phase); + extern virtual task pre_configure_phase(uvm_phase phase); + extern virtual task configure_phase(uvm_phase phase); + extern virtual task post_configure_phase(uvm_phase phase); + extern virtual task pre_main_phase(uvm_phase phase); + extern virtual task main_phase(uvm_phase phase); + extern virtual task post_main_phase(uvm_phase phase); + extern virtual task pre_shutdown_phase(uvm_phase phase); + extern virtual task shutdown_phase(uvm_phase phase); + extern virtual task post_shutdown_phase(uvm_phase phase); + extern virtual function void extract_phase(uvm_phase phase); + extern virtual function void check_phase(uvm_phase phase); + extern virtual function void report_phase(uvm_phase phase); + extern virtual function void final_phase(uvm_phase phase); + extern virtual function void phase_started (uvm_phase phase); + extern virtual function void phase_ready_to_end (uvm_phase phase); + extern virtual function void phase_ended (uvm_phase phase); + extern function void set_domain(uvm_domain domain, int hier=1); + extern function uvm_domain get_domain(); + extern virtual protected function void define_domain(uvm_domain domain); + extern virtual task suspend (); + extern virtual task resume (); + extern virtual function void resolve_bindings (); + extern function string massage_scope(string scope); + extern virtual function void apply_config_settings (bit verbose = 0); + extern virtual function bit use_automatic_config(); + extern function void print_config(bit recurse = 0, bit audit = 0); + extern function void print_config_with_audit(bit recurse = 0); + static bit print_config_matches; + virtual function void raised (uvm_objection objection, uvm_object source_obj, + string description, int count); + endfunction + virtual function void dropped (uvm_objection objection, uvm_object source_obj, + string description, int count); + endfunction + virtual task all_dropped (uvm_objection objection, uvm_object source_obj, + string description, int count); + endtask + extern function uvm_component create_component (string requested_type_name, + string name); + extern function uvm_object create_object (string requested_type_name, + string name=""); + extern static function void set_type_override_by_type + (uvm_object_wrapper original_type, + uvm_object_wrapper override_type, + bit replace=1); + extern function void set_inst_override_by_type(string relative_inst_path, + uvm_object_wrapper original_type, + uvm_object_wrapper override_type); + extern static function void set_type_override(string original_type_name, + string override_type_name, + bit replace=1); + extern function void set_inst_override(string relative_inst_path, + string original_type_name, + string override_type_name); + extern function void print_override_info(string requested_type_name, + string name=""); + extern function void set_report_id_verbosity_hier (string id, + int verbosity); + extern function void set_report_severity_id_verbosity_hier(uvm_severity severity, + string id, + int verbosity); + extern function void set_report_severity_action_hier (uvm_severity severity, + uvm_action action); + extern function void set_report_id_action_hier (string id, + uvm_action action); + extern function void set_report_severity_id_action_hier(uvm_severity severity, + string id, + uvm_action action); + extern function void set_report_default_file_hier (UVM_FILE file); + extern function void set_report_severity_file_hier (uvm_severity severity, + UVM_FILE file); + extern function void set_report_id_file_hier (string id, + UVM_FILE file); + extern function void set_report_severity_id_file_hier(uvm_severity severity, + string id, + UVM_FILE file); + extern function void set_report_verbosity_level_hier (int verbosity); + virtual function void pre_abort; + endfunction + extern function void accept_tr (uvm_transaction tr, time accept_time = 0); + extern virtual protected function void do_accept_tr (uvm_transaction tr); + extern function int begin_tr (uvm_transaction tr, + string stream_name="main", + string label="", + string desc="", + time begin_time=0, + int parent_handle=0); + extern virtual protected + function void do_begin_tr (uvm_transaction tr, + string stream_name, + int tr_handle); + extern function void end_tr (uvm_transaction tr, + time end_time=0, + bit free_handle=1); + extern virtual protected function void do_end_tr (uvm_transaction tr, + int tr_handle); + extern function int record_error_tr (string stream_name="main", + uvm_object info=null, + string label="error_tr", + string desc="", + time error_time=0, + bit keep_active=0); + extern function int record_event_tr (string stream_name="main", + uvm_object info=null, + string label="event_tr", + string desc="", + time event_time=0, + bit keep_active=0); + extern virtual function uvm_tr_stream get_tr_stream(string name, + string stream_type_name=""); + extern virtual function void free_tr_stream(uvm_tr_stream stream); + bit print_enabled = 1; + uvm_tr_database tr_database; + extern virtual function uvm_tr_database get_tr_database(); + extern virtual function void set_tr_database(uvm_tr_database db); + protected uvm_domain m_domain; + uvm_phase m_phase_imps[uvm_phase]; + uvm_phase m_current_phase; + protected process m_phase_process; + bit m_build_done; + int m_phasing_active; + extern function void set_local(uvm_resource_base rsrc) ; + uvm_component m_parent; + protected uvm_component m_children[string]; + protected uvm_component m_children_by_handle[uvm_component]; + extern protected virtual function bit m_add_child(uvm_component child); + extern local virtual function void m_set_full_name(); + extern function void do_resolve_bindings(); + extern function void do_flush(); + extern virtual function void flush (); + extern local function void m_extract_name(string name , + output string leaf , + output string remainder ); + extern virtual function uvm_object create (string name=""); + extern virtual function uvm_object clone (); + local uvm_tr_stream m_streams[string][string]; + local uvm_recorder m_tr_h[uvm_transaction]; + extern protected function int m_begin_tr (uvm_transaction tr, + int parent_handle=0, + string stream_name="main", string label="", + string desc="", time begin_time=0); + string m_name; + typedef uvm_abstract_component_registry#(uvm_component, "uvm_component") type_id; + static function string type_name(); + return "uvm_component"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_component"; + endfunction : get_type_name + protected uvm_event_pool event_pool; + int unsigned recording_detail = UVM_NONE; + extern function void do_print(uvm_printer printer); + extern function void m_set_cl_msg_args; + extern function void m_set_cl_verb; + extern function void m_set_cl_action; + extern function void m_set_cl_sev; + extern function void m_apply_verbosity_settings(uvm_phase phase); + typedef struct { + string comp; + string phase; + time offset; + uvm_verbosity verbosity; + string id; + } m_verbosity_setting; + m_verbosity_setting m_verbosity_settings[$]; + static m_verbosity_setting m_time_settings[$]; + extern function void m_do_pre_abort; + uvm_resource_base m_unsupported_resource_base = null; + extern function void m_unsupported_set_local(uvm_resource_base rsrc); +typedef struct { + string arg; + string args[$]; + int unsigned used; +} uvm_cmdline_parsed_arg_t; +static uvm_cmdline_parsed_arg_t m_uvm_applied_cl_action[$]; +static uvm_cmdline_parsed_arg_t m_uvm_applied_cl_sev[$]; +endclass : uvm_component +typedef class uvm_cmdline_processor; +typedef class uvm_component_proxy; +typedef class uvm_top_down_visitor_adapter; +typedef class uvm_report_message; +typedef class uvm_report_object; +typedef class uvm_report_handler; +typedef class uvm_default_report_server; +class uvm_root extends uvm_component; + extern static function uvm_root get(); + uvm_cmdline_processor clp; + virtual function string get_type_name(); + return "uvm_root"; + endfunction + extern virtual task run_test (string test_name=""); + virtual function void die(); + uvm_report_server l_rs = uvm_report_server::get_server(); + m_uvm_core_state=UVM_CORE_PRE_ABORT; + m_do_pre_abort(); + uvm_run_test_callback::m_do_pre_abort(); + l_rs.report_summarize(); + m_uvm_core_state=UVM_CORE_ABORTED; + $finish; + endfunction + extern function void set_timeout(time timeout, bit overridable=1); + local bit finish_on_completion = 1; + virtual function bit get_finish_on_completion(); + return finish_on_completion; + endfunction : get_finish_on_completion + virtual function void set_finish_on_completion(bit f); + finish_on_completion = f; + endfunction : set_finish_on_completion + extern function uvm_component find (string comp_match); + extern function void find_all (string comp_match, + ref uvm_component comps[$], + input uvm_component comp=null); + extern function void print_topology (uvm_printer printer=null); + bit enable_print_topology = 0; + extern function void set_enable_print_topology (bit enable); + extern function bit get_enable_print_topology (); + time phase_timeout = 9200s; + extern function void m_find_all_recurse(string comp_match, + ref uvm_component comps[$], + input uvm_component comp=null); + extern protected function new (); + extern protected virtual function bit m_add_child (uvm_component child); + extern function void build_phase(uvm_phase phase); + extern local function void m_do_verbosity_settings(); + extern local function void m_do_timeout_settings(); + extern local function void m_do_factory_settings(); + extern local function void m_process_inst_override(string ovr); + extern local function void m_process_type_override(string ovr); + extern local function void m_do_config_settings(); + extern local function void m_do_max_quit_settings(); + extern local function void m_do_dump_args(); + extern local function void m_process_config(string cfg, bit is_int); + extern local function void m_process_default_sequence(string cfg); + extern function void m_check_verbosity(); + extern function void m_check_uvm_field_flag_size(); + extern virtual function void report_header(UVM_FILE file = 0); + static local uvm_root m_inst; + extern virtual task run_phase (uvm_phase phase); + function void phase_started(uvm_phase phase); + if (phase == end_of_elaboration_ph) begin + do_resolve_bindings(); + if (enable_print_topology) print_topology(); + begin + uvm_report_server srvr; + srvr = uvm_report_server::get_server(); + if(srvr.get_severity_count(UVM_ERROR) > 0) begin + uvm_report_fatal("BUILDERR", "stopping due to build errors", UVM_NONE); + end + end + end + endfunction + bit m_phase_all_done; + extern static function uvm_root m_uvm_get_root(); + static local bit m_relnotes_done=0; + function void end_of_elaboration_phase(uvm_phase phase); + uvm_component_proxy p = new("proxy"); + uvm_top_down_visitor_adapter#(uvm_component) adapter = new("adapter"); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_visitor#(uvm_component) v = cs.get_component_visitor(); + adapter.accept(this, v, p); + endfunction +endclass +function uvm_root uvm_root::get(); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + return cs.get_root(); +endfunction +function uvm_root::new(); + uvm_report_handler rh; + super.new("__top__", null); + rh = new("reporter"); + set_report_handler(rh); + if (m_inst != null) begin + begin + if (m_inst.uvm_report_enabled(UVM_NONE,UVM_FATAL,"UVM/ROOT/MULTI")) + m_inst.uvm_report_fatal ("UVM/ROOT/MULTI", "Attempting to construct multiple roots", UVM_NONE, "t/uvm/src/base/uvm_root.svh", 378, "", 1); + end + return; + end + m_inst = this; + clp = uvm_cmdline_processor::get_inst(); +endfunction +function uvm_root uvm_root::m_uvm_get_root(); + if (m_inst == null) begin + uvm_root top; + top = new(); + if (top != m_inst) + return null; + top.m_domain = uvm_domain::get_uvm_domain(); + end + return m_inst; +endfunction +function void uvm_root::report_header(UVM_FILE file = 0); + string q[$]; + uvm_report_server srvr; + uvm_cmdline_processor clp; + string args[$]; + srvr = uvm_report_server::get_server(); + clp = uvm_cmdline_processor::get_inst(); + if (clp.get_arg_matches("+UVM_NO_RELNOTES", args)) return; + if (!m_relnotes_done) begin + q.push_back("\n *********** IMPORTANT RELEASE NOTES ************\n"); + m_relnotes_done = 1; + q.push_back("\n This implementation of the UVM Library deviates from the 1800.2-2017\n"); + q.push_back(" standard. See the DEVIATIONS.md file contained in the release\n"); + q.push_back(" for more details.\n"); + end + q.push_back("\n----------------------------------------------------------------\n"); + q.push_back({uvm_revision_string(),"\n"}); + q.push_back("\n"); + q.push_back("All copyright owners for this kit are listed in NOTICE.txt\n"); + q.push_back("All Rights Reserved Worldwide\n"); + q.push_back("----------------------------------------------------------------\n"); + if(m_relnotes_done) + q.push_back("\n (Specify +UVM_NO_RELNOTES to turn off this notice)\n"); + begin + if (uvm_report_enabled(UVM_LOW,UVM_INFO,"UVM/RELNOTES")) + uvm_report_info ("UVM/RELNOTES", uvm_pkg::m_uvm_string_queue_join(q), UVM_LOW, "t/uvm/src/base/uvm_root.svh", 449, "", 1); + end +endfunction +task uvm_root::run_test(string test_name=""); + uvm_report_server l_rs; + uvm_factory factory; + bit testname_plusarg; + int test_name_count; + string test_names[$]; + string msg; + uvm_component uvm_test_top; + process phase_runner_proc; + uvm_run_test_callback::m_do_pre_run_test(); + factory=uvm_factory::get(); + m_uvm_core_state=UVM_CORE_PRE_RUN; + testname_plusarg = 0; + uvm_objection::m_init_objections(); + m_do_dump_args(); + test_name_count = clp.get_arg_values("+UVM_TESTNAME=", test_names); + if (test_name_count > 0) begin + test_name = test_names[0]; + testname_plusarg = 1; + end + if (test_name_count > 1) begin + string test_list; + string sep; + for (int i = 0; i < test_names.size(); i++) begin + if (i != 0) + sep = ", "; + test_list = {test_list, sep, test_names[i]}; + end + uvm_report_warning("MULTTST", + $sformatf("Multiple (%0d) +UVM_TESTNAME arguments provided on the command line. '%s' will be used. Provided list: %s.", test_name_count, test_name, test_list), UVM_NONE); + end + if (test_name != "") begin + if(m_children.exists("uvm_test_top")) begin + uvm_report_fatal("TTINST", + "An uvm_test_top already exists via a previous call to run_test", UVM_NONE); + #0; + end + $cast(uvm_test_top, factory.create_component_by_name(test_name, + "", "uvm_test_top", null)); + if (uvm_test_top == null) begin + msg = testname_plusarg ? {"command line +UVM_TESTNAME=",test_name} : + {"call to run_test(",test_name,")"}; + uvm_report_fatal("INVTST", + {"Requested test from ",msg, " not found." }, UVM_NONE); + end + end + if (m_children.num() == 0) begin + uvm_report_fatal("NOCOMP", + {"No components instantiated. You must either instantiate", + " at least one component before calling run_test or use", + " run_test to do so. To run a test using run_test,", + " use +UVM_TESTNAME or supply the test name in", + " the argument to run_test(). Exiting simulation."}, UVM_NONE); + return; + end + begin + if(test_name=="") + uvm_report_info("RNTST", "Running test ...", UVM_LOW); + else if (test_name == uvm_test_top.get_type_name()) + uvm_report_info("RNTST", {"Running test ",test_name,"..."}, UVM_LOW); + else + uvm_report_info("RNTST", {"Running test ",uvm_test_top.get_type_name()," (via factory override for test \"",test_name,"\")..."}, UVM_LOW); + end + fork begin + phase_runner_proc = process::self(); + uvm_phase::m_run_phases(); + end + join_none + #0; + wait (m_phase_all_done == 1); + m_uvm_core_state=UVM_CORE_POST_RUN; + phase_runner_proc.kill(); + l_rs = uvm_report_server::get_server(); + uvm_run_test_callback::m_do_post_run_test(); + l_rs.report_summarize(); + m_uvm_core_state=UVM_CORE_FINISHED; + if (get_finish_on_completion()) + $finish; +endtask +function void uvm_root::find_all(string comp_match, ref uvm_component comps[$], + input uvm_component comp=null); + if (comp==null) + comp = this; + m_find_all_recurse(comp_match, comps, comp); +endfunction +function uvm_component uvm_root::find (string comp_match); + uvm_component comp_list[$]; + find_all(comp_match,comp_list); + if (comp_list.size() > 1) + uvm_report_warning("MMATCH", + $sformatf("Found %0d components matching '%s'. Returning first match, %0s.", + comp_list.size(),comp_match,comp_list[0].get_full_name()), UVM_NONE); + if (comp_list.size() == 0) begin + uvm_report_warning("CMPNFD", + {"Component matching '",comp_match, + "' was not found in the list of uvm_components"}, UVM_NONE); + return null; + end + return comp_list[0]; +endfunction +function void uvm_root::print_topology(uvm_printer printer=null); + if (m_children.num()==0) begin + uvm_report_warning("EMTCOMP", "print_topology - No UVM components to print.", UVM_NONE); + return; + end + if (printer==null) + printer = uvm_printer::get_default(); + begin + if (uvm_report_enabled(UVM_NONE,UVM_INFO,"UVMTOP")) + uvm_report_info ("UVMTOP", "UVM testbench topology:", UVM_NONE, "t/uvm/src/base/uvm_root.svh", 640, "", 1); + end + print(printer) ; +endfunction +function void uvm_root::set_timeout(time timeout, bit overridable=1); + static bit m_uvm_timeout_overridable = 1; + if (m_uvm_timeout_overridable == 0) begin + uvm_report_info("NOTIMOUTOVR", + $sformatf("The global timeout setting of %0d is not overridable to %0d due to a previous setting.", + phase_timeout, timeout), UVM_NONE); + return; + end + m_uvm_timeout_overridable = overridable; + phase_timeout = timeout; +endfunction +function void uvm_root::m_find_all_recurse(string comp_match, ref uvm_component comps[$], + input uvm_component comp=null); + string name; + if (comp.get_first_child(name)) + do begin + this.m_find_all_recurse(comp_match, comps, comp.get_child(name)); + end + while (comp.get_next_child(name)); + if (uvm_is_match(comp_match, comp.get_full_name()) && + comp.get_name() != "") + comps.push_back(comp); +endfunction +function bit uvm_root::m_add_child (uvm_component child); + if(super.m_add_child(child)) begin + return 1; + end + else + return 0; +endfunction +function void uvm_root::build_phase(uvm_phase phase); + super.build_phase(phase); + m_set_cl_msg_args(); + m_do_verbosity_settings(); + m_do_timeout_settings(); + m_do_factory_settings(); + m_do_config_settings(); + m_do_max_quit_settings(); +endfunction +function void uvm_root::m_do_verbosity_settings(); + string set_verbosity_settings[$]; + string split_vals[$]; + uvm_verbosity tmp_verb; + void'(clp.get_arg_values("+uvm_set_verbosity=", set_verbosity_settings)); + for(int i = 0; i < set_verbosity_settings.size(); i++) begin + uvm_split_string(set_verbosity_settings[i], ",", split_vals); + if(split_vals.size() < 4 || split_vals.size() > 5) begin + uvm_report_warning("INVLCMDARGS", + $sformatf("Invalid number of arguments found on the command line for setting '+uvm_set_verbosity=%s'. Setting ignored.", + set_verbosity_settings[i]), UVM_NONE, "", ""); + end + if(!clp.m_convert_verb(split_vals[2], tmp_verb)) begin + uvm_report_warning("INVLCMDVERB", + $sformatf("Invalid verbosity found on the command line for setting '%s'.", + set_verbosity_settings[i]), UVM_NONE, "", ""); + end + end +endfunction +function void uvm_root::m_do_timeout_settings(); + string timeout_settings[$]; + string timeout; + string split_timeout[$]; + int timeout_count; + time timeout_int; + string override_spec; + timeout_count = clp.get_arg_values("+UVM_TIMEOUT=", timeout_settings); + if (timeout_count == 0) + return; + else begin + timeout = timeout_settings[0]; + if (timeout_count > 1) begin + string timeout_list; + string sep; + for (int i = 0; i < timeout_settings.size(); i++) begin + if (i != 0) + sep = "; "; + timeout_list = {timeout_list, sep, timeout_settings[i]}; + end + uvm_report_warning("MULTTIMOUT", + $sformatf("Multiple (%0d) +UVM_TIMEOUT arguments provided on the command line. '%s' will be used. Provided list: %s.", + timeout_count, timeout, timeout_list), UVM_NONE); + end + uvm_report_info("TIMOUTSET", + $sformatf("'+UVM_TIMEOUT=%s' provided on the command line is being applied.", timeout), UVM_NONE); + void'($sscanf(timeout,"%d,%s",timeout_int,override_spec)); + case(override_spec) + "YES" : set_timeout(timeout_int, 1); + "NO" : set_timeout(timeout_int, 0); + default : set_timeout(timeout_int, 1); + endcase + end +endfunction +function void uvm_root::m_do_factory_settings(); + string args[$]; + void'(clp.get_arg_matches("/^\\+(UVM_SET_INST_OVERRIDE|uvm_set_inst_override)=/",args)); + foreach(args[i]) begin + m_process_inst_override(args[i].substr(23, args[i].len()-1)); + end + void'(clp.get_arg_matches("/^\\+(UVM_SET_TYPE_OVERRIDE|uvm_set_type_override)=/",args)); + foreach(args[i]) begin + m_process_type_override(args[i].substr(23, args[i].len()-1)); + end +endfunction +function void uvm_root::m_process_inst_override(string ovr); + string split_val[$]; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory=cs.get_factory(); + uvm_split_string(ovr, ",", split_val); + if(split_val.size() != 3 ) begin + uvm_report_error("UVM_CMDLINE_PROC", {"Invalid setting for +uvm_set_inst_override=", ovr, + ", setting must specify ,,"}, UVM_NONE); + return; + end + uvm_report_info("INSTOVR", {"Applying instance override from the command line: +uvm_set_inst_override=", ovr}, UVM_NONE); + factory.set_inst_override_by_name(split_val[0], split_val[1], split_val[2]); +endfunction +function void uvm_root::m_process_type_override(string ovr); + string split_val[$]; + int replace=1; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory=cs.get_factory(); + uvm_split_string(ovr, ",", split_val); + if(split_val.size() > 3 || split_val.size() < 2) begin + uvm_report_error("UVM_CMDLINE_PROC", {"Invalid setting for +uvm_set_type_override=", ovr, + ", setting must specify ,[,]"}, UVM_NONE); + return; + end + if(split_val.size() == 3) begin + if(split_val[2]=="0") replace = 0; + else if (split_val[2] == "1") replace = 1; + else begin + uvm_report_error("UVM_CMDLINE_PROC", {"Invalid replace arg for +uvm_set_type_override=", ovr ," value must be 0 or 1"}, UVM_NONE); + return; + end + end + uvm_report_info("UVM_CMDLINE_PROC", {"Applying type override from the command line: +uvm_set_type_override=", ovr}, UVM_NONE); + factory.set_type_override_by_name(split_val[0], split_val[1], replace); +endfunction +function void uvm_root::m_process_config(string cfg, bit is_int); + uvm_bitstream_t v; + string split_val[$]; + uvm_root m_uvm_top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + m_uvm_top = cs.get_root(); + uvm_split_string(cfg, ",", split_val); + if(split_val.size() == 1) begin + uvm_report_error("UVM_CMDLINE_PROC", {"Invalid +uvm_set_config command\"", cfg, + "\" missing field and value: component is \"", split_val[0], "\""}, UVM_NONE); + return; + end + if(split_val.size() == 2) begin + uvm_report_error("UVM_CMDLINE_PROC", {"Invalid +uvm_set_config command\"", cfg, + "\" missing value: component is \"", split_val[0], "\" field is \"", split_val[1], "\""}, UVM_NONE); + return; + end + if(split_val.size() > 3) begin + uvm_report_error("UVM_CMDLINE_PROC", + $sformatf("Invalid +uvm_set_config command\"%s\" : expected only 3 fields (component, field and value).", cfg), UVM_NONE); + return; + end + if(is_int) begin + if(split_val[2].len() > 2) begin + string base, extval; + base = split_val[2].substr(0,1); + extval = split_val[2].substr(2,split_val[2].len()-1); + case(base) + "'b" : v = extval.atobin(); + "0b" : v = extval.atobin(); + "'o" : v = extval.atooct(); + "'d" : v = extval.atoi(); + "'h" : v = extval.atohex(); + "'x" : v = extval.atohex(); + "0x" : v = extval.atohex(); + default : v = split_val[2].atoi(); + endcase + end + else begin + v = split_val[2].atoi(); + end + uvm_report_info("UVM_CMDLINE_PROC", {"Applying config setting from the command line: +uvm_set_config_int=", cfg}, UVM_NONE); + uvm_config_int::set(m_uvm_top, split_val[0], split_val[1], v); + end + else begin + uvm_report_info("UVM_CMDLINE_PROC", {"Applying config setting from the command line: +uvm_set_config_string=", cfg}, UVM_NONE); + uvm_config_string::set(m_uvm_top, split_val[0], split_val[1], split_val[2]); + end +endfunction +function void uvm_root::m_process_default_sequence(string cfg); + string split_val[$]; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_root m_uvm_top = cs.get_root(); + uvm_factory f = cs.get_factory(); + uvm_object_wrapper w; + uvm_split_string(cfg, ",", split_val); + if(split_val.size() == 1) begin + uvm_report_error("UVM_CMDLINE_PROC", {"Invalid +uvm_set_default_sequence command\"", cfg, + "\" missing phase and type: sequencer is \"", split_val[0], "\""}, UVM_NONE); + return; + end + if(split_val.size() == 2) begin + uvm_report_error("UVM_CMDLINE_PROC", {"Invalid +uvm_set_default_sequence command\"", cfg, + "\" missing type: sequencer is \"", split_val[0], "\" phase is \"", split_val[1], "\""}, UVM_NONE); + return; + end + if(split_val.size() > 3) begin + uvm_report_error("UVM_CMDLINE_PROC", + $sformatf("Invalid +uvm_set_default_sequence command\"%s\" : expected only 3 fields (sequencer, phase and type).", cfg), UVM_NONE); + return; + end + w = f.find_wrapper_by_name(split_val[2]); + if (w == null) begin + uvm_report_error("UVM_CMDLINE_PROC", + $sformatf("Invalid type '%s' provided to +uvm_set_default_sequence", split_val[2]), + UVM_NONE); + return; + end + else begin + uvm_report_info("UVM_CMDLINE_PROC", {"Setting default sequence from the command line: +uvm_set_default_sequence=", cfg}, UVM_NONE); + uvm_config_db#(uvm_object_wrapper)::set(this, {split_val[0], ".", split_val[1]}, "default_sequence", w); + end +endfunction : m_process_default_sequence +function void uvm_root::m_do_config_settings(); + string args[$]; + void'(clp.get_arg_matches("/^\\+(UVM_SET_CONFIG_INT|uvm_set_config_int)=/",args)); + foreach(args[i]) begin + m_process_config(args[i].substr(20, args[i].len()-1), 1); + end + void'(clp.get_arg_matches("/^\\+(UVM_SET_CONFIG_STRING|uvm_set_config_string)=/",args)); + foreach(args[i]) begin + m_process_config(args[i].substr(23, args[i].len()-1), 0); + end + void'(clp.get_arg_matches("/^\\+(UVM_SET_DEFAULT_SEQUENCE|uvm_set_default_sequence)=/", args)); + foreach(args[i]) begin + m_process_default_sequence(args[i].substr(26, args[i].len()-1)); + end +endfunction +function void uvm_root::m_do_max_quit_settings(); + uvm_report_server srvr; + string max_quit_settings[$]; + int max_quit_count; + string max_quit; + string split_max_quit[$]; + int max_quit_int; + srvr = uvm_report_server::get_server(); + max_quit_count = clp.get_arg_values("+UVM_MAX_QUIT_COUNT=", max_quit_settings); + if (max_quit_count == 0) + return; + else begin + max_quit = max_quit_settings[0]; + if (max_quit_count > 1) begin + string max_quit_list; + string sep; + for (int i = 0; i < max_quit_settings.size(); i++) begin + if (i != 0) + sep = "; "; + max_quit_list = {max_quit_list, sep, max_quit_settings[i]}; + end + uvm_report_warning("MULTMAXQUIT", + $sformatf("Multiple (%0d) +UVM_MAX_QUIT_COUNT arguments provided on the command line. '%s' will be used. Provided list: %s.", + max_quit_count, max_quit, max_quit_list), UVM_NONE); + end + uvm_report_info("MAXQUITSET", + $sformatf("'+UVM_MAX_QUIT_COUNT=%s' provided on the command line is being applied.", max_quit), UVM_NONE); + uvm_split_string(max_quit, ",", split_max_quit); + max_quit_int = split_max_quit[0].atoi(); + case(split_max_quit[1]) + "YES" : srvr.set_max_quit_count(max_quit_int, 1); + "NO" : srvr.set_max_quit_count(max_quit_int, 0); + default : srvr.set_max_quit_count(max_quit_int, 1); + endcase + end +endfunction +function void uvm_root::m_do_dump_args(); + string dump_args[$]; + string all_args[$]; + string out_string; + if(clp.get_arg_matches("+UVM_DUMP_CMDLINE_ARGS", dump_args)) begin + clp.get_args(all_args); + foreach (all_args[idx]) begin + uvm_report_info("DUMPARGS", $sformatf("idx=%0d arg=[%s]",idx,all_args[idx]), UVM_NONE); + end + end +endfunction +function void uvm_root::m_check_verbosity(); + string verb_string; + string verb_settings[$]; + int verb_count; + int plusarg; + int verbosity = UVM_MEDIUM; + verb_count = clp.get_arg_values("+UVM_VERBOSITY=", verb_settings); + if (verb_count > 0) begin + verb_string = verb_settings[0]; + plusarg = 1; + end + if (verb_count > 1) begin + string verb_list; + string sep; + for (int i = 0; i < verb_settings.size(); i++) begin + if (i != 0) + sep = ", "; + verb_list = {verb_list, sep, verb_settings[i]}; + end + uvm_report_warning("MULTVERB", + $sformatf("Multiple (%0d) +UVM_VERBOSITY arguments provided on the command line. '%s' will be used. Provided list: %s.", verb_count, verb_string, verb_list), UVM_NONE); + end + if(plusarg == 1) begin + case(verb_string) + "UVM_NONE" : verbosity = UVM_NONE; + "NONE" : verbosity = UVM_NONE; + "UVM_LOW" : verbosity = UVM_LOW; + "LOW" : verbosity = UVM_LOW; + "UVM_MEDIUM" : verbosity = UVM_MEDIUM; + "MEDIUM" : verbosity = UVM_MEDIUM; + "UVM_HIGH" : verbosity = UVM_HIGH; + "HIGH" : verbosity = UVM_HIGH; + "UVM_FULL" : verbosity = UVM_FULL; + "FULL" : verbosity = UVM_FULL; + "UVM_DEBUG" : verbosity = UVM_DEBUG; + "DEBUG" : verbosity = UVM_DEBUG; + default : begin + verbosity = verb_string.atoi(); + if(verbosity > 0) + uvm_report_info("NSTVERB", $sformatf("Non-standard verbosity value, using provided '%0d'.", verbosity), UVM_NONE); + if(verbosity == 0) begin + verbosity = UVM_MEDIUM; + uvm_report_warning("ILLVERB", "Illegal verbosity value, using default of UVM_MEDIUM.", UVM_NONE); + end + end + endcase + end + set_report_verbosity_level_hier(verbosity); +endfunction +function void uvm_root::m_check_uvm_field_flag_size(); + if ( (UVM_FIELD_FLAG_RESERVED_BITS) < UVM_FIELD_FLAG_RESERVED_BITS ) begin + uvm_report_fatal( "BAD_FIELD_FLAG_SZ", + $sformatf( + "Macro UVM_FIELD_FLAG_SIZE is set to %0d which is less than the required minimum of UVM_FIELD_FLAG_RESERVED_BITS (%0d).", + UVM_FIELD_FLAG_RESERVED_BITS, UVM_FIELD_FLAG_RESERVED_BITS + ) + ); + end +endfunction +task uvm_root::run_phase (uvm_phase phase); + foreach(m_uvm_applied_cl_action[idx]) + if(m_uvm_applied_cl_action[idx].used==0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"INVLCMDARGS")) + uvm_report_warning ("INVLCMDARGS", $sformatf("\"+uvm_set_action=%s\" never took effect due to a mismatching component pattern",m_uvm_applied_cl_action[idx].arg), UVM_NONE, "t/uvm/src/base/uvm_root.svh", 1130, "", 1); + end + end + foreach(m_uvm_applied_cl_sev[idx]) + if(m_uvm_applied_cl_sev[idx].used==0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"INVLCMDARGS")) + uvm_report_warning ("INVLCMDARGS", $sformatf("\"+uvm_set_severity=%s\" never took effect due to a mismatching component pattern",m_uvm_applied_cl_sev[idx].arg), UVM_NONE, "t/uvm/src/base/uvm_root.svh", 1134, "", 1); + end + end + if($time > 0) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"RUNPHSTIME")) + uvm_report_fatal ("RUNPHSTIME", {"The run phase must start at time 0, current time is ", $sformatf("%0t", $realtime), ". No non-zero delays are allowed before ", "run_test(), and pre-run user defined phases may not consume ", "simulation time before the start of the run phase."}, UVM_NONE, "t/uvm/src/base/uvm_root.svh", 1141, "", 1); + end +endtask +function void uvm_root::set_enable_print_topology (bit enable); + enable_print_topology = enable; +endfunction +function bit uvm_root::get_enable_print_topology(); + return enable_print_topology; +endfunction +function uvm_component::new (string name, uvm_component parent); + string error_str; + uvm_root top; + uvm_coreservice_t cs; + super.new(name); + if (parent==null && name == "__top__") begin + set_name(""); + return; + end + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + begin + uvm_phase bld; + uvm_domain common; + common = uvm_domain::get_common_domain(); + bld = common.find(uvm_build_phase::get()); + if (bld == null) + uvm_report_fatal("COMP/INTERNAL", + "attempt to find build phase object failed",UVM_NONE); + if (bld.get_state() == UVM_PHASE_DONE) begin + uvm_report_fatal("ILLCRT", {"It is illegal to create a component ('", + name,"' under '", + (parent == null ? top.get_full_name() : parent.get_full_name()), + "') after the build phase has ended."}, + UVM_NONE); + end + end + if (name == "") begin + name.itoa(m_inst_count); + name = {"COMP_", name}; + end + if(parent == this) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"THISPARENT")) + uvm_report_fatal ("THISPARENT", "cannot set the parent of a component to itself", UVM_NONE, "t/uvm/src/base/uvm_component.svh", 1635, "", 1); + end + end + if (parent == null) + parent = top; + if(uvm_report_enabled(UVM_MEDIUM+1, UVM_INFO, "NEWCOMP")) + begin + if (uvm_report_enabled(UVM_MEDIUM+1,UVM_INFO,"NEWCOMP")) + uvm_report_info ("NEWCOMP", {"Creating ", (parent==top?"uvm_top":parent.get_full_name()),".",name}, UVM_MEDIUM+1, "t/uvm/src/base/uvm_component.svh", 1643, "", 1); + end + if (parent.has_child(name) && this != parent.get_child(name)) begin + if (parent == top) begin + error_str = {"Name '",name,"' is not unique to other top-level ", + "instances. If parent is a module, build a unique name by combining the ", + "the module name and component name: $sformatf(\"\%m.\%s\",\"",name,"\")."}; + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"CLDEXT")) + uvm_report_fatal ("CLDEXT", error_str, UVM_NONE, "t/uvm/src/base/uvm_component.svh", 1650, "", 1); + end + end + else + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"CLDEXT")) + uvm_report_fatal ("CLDEXT", $sformatf("Cannot set '%s' as a child of '%s', %s", name, parent.get_full_name(), "which already has a child by that name."), UVM_NONE, "t/uvm/src/base/uvm_component.svh", 1656, "", 1); + end + return; + end + m_parent = parent; + set_name(name); + if (!m_parent.m_add_child(this)) + m_parent = null; + event_pool = new("event_pool"); + m_domain = parent.m_domain; + reseed(); +//TODO issue #4467 - Fix UVM function output width reassignment +//TODO %Error-UNSUPPORTED: t/t_uvm_pkg_todo.vh:13463:76: Unsupported: Function output argument 'value' requires 4096 bits, but connection's VARREF 'recording_detail' generates 32 bits. +//TODO if (!uvm_config_db #(uvm_bitstream_t)::get(this, "", "recording_detail", recording_detail)) +//TODO void'(uvm_config_db #(int)::get(this, "", "recording_detail", recording_detail)); + m_rh.set_name(get_full_name()); + set_report_verbosity_level(parent.get_report_verbosity_level()); + m_set_cl_msg_args(); +endfunction +function bit uvm_component::m_add_child(uvm_component child); + if (m_children.exists(child.get_name()) && + m_children[child.get_name()] != child) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"BDCLD")) + uvm_report_warning ("BDCLD", $sformatf("A child with the name '%0s' (type=%0s) already exists.", child.get_name(), m_children[child.get_name()].get_type_name()), UVM_NONE, "t/uvm/src/base/uvm_component.svh", 1695, "", 1); + end + return 0; + end + if (m_children_by_handle.exists(child)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"BDCHLD")) + uvm_report_warning ("BDCHLD", $sformatf("A child with the name '%0s' %0s %0s'", child.get_name(), "already exists in parent under name '", m_children_by_handle[child].get_name()), UVM_NONE, "t/uvm/src/base/uvm_component.svh", 1704, "", 1); + end + return 0; + end + m_children[child.get_name()] = child; + m_children_by_handle[child] = child; + return 1; +endfunction +function void uvm_component::get_children(ref uvm_component children[$]); + foreach(m_children[i]) + children.push_back(m_children[i]); +endfunction +function int uvm_component::get_first_child(ref string name); + return m_children.first(name); +endfunction +function int uvm_component::get_next_child(ref string name); + return m_children.next(name); +endfunction +function uvm_component uvm_component::get_child(string name); + if (m_children.exists(name)) + return m_children[name]; + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"NOCHILD")) + uvm_report_warning ("NOCHILD", {"Component with name '",name, "' is not a child of component '",get_full_name(),"'"}, UVM_NONE, "t/uvm/src/base/uvm_component.svh", 1754, "", 1); + end + return null; +endfunction +function int uvm_component::has_child(string name); + return m_children.exists(name); +endfunction +function int uvm_component::get_num_children(); + return m_children.num(); +endfunction +function string uvm_component::get_full_name (); + if(m_name == "") + return get_name(); + else + return m_name; +endfunction +function uvm_component uvm_component::get_parent (); + return m_parent; +endfunction +function void uvm_component::set_name (string name); + if(m_name != "") begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"INVSTNM")) + uvm_report_error ("INVSTNM", $sformatf("It is illegal to change the name of a component. The component name will not be changed to \"%s\"", name), UVM_NONE, "t/uvm/src/base/uvm_component.svh", 1801, "", 1); + end + return; + end + super.set_name(name); + m_set_full_name(); +endfunction +function void uvm_component::m_set_full_name(); + uvm_root top; + if ($cast(top, m_parent) || m_parent==null) + m_name = get_name(); + else + m_name = {m_parent.get_full_name(), ".", get_name()}; + foreach (m_children[c]) begin + uvm_component tmp; + tmp = m_children[c]; + tmp.m_set_full_name(); + end +endfunction +function uvm_component uvm_component::lookup( string name ); + string leaf , remainder; + uvm_component comp; + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + comp = this; + m_extract_name(name, leaf, remainder); + if (leaf == "") begin + comp = top; + m_extract_name(remainder, leaf, remainder); + end + if (!comp.has_child(leaf)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"Lookup Error")) + uvm_report_warning ("Lookup Error", $sformatf("Cannot find child %0s",leaf), UVM_NONE, "t/uvm/src/base/uvm_component.svh", 1852, "", 1); + end + return null; + end + if( remainder != "" ) + return comp.m_children[leaf].lookup(remainder); + return comp.m_children[leaf]; +endfunction +function int unsigned uvm_component::get_depth(); + if(m_name == "") return 0; + get_depth = 1; + foreach(m_name[i]) + if(m_name[i] == ".") ++get_depth; +endfunction +function void uvm_component::m_extract_name(input string name , + output string leaf , + output string remainder ); + int i , len; + len = name.len(); + for( i = 0; i < name.len(); i++ ) begin + if( name[i] == "." ) begin + break; + end + end + if( i == len ) begin + leaf = name; + remainder = ""; + return; + end + leaf = name.substr( 0 , i - 1 ); + remainder = name.substr( i + 1 , len - 1 ); + return; +endfunction +function void uvm_component::flush(); + return; +endfunction +function void uvm_component::do_flush(); + foreach( m_children[s] ) + m_children[s].do_flush(); + flush(); +endfunction +function uvm_object uvm_component::create (string name =""); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"ILLCRT")) + uvm_report_error ("ILLCRT", "create cannot be called on a uvm_component. Use create_component instead.", UVM_NONE, "t/uvm/src/base/uvm_component.svh", 1934, "", 1); + end + return null; +endfunction +function uvm_object uvm_component::clone (); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"ILLCLN")) + uvm_report_error ("ILLCLN", $sformatf("Attempting to clone '%s'. Clone cannot be called on a uvm_component. The clone target variable will be set to null.", get_full_name()), UVM_NONE, "t/uvm/src/base/uvm_component.svh", 1943, "", 1); + end + return null; +endfunction +function void uvm_component::print_override_info (string requested_type_name, + string name=""); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory=cs.get_factory(); + factory.debug_create_by_name(requested_type_name, get_full_name(), name); +endfunction +function uvm_component uvm_component::create_component (string requested_type_name, + string name); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory=cs.get_factory(); + return factory.create_component_by_name(requested_type_name, get_full_name(), + name, this); +endfunction +function uvm_object uvm_component::create_object (string requested_type_name, + string name=""); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory=cs.get_factory(); + return factory.create_object_by_name(requested_type_name, + get_full_name(), name); +endfunction +function void uvm_component::set_type_override (string original_type_name, + string override_type_name, + bit replace=1); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory=cs.get_factory(); + factory.set_type_override_by_name(original_type_name,override_type_name, replace); +endfunction +function void uvm_component::set_type_override_by_type (uvm_object_wrapper original_type, + uvm_object_wrapper override_type, + bit replace=1); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory=cs.get_factory(); + factory.set_type_override_by_type(original_type, override_type, replace); +endfunction +function void uvm_component::set_inst_override (string relative_inst_path, + string original_type_name, + string override_type_name); + string full_inst_path; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory=cs.get_factory(); + if (relative_inst_path == "") + full_inst_path = get_full_name(); + else + full_inst_path = {get_full_name(), ".", relative_inst_path}; + factory.set_inst_override_by_name( + original_type_name, + override_type_name, + full_inst_path); +endfunction +function void uvm_component::set_inst_override_by_type (string relative_inst_path, + uvm_object_wrapper original_type, + uvm_object_wrapper override_type); + string full_inst_path; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory=cs.get_factory(); + if (relative_inst_path == "") + full_inst_path = get_full_name(); + else + full_inst_path = {get_full_name(), ".", relative_inst_path}; + factory.set_inst_override_by_type(original_type, override_type, full_inst_path); +endfunction +function void uvm_component::set_report_id_verbosity_hier( string id, int verbosity); + set_report_id_verbosity(id, verbosity); + foreach( m_children[c] ) + m_children[c].set_report_id_verbosity_hier(id, verbosity); +endfunction +function void uvm_component::set_report_severity_id_verbosity_hier( uvm_severity severity, + string id, + int verbosity); + set_report_severity_id_verbosity(severity, id, verbosity); + foreach( m_children[c] ) + m_children[c].set_report_severity_id_verbosity_hier(severity, id, verbosity); +endfunction +function void uvm_component::set_report_severity_action_hier( uvm_severity severity, + uvm_action action); + set_report_severity_action(severity, action); + foreach( m_children[c] ) + m_children[c].set_report_severity_action_hier(severity, action); +endfunction +function void uvm_component::set_report_id_action_hier( string id, uvm_action action); + set_report_id_action(id, action); + foreach( m_children[c] ) + m_children[c].set_report_id_action_hier(id, action); +endfunction +function void uvm_component::set_report_severity_id_action_hier( uvm_severity severity, + string id, + uvm_action action); + set_report_severity_id_action(severity, id, action); + foreach( m_children[c] ) + m_children[c].set_report_severity_id_action_hier(severity, id, action); +endfunction +function void uvm_component::set_report_severity_file_hier( uvm_severity severity, + UVM_FILE file); + set_report_severity_file(severity, file); + foreach( m_children[c] ) + m_children[c].set_report_severity_file_hier(severity, file); +endfunction +function void uvm_component::set_report_default_file_hier( UVM_FILE file); + set_report_default_file(file); + foreach( m_children[c] ) + m_children[c].set_report_default_file_hier(file); +endfunction +function void uvm_component::set_report_id_file_hier( string id, UVM_FILE file); + set_report_id_file(id, file); + foreach( m_children[c] ) + m_children[c].set_report_id_file_hier(id, file); +endfunction +function void uvm_component::set_report_severity_id_file_hier ( uvm_severity severity, + string id, + UVM_FILE file); + set_report_severity_id_file(severity, id, file); + foreach( m_children[c] ) + m_children[c].set_report_severity_id_file_hier(severity, id, file); +endfunction +function void uvm_component::set_report_verbosity_level_hier(int verbosity); + set_report_verbosity_level(verbosity); + foreach( m_children[c] ) + m_children[c].set_report_verbosity_level_hier(verbosity); +endfunction +function void uvm_component::build_phase(uvm_phase phase); + m_build_done = 1; + if (use_automatic_config()) + apply_config_settings(print_config_matches); +endfunction +function void uvm_component::connect_phase(uvm_phase phase); + return; +endfunction +function void uvm_component::start_of_simulation_phase(uvm_phase phase); + return; +endfunction +function void uvm_component::end_of_elaboration_phase(uvm_phase phase); + return; +endfunction +task uvm_component::run_phase(uvm_phase phase); + return; +endtask +function void uvm_component::extract_phase(uvm_phase phase); + return; +endfunction +function void uvm_component::check_phase(uvm_phase phase); + return; +endfunction +function void uvm_component::report_phase(uvm_phase phase); + return; +endfunction +function void uvm_component::final_phase(uvm_phase phase); return; endfunction +task uvm_component::pre_reset_phase(uvm_phase phase); return; endtask +task uvm_component::reset_phase(uvm_phase phase); return; endtask +task uvm_component::post_reset_phase(uvm_phase phase); return; endtask +task uvm_component::pre_configure_phase(uvm_phase phase); return; endtask +task uvm_component::configure_phase(uvm_phase phase); return; endtask +task uvm_component::post_configure_phase(uvm_phase phase); return; endtask +task uvm_component::pre_main_phase(uvm_phase phase); return; endtask +task uvm_component::main_phase(uvm_phase phase); return; endtask +task uvm_component::post_main_phase(uvm_phase phase); return; endtask +task uvm_component::pre_shutdown_phase(uvm_phase phase); return; endtask +task uvm_component::shutdown_phase(uvm_phase phase); return; endtask +task uvm_component::post_shutdown_phase(uvm_phase phase); return; endtask +function void uvm_component::phase_started(uvm_phase phase); +endfunction +function void uvm_component::phase_ended(uvm_phase phase); +endfunction +function void uvm_component::phase_ready_to_end (uvm_phase phase); +endfunction +function void uvm_component::define_domain(uvm_domain domain); + uvm_phase schedule; + schedule = domain.find_by_name("uvm_sched"); + if (schedule == null) begin + uvm_domain common; + schedule = new("uvm_sched", UVM_PHASE_SCHEDULE); + uvm_domain::add_uvm_phases(schedule); + domain.add(schedule); + common = uvm_domain::get_common_domain(); + if (common.find(domain,0) == null) + common.add(domain,.with_phase(uvm_run_phase::get())); + end +endfunction +function void uvm_component::set_domain(uvm_domain domain, int hier=1); + m_domain = domain; + define_domain(domain); + if (hier) + foreach (m_children[c]) + m_children[c].set_domain(domain); +endfunction +function uvm_domain uvm_component::get_domain(); + return m_domain; +endfunction +task uvm_component::suspend(); + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"COMP/SPND/UNIMP")) + uvm_report_warning ("COMP/SPND/UNIMP", "suspend() not implemented", UVM_NONE, "t/uvm/src/base/uvm_component.svh", 2395, "", 1); + end +endtask +task uvm_component::resume(); + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"COMP/RSUM/UNIMP")) + uvm_report_warning ("COMP/RSUM/UNIMP", "resume() not implemented", UVM_NONE, "t/uvm/src/base/uvm_component.svh", 2403, "", 1); + end +endtask +function void uvm_component::resolve_bindings(); + return; +endfunction +function void uvm_component::do_resolve_bindings(); + foreach( m_children[s] ) + m_children[s].do_resolve_bindings(); + resolve_bindings(); +endfunction +function void uvm_component::accept_tr (uvm_transaction tr, + time accept_time=0); + uvm_event#(uvm_object) e; + if(tr == null) + return; + tr.accept_tr(accept_time); + do_accept_tr(tr); + e = event_pool.get("accept_tr"); + if(e!=null) + e.trigger(); +endfunction +function int uvm_component::begin_tr (uvm_transaction tr, + string stream_name="main", + string label="", + string desc="", + time begin_time=0, + int parent_handle=0); + return m_begin_tr(tr, parent_handle, stream_name, label, desc, begin_time); +endfunction + function uvm_tr_database uvm_component::get_tr_database(); + if (tr_database == null) begin + uvm_coreservice_t cs = uvm_coreservice_t::get(); + tr_database = cs.get_default_tr_database(); + end + return tr_database; + endfunction : get_tr_database + function void uvm_component::set_tr_database(uvm_tr_database db); + tr_database = db; + endfunction : set_tr_database +function uvm_tr_stream uvm_component::get_tr_stream( string name, + string stream_type_name="" ); + uvm_tr_database db = get_tr_database(); + if (!m_streams.exists(name) || !m_streams[name].exists(stream_type_name)) + m_streams[name][stream_type_name] = db.open_stream(name, this.get_full_name(), stream_type_name); + return m_streams[name][stream_type_name]; +endfunction : get_tr_stream +function void uvm_component::free_tr_stream(uvm_tr_stream stream); + if (stream == null) + return; + if (!m_streams.exists(stream.get_name()) || + !m_streams[stream.get_name()].exists(stream.get_stream_type_name())) + return; + if (m_streams[stream.get_name()][stream.get_stream_type_name()] != stream) + return; + m_streams[stream.get_name()].delete(stream.get_type_name()); + if (m_streams[stream.get_name()].size() == 0) + m_streams.delete(stream.get_name()); + if (stream.is_open() || stream.is_closed()) begin + stream.free(); + end +endfunction : free_tr_stream +function int uvm_component::m_begin_tr (uvm_transaction tr, + int parent_handle=0, + string stream_name="main", + string label="", + string desc="", + time begin_time=0); + uvm_event#(uvm_object) e; + string name; + string kind; + uvm_tr_database db; + int handle, link_handle; + uvm_tr_stream stream; + uvm_recorder recorder, parent_recorder, link_recorder; + if (tr == null) + return 0; + db = get_tr_database(); + if (parent_handle != 0) + parent_recorder = uvm_recorder::get_recorder_from_handle(parent_handle); + if (parent_recorder == null) begin + uvm_sequence_item seq; + if ($cast(seq,tr)) begin + uvm_sequence_base parent_seq = seq.get_parent_sequence(); + if (parent_seq != null) begin + parent_recorder = parent_seq.m_tr_recorder; + end + end + end + if(parent_recorder != null) begin + link_handle = tr.begin_child_tr(begin_time, parent_recorder.get_handle()); + end + else begin + link_handle = tr.begin_tr(begin_time); + end + if (link_handle != 0) + link_recorder = uvm_recorder::get_recorder_from_handle(link_handle); + if (tr.get_name() != "") + name = tr.get_name(); + else + name = tr.get_type_name(); + if (uvm_verbosity'(recording_detail) != UVM_NONE) begin + if (stream_name == "") + stream_name = "main"; + stream = get_tr_stream(stream_name, "TVM"); + if (stream != null ) begin + kind = (parent_recorder == null) ? "Begin_No_Parent, Link" : "Begin_End, Link"; + recorder = stream.open_recorder(name, begin_time, kind); + if (recorder != null) begin + if (label != "") + recorder.record_string("label", label); + if (desc != "") + recorder.record_string("desc", desc); + if (parent_recorder != null) begin + tr_database.establish_link(uvm_parent_child_link::get_link(parent_recorder, + recorder)); + end + if (link_recorder != null) begin + tr_database.establish_link(uvm_related_link::get_link(recorder, + link_recorder)); + end + m_tr_h[tr] = recorder; + end + end + handle = (recorder == null) ? 0 : recorder.get_handle(); + do_begin_tr(tr, stream_name, handle); + end + e = event_pool.get("begin_tr"); + if (e!=null) + e.trigger(tr); + return handle; +endfunction +function void uvm_component::end_tr (uvm_transaction tr, + time end_time=0, + bit free_handle=1); + uvm_event#(uvm_object) e; + uvm_recorder recorder; + if (tr == null) + return; + tr.end_tr(end_time,free_handle); + if (uvm_verbosity'(recording_detail) != UVM_NONE) begin + if (m_tr_h.exists(tr)) begin + recorder = m_tr_h[tr]; + do_end_tr(tr, recorder.get_handle()); + m_tr_h.delete(tr); + tr.record(recorder); + recorder.close(end_time); + if (free_handle) + recorder.free(); + end + else begin + do_end_tr(tr, 0); + end + end + e = event_pool.get("end_tr"); + if(e!=null) + e.trigger(); +endfunction +function int uvm_component::record_error_tr (string stream_name="main", + uvm_object info=null, + string label="error_tr", + string desc="", + time error_time=0, + bit keep_active=0); + uvm_recorder recorder; + string etype; + uvm_tr_stream stream; + int handle; + if(keep_active) etype = "Error, Link"; + else etype = "Error"; + if(error_time == 0) error_time = $realtime; + if (stream_name == "") + stream_name = "main"; + stream = get_tr_stream(stream_name, "TVM"); + handle = 0; + if (stream != null) begin + recorder = stream.open_recorder(label, + error_time, + etype); + if (recorder != null) begin + if (label != "") + recorder.record_string("label", label); + if (desc != "") + recorder.record_string("desc", desc); + if (info!=null) + info.record(recorder); + recorder.close(error_time); + if (keep_active == 0) begin + recorder.free(); + end + else begin + handle = recorder.get_handle(); + end + end + end + return handle; +endfunction +function int uvm_component::record_event_tr (string stream_name="main", + uvm_object info=null, + string label="event_tr", + string desc="", + time event_time=0, + bit keep_active=0); + uvm_recorder recorder; + string etype; + int handle; + uvm_tr_stream stream; + if(keep_active) etype = "Event, Link"; + else etype = "Event"; + if(event_time == 0) event_time = $realtime; + if (stream_name == "") + stream_name = "main"; + stream = get_tr_stream(stream_name, "TVM"); + handle = 0; + if (stream != null) begin + recorder = stream.open_recorder(label, + event_time, + etype); + if (recorder != null) begin + if (label != "") + recorder.record_string("label", label); + if (desc != "") + recorder.record_string("desc", desc); + if (info!=null) + info.record(recorder); + recorder.close(event_time); + if (keep_active == 0) begin + recorder.free(); + end + else begin + handle = recorder.get_handle(); + end + end + end + return handle; +endfunction +function void uvm_component::do_accept_tr (uvm_transaction tr); + return; +endfunction +function void uvm_component::do_begin_tr (uvm_transaction tr, + string stream_name, + int tr_handle); + return; +endfunction +function void uvm_component::do_end_tr (uvm_transaction tr, + int tr_handle); + return; +endfunction +function string uvm_component::massage_scope(string scope); + if(scope == "") + return "^$"; + if(scope == "*") + return {get_full_name(), ".*"}; + if(scope == "uvm_test_top") + return "uvm_test_top"; + if(scope[0] == ".") + return {get_full_name(), scope}; + return {get_full_name(), ".", scope}; +endfunction +function bit uvm_component::use_automatic_config(); + return 1; +endfunction +function void uvm_component::apply_config_settings (bit verbose=0); + uvm_resource_pool rp = uvm_resource_pool::get(); + uvm_queue#(uvm_resource_base) rq; + uvm_resource_base r; + rq = rp.lookup_scope(get_full_name()); + rp.sort_by_precedence(rq); + for(int i=rq.size()-1; i>=0; --i) begin + r = rq.get(i); + if(verbose) + uvm_report_info("CFGAPL",$sformatf("applying configuration to field %s", r.get_name()),UVM_NONE); + set_local(r); + end +endfunction +function void uvm_component::print_config(bit recurse = 0, audit = 0); + uvm_resource_pool rp = uvm_resource_pool::get(); + uvm_report_info("CFGPRT","visible resources:",UVM_INFO); + rp.print_resources(rp.lookup_scope(get_full_name()), audit); + if(recurse) begin + uvm_component c; + foreach(m_children[name]) begin + c = m_children[name]; + c.print_config(recurse, audit); + end + end +endfunction +function void uvm_component::print_config_with_audit(bit recurse = 0); + print_config(recurse, 1); +endfunction +function void uvm_component::do_print(uvm_printer printer); + super.do_print(printer); + if(uvm_verbosity'(recording_detail) != UVM_NONE) + case (recording_detail) + UVM_LOW : printer.print_generic("recording_detail", "uvm_verbosity", + $bits(recording_detail), "UVM_LOW"); + UVM_MEDIUM : printer.print_generic("recording_detail", "uvm_verbosity", + $bits(recording_detail), "UVM_MEDIUM"); + UVM_HIGH : printer.print_generic("recording_detail", "uvm_verbosity", + $bits(recording_detail), "UVM_HIGH"); + UVM_FULL : printer.print_generic("recording_detail", "uvm_verbosity", + $bits(recording_detail), "UVM_FULL"); + default : printer.print_field_int("recording_detail", recording_detail, + $bits(recording_detail), UVM_DEC, , "integral"); + endcase +endfunction +function void uvm_component::set_local(uvm_resource_base rsrc) ; + bit success; + if((rsrc != null) && (rsrc.get_name() == "recording_detail")) begin +begin +begin + uvm_resource#(uvm_integral_t) __tmp_rsrc__; + success = $cast(__tmp_rsrc__, rsrc); + if (success) begin + recording_detail = __tmp_rsrc__.read(this); + end +end + if (!success) +begin + uvm_resource#(uvm_bitstream_t) __tmp_rsrc__; + success = $cast(__tmp_rsrc__, rsrc); + if (success) begin + recording_detail = __tmp_rsrc__.read(this); + end +end + if (!success) +begin + uvm_resource#(int) __tmp_rsrc__; + success = $cast(__tmp_rsrc__, rsrc); + if (success) begin + recording_detail = __tmp_rsrc__.read(this); + end +end + if (!success) +begin + uvm_resource#(int unsigned) __tmp_rsrc__; + success = $cast(__tmp_rsrc__, rsrc); + if (success) begin + recording_detail = __tmp_rsrc__.read(this); + end +end +end + end + if (!success) + super.set_local(rsrc); +endfunction +function void uvm_component::m_unsupported_set_local(uvm_resource_base rsrc); + m_unsupported_resource_base = rsrc; +endfunction +typedef class uvm_cmdline_processor; +function void uvm_component::m_set_cl_msg_args; + string s_; + process p_; + p_=process::self(); + if(p_!=null) + s_=p_.get_randstate(); + else + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM")) + uvm_report_warning ("UVM", "run_test() invoked from a non process context", UVM_NONE, "t/uvm/src/base/uvm_component.svh", 3043, "", 1); + end + m_set_cl_verb(); + m_set_cl_action(); + m_set_cl_sev(); + if(p_!=null) + p_.set_randstate(s_); +endfunction +function void uvm_component::m_set_cl_verb; + static string values[$]; + static bit first = 1; + string args[$]; + uvm_cmdline_processor clp = uvm_cmdline_processor::get_inst(); + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + if(first) begin + string t[$]; + m_verbosity_setting setting; + void'(clp.get_arg_values("+uvm_set_verbosity=",values)); + foreach(values[i]) begin + args.delete(); + uvm_split_string(values[i], ",", args); + if(((args.size() == 4) || (args.size() == 5)) && (clp.m_convert_verb(args[2], setting.verbosity) == 1) ) + t.push_back(values[i]); + else + uvm_report_warning("UVM/CMDLINE",$sformatf("argument %s not recognized and therefore dropped",values[i])); + end + values=t; + first=0; + end + foreach(values[i]) begin + m_verbosity_setting setting; + args.delete(); + uvm_split_string(values[i], ",", args); + begin + setting.comp = args[0]; + setting.id = args[1]; + void'(clp.m_convert_verb(args[2],setting.verbosity)); + setting.phase = args[3]; + setting.offset = 0; + if(args.size() == 5) setting.offset = args[4].atoi(); + if((setting.phase == "time") && (this == top)) begin + m_time_settings.push_back(setting); + end + if (uvm_is_match(setting.comp, get_full_name()) ) begin + if((setting.phase == "" || setting.phase == "build" || setting.phase == "time") && + (setting.offset == 0) ) + begin + if(setting.id == "_ALL_") + set_report_verbosity_level(setting.verbosity); + else + set_report_id_verbosity(setting.id, setting.verbosity); + end + else begin + if(setting.phase != "time") begin + m_verbosity_settings.push_back(setting); + end + end + end + end + end + if(this == top) begin + fork begin + time last_time = 0; + if (m_time_settings.size() > 0) + m_time_settings.sort() with ( item.offset ); + foreach(m_time_settings[i]) begin + uvm_component comps[$]; + top.find_all(m_time_settings[i].comp,comps); + #(m_time_settings[i].offset - last_time); + last_time = m_time_settings[i].offset; + if(m_time_settings[i].id == "_ALL_") begin + foreach(comps[j]) begin + comps[j].set_report_verbosity_level(m_time_settings[i].verbosity); + end + end + else begin + foreach(comps[j]) begin + comps[j].set_report_id_verbosity(m_time_settings[i].id, m_time_settings[i].verbosity); + end + end + end + end join_none + end +endfunction +function void uvm_component::m_set_cl_action; + static bit initialized = 0; + uvm_severity sev; + uvm_action action; + uvm_cmdline_processor uvm_cmdline_proc = uvm_cmdline_processor::get_inst(); + if(!initialized) begin + string values[$]; + void'(uvm_cmdline_proc.get_arg_values("+uvm_set_action=",values)); + foreach(values[idx]) begin + uvm_cmdline_parsed_arg_t t; + string args[$]; + uvm_split_string(values[idx], ",", args); + if(args.size() != 4) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"INVLCMDARGS")) + uvm_report_warning ("INVLCMDARGS", $sformatf("+uvm_set_action requires 4 arguments, but %0d given for command +uvm_set_action=%s, Usage: +uvm_set_action=,,,", args.size(), values[idx]), UVM_NONE, "t/uvm/src/base/uvm_component.svh", 3169, "", 1); + end + continue; + end + if((args[2] != "_ALL_") && !uvm_string_to_severity(args[2], sev)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"INVLCMDARGS")) + uvm_report_warning ("INVLCMDARGS", $sformatf("Bad severity argument \"%s\" given to command +uvm_set_action=%s, Usage: +uvm_set_action=,,,", args[2], values[idx]), UVM_NONE, "t/uvm/src/base/uvm_component.svh", 3173, "", 1); + end + continue; + end + if(!uvm_string_to_action(args[3], action)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"INVLCMDARGS")) + uvm_report_warning ("INVLCMDARGS", $sformatf("Bad action argument \"%s\" given to command +uvm_set_action=%s, Usage: +uvm_set_action=,,,", args[3], values[idx]), UVM_NONE, "t/uvm/src/base/uvm_component.svh", 3177, "", 1); + end + continue; + end + t.args=args; + t.arg=values[idx]; + m_uvm_applied_cl_action.push_back(t); + end + initialized=1; + end + foreach(m_uvm_applied_cl_action[i]) begin + string args[$] = m_uvm_applied_cl_action[i].args; + if (!uvm_is_match(args[0], get_full_name()) ) continue; + void'(uvm_string_to_severity(args[2], sev)); + void'(uvm_string_to_action(args[3], action)); + m_uvm_applied_cl_action[i].used++; + if(args[1] == "_ALL_") begin + if(args[2] == "_ALL_") begin + set_report_severity_action(UVM_INFO, action); + set_report_severity_action(UVM_WARNING, action); + set_report_severity_action(UVM_ERROR, action); + set_report_severity_action(UVM_FATAL, action); + end + else begin + set_report_severity_action(sev, action); + end + end + else begin + if(args[2] == "_ALL_") begin + set_report_id_action(args[1], action); + end + else begin + set_report_severity_id_action(sev, args[1], action); + end + end + end +endfunction +function void uvm_component::m_set_cl_sev; + static bit initialized; + uvm_severity orig_sev, sev; + uvm_cmdline_processor uvm_cmdline_proc = uvm_cmdline_processor::get_inst(); + if(!initialized) begin + string values[$]; + void'(uvm_cmdline_proc.get_arg_values("+uvm_set_severity=",values)); + foreach(values[idx]) begin + uvm_cmdline_parsed_arg_t t; + string args[$]; + uvm_split_string(values[idx], ",", args); + if(args.size() != 4) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"INVLCMDARGS")) + uvm_report_warning ("INVLCMDARGS", $sformatf("+uvm_set_severity requires 4 arguments, but %0d given for command +uvm_set_severity=%s, Usage: +uvm_set_severity=,,,", args.size(), values[idx]), UVM_NONE, "t/uvm/src/base/uvm_component.svh", 3240, "", 1); + end + continue; + end + if(args[2] != "_ALL_" && !uvm_string_to_severity(args[2], orig_sev)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"INVLCMDARGS")) + uvm_report_warning ("INVLCMDARGS", $sformatf("Bad severity argument \"%s\" given to command +uvm_set_severity=%s, Usage: +uvm_set_severity=,,,", args[2], values[idx]), UVM_NONE, "t/uvm/src/base/uvm_component.svh", 3244, "", 1); + end + continue; + end + if(!uvm_string_to_severity(args[3], sev)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"INVLCMDARGS")) + uvm_report_warning ("INVLCMDARGS", $sformatf("Bad severity argument \"%s\" given to command +uvm_set_severity=%s, Usage: +uvm_set_severity=,,,", args[3], values[idx]), UVM_NONE, "t/uvm/src/base/uvm_component.svh", 3248, "", 1); + end + continue; + end + t.args=args; + t.arg=values[idx]; + m_uvm_applied_cl_sev.push_back(t); + end + initialized=1; + end + foreach(m_uvm_applied_cl_sev[i]) begin + string args[$]=m_uvm_applied_cl_sev[i].args; + if (!uvm_is_match(args[0], get_full_name()) ) continue; + void'(uvm_string_to_severity(args[2], orig_sev)); + void'(uvm_string_to_severity(args[3], sev)); + m_uvm_applied_cl_sev[i].used++; + if(args[1] == "_ALL_" && args[2] == "_ALL_") begin + set_report_severity_override(UVM_INFO,sev); + set_report_severity_override(UVM_WARNING,sev); + set_report_severity_override(UVM_ERROR,sev); + set_report_severity_override(UVM_FATAL,sev); + end + else if(args[1] == "_ALL_") begin + set_report_severity_override(orig_sev,sev); + end + else if(args[2] == "_ALL_") begin + set_report_severity_id_override(UVM_INFO,args[1],sev); + set_report_severity_id_override(UVM_WARNING,args[1],sev); + set_report_severity_id_override(UVM_ERROR,args[1],sev); + set_report_severity_id_override(UVM_FATAL,args[1],sev); + end + else begin + set_report_severity_id_override(orig_sev,args[1],sev); + end + end +endfunction +function void uvm_component::m_apply_verbosity_settings(uvm_phase phase); + int i; + while (i < m_verbosity_settings.size()) begin + if(phase.get_name() == m_verbosity_settings[i].phase) begin + if( m_verbosity_settings[i].offset == 0 ) begin + if(m_verbosity_settings[i].id == "_ALL_") + set_report_verbosity_level(m_verbosity_settings[i].verbosity); + else + set_report_id_verbosity(m_verbosity_settings[i].id, m_verbosity_settings[i].verbosity); + end + else begin + process p = process::self(); + string p_rand = p.get_randstate(); + fork begin + m_verbosity_setting setting = m_verbosity_settings[i]; + #(setting.offset); + if(setting.id == "_ALL_") + set_report_verbosity_level(setting.verbosity); + else + set_report_id_verbosity(setting.id, setting.verbosity); + end join_none + p.set_randstate(p_rand); + end + m_verbosity_settings.delete(i); + continue; + end + i++; + end +endfunction +function void uvm_component::m_do_pre_abort; + foreach(m_children[i]) + m_children[i].m_do_pre_abort(); + pre_abort(); +endfunction +typedef class uvm_objection_context_object; +typedef class uvm_objection; +typedef class uvm_sequence_base; +typedef class uvm_objection_callback; +typedef uvm_callbacks #(uvm_objection,uvm_objection_callback) uvm_objection_cbs_t; +typedef class uvm_cmdline_processor; +class uvm_objection_events; + int waiters; + event raised; + event dropped; + event all_dropped; +endclass +class uvm_objection extends uvm_report_object; + static local bit m_register_cb_uvm_objection_callback = uvm_callbacks#(uvm_objection,uvm_objection_callback)::m_register_pair("uvm_objection","uvm_objection_callback"); + protected bit m_trace_mode; + protected int m_source_count[uvm_object]; + protected int m_total_count [uvm_object]; + protected time m_drain_time [uvm_object]; + protected uvm_objection_events m_events [uvm_object]; + bit m_top_all_dropped; + protected uvm_root m_top; + static uvm_objection m_objections[$]; + local static uvm_objection_context_object m_context_pool[$]; + local process m_drain_proc[uvm_object]; + local static uvm_objection_context_object m_scheduled_list[$]; + local uvm_objection_context_object m_scheduled_contexts[uvm_object]; + local uvm_objection_context_object m_forked_list[$]; + local uvm_objection_context_object m_forked_contexts[uvm_object]; + protected bit m_prop_mode = 1; + protected bit m_cleared; + function new(string name=""); + uvm_cmdline_processor clp; + uvm_coreservice_t cs_ ; + string trace_args[$]; + super.new(name); + cs_ = uvm_coreservice_t::get(); + m_top = cs_.get_root(); + set_report_verbosity_level(m_top.get_report_verbosity_level()); + clp = uvm_cmdline_processor::get_inst(); + if(clp.get_arg_matches("+UVM_OBJECTION_TRACE", trace_args)) begin + m_trace_mode=1; + end + m_objections.push_back(this); + endfunction + function bit trace_mode (int mode=-1); + trace_mode = m_trace_mode; + if(mode == 0) m_trace_mode = 0; + else if(mode == 1) m_trace_mode = 1; + endfunction + function void m_report(uvm_object obj, uvm_object source_obj, string description, int count, string action); + int _count = m_source_count.exists(obj) ? m_source_count[obj] : 0; + int _total = m_total_count.exists(obj) ? m_total_count[obj] : 0; + if (!uvm_report_enabled(UVM_NONE,UVM_INFO,"OBJTN_TRC") || !m_trace_mode) return; + if (source_obj == obj) + uvm_report_info("OBJTN_TRC", + $sformatf("Object %0s %0s %0d objection(s)%s: count=%0d total=%0d", + obj.get_full_name()==""?"uvm_top":obj.get_full_name(), action, + count, description != ""? {" (",description,")"}:"", _count, _total), UVM_NONE); + else begin + int cpath = 0, last_dot=0; + string sname = source_obj.get_full_name(), nm = obj.get_full_name(); + int max = sname.len() > nm.len() ? nm.len() : sname.len(); + while((sname[cpath] == nm[cpath]) && (cpath < max)) begin + if(sname[cpath] == ".") last_dot = cpath; + cpath++; + end + if(last_dot) sname = sname.substr(last_dot+1, sname.len()); + uvm_report_info("OBJTN_TRC", + $sformatf("Object %0s %0s %0d objection(s) %0s its total (%s from source object %s%s): count=%0d total=%0d", + obj.get_full_name()==""?"uvm_top":obj.get_full_name(), action=="raised"?"added":"subtracted", + count, action=="raised"?"to":"from", action, sname, + description != ""?{", ",description}:"", _count, _total), UVM_NONE); + end + endfunction + function uvm_object m_get_parent(uvm_object obj); + uvm_component comp; + uvm_sequence_base seq; + if ($cast(comp, obj)) begin + obj = comp.get_parent(); + end + else if ($cast(seq, obj)) begin + obj = seq.get_sequencer(); + end + else + obj = m_top; + if (obj == null) + obj = m_top; + return obj; + endfunction + function void m_propagate (uvm_object obj, + uvm_object source_obj, + string description, + int count, + bit raise, + int in_top_thread); + if (obj != null && obj != m_top) begin + obj = m_get_parent(obj); + if(raise) + m_raise(obj, source_obj, description, count); + else + m_drop(obj, source_obj, description, count, in_top_thread); + end + endfunction + function void set_propagate_mode (bit prop_mode); + if (!m_top_all_dropped && (get_objection_total() != 0)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/BASE/OBJTN/PROP_MODE")) + uvm_report_error ("UVM/BASE/OBJTN/PROP_MODE", {"The propagation mode of '", this.get_full_name(), "' cannot be changed while the objection is raised ", "or draining!"}, UVM_NONE, "t/uvm/src/base/uvm_objection.svh", 265, "", 1); + end + return; + end + m_prop_mode = prop_mode; + endfunction : set_propagate_mode + function bit get_propagate_mode(); + return m_prop_mode; + endfunction : get_propagate_mode + virtual function void raise_objection (uvm_object obj=null, + string description="", + int count=1); + if(obj == null) + obj = m_top; + m_cleared = 0; + m_top_all_dropped = 0; + m_raise (obj, obj, description, count); + endfunction + function void m_raise (uvm_object obj, + uvm_object source_obj, + string description="", + int count=1); + int idx; + uvm_objection_context_object ctxt; + if (count == 0) + return; + if (m_total_count.exists(obj)) + m_total_count[obj] += count; + else + m_total_count[obj] = count; + if (source_obj==obj) begin + if (m_source_count.exists(obj)) + m_source_count[obj] += count; + else + m_source_count[obj] = count; + end + if (m_trace_mode) + m_report(obj,source_obj,description,count,"raised"); + raised(obj, source_obj, description, count); + idx = 0; + while (idx < m_scheduled_list.size()) begin + if ((m_scheduled_list[idx].obj == obj) && + (m_scheduled_list[idx].objection == this)) begin + ctxt = m_scheduled_list[idx]; + m_scheduled_list.delete(idx); + break; + end + idx++; + end + if (ctxt == null) begin + idx = 0; + while (idx < m_forked_list.size()) begin + if (m_forked_list[idx].obj == obj) begin + ctxt = m_forked_list[idx]; + m_forked_list.delete(idx); + m_scheduled_contexts.delete(ctxt.obj); + break; + end + idx++; + end + end + if (ctxt == null) begin + if (m_forked_contexts.exists(obj)) begin + ctxt = m_forked_contexts[obj]; + m_forked_contexts.delete(obj); + m_drain_proc[obj].kill(); + m_drain_proc.delete(obj); + end + end + if (ctxt == null) begin + if (!m_prop_mode && obj != m_top) + m_raise(m_top,source_obj,description,count); + else if (obj != m_top) + m_propagate(obj, source_obj, description, count, 1, 0); + end + else begin + int diff_count; + diff_count = count - ctxt.count; + if (diff_count != 0) begin + if (diff_count > 0) begin + if (!m_prop_mode && obj != m_top) + m_raise(m_top, source_obj, description, diff_count); + else if (obj != m_top) + m_propagate(obj, source_obj, description, diff_count, 1, 0); + end + else begin + diff_count = -diff_count; + if (!m_prop_mode && obj != m_top) + m_drop(m_top, source_obj, description, diff_count); + else if (obj != m_top) + m_propagate(obj, source_obj, description, diff_count, 0, 0); + end + end + ctxt.clear(); + m_context_pool.push_back(ctxt); + end + endfunction + virtual function void drop_objection (uvm_object obj=null, + string description="", + int count=1); + if(obj == null) + obj = m_top; + m_drop (obj, obj, description, count, 0); + endfunction + function void m_drop (uvm_object obj, + uvm_object source_obj, + string description="", + int count=1, + int in_top_thread=0); + if (count == 0) + return; + if (!m_total_count.exists(obj) || (count > m_total_count[obj])) begin + if(m_cleared) + return; + uvm_report_fatal("OBJTN_ZERO", {"Object \"", obj.get_full_name(), + "\" attempted to drop objection '",this.get_name(),"' count below zero"}); + return; + end + if (obj == source_obj) begin + if (!m_source_count.exists(obj) || (count > m_source_count[obj])) begin + if(m_cleared) + return; + uvm_report_fatal("OBJTN_ZERO", {"Object \"", obj.get_full_name(), + "\" attempted to drop objection '",this.get_name(),"' count below zero"}); + return; + end + m_source_count[obj] -= count; + end + m_total_count[obj] -= count; + if (m_trace_mode) + m_report(obj,source_obj,description,count,"dropped"); + dropped(obj, source_obj, description, count); + if (m_total_count[obj] != 0) begin + if (!m_prop_mode && obj != m_top) + m_drop(m_top,source_obj,description, count, in_top_thread); + else if (obj != m_top) begin + this.m_propagate(obj, source_obj, description, count, 0, in_top_thread); + end + end + else begin + uvm_objection_context_object ctxt; + if (m_context_pool.size()) + ctxt = m_context_pool.pop_front(); + else + ctxt = new; + ctxt.obj = obj; + ctxt.source_obj = source_obj; + ctxt.description = description; + ctxt.count = count; + ctxt.objection = this; + m_scheduled_list.push_back(ctxt); + end + endfunction + virtual function void clear(uvm_object obj=null); + string name; + int idx; + if (obj==null) + obj=m_top; + name = obj.get_full_name(); + if (name == "") + name = "uvm_top"; + else + name = obj.get_full_name(); + if (!m_top_all_dropped && get_objection_total(m_top)) + uvm_report_warning("OBJTN_CLEAR",{"Object '",name, + "' cleared objection counts for ",get_name()}); + m_source_count.delete(); + m_total_count.delete(); + idx = 0; + while (idx < m_scheduled_list.size()) begin + if (m_scheduled_list[idx].objection == this) begin + m_scheduled_list[idx].clear(); + m_context_pool.push_back(m_scheduled_list[idx]); + m_scheduled_list.delete(idx); + end + else begin + idx++; + end + end + m_scheduled_contexts.delete(); + while (m_forked_list.size()) begin + m_forked_list[0].clear(); + m_context_pool.push_back(m_forked_list[0]); + void'(m_forked_list.pop_front()); + end + foreach (m_forked_contexts[o]) begin + m_drain_proc[o].kill(); + m_drain_proc.delete(o); + m_forked_contexts[o].clear(); + m_context_pool.push_back(m_forked_contexts[o]); + m_forked_contexts.delete(o); + end + m_top_all_dropped = 0; + m_cleared = 1; + if (m_events.exists(m_top)) + ->m_events[m_top].all_dropped; + endfunction + static task m_execute_scheduled_forks(); + while(1) begin + wait(m_scheduled_list.size() != 0); + if(m_scheduled_list.size() != 0) begin + uvm_objection_context_object c; + c = m_scheduled_list.pop_front(); + c.objection.m_scheduled_contexts[c.obj] = c; + c.objection.m_forked_list.push_back(c); + fork : guard + automatic uvm_objection objection = c.objection; + begin + if (objection.m_forked_list.size() > 0) begin + uvm_objection_context_object ctxt; + ctxt = objection.m_forked_list.pop_front(); + objection.m_scheduled_contexts.delete(ctxt.obj); + objection.m_forked_contexts[ctxt.obj] = ctxt; + objection.m_drain_proc[ctxt.obj] = process::self(); + objection.m_forked_drain(ctxt.obj, ctxt.source_obj, ctxt.description, ctxt.count, 1); + objection.m_drain_proc.delete(ctxt.obj); + objection.m_forked_contexts.delete(ctxt.obj); + ctxt.clear(); + m_context_pool.push_back(ctxt); + end + end + join_none : guard + end + end + endtask + task m_forked_drain (uvm_object obj, + uvm_object source_obj, + string description="", + int count=1, + int in_top_thread=0); + if (m_drain_time.exists(obj)) + #(m_drain_time[obj]); + if (m_trace_mode) + m_report(obj,source_obj,description,count,"all_dropped"); + all_dropped(obj,source_obj,description, count); +//TODO issue #4465 - Support wait fork +//TODO %Error-UNSUPPORTED: t/t_uvm_pkg_todo.vh:14761:7: Unsupported: wait fork statements +//TODO wait fork; + if (m_source_count.exists(obj) && m_source_count[obj] == 0) + m_source_count.delete(obj); + if (m_total_count.exists(obj) && m_total_count[obj] == 0) + m_total_count.delete(obj); + if (!m_prop_mode && obj != m_top) + m_drop(m_top,source_obj,description, count, 1); + else if (obj != m_top) + m_propagate(obj, source_obj, description, count, 0, 1); + endtask + static function void m_init_objections(); + fork + uvm_objection::m_execute_scheduled_forks(); + join_none + endfunction + function void set_drain_time (uvm_object obj=null, time drain); + if (obj==null) + obj = m_top; + m_drain_time[obj] = drain; + endfunction + virtual function void raised (uvm_object obj, + uvm_object source_obj, + string description, + int count); + uvm_component comp; + if ($cast(comp,obj)) + comp.raised(this, source_obj, description, count); + begin + uvm_callback_iter#(uvm_objection,uvm_objection_callback) iter = new(this); + uvm_objection_callback cb = iter.first(); + while(cb != null) begin + cb.raised(this,obj,source_obj,description,count); + cb = iter.next(); + end + end + if (m_events.exists(obj)) + ->m_events[obj].raised; + endfunction + virtual function void dropped (uvm_object obj, + uvm_object source_obj, + string description, + int count); + uvm_component comp; + if($cast(comp,obj)) + comp.dropped(this, source_obj, description, count); + begin + uvm_callback_iter#(uvm_objection,uvm_objection_callback) iter = new(this); + uvm_objection_callback cb = iter.first(); + while(cb != null) begin + cb.dropped(this,obj,source_obj,description,count); + cb = iter.next(); + end + end + if (m_events.exists(obj)) + ->m_events[obj].dropped; + endfunction + virtual task all_dropped (uvm_object obj, + uvm_object source_obj, + string description, + int count); + uvm_component comp; + if($cast(comp,obj)) + comp.all_dropped(this, source_obj, description, count); + begin + uvm_callback_iter#(uvm_objection,uvm_objection_callback) iter = new(this); + uvm_objection_callback cb = iter.first(); + while(cb != null) begin + cb.all_dropped(this,obj,source_obj,description,count); + cb = iter.next(); + end + end + if (m_events.exists(obj)) + ->m_events[obj].all_dropped; + if (obj == m_top) + m_top_all_dropped = 1; + endtask + function void get_objectors(ref uvm_object list[$]); + list.delete(); + foreach (m_source_count[obj]) list.push_back(obj); + endfunction + task wait_for(uvm_objection_event objt_event, uvm_object obj=null); + if (obj==null) + obj = m_top; + if (!m_events.exists(obj)) begin + m_events[obj] = new; + end + m_events[obj].waiters++; + case (objt_event) + UVM_RAISED: @(m_events[obj].raised); + UVM_DROPPED: @(m_events[obj].dropped); + UVM_ALL_DROPPED: @(m_events[obj].all_dropped); + endcase + m_events[obj].waiters--; + if (m_events[obj].waiters == 0) + m_events.delete(obj); + endtask + task wait_for_total_count(uvm_object obj=null, int count=0); + if (obj==null) + obj = m_top; + if(!m_total_count.exists(obj) && count == 0) + return; + if (count == 0) + wait (!m_total_count.exists(obj) && count == 0); + else + wait (m_total_count.exists(obj) && m_total_count[obj] == count); + endtask + function int get_objection_count (uvm_object obj=null); + if (obj==null) + obj = m_top; + if (!m_source_count.exists(obj)) + return 0; + return m_source_count[obj]; + endfunction + function int get_objection_total (uvm_object obj=null); + if (obj==null) + obj = m_top; + if (!m_total_count.exists(obj)) + return 0; + else + return m_total_count[obj]; + endfunction + function time get_drain_time (uvm_object obj=null); + if (obj==null) + obj = m_top; + if (!m_drain_time.exists(obj)) + return 0; + return m_drain_time[obj]; + endfunction + protected function string m_display_objections(uvm_object obj=null, bit show_header=1); + static string blank=" "; + string s; + int total; + uvm_object list[string]; + uvm_object curr_obj; + int depth; + string name; + string this_obj_name; + string curr_obj_name; + foreach (m_total_count[o]) begin + uvm_object theobj = o; + if ( m_total_count[o] > 0) + list[theobj.get_full_name()] = theobj; + end + if (obj==null) + obj = m_top; + total = get_objection_total(obj); + s = $sformatf("The total objection count is %0d\n",total); + if (total == 0) + return s; + s = {s,"---------------------------------------------------------\n"}; + s = {s,"Source Total \n"}; + s = {s,"Count Count Object\n"}; + s = {s,"---------------------------------------------------------\n"}; + this_obj_name = obj.get_full_name(); + curr_obj_name = this_obj_name; + do begin + curr_obj = list[curr_obj_name]; + depth=0; + foreach (curr_obj_name[i]) + if (curr_obj_name[i] == ".") + depth++; + name = curr_obj_name; + for (int i=curr_obj_name.len()-1;i >= 0; i--) + if (curr_obj_name[i] == ".") begin + name = curr_obj_name.substr(i+1,curr_obj_name.len()-1); + break; + end + if (curr_obj_name == "") + name = "uvm_top"; + else + depth++; + s = {s, $sformatf("%-6d %-6d %s%s\n", + m_source_count.exists(curr_obj) ? m_source_count[curr_obj] : 0, + m_total_count.exists(curr_obj) ? m_total_count[curr_obj] : 0, + blank.substr(0,2*depth), name)}; + end while (list.next(curr_obj_name) && + curr_obj_name.substr(0,this_obj_name.len()-1) == this_obj_name); + s = {s,"---------------------------------------------------------\n"}; + return s; + endfunction + function string convert2string(); + return m_display_objections(m_top,1); + endfunction + function void display_objections(uvm_object obj=null, bit show_header=1); + string m = m_display_objections(obj,show_header); + begin + if (uvm_report_enabled(UVM_NONE,UVM_INFO,"UVM/OBJ/DISPLAY")) + uvm_report_info ("UVM/OBJ/DISPLAY", m, UVM_NONE, "t/uvm/src/base/uvm_objection.svh", 1033, "", 1); + end + endfunction + typedef uvm_object_registry#(uvm_objection,"uvm_objection") type_id; + static function uvm_objection type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_objection tmp = new(name); + return tmp; + endfunction + virtual function string get_type_name (); + return "uvm_objection"; + endfunction + function void do_copy (uvm_object rhs); + uvm_objection _rhs; + $cast(_rhs, rhs); + m_source_count = _rhs.m_source_count; + m_total_count = _rhs.m_total_count; + m_drain_time = _rhs.m_drain_time; + m_prop_mode = _rhs.m_prop_mode; + endfunction +endclass +typedef class uvm_cmdline_processor; +class uvm_objection_context_object; + uvm_object obj; + uvm_object source_obj; + string description; + int count; + uvm_objection objection; + function void clear(); + obj = null; + source_obj = null; + description = ""; + count = 0; + objection = null; + endfunction : clear +endclass +typedef uvm_objection uvm_callbacks_objection; +class uvm_objection_callback extends uvm_callback; + function new(string name); + super.new(name); + endfunction + virtual function void raised (uvm_objection objection, uvm_object obj, + uvm_object source_obj, string description, int count); + endfunction + virtual function void dropped (uvm_objection objection, uvm_object obj, + uvm_object source_obj, string description, int count); + endfunction + virtual task all_dropped (uvm_objection objection, uvm_object obj, + uvm_object source_obj, string description, int count); + endtask +endclass +typedef enum { + UVM_ALL_ACTIVE, + UVM_ONE_ACTIVE, + UVM_ANY_ACTIVE, + UVM_NO_HB_MODE +} uvm_heartbeat_modes; +typedef class uvm_heartbeat_callback; +typedef uvm_callbacks #(uvm_objection,uvm_heartbeat_callback) uvm_heartbeat_cbs_t ; +typedef class uvm_objection_callback; +class uvm_heartbeat extends uvm_object; + protected uvm_objection m_objection; + protected uvm_heartbeat_callback m_cb; + protected uvm_component m_cntxt; + protected uvm_heartbeat_modes m_mode; + protected uvm_component m_hblist[$]; + protected uvm_event#(uvm_object) m_event; + protected bit m_started; + protected event m_stop_event; + function new(string name, uvm_component cntxt, uvm_objection objection=null); + uvm_coreservice_t cs; + super.new(name); + m_objection = objection; + cs = uvm_coreservice_t::get(); + if(cntxt != null) m_cntxt = cntxt; + else m_cntxt = cs.get_root(); + m_cb = new({name,"_cb"},m_cntxt); + endfunction + function uvm_heartbeat_modes set_mode (uvm_heartbeat_modes mode = UVM_NO_HB_MODE); + set_mode = m_mode; + if(mode == UVM_ANY_ACTIVE || mode == UVM_ONE_ACTIVE || mode == UVM_ALL_ACTIVE) + m_mode = mode; + endfunction + function void set_heartbeat (uvm_event#(uvm_object) e, ref uvm_component comps[$]); + uvm_object c; + foreach(comps[i]) begin + c = comps[i]; + if(!m_cb.cnt.exists(c)) + m_cb.cnt[c]=0; + if(!m_cb.last_trigger.exists(c)) + m_cb.last_trigger[c]=0; + end + if(e==null && m_event==null) return; + start(e); + endfunction + function void add (uvm_component comp); + uvm_object c = comp; + if(m_cb.cnt.exists(c)) return; + m_cb.cnt[c]=0; + m_cb.last_trigger[c]=0; + endfunction + function void remove (uvm_component comp); + uvm_object c = comp; + if(m_cb.cnt.exists(c)) m_cb.cnt.delete(c); + if(m_cb.last_trigger.exists(c)) m_cb.last_trigger.delete(c); + endfunction + function void start (uvm_event#(uvm_object) e=null); + if(m_event == null && e == null) begin + m_cntxt.uvm_report_warning("NOEVNT", { "start() was called for: ", + get_name(), " with a null trigger and no currently set trigger" }, + UVM_NONE); + return; + end + if((m_event != null) && (e != m_event) && m_started) begin + m_cntxt.uvm_report_error("ILHBVNT", { "start() was called for: ", + get_name(), " with trigger ", e.get_name(), " which is different ", + "from the original trigger ", m_event.get_name() }, UVM_NONE); + return; + end + if(e != null) m_event = e; + m_enable_cb(); + m_start_hb_process(); + endfunction + function void stop (); + m_started = 0; + ->m_stop_event; + m_disable_cb(); + endfunction + function void m_start_hb_process(); + if(m_started) return; + m_started = 1; + fork + m_hb_process; + join_none + endfunction + protected bit m_added; + function void m_enable_cb; + void'(m_cb.callback_mode(1)); + if(m_objection == null) return; + if(!m_added) + uvm_heartbeat_cbs_t::add(m_objection, m_cb); + m_added = 1; + endfunction + function void m_disable_cb; + void'(m_cb.callback_mode(0)); + endfunction + task m_hb_process; + uvm_object obj; + bit triggered; + time last_trigger=0; + fork + begin + while(1) begin + m_event.wait_trigger(); + if(triggered) begin + case (m_mode) + UVM_ALL_ACTIVE: + begin + foreach(m_cb.cnt[idx]) begin + obj = idx; + if(!m_cb.cnt[obj]) begin + m_cntxt.uvm_report_fatal("HBFAIL", $sformatf("Did not recieve an update of %s for component %s since last event trigger at time %0t : last update time was %0t", + m_objection.get_name(), obj.get_full_name(), + last_trigger, m_cb.last_trigger[obj]), UVM_NONE); + end + end + end + UVM_ANY_ACTIVE: + begin + if(m_cb.cnt.num() && !m_cb.objects_triggered()) begin + string s; + foreach(m_cb.cnt[idx]) begin + obj = idx; + s={s,"\n ",obj.get_full_name()}; + end + m_cntxt.uvm_report_fatal("HBFAIL", $sformatf("Did not recieve an update of %s on any component since last event trigger at time %0t. The list of registered components is:%s", + m_objection.get_name(), last_trigger, s), UVM_NONE); + end + end + UVM_ONE_ACTIVE: + begin + if(m_cb.objects_triggered() > 1) begin + string s; + foreach(m_cb.cnt[idx]) begin + obj = idx; + if(m_cb.cnt[obj]) $swrite(s,"%s\n %s (updated: %0t)", + s, obj.get_full_name(), m_cb.last_trigger[obj]); + end + m_cntxt.uvm_report_fatal("HBFAIL", $sformatf("Recieved update of %s from more than one component since last event trigger at time %0t. The list of triggered components is:%s", + m_objection.get_name(), last_trigger, s), UVM_NONE); + end + if(m_cb.cnt.num() && !m_cb.objects_triggered()) begin + string s; + foreach(m_cb.cnt[idx]) begin + obj = idx; + s={s,"\n ",obj.get_full_name()}; + end + m_cntxt.uvm_report_fatal("HBFAIL", $sformatf("Did not recieve an update of %s on any component since last event trigger at time %0t. The list of registered components is:%s", + m_objection.get_name(), last_trigger, s), UVM_NONE); + end + end + endcase + end + m_cb.reset_counts(); + last_trigger = $realtime; + triggered = 1; + end + end + @(m_stop_event); + join_any +//TODO issue #4125 - Support disable fork +//TODO %Error-UNSUPPORTED: t/t_uvm_pkg_todo.vh:15167:12: Unsupported: disable fork statements +//TODO disable fork; + endtask +endclass +class uvm_heartbeat_callback extends uvm_objection_callback; + int cnt [uvm_object]; + time last_trigger [uvm_object]; + uvm_object target; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + function new(string name, uvm_object target); + super.new(name); + if (target != null) + this.target = target; + else + this.target = cs.get_root(); + endfunction + virtual function void raised (uvm_objection objection, + uvm_object obj, + uvm_object source_obj, + string description, + int count); + if(obj == target) begin + if(!cnt.exists(source_obj)) + cnt[source_obj] = 0; + cnt[source_obj] = cnt[source_obj]+1; + last_trigger[source_obj] = $realtime; + end + endfunction + virtual function void dropped (uvm_objection objection, + uvm_object obj, + uvm_object source_obj, + string description, + int count); + raised(objection,obj,source_obj,description,count); + endfunction + function void reset_counts; + foreach(cnt[i]) cnt[i] = 0; + endfunction + function int objects_triggered; + objects_triggered = 0; + foreach(cnt[i]) + if (cnt[i] != 0) + objects_triggered++; + endfunction +endclass +class uvm_cmd_line_verb; + string comp_path; + string id; + uvm_verbosity verb; + int exec_time; +endclass +typedef class uvm_cmdline_processor; +uvm_cmdline_processor uvm_cmdline_proc; +class uvm_cmdline_processor extends uvm_report_object; + static local uvm_cmdline_processor m_inst; + static function uvm_cmdline_processor get_inst(); + if(m_inst == null) + m_inst = new("uvm_cmdline_proc"); + uvm_cmdline_proc = m_inst; + return m_inst; + endfunction + protected string m_argv[$]; + protected string m_plus_argv[$]; + protected string m_uvm_argv[$]; + function void get_args (output string args[$]); + args = m_argv; + endfunction + function void get_plusargs (output string args[$]); + args = m_plus_argv; + endfunction + function void get_uvm_args (output string args[$]); + args = m_uvm_argv; + endfunction + function int get_arg_matches (string match, ref string args[$]); + bit match_is_regex = (match.len() > 2) && (match[0] == "/") && (match[match.len()-1] == "/"); + int len = match.len(); + args.delete(); + foreach (m_argv[i]) begin + if ( match_is_regex && uvm_is_match( match, m_argv[i] ) ) begin + args.push_back( m_argv[i] ); + end + else if((m_argv[i].len() >= len) && (m_argv[i].substr(0,len - 1) == match)) begin + args.push_back(m_argv[i]); + end + end + return args.size(); + endfunction + function int get_arg_value (string match, ref string value); + int chars = match.len(); + get_arg_value = 0; + foreach (m_argv[i]) begin + if(m_argv[i].len() >= chars) begin + if(m_argv[i].substr(0,chars-1) == match) begin + get_arg_value++; + if(get_arg_value == 1) + value = m_argv[i].substr(chars,m_argv[i].len()-1); + end + end + end + endfunction + function int get_arg_values (string match, ref string values[$]); + int chars = match.len(); + values.delete(); + foreach (m_argv[i]) begin + if(m_argv[i].len() >= chars) begin + if(m_argv[i].substr(0,chars-1) == match) + values.push_back(m_argv[i].substr(chars,m_argv[i].len()-1)); + end + end + return values.size(); + endfunction + function string get_tool_name (); + return uvm_dpi_get_tool_name(); + endfunction + function string get_tool_version (); + return uvm_dpi_get_tool_version(); + endfunction + function new(string name = ""); + string s; + string sub; + int doInit=1; + super.new(name); + do begin + s = uvm_dpi_get_next_arg(doInit); + doInit=0; + if(s!="") begin + m_argv.push_back(s); + if(s[0] == "+") begin + m_plus_argv.push_back(s); + end + if(s.len() >= 4 && (s[0]=="-" || s[0]=="+")) begin + sub = s.substr(1,3); + sub = sub.toupper(); + if(sub == "UVM") + m_uvm_argv.push_back(s); + end + end + end while(s!=""); + endfunction + function bit m_convert_verb(string verb_str, output uvm_verbosity verb_enum); + case (verb_str) + "NONE" : begin verb_enum = UVM_NONE; return 1; end + "UVM_NONE" : begin verb_enum = UVM_NONE; return 1; end + "LOW" : begin verb_enum = UVM_LOW; return 1; end + "UVM_LOW" : begin verb_enum = UVM_LOW; return 1; end + "MEDIUM" : begin verb_enum = UVM_MEDIUM; return 1; end + "UVM_MEDIUM" : begin verb_enum = UVM_MEDIUM; return 1; end + "HIGH" : begin verb_enum = UVM_HIGH; return 1; end + "UVM_HIGH" : begin verb_enum = UVM_HIGH; return 1; end + "FULL" : begin verb_enum = UVM_FULL; return 1; end + "UVM_FULL" : begin verb_enum = UVM_FULL; return 1; end + "DEBUG" : begin verb_enum = UVM_DEBUG; return 1; end + "UVM_DEBUG" : begin verb_enum = UVM_DEBUG; return 1; end + default : begin return 0; end + endcase + endfunction +endclass +virtual class uvm_visitor#(type NODE=uvm_component) extends uvm_object; + function new (string name = ""); + super.new(name); + endfunction + virtual function void begin_v(); endfunction + virtual function void end_v(); endfunction + pure virtual function void visit(NODE node); +endclass +virtual class uvm_structure_proxy#(type STRUCTURE=uvm_component) extends uvm_object; + function new (string name = ""); + super.new(name); + endfunction + pure virtual function void get_immediate_children(STRUCTURE s, ref STRUCTURE children[$]); +endclass +virtual class uvm_visitor_adapter#(type STRUCTURE=uvm_component,VISITOR=uvm_visitor#(STRUCTURE)) extends uvm_object; + pure virtual function void accept(STRUCTURE s, VISITOR v,uvm_structure_proxy#(STRUCTURE) p, bit invoke_begin_end=1); + function new (string name = ""); + super.new(name); + endfunction +endclass +class uvm_top_down_visitor_adapter#(type STRUCTURE=uvm_component,VISITOR=uvm_visitor#(STRUCTURE)) extends + uvm_visitor_adapter#(STRUCTURE,VISITOR); + function new (string name = ""); + super.new(name); + endfunction + virtual function void accept(STRUCTURE s, VISITOR v,uvm_structure_proxy#(STRUCTURE) p, bit invoke_begin_end=1); + STRUCTURE c[$]; + if(invoke_begin_end) + v.begin_v(); + v.visit(s); + p.get_immediate_children(s, c); + foreach(c[idx]) + accept(c[idx],v,p,0); + if(invoke_begin_end) + v.end_v(); + endfunction +endclass +class uvm_bottom_up_visitor_adapter#(type STRUCTURE=uvm_component,VISITOR=uvm_visitor#(STRUCTURE)) extends + uvm_visitor_adapter#(STRUCTURE,VISITOR); + function new (string name = ""); + super.new(name); + endfunction + virtual function void accept(STRUCTURE s, VISITOR v,uvm_structure_proxy#(STRUCTURE) p, bit invoke_begin_end=1); + STRUCTURE c[$]; + if(invoke_begin_end) + v.begin_v(); + p.get_immediate_children(s, c); + foreach(c[idx]) + accept(c[idx],v,p,0); + v.visit(s); + if(invoke_begin_end) + v.end_v(); + endfunction +endclass +class uvm_by_level_visitor_adapter#(type STRUCTURE=uvm_component,VISITOR=uvm_visitor#(STRUCTURE)) extends + uvm_visitor_adapter#(STRUCTURE,VISITOR); + function new (string name = ""); + super.new(name); + endfunction + virtual function void accept(STRUCTURE s, VISITOR v,uvm_structure_proxy#(STRUCTURE) p, bit invoke_begin_end=1); + STRUCTURE c[$]; + c.push_back(s); + if(invoke_begin_end) + v.begin_v(); + while(c.size() > 0) begin + STRUCTURE q[$]; + foreach(c[idx]) begin + STRUCTURE t[$]; + v.visit(c[idx]); + p.get_immediate_children(c[idx], t); + q = {q,t}; + end + c=q; + end + if(invoke_begin_end) + v.end_v(); + endfunction +endclass +class uvm_component_proxy extends uvm_structure_proxy#(uvm_component); + virtual function void get_immediate_children(STRUCTURE s, ref STRUCTURE children[$]); + s.get_children(children); + endfunction + function new (string name = ""); + super.new(name); + endfunction +endclass +class uvm_component_name_check_visitor extends uvm_visitor#(uvm_component); + local uvm_root _root; + virtual function string get_name_constraint(); + return "/^[][[:alnum:](){}_:-]([][[:alnum:](){} _:-]*[][[:alnum:](){}_:-])?$/"; + endfunction + virtual function void visit(NODE node); + if(_root != node) begin + if ( ! uvm_is_match( get_name_constraint(), node.get_name() ) ) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/COMP/NAME")) + uvm_report_warning ("UVM/COMP/NAME", $sformatf("the name \"%s\" of the component \"%s\" violates the uvm component name constraints",node.get_name(),node.get_full_name()), UVM_NONE, "t/uvm/src/base/uvm_traversal.svh", 274, "", 1); + end + end + end + endfunction + function new (string name = ""); + super.new(name); + endfunction + virtual function void begin_v(); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + _root = cs.get_root(); + endfunction +endclass +virtual class uvm_set_get_dap_base#(type T=int) extends uvm_object; + typedef uvm_set_get_dap_base#(T) this_type; + function new(string name="unnamed-uvm_set_get_dap_base#(T)"); + super.new(name); + endfunction : new + pure virtual function void set(T value); + pure virtual function bit try_set(T value); + pure virtual function T get(); + pure virtual function bit try_get(output T value); +endclass : uvm_set_get_dap_base +class uvm_simple_lock_dap#(type T=int) extends uvm_set_get_dap_base#(T); + typedef uvm_simple_lock_dap#(T) this_type; + typedef uvm_object_registry #(uvm_simple_lock_dap#(T)) type_id; + static function uvm_simple_lock_dap#(T) type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_simple_lock_dap#(T) tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + local T m_value; + local bit m_locked; + function new(string name="unnamed-uvm_simple_lock_dap#(T)"); + super.new(name); + m_locked = 0; + endfunction : new + virtual function void set(T value); + if (m_locked) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/SIMPLE_LOCK_DAP/SAG")) + uvm_report_error ("UVM/SIMPLE_LOCK_DAP/SAG", $sformatf("Attempt to set new value on '%s', but the data access policy forbids setting while locked!", get_full_name()), UVM_NONE, "t/uvm/src/dap/uvm_simple_lock_dap.svh", 68, "", 1); + end + else begin + m_value = value; + end + endfunction : set + virtual function bit try_set(T value); + if (m_locked) + return 0; + else begin + m_value = value; + return 1; + end + endfunction : try_set + virtual function T get(); + return m_value; + endfunction : get + virtual function bit try_get(output T value); + value = get(); + return 1; + endfunction : try_get + function void lock(); + m_locked = 1; + endfunction : lock + function void unlock(); + m_locked = 0; + endfunction : unlock + function bit is_locked(); + return m_locked; + endfunction : is_locked + virtual function void do_copy(uvm_object rhs); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/SIMPLE_LOCK_DAP/CPY")) + uvm_report_error ("UVM/SIMPLE_LOCK_DAP/CPY", "'copy()' is not supported for 'uvm_simple_lock_dap#(T)'", UVM_NONE, "t/uvm/src/dap/uvm_simple_lock_dap.svh", 144, "", 1); + end + endfunction : do_copy + virtual function void do_pack(uvm_packer packer); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/SIMPLE_LOCK_DAP/PCK")) + uvm_report_error ("UVM/SIMPLE_LOCK_DAP/PCK", "'pack()' is not supported for 'uvm_simple_lock_dap#(T)'", UVM_NONE, "t/uvm/src/dap/uvm_simple_lock_dap.svh", 149, "", 1); + end + endfunction : do_pack + virtual function void do_unpack(uvm_packer packer); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/SIMPLE_LOCK_DAP/UPK")) + uvm_report_error ("UVM/SIMPLE_LOCK_DAP/UPK", "'unpack()' is not supported for 'uvm_simple_lock_dap#(T)'", UVM_NONE, "t/uvm/src/dap/uvm_simple_lock_dap.svh", 154, "", 1); + end + endfunction : do_unpack + virtual function string convert2string(); + if (m_locked) + return $sformatf("(%s) %0p [LOCKED]", $typename(m_value), m_value); + else + return $sformatf("(%s) %0p [UNLOCKED]", $typename(m_value), m_value); + endfunction : convert2string + virtual function void do_print(uvm_printer printer); + super.do_print(printer); + printer.print_field("lock_state", m_locked, $bits(m_locked)); + printer.print_generic("value", + $typename(m_value), + 0, + $sformatf("%0p", m_value)); + endfunction : do_print +endclass +class uvm_get_to_lock_dap#(type T=int) extends uvm_set_get_dap_base#(T); + typedef uvm_get_to_lock_dap#(T) this_type; + typedef uvm_object_registry #(uvm_get_to_lock_dap#(T)) type_id; + static function uvm_get_to_lock_dap#(T) type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_get_to_lock_dap#(T) tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + local T m_value; + local bit m_locked; + function new(string name="unnamed-uvm_get_to_lock_dap#(T)"); + super.new(name); + m_locked = 0; + endfunction : new + virtual function void set(T value); + if (m_locked) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/GET_TO_LOCK_DAP/SAG")) + uvm_report_error ("UVM/GET_TO_LOCK_DAP/SAG", $sformatf("Attempt to set new value on '%s', but the data access policy forbids setting after a get!", get_full_name()), UVM_NONE, "t/uvm/src/dap/uvm_get_to_lock_dap.svh", 67, "", 1); + end + else begin + m_value = value; + end + endfunction : set + virtual function bit try_set(T value); + if (m_locked) + return 0; + else begin + m_value = value; + return 1; + end + endfunction : try_set + virtual function T get(); + m_locked = 1; + return m_value; + endfunction : get + virtual function bit try_get(output T value); + value = get(); + return 1; + endfunction : try_get + virtual function void do_copy(uvm_object rhs); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/GET_TO_LOCK_DAP/CPY")) + uvm_report_error ("UVM/GET_TO_LOCK_DAP/CPY", "'copy()' is not supported for 'uvm_get_to_lock_dap#(T)'", UVM_NONE, "t/uvm/src/dap/uvm_get_to_lock_dap.svh", 119, "", 1); + end + endfunction : do_copy + virtual function void do_pack(uvm_packer packer); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/GET_TO_LOCK_DAP/PCK")) + uvm_report_error ("UVM/GET_TO_LOCK_DAP/PCK", "'pack()' is not supported for 'uvm_get_to_lock_dap#(T)'", UVM_NONE, "t/uvm/src/dap/uvm_get_to_lock_dap.svh", 124, "", 1); + end + endfunction : do_pack + virtual function void do_unpack(uvm_packer packer); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/GET_TO_LOCK_DAP/UPK")) + uvm_report_error ("UVM/GET_TO_LOCK_DAP/UPK", "'unpack()' is not supported for 'uvm_get_to_lock_dap#(T)'", UVM_NONE, "t/uvm/src/dap/uvm_get_to_lock_dap.svh", 129, "", 1); + end + endfunction : do_unpack + virtual function string convert2string(); + if (m_locked) + return $sformatf("(%s) %0p [LOCKED]", $typename(m_value), m_value); + else + return $sformatf("(%s) %0p [UNLOCKED]", $typename(m_value), m_value); + endfunction : convert2string + virtual function void do_print(uvm_printer printer); + super.do_print(printer); + printer.print_field_int("lock_state", m_locked, $bits(m_locked)); + printer.print_generic("value", + $typename(m_value), + 0, + $sformatf("%0p", m_value)); + endfunction : do_print +endclass +class uvm_set_before_get_dap#(type T=int) extends uvm_set_get_dap_base#(T); + typedef uvm_set_before_get_dap#(T) this_type; + typedef uvm_object_registry #(uvm_set_before_get_dap#(T)) type_id; + static function uvm_set_before_get_dap#(T) type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_set_before_get_dap#(T) tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + local T m_value; + local bit m_set; + function new(string name="unnamed-uvm_set_before_get_dap#(T)"); + super.new(name); + m_set = 0; + endfunction : new + virtual function void set(T value); + m_set = 1; + m_value = value; + endfunction : set + virtual function bit try_set(T value); + set(value); + return 1; + endfunction : try_set + virtual function T get(); + if (!m_set) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/SET_BEFORE_GET_DAP/NO_SET")) + uvm_report_error ("UVM/SET_BEFORE_GET_DAP/NO_SET", $sformatf("Attempt to get value on '%s', but the data access policy forbits calling 'get' prior to calling 'set' or 'try_set'!", get_full_name()), UVM_NONE, "t/uvm/src/dap/uvm_set_before_get_dap.svh", 117, "", 1); + end + end + return m_value; + endfunction : get + virtual function bit try_get(output T value); + if (!m_set) begin + return 0; + end + else begin + value = m_value; + return 1; + end + endfunction : try_get + virtual function void do_copy(uvm_object rhs); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/SET_BEFORE_GET_DAP/CPY")) + uvm_report_error ("UVM/SET_BEFORE_GET_DAP/CPY", "'copy()' is not supported for 'uvm_set_before_get_dap#(T)'", UVM_NONE, "t/uvm/src/dap/uvm_set_before_get_dap.svh", 149, "", 1); + end + endfunction : do_copy + virtual function void do_pack(uvm_packer packer); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/SET_BEFORE_GET_DAP/PCK")) + uvm_report_error ("UVM/SET_BEFORE_GET_DAP/PCK", "'pack()' is not supported for 'uvm_set_before_get_dap#(T)'", UVM_NONE, "t/uvm/src/dap/uvm_set_before_get_dap.svh", 154, "", 1); + end + endfunction : do_pack + virtual function void do_unpack(uvm_packer packer); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/SET_BEFORE_GET_DAP/UPK")) + uvm_report_error ("UVM/SET_BEFORE_GET_DAP/UPK", "'unpack()' is not supported for 'uvm_set_before_get_dap#(T)'", UVM_NONE, "t/uvm/src/dap/uvm_set_before_get_dap.svh", 159, "", 1); + end + endfunction : do_unpack + virtual function string convert2string(); + if (m_set) + return $sformatf("(%s) %0p [SET]", $typename(m_value), m_value); + else + return $sformatf("(%s) %0p [UNSET]", $typename(m_value), m_value); + endfunction : convert2string + virtual function void do_print(uvm_printer printer); + super.do_print(printer); + printer.print_field_int("set_state", m_set, $bits(m_set)); + printer.print_generic("value", + $typename(m_value), + 0, + $sformatf("%0p", m_value)); + endfunction : do_print +endclass +virtual class uvm_tlm_if_base #(type T1=int, type T2=int); + virtual task put( input T1 t ); + uvm_report_error("put", "UVM TLM interface task not implemented", UVM_NONE); + endtask + virtual task get( output T2 t ); + uvm_report_error("get", "UVM TLM interface task not implemented", UVM_NONE); + endtask + virtual task peek( output T2 t ); + uvm_report_error("peek", "UVM TLM interface task not implemented", UVM_NONE); + endtask + virtual function bit try_put( input T1 t ); + uvm_report_error("try_put", "UVM TLM interface function not implemented", UVM_NONE); + return 0; + endfunction + virtual function bit can_put(); + uvm_report_error("can_put", "UVM TLM interface function not implemented", UVM_NONE); + return 0; + endfunction + virtual function bit try_get( output T2 t ); + uvm_report_error("try_get", "UVM TLM interface function not implemented", UVM_NONE); + return 0; + endfunction + virtual function bit can_get(); + uvm_report_error("can_get", "UVM TLM interface function not implemented", UVM_NONE); + return 0; + endfunction + virtual function bit try_peek( output T2 t ); + uvm_report_error("try_peek", "UVM TLM interface function not implemented", UVM_NONE); + return 0; + endfunction + virtual function bit can_peek(); + uvm_report_error("can_ppeek", "UVM TLM interface function not implemented", UVM_NONE); + return 0; + endfunction + virtual task transport( input T1 req , output T2 rsp ); + uvm_report_error("transport", "UVM TLM interface task not implemented", UVM_NONE); + endtask + virtual function bit nb_transport(input T1 req, output T2 rsp); + uvm_report_error("nb_transport", "UVM TLM interface function not implemented", UVM_NONE); + return 0; + endfunction + virtual function void write( input T1 t ); + uvm_report_error("write", "UVM TLM interface function not implemented", UVM_NONE); + endfunction +endclass +virtual class uvm_sqr_if_base #(type T1=uvm_object, T2=T1); + virtual task get_next_item(output T1 t); + uvm_report_error("get_next_item", "Sequencer interface task not implemented", UVM_NONE); + endtask + virtual task try_next_item(output T1 t); + uvm_report_error("try_next_item", "Sequencer interface task not implemented", UVM_NONE); + endtask + virtual function void item_done(input T2 t = null); + uvm_report_error("item_done", "Sequencer interface function not implemented", UVM_NONE); + endfunction + virtual task wait_for_sequences(); + uvm_report_error("wait_for_sequences", "Sequencer interface task not implemented", UVM_NONE); + endtask + virtual function bit has_do_available(); + uvm_report_error("has_do_available", "Sequencer interface function not implemented", UVM_NONE); + return 0; + endfunction + virtual task get(output T1 t); + uvm_report_error("get", "Sequencer interface task not implemented", UVM_NONE); + endtask + virtual task peek(output T1 t); + uvm_report_error("peek", "Sequencer interface task not implemented", UVM_NONE); + endtask + virtual task put(input T2 t); + uvm_report_error("put", "Sequencer interface task not implemented", UVM_NONE); + endtask + virtual function void put_response(input T2 t); + uvm_report_error("put_response", "Sequencer interface function not implemented", UVM_NONE); + endfunction + virtual function void disable_auto_item_recording(); + uvm_report_error("disable_auto_item_recording", "Sequencer interface function not implemented", UVM_NONE); + endfunction + virtual function bit is_auto_item_recording_enabled(); + uvm_report_error("is_auto_item_recording_enabled", "Sequencer interface function not implemented", UVM_NONE); + return 0; + endfunction +endclass +const int UVM_UNBOUNDED_CONNECTIONS = -1; +const string s_connection_error_id = "Connection Error"; +const string s_connection_warning_id = "Connection Warning"; +const string s_spaces = " "; +typedef class uvm_port_component_base; +typedef uvm_port_component_base uvm_port_list[string]; +virtual class uvm_port_component_base extends uvm_component; + function new (string name, uvm_component parent); + super.new(name,parent); + endfunction + pure virtual function void get_connected_to(ref uvm_port_list list); + pure virtual function bit is_port(); + pure virtual function bit is_export(); + pure virtual function bit is_imp(); + virtual function bit use_automatic_config(); + return 0; + endfunction : use_automatic_config + virtual task do_task_phase (uvm_phase phase); + endtask +endclass +class uvm_port_component #(type PORT=uvm_object) extends uvm_port_component_base; + PORT m_port; + function new (string name, uvm_component parent, PORT port); + super.new(name,parent); + if (port == null) + uvm_report_fatal("Bad usage", "Null handle to port", UVM_NONE); + m_port = port; + endfunction + virtual function string get_type_name(); + if(m_port == null) return "uvm_port_component"; + return m_port.get_type_name(); + endfunction + virtual function void resolve_bindings(); + m_port.resolve_bindings(); + endfunction + function PORT get_port(); + return m_port; + endfunction + virtual function void get_connected_to(ref uvm_port_list list); + PORT list1[string]; + m_port.get_connected_to(list1); + list.delete(); + foreach(list1[name]) begin + list[name] = list1[name].get_comp(); + end + endfunction + function bit is_port (); + return m_port.is_port(); + endfunction + function bit is_export (); + return m_port.is_export(); + endfunction + function bit is_imp (); + return m_port.is_imp(); + endfunction +endclass +virtual class uvm_port_base #(type IF=uvm_void) extends IF; + typedef uvm_port_base #(IF) this_type; + protected int unsigned m_if_mask; + protected this_type m_if; + protected int unsigned m_def_index; + uvm_port_component #(this_type) m_comp; + local this_type m_provided_by[string]; + local this_type m_provided_to[string]; + local uvm_port_type_e m_port_type; + local int m_min_size; + local int m_max_size; + local bit m_resolved; + local this_type m_imp_list[string]; + function new (string name, + uvm_component parent, + uvm_port_type_e port_type, + int min_size=0, + int max_size=1); + uvm_component comp; + int tmp; + m_port_type = port_type; + m_min_size = min_size; + m_max_size = max_size; + m_comp = new(name, parent, this); +//TODO issue #4467 - Fix UVM function output width reassignment +//TODO %Error-UNSUPPORTED: t/t_uvm_pkg_todo.vh:15875:75: Unsupported: Function output argument 'value' requires 4096 bits, but connection's VARREF 'tmp' generates 32 bits. +//TODO if (!uvm_config_int::get(m_comp, "", "check_connection_relationships",tmp)) +//TODO m_comp.set_report_id_action(s_connection_warning_id, UVM_NO_ACTION); + endfunction + function string get_name(); + return m_comp.get_name(); + endfunction + virtual function string get_full_name(); + return m_comp.get_full_name(); + endfunction + virtual function uvm_component get_parent(); + return m_comp.get_parent(); + endfunction + virtual function uvm_port_component_base get_comp(); + return m_comp; + endfunction + virtual function string get_type_name(); + case( m_port_type ) + UVM_PORT : return "port"; + UVM_EXPORT : return "export"; + UVM_IMPLEMENTATION : return "implementation"; + endcase + endfunction + function int max_size (); + return m_max_size; + endfunction + function int min_size (); + return m_min_size; + endfunction + function bit is_unbounded (); + return (m_max_size == UVM_UNBOUNDED_CONNECTIONS); + endfunction + function bit is_port (); + return m_port_type == UVM_PORT; + endfunction + function bit is_export (); + return m_port_type == UVM_EXPORT; + endfunction + function bit is_imp (); + return m_port_type == UVM_IMPLEMENTATION; + endfunction + function int size (); + return m_imp_list.num(); + endfunction + function void set_if (int index=0); + m_if = get_if(index); + if (m_if != null) + m_def_index = index; + endfunction + function int m_get_if_mask(); + return m_if_mask; + endfunction + function void set_default_index (int index); + m_def_index = index; + endfunction + virtual function void connect (this_type provider); + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + if (end_of_elaboration_ph.get_state() == UVM_PHASE_EXECUTING || + end_of_elaboration_ph.get_state() == UVM_PHASE_DONE ) begin + m_comp.uvm_report_warning("Late Connection", + {"Attempt to connect ",this.get_full_name()," (of type ",this.get_type_name(), + ") at or after end_of_elaboration phase. Ignoring."}); + return; + end + if (provider == null) begin + m_comp.uvm_report_error(s_connection_error_id, + "Cannot connect to null port handle", UVM_NONE); + return; + end + if (provider == this) begin + m_comp.uvm_report_error(s_connection_error_id, + "Cannot connect a port instance to itself", UVM_NONE); + return; + end + if ((provider.m_if_mask & m_if_mask) != m_if_mask) begin + m_comp.uvm_report_error(s_connection_error_id, + {provider.get_full_name(), + " (of type ",provider.get_type_name(), + ") does not provide the complete interface required of this port (type ", + get_type_name(),")"}, UVM_NONE); + return; + end + if (is_imp()) begin + m_comp.uvm_report_error(s_connection_error_id, + $sformatf( +"Cannot call an imp port's connect method. An imp is connected only to the component passed in its constructor. (You attempted to bind this imp to %s)", provider.get_full_name()), UVM_NONE); + return; + end + if (is_export() && provider.is_port()) begin + m_comp.uvm_report_error(s_connection_error_id, + $sformatf( +"Cannot connect exports to ports Try calling port.connect(export) instead. (You attempted to bind this export to %s).", provider.get_full_name()), UVM_NONE); + return; + end + void'(m_check_relationship(provider)); + m_provided_by[provider.get_full_name()] = provider; + provider.m_provided_to[get_full_name()] = this; + endfunction + function void debug_connected_to (int level=0, int max_level=-1); + int sz, num, curr_num; + string s_sz; + static string indent, save; + this_type port; + if (level < 0) level = 0; + if (level == 0) begin save = ""; indent=" "; end + if (max_level != -1 && level >= max_level) + return; + num = m_provided_by.num(); + if (m_provided_by.num() != 0) begin + foreach (m_provided_by[nm]) begin + curr_num++; + port = m_provided_by[nm]; + save = {save, indent, " | \n"}; + save = {save, indent, " |_",nm," (",port.get_type_name(),")\n"}; + indent = (num > 1 && curr_num != num) ? {indent," | "}:{indent, " "}; + port.debug_connected_to(level+1, max_level); + indent = indent.substr(0,indent.len()-4-1); + end + end + if (level == 0) begin + if (save != "") + save = {"This port's fanout network:\n\n ", + get_full_name()," (",get_type_name(),")\n",save,"\n"}; + if (m_imp_list.num() == 0) begin + uvm_root top; + uvm_coreservice_t cs; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + if (end_of_elaboration_ph.get_state() == UVM_PHASE_EXECUTING || + end_of_elaboration_ph.get_state() == UVM_PHASE_DONE ) + save = {save," Connected implementations: none\n"}; + else + save = {save, + " Connected implementations: not resolved until end-of-elab\n"}; + end + else begin + save = {save," Resolved implementation list:\n"}; + foreach (m_imp_list[nm]) begin + port = m_imp_list[nm]; + s_sz.itoa(sz); + save = {save, indent, s_sz, ": ",nm," (",port.get_type_name(),")\n"}; + sz++; + end + end + m_comp.uvm_report_info("debug_connected_to", save); + end + endfunction + function void debug_provided_to (int level=0, int max_level=-1); + string nm; + int num,curr_num; + this_type port; + static string indent, save; + if (level < 0) level = 0; + if (level == 0) begin save = ""; indent = " "; end + if (max_level != -1 && level > max_level) + return; + num = m_provided_to.num(); + if (num != 0) begin + foreach (m_provided_to[nm]) begin + curr_num++; + port = m_provided_to[nm]; + save = {save, indent, " | \n"}; + save = {save, indent, " |_",nm," (",port.get_type_name(),")\n"}; + indent = (num > 1 && curr_num != num) ? {indent," | "}:{indent, " "}; + port.debug_provided_to(level+1, max_level); + indent = indent.substr(0,indent.len()-4-1); + end + end + if (level == 0) begin + if (save != "") + save = {"This port's fanin network:\n\n ", + get_full_name()," (",get_type_name(),")\n",save,"\n"}; + if (m_provided_to.num() == 0) + save = {save,indent,"This port has not been bound\n"}; + m_comp.uvm_report_info("debug_provided_to", save); + end + endfunction + function void get_connected_to (ref uvm_port_base #(IF) list[string]); + this_type port; + list.delete(); + foreach (m_provided_by[name]) begin + port = m_provided_by[name]; + list[name] = port; + end + endfunction + function void get_provided_to (ref uvm_port_base #(IF) list[string]); + this_type port; + list.delete(); + foreach (m_provided_to[name]) begin + port = m_provided_to[name]; + list[name] = port; + end + endfunction + local function bit m_check_relationship (this_type provider); + string s; + this_type from; + uvm_component from_parent; + uvm_component to_parent; + uvm_component from_gparent; + uvm_component to_gparent; + if (get_type_name() == "uvm_analysis_port") + return 1; + from = this; + from_parent = get_parent(); + to_parent = provider.get_parent(); + if (from_parent == null || to_parent == null) + return 1; + from_gparent = from_parent.get_parent(); + to_gparent = to_parent.get_parent(); + if (from.is_port() && provider.is_port() && from_gparent != to_parent) begin + s = {provider.get_full_name(), + " (of type ",provider.get_type_name(), + ") is not up one level of hierarchy from this port. ", + "A port-to-port connection takes the form ", + "child_component.child_port.connect(parent_port)"}; + m_comp.uvm_report_warning(s_connection_warning_id, s, UVM_NONE); + return 0; + end + else if (from.is_port() && (provider.is_export() || provider.is_imp()) && + from_gparent != to_gparent) begin + s = {provider.get_full_name(), + " (of type ",provider.get_type_name(), + ") is not at the same level of hierarchy as this port. ", + "A port-to-export connection takes the form ", + "component1.port.connect(component2.export)"}; + m_comp.uvm_report_warning(s_connection_warning_id, s, UVM_NONE); + return 0; + end + else if (from.is_export() && (provider.is_export() || provider.is_imp()) && + from_parent != to_gparent) begin + s = {provider.get_full_name(), + " (of type ",provider.get_type_name(), + ") is not down one level of hierarchy from this export. ", + "An export-to-export or export-to-imp connection takes the form ", + "parent_export.connect(child_component.child_export)"}; + m_comp.uvm_report_warning(s_connection_warning_id, s, UVM_NONE); + return 0; + end + return 1; + endfunction + local function void m_add_list (this_type provider); + string sz; + this_type imp; + for (int i = 0; i < provider.size(); i++) begin + imp = provider.get_if(i); + if (!m_imp_list.exists(imp.get_full_name())) + m_imp_list[imp.get_full_name()] = imp; + end + endfunction + virtual function void resolve_bindings(); + if (m_resolved) + return; + if (is_imp()) begin + m_imp_list[get_full_name()] = this; + end + else begin + foreach (m_provided_by[nm]) begin + this_type port; + port = m_provided_by[nm]; + port.resolve_bindings(); + m_add_list(port); + end + end + m_resolved = 1; + if (size() < min_size() ) begin + m_comp.uvm_report_error(s_connection_error_id, + $sformatf("connection count of %0d does not meet required minimum of %0d", + size(), min_size()), UVM_NONE); + end + if (max_size() != UVM_UNBOUNDED_CONNECTIONS && size() > max_size() ) begin + m_comp.uvm_report_error(s_connection_error_id, + $sformatf("connection count of %0d exceeds maximum of %0d", + size(), max_size()), UVM_NONE); + end + if (size()) + set_if(0); + endfunction + function uvm_port_base #(IF) get_if(int index=0); + string s; + if (size()==0) begin + m_comp.uvm_report_warning("get_if", + "Port size is zero; cannot get interface at any index", UVM_NONE); + return null; + end + if (index < 0 || index >= size()) begin + $sformat(s, "Index %0d out of range [0,%0d]", index, size()-1); + m_comp.uvm_report_warning(s_connection_error_id, s, UVM_NONE); + return null; + end + foreach (m_imp_list[nm]) begin + if (index == 0) + return m_imp_list[nm]; + index--; + end + endfunction +endclass +class uvm_blocking_put_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = (1<<0); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_put_imp"; + endfunction + task put (T t); + m_imp.put(t); + endtask +endclass +class uvm_nonblocking_put_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = (1<<4); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_put_imp"; + endfunction + function bit try_put (T t); + return m_imp.try_put(t); + endfunction + function bit can_put(); + return m_imp.can_put(); + endfunction +endclass +class uvm_put_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = ((1<<0) | (1<<4)); + endfunction + virtual function string get_type_name(); + return "uvm_put_imp"; + endfunction + task put (T t); + m_imp.put(t); + endtask + function bit try_put (T t); + return m_imp.try_put(t); + endfunction + function bit can_put(); + return m_imp.can_put(); + endfunction +endclass +class uvm_blocking_get_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = (1<<1); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_get_imp"; + endfunction + task get (output T t); + m_imp.get(t); + endtask +endclass +class uvm_nonblocking_get_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = (1<<5); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_get_imp"; + endfunction + function bit try_get (output T t); + return m_imp.try_get(t); + endfunction + function bit can_get(); + return m_imp.can_get(); + endfunction +endclass +class uvm_get_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = ((1<<1) | (1<<5)); + endfunction + virtual function string get_type_name(); + return "uvm_get_imp"; + endfunction + task get (output T t); + m_imp.get(t); + endtask + function bit try_get (output T t); + return m_imp.try_get(t); + endfunction + function bit can_get(); + return m_imp.can_get(); + endfunction +endclass +class uvm_blocking_peek_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = (1<<2); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_peek_imp"; + endfunction + task peek (output T t); + m_imp.peek(t); + endtask +endclass +class uvm_nonblocking_peek_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = (1<<6); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_peek_imp"; + endfunction + function bit try_peek (output T t); + return m_imp.try_peek(t); + endfunction + function bit can_peek(); + return m_imp.can_peek(); + endfunction +endclass +class uvm_peek_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = ((1<<2) | (1<<6)); + endfunction + virtual function string get_type_name(); + return "uvm_peek_imp"; + endfunction + task peek (output T t); + m_imp.peek(t); + endtask + function bit try_peek (output T t); + return m_imp.try_peek(t); + endfunction + function bit can_peek(); + return m_imp.can_peek(); + endfunction +endclass +class uvm_blocking_get_peek_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = ((1<<1) | (1<<2)); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_get_peek_imp"; + endfunction + task get (output T t); + m_imp.get(t); + endtask + task peek (output T t); + m_imp.peek(t); + endtask +endclass +class uvm_nonblocking_get_peek_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = ((1<<5) | (1<<6)); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_get_peek_imp"; + endfunction + function bit try_get (output T t); + return m_imp.try_get(t); + endfunction + function bit can_get(); + return m_imp.can_get(); + endfunction + function bit try_peek (output T t); + return m_imp.try_peek(t); + endfunction + function bit can_peek(); + return m_imp.can_peek(); + endfunction +endclass +class uvm_get_peek_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = (((1<<1) | (1<<5)) | ((1<<2) | (1<<6))); + endfunction + virtual function string get_type_name(); + return "uvm_get_peek_imp"; + endfunction + task get (output T t); + m_imp.get(t); + endtask + task peek (output T t); + m_imp.peek(t); + endtask + function bit try_get (output T t); + return m_imp.try_get(t); + endfunction + function bit can_get(); + return m_imp.can_get(); + endfunction + function bit try_peek (output T t); + return m_imp.try_peek(t); + endfunction + function bit can_peek(); + return m_imp.can_peek(); + endfunction +endclass +class uvm_blocking_master_imp #(type REQ=int, type RSP=REQ, type IMP=int, + type REQ_IMP=IMP, type RSP_IMP=IMP) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + typedef IMP this_imp_type; + typedef REQ_IMP this_req_type; + typedef RSP_IMP this_rsp_type; + local this_req_type m_req_imp; + local this_rsp_type m_rsp_imp; + function new (string name, this_imp_type imp, + this_req_type req_imp = null, this_rsp_type rsp_imp = null); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + if(req_imp==null) $cast(req_imp, imp); + if(rsp_imp==null) $cast(rsp_imp, imp); + m_req_imp = req_imp; + m_rsp_imp = rsp_imp; + m_if_mask = ((1<<0) | (1<<1) | (1<<2) | (1<<9)); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_master_imp"; + endfunction + task put (REQ t); + m_req_imp.put(t); + endtask + task get (output RSP t); + m_rsp_imp.get(t); + endtask + task peek (output RSP t); + m_rsp_imp.peek(t); + endtask +endclass +class uvm_nonblocking_master_imp #(type REQ=int, type RSP=REQ, type IMP=int, + type REQ_IMP=IMP, type RSP_IMP=IMP) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + typedef IMP this_imp_type; + typedef REQ_IMP this_req_type; + typedef RSP_IMP this_rsp_type; + local this_req_type m_req_imp; + local this_rsp_type m_rsp_imp; + function new (string name, this_imp_type imp, + this_req_type req_imp = null, this_rsp_type rsp_imp = null); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + if(req_imp==null) $cast(req_imp, imp); + if(rsp_imp==null) $cast(rsp_imp, imp); + m_req_imp = req_imp; + m_rsp_imp = rsp_imp; + m_if_mask = ((1<<4) | (1<<5) | (1<<6) | (1<<9)); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_master_imp"; + endfunction + function bit try_put (REQ t); + return m_req_imp.try_put(t); + endfunction + function bit can_put(); + return m_req_imp.can_put(); + endfunction + function bit try_get (output RSP t); + return m_rsp_imp.try_get(t); + endfunction + function bit can_get(); + return m_rsp_imp.can_get(); + endfunction + function bit try_peek (output RSP t); + return m_rsp_imp.try_peek(t); + endfunction + function bit can_peek(); + return m_rsp_imp.can_peek(); + endfunction +endclass +class uvm_master_imp #(type REQ=int, type RSP=REQ, type IMP=int, + type REQ_IMP=IMP, type RSP_IMP=IMP) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + typedef IMP this_imp_type; + typedef REQ_IMP this_req_type; + typedef RSP_IMP this_rsp_type; + local this_req_type m_req_imp; + local this_rsp_type m_rsp_imp; + function new (string name, this_imp_type imp, + this_req_type req_imp = null, this_rsp_type rsp_imp = null); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + if(req_imp==null) $cast(req_imp, imp); + if(rsp_imp==null) $cast(rsp_imp, imp); + m_req_imp = req_imp; + m_rsp_imp = rsp_imp; + m_if_mask = (((1<<0) | (1<<1) | (1<<2) | (1<<9)) | ((1<<4) | (1<<5) | (1<<6) | (1<<9))); + endfunction + virtual function string get_type_name(); + return "uvm_master_imp"; + endfunction + task put (REQ t); + m_req_imp.put(t); + endtask + function bit try_put (REQ t); + return m_req_imp.try_put(t); + endfunction + function bit can_put(); + return m_req_imp.can_put(); + endfunction + task get (output RSP t); + m_rsp_imp.get(t); + endtask + task peek (output RSP t); + m_rsp_imp.peek(t); + endtask + function bit try_get (output RSP t); + return m_rsp_imp.try_get(t); + endfunction + function bit can_get(); + return m_rsp_imp.can_get(); + endfunction + function bit try_peek (output RSP t); + return m_rsp_imp.try_peek(t); + endfunction + function bit can_peek(); + return m_rsp_imp.can_peek(); + endfunction +endclass +class uvm_blocking_slave_imp #(type REQ=int, type RSP=REQ, type IMP=int, + type REQ_IMP=IMP, type RSP_IMP=IMP) + extends uvm_port_base #(uvm_tlm_if_base #(RSP, REQ)); + typedef IMP this_imp_type; + typedef REQ_IMP this_req_type; + typedef RSP_IMP this_rsp_type; + local this_req_type m_req_imp; + local this_rsp_type m_rsp_imp; + function new (string name, this_imp_type imp, + this_req_type req_imp = null, this_rsp_type rsp_imp = null); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + if(req_imp==null) $cast(req_imp, imp); + if(rsp_imp==null) $cast(rsp_imp, imp); + m_req_imp = req_imp; + m_rsp_imp = rsp_imp; + m_if_mask = ((1<<0) | (1<<1) | (1<<2) | (1<<10)); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_slave_imp"; + endfunction + task put (RSP t); + m_rsp_imp.put(t); + endtask + task get (output REQ t); + m_req_imp.get(t); + endtask + task peek (output REQ t); + m_req_imp.peek(t); + endtask +endclass +class uvm_nonblocking_slave_imp #(type REQ=int, type RSP=REQ, type IMP=int, + type REQ_IMP=IMP, type RSP_IMP=IMP) + extends uvm_port_base #(uvm_tlm_if_base #(RSP, REQ)); + typedef IMP this_imp_type; + typedef REQ_IMP this_req_type; + typedef RSP_IMP this_rsp_type; + local this_req_type m_req_imp; + local this_rsp_type m_rsp_imp; + function new (string name, this_imp_type imp, + this_req_type req_imp = null, this_rsp_type rsp_imp = null); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + if(req_imp==null) $cast(req_imp, imp); + if(rsp_imp==null) $cast(rsp_imp, imp); + m_req_imp = req_imp; + m_rsp_imp = rsp_imp; + m_if_mask = ((1<<4) | (1<<5) | (1<<6) | (1<<10)); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_slave_imp"; + endfunction + function bit try_put (RSP t); + return m_rsp_imp.try_put(t); + endfunction + function bit can_put(); + return m_rsp_imp.can_put(); + endfunction + function bit try_get (output REQ t); + return m_req_imp.try_get(t); + endfunction + function bit can_get(); + return m_req_imp.can_get(); + endfunction + function bit try_peek (output REQ t); + return m_req_imp.try_peek(t); + endfunction + function bit can_peek(); + return m_req_imp.can_peek(); + endfunction +endclass +class uvm_slave_imp #(type REQ=int, type RSP=REQ, type IMP=int, + type REQ_IMP=IMP, type RSP_IMP=IMP) + extends uvm_port_base #(uvm_tlm_if_base #(RSP, REQ)); + typedef IMP this_imp_type; + typedef REQ_IMP this_req_type; + typedef RSP_IMP this_rsp_type; + local this_req_type m_req_imp; + local this_rsp_type m_rsp_imp; + function new (string name, this_imp_type imp, + this_req_type req_imp = null, this_rsp_type rsp_imp = null); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + if(req_imp==null) $cast(req_imp, imp); + if(rsp_imp==null) $cast(rsp_imp, imp); + m_req_imp = req_imp; + m_rsp_imp = rsp_imp; + m_if_mask = (((1<<0) | (1<<1) | (1<<2) | (1<<10)) | ((1<<4) | (1<<5) | (1<<6) | (1<<10))); + endfunction + virtual function string get_type_name(); + return "uvm_slave_imp"; + endfunction + task put (RSP t); + m_rsp_imp.put(t); + endtask + function bit try_put (RSP t); + return m_rsp_imp.try_put(t); + endfunction + function bit can_put(); + return m_rsp_imp.can_put(); + endfunction + task get (output REQ t); + m_req_imp.get(t); + endtask + task peek (output REQ t); + m_req_imp.peek(t); + endtask + function bit try_get (output REQ t); + return m_req_imp.try_get(t); + endfunction + function bit can_get(); + return m_req_imp.can_get(); + endfunction + function bit try_peek (output REQ t); + return m_req_imp.try_peek(t); + endfunction + function bit can_peek(); + return m_req_imp.can_peek(); + endfunction +endclass +class uvm_blocking_transport_imp #(type REQ=int, type RSP=REQ, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = (1<<3); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_transport_imp"; + endfunction + task transport (REQ req, output RSP rsp); + m_imp.transport(req, rsp); + endtask +endclass +class uvm_nonblocking_transport_imp #(type REQ=int, type RSP=REQ, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = (1<<7); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_transport_imp"; + endfunction + function bit nb_transport (REQ req, output RSP rsp); + return m_imp.nb_transport(req, rsp); + endfunction +endclass +class uvm_transport_imp #(type REQ=int, type RSP=REQ, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = ((1<<3) | (1<<7)); + endfunction + virtual function string get_type_name(); + return "uvm_transport_imp"; + endfunction + task transport (REQ req, output RSP rsp); + m_imp.transport(req, rsp); + endtask + function bit nb_transport (REQ req, output RSP rsp); + return m_imp.nb_transport(req, rsp); + endfunction +endclass +class uvm_blocking_put_port #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = (1<<0); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_put_port"; + endfunction + task put (T t); + this.m_if.put(t); + endtask +endclass +class uvm_nonblocking_put_port #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = (1<<4); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_put_port"; + endfunction + function bit try_put (T t); + return this.m_if.try_put(t); + endfunction + function bit can_put(); + return this.m_if.can_put(); + endfunction +endclass +class uvm_put_port #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = ((1<<0) | (1<<4)); + endfunction + virtual function string get_type_name(); + return "uvm_put_port"; + endfunction + task put (T t); + this.m_if.put(t); + endtask + function bit try_put (T t); + return this.m_if.try_put(t); + endfunction + function bit can_put(); + return this.m_if.can_put(); + endfunction +endclass +class uvm_blocking_get_port #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = (1<<1); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_get_port"; + endfunction + task get (output T t); + this.m_if.get(t); + endtask +endclass +class uvm_nonblocking_get_port #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = (1<<5); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_get_port"; + endfunction + function bit try_get (output T t); + return this.m_if.try_get(t); + endfunction + function bit can_get(); + return this.m_if.can_get(); + endfunction +endclass +class uvm_get_port #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = ((1<<1) | (1<<5)); + endfunction + virtual function string get_type_name(); + return "uvm_get_port"; + endfunction + task get (output T t); + this.m_if.get(t); + endtask + function bit try_get (output T t); + return this.m_if.try_get(t); + endfunction + function bit can_get(); + return this.m_if.can_get(); + endfunction +endclass +class uvm_blocking_peek_port #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = (1<<2); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_peek_port"; + endfunction + task peek (output T t); + this.m_if.peek(t); + endtask +endclass +class uvm_nonblocking_peek_port #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = (1<<6); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_peek_port"; + endfunction + function bit try_peek (output T t); + return this.m_if.try_peek(t); + endfunction + function bit can_peek(); + return this.m_if.can_peek(); + endfunction +endclass +class uvm_peek_port #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = ((1<<2) | (1<<6)); + endfunction + virtual function string get_type_name(); + return "uvm_peek_port"; + endfunction + task peek (output T t); + this.m_if.peek(t); + endtask + function bit try_peek (output T t); + return this.m_if.try_peek(t); + endfunction + function bit can_peek(); + return this.m_if.can_peek(); + endfunction +endclass +class uvm_blocking_get_peek_port #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = ((1<<1) | (1<<2)); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_get_peek_port"; + endfunction + task get (output T t); + this.m_if.get(t); + endtask + task peek (output T t); + this.m_if.peek(t); + endtask +endclass +class uvm_nonblocking_get_peek_port #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = ((1<<5) | (1<<6)); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_get_peek_port"; + endfunction + function bit try_get (output T t); + return this.m_if.try_get(t); + endfunction + function bit can_get(); + return this.m_if.can_get(); + endfunction + function bit try_peek (output T t); + return this.m_if.try_peek(t); + endfunction + function bit can_peek(); + return this.m_if.can_peek(); + endfunction +endclass +class uvm_get_peek_port #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = (((1<<1) | (1<<5)) | ((1<<2) | (1<<6))); + endfunction + virtual function string get_type_name(); + return "uvm_get_peek_port"; + endfunction + task get (output T t); + this.m_if.get(t); + endtask + task peek (output T t); + this.m_if.peek(t); + endtask + function bit try_get (output T t); + return this.m_if.try_get(t); + endfunction + function bit can_get(); + return this.m_if.can_get(); + endfunction + function bit try_peek (output T t); + return this.m_if.try_peek(t); + endfunction + function bit can_peek(); + return this.m_if.can_peek(); + endfunction +endclass +class uvm_blocking_master_port #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = ((1<<0) | (1<<1) | (1<<2) | (1<<9)); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_master_port"; + endfunction + task put (REQ t); + this.m_if.put(t); + endtask + task get (output RSP t); + this.m_if.get(t); + endtask + task peek (output RSP t); + this.m_if.peek(t); + endtask +endclass +class uvm_nonblocking_master_port #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = ((1<<4) | (1<<5) | (1<<6) | (1<<9)); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_master_port"; + endfunction + function bit try_put (REQ t); + return this.m_if.try_put(t); + endfunction + function bit can_put(); + return this.m_if.can_put(); + endfunction + function bit try_get (output RSP t); + return this.m_if.try_get(t); + endfunction + function bit can_get(); + return this.m_if.can_get(); + endfunction + function bit try_peek (output RSP t); + return this.m_if.try_peek(t); + endfunction + function bit can_peek(); + return this.m_if.can_peek(); + endfunction +endclass +class uvm_master_port #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = (((1<<0) | (1<<1) | (1<<2) | (1<<9)) | ((1<<4) | (1<<5) | (1<<6) | (1<<9))); + endfunction + virtual function string get_type_name(); + return "uvm_master_port"; + endfunction + task put (REQ t); + this.m_if.put(t); + endtask + function bit try_put (REQ t); + return this.m_if.try_put(t); + endfunction + function bit can_put(); + return this.m_if.can_put(); + endfunction + task get (output RSP t); + this.m_if.get(t); + endtask + task peek (output RSP t); + this.m_if.peek(t); + endtask + function bit try_get (output RSP t); + return this.m_if.try_get(t); + endfunction + function bit can_get(); + return this.m_if.can_get(); + endfunction + function bit try_peek (output RSP t); + return this.m_if.try_peek(t); + endfunction + function bit can_peek(); + return this.m_if.can_peek(); + endfunction +endclass +class uvm_blocking_slave_port #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(RSP, REQ)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = ((1<<0) | (1<<1) | (1<<2) | (1<<10)); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_slave_port"; + endfunction + task put (RSP t); + this.m_if.put(t); + endtask + task get (output REQ t); + this.m_if.get(t); + endtask + task peek (output REQ t); + this.m_if.peek(t); + endtask +endclass +class uvm_nonblocking_slave_port #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(RSP, REQ)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = ((1<<4) | (1<<5) | (1<<6) | (1<<10)); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_slave_port"; + endfunction + function bit try_put (RSP t); + return this.m_if.try_put(t); + endfunction + function bit can_put(); + return this.m_if.can_put(); + endfunction + function bit try_get (output REQ t); + return this.m_if.try_get(t); + endfunction + function bit can_get(); + return this.m_if.can_get(); + endfunction + function bit try_peek (output REQ t); + return this.m_if.try_peek(t); + endfunction + function bit can_peek(); + return this.m_if.can_peek(); + endfunction +endclass +class uvm_slave_port #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(RSP, REQ)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = (((1<<0) | (1<<1) | (1<<2) | (1<<10)) | ((1<<4) | (1<<5) | (1<<6) | (1<<10))); + endfunction + virtual function string get_type_name(); + return "uvm_slave_port"; + endfunction + task put (RSP t); + this.m_if.put(t); + endtask + function bit try_put (RSP t); + return this.m_if.try_put(t); + endfunction + function bit can_put(); + return this.m_if.can_put(); + endfunction + task get (output REQ t); + this.m_if.get(t); + endtask + task peek (output REQ t); + this.m_if.peek(t); + endtask + function bit try_get (output REQ t); + return this.m_if.try_get(t); + endfunction + function bit can_get(); + return this.m_if.can_get(); + endfunction + function bit try_peek (output REQ t); + return this.m_if.try_peek(t); + endfunction + function bit can_peek(); + return this.m_if.can_peek(); + endfunction +endclass +class uvm_blocking_transport_port #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = (1<<3); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_transport_port"; + endfunction + task transport (REQ req, output RSP rsp); + this.m_if.transport(req, rsp); + endtask +endclass +class uvm_nonblocking_transport_port #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = (1<<7); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_transport_port"; + endfunction + function bit nb_transport (REQ req, output RSP rsp); + return this.m_if.nb_transport(req, rsp); + endfunction +endclass +class uvm_transport_port #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = ((1<<3) | (1<<7)); + endfunction + virtual function string get_type_name(); + return "uvm_transport_port"; + endfunction + task transport (REQ req, output RSP rsp); + this.m_if.transport(req, rsp); + endtask + function bit nb_transport (REQ req, output RSP rsp); + return this.m_if.nb_transport(req, rsp); + endfunction +endclass +class uvm_blocking_put_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = (1<<0); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_put_export"; + endfunction + task put (T t); + this.m_if.put(t); + endtask +endclass +class uvm_nonblocking_put_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = (1<<4); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_put_export"; + endfunction + function bit try_put (T t); + return this.m_if.try_put(t); + endfunction + function bit can_put(); + return this.m_if.can_put(); + endfunction +endclass +class uvm_put_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = ((1<<0) | (1<<4)); + endfunction + virtual function string get_type_name(); + return "uvm_put_export"; + endfunction + task put (T t); + this.m_if.put(t); + endtask + function bit try_put (T t); + return this.m_if.try_put(t); + endfunction + function bit can_put(); + return this.m_if.can_put(); + endfunction +endclass +class uvm_blocking_get_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = (1<<1); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_get_export"; + endfunction + task get (output T t); + this.m_if.get(t); + endtask +endclass +class uvm_nonblocking_get_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = (1<<5); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_get_export"; + endfunction + function bit try_get (output T t); + return this.m_if.try_get(t); + endfunction + function bit can_get(); + return this.m_if.can_get(); + endfunction +endclass +class uvm_get_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = ((1<<1) | (1<<5)); + endfunction + virtual function string get_type_name(); + return "uvm_get_export"; + endfunction + task get (output T t); + this.m_if.get(t); + endtask + function bit try_get (output T t); + return this.m_if.try_get(t); + endfunction + function bit can_get(); + return this.m_if.can_get(); + endfunction +endclass +class uvm_blocking_peek_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = (1<<2); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_peek_export"; + endfunction + task peek (output T t); + this.m_if.peek(t); + endtask +endclass +class uvm_nonblocking_peek_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = (1<<6); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_peek_export"; + endfunction + function bit try_peek (output T t); + return this.m_if.try_peek(t); + endfunction + function bit can_peek(); + return this.m_if.can_peek(); + endfunction +endclass +class uvm_peek_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = ((1<<2) | (1<<6)); + endfunction + virtual function string get_type_name(); + return "uvm_peek_export"; + endfunction + task peek (output T t); + this.m_if.peek(t); + endtask + function bit try_peek (output T t); + return this.m_if.try_peek(t); + endfunction + function bit can_peek(); + return this.m_if.can_peek(); + endfunction +endclass +class uvm_blocking_get_peek_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = ((1<<1) | (1<<2)); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_get_peek_export"; + endfunction + task get (output T t); + this.m_if.get(t); + endtask + task peek (output T t); + this.m_if.peek(t); + endtask +endclass +class uvm_nonblocking_get_peek_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = ((1<<5) | (1<<6)); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_get_peek_export"; + endfunction + function bit try_get (output T t); + return this.m_if.try_get(t); + endfunction + function bit can_get(); + return this.m_if.can_get(); + endfunction + function bit try_peek (output T t); + return this.m_if.try_peek(t); + endfunction + function bit can_peek(); + return this.m_if.can_peek(); + endfunction +endclass +class uvm_get_peek_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = (((1<<1) | (1<<5)) | ((1<<2) | (1<<6))); + endfunction + virtual function string get_type_name(); + return "uvm_get_peek_export"; + endfunction + task get (output T t); + this.m_if.get(t); + endtask + task peek (output T t); + this.m_if.peek(t); + endtask + function bit try_get (output T t); + return this.m_if.try_get(t); + endfunction + function bit can_get(); + return this.m_if.can_get(); + endfunction + function bit try_peek (output T t); + return this.m_if.try_peek(t); + endfunction + function bit can_peek(); + return this.m_if.can_peek(); + endfunction +endclass +class uvm_blocking_master_export #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = ((1<<0) | (1<<1) | (1<<2) | (1<<9)); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_master_export"; + endfunction + task put (REQ t); + this.m_if.put(t); + endtask + task get (output RSP t); + this.m_if.get(t); + endtask + task peek (output RSP t); + this.m_if.peek(t); + endtask +endclass +class uvm_nonblocking_master_export #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = ((1<<4) | (1<<5) | (1<<6) | (1<<9)); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_master_export"; + endfunction + function bit try_put (REQ t); + return this.m_if.try_put(t); + endfunction + function bit can_put(); + return this.m_if.can_put(); + endfunction + function bit try_get (output RSP t); + return this.m_if.try_get(t); + endfunction + function bit can_get(); + return this.m_if.can_get(); + endfunction + function bit try_peek (output RSP t); + return this.m_if.try_peek(t); + endfunction + function bit can_peek(); + return this.m_if.can_peek(); + endfunction +endclass +class uvm_master_export #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = (((1<<0) | (1<<1) | (1<<2) | (1<<9)) | ((1<<4) | (1<<5) | (1<<6) | (1<<9))); + endfunction + virtual function string get_type_name(); + return "uvm_master_export"; + endfunction + task put (REQ t); + this.m_if.put(t); + endtask + function bit try_put (REQ t); + return this.m_if.try_put(t); + endfunction + function bit can_put(); + return this.m_if.can_put(); + endfunction + task get (output RSP t); + this.m_if.get(t); + endtask + task peek (output RSP t); + this.m_if.peek(t); + endtask + function bit try_get (output RSP t); + return this.m_if.try_get(t); + endfunction + function bit can_get(); + return this.m_if.can_get(); + endfunction + function bit try_peek (output RSP t); + return this.m_if.try_peek(t); + endfunction + function bit can_peek(); + return this.m_if.can_peek(); + endfunction +endclass +class uvm_blocking_slave_export #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(RSP, REQ)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = ((1<<0) | (1<<1) | (1<<2) | (1<<10)); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_slave_export"; + endfunction + task put (RSP t); + this.m_if.put(t); + endtask + task get (output REQ t); + this.m_if.get(t); + endtask + task peek (output REQ t); + this.m_if.peek(t); + endtask +endclass +class uvm_nonblocking_slave_export #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(RSP, REQ)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = ((1<<4) | (1<<5) | (1<<6) | (1<<10)); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_slave_export"; + endfunction + function bit try_put (RSP t); + return this.m_if.try_put(t); + endfunction + function bit can_put(); + return this.m_if.can_put(); + endfunction + function bit try_get (output REQ t); + return this.m_if.try_get(t); + endfunction + function bit can_get(); + return this.m_if.can_get(); + endfunction + function bit try_peek (output REQ t); + return this.m_if.try_peek(t); + endfunction + function bit can_peek(); + return this.m_if.can_peek(); + endfunction +endclass +class uvm_slave_export #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(RSP, REQ)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = (((1<<0) | (1<<1) | (1<<2) | (1<<10)) | ((1<<4) | (1<<5) | (1<<6) | (1<<10))); + endfunction + virtual function string get_type_name(); + return "uvm_slave_export"; + endfunction + task put (RSP t); + this.m_if.put(t); + endtask + function bit try_put (RSP t); + return this.m_if.try_put(t); + endfunction + function bit can_put(); + return this.m_if.can_put(); + endfunction + task get (output REQ t); + this.m_if.get(t); + endtask + task peek (output REQ t); + this.m_if.peek(t); + endtask + function bit try_get (output REQ t); + return this.m_if.try_get(t); + endfunction + function bit can_get(); + return this.m_if.can_get(); + endfunction + function bit try_peek (output REQ t); + return this.m_if.try_peek(t); + endfunction + function bit can_peek(); + return this.m_if.can_peek(); + endfunction +endclass +class uvm_blocking_transport_export #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = (1<<3); + endfunction + virtual function string get_type_name(); + return "uvm_blocking_transport_export"; + endfunction + task transport (REQ req, output RSP rsp); + this.m_if.transport(req, rsp); + endtask +endclass +class uvm_nonblocking_transport_export #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = (1<<7); + endfunction + virtual function string get_type_name(); + return "uvm_nonblocking_transport_export"; + endfunction + function bit nb_transport (REQ req, output RSP rsp); + return this.m_if.nb_transport(req, rsp); + endfunction +endclass +class uvm_transport_export #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_tlm_if_base #(REQ, RSP)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = ((1<<3) | (1<<7)); + endfunction + virtual function string get_type_name(); + return "uvm_transport_export"; + endfunction + task transport (REQ req, output RSP rsp); + this.m_if.transport(req, rsp); + endtask + function bit nb_transport (REQ req, output RSP rsp); + return this.m_if.nb_transport(req, rsp); + endfunction +endclass +class uvm_analysis_port # (type T = int) + extends uvm_port_base # (uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent); + super.new (name, parent, UVM_PORT, 0, UVM_UNBOUNDED_CONNECTIONS); + m_if_mask = (1<<8); + endfunction + virtual function string get_type_name(); + return "uvm_analysis_port"; + endfunction + function void write (input T t); + uvm_tlm_if_base # (T, T) tif; + for (int i = 0; i < this.size(); i++) begin + tif = this.get_if (i); + if ( tif == null ) + uvm_report_fatal ("NTCONN", {"No uvm_tlm interface is connected to ", get_full_name(), " for executing write()"}, UVM_NONE); + tif.write (t); + end + endfunction +endclass +class uvm_analysis_imp #(type T=int, type IMP=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = (1<<8); + endfunction + virtual function string get_type_name(); + return "uvm_analysis_imp"; + endfunction + function void write (input T t); + m_imp.write (t); + endfunction +endclass +class uvm_analysis_export #(type T=int) + extends uvm_port_base #(uvm_tlm_if_base #(T,T)); + function new (string name, uvm_component parent = null); + super.new (name, parent, UVM_EXPORT, 1, UVM_UNBOUNDED_CONNECTIONS); + m_if_mask = (1<<8); + endfunction + virtual function string get_type_name(); + return "uvm_analysis_export"; + endfunction + function void write (input T t); + uvm_tlm_if_base #(T, T) tif; + for (int i = 0; i < this.size(); i++) begin + tif = this.get_if (i); + if (tif == null) + uvm_report_fatal ("NTCONN", {"No uvm_tlm interface is connected to ", get_full_name(), " for executing write()"}, UVM_NONE); + tif.write (t); + end + endfunction +endclass +class uvm_tlm_event; + event trigger; +endclass +virtual class uvm_tlm_fifo_base #(type T=int) extends uvm_component; + typedef uvm_abstract_component_registry #(uvm_tlm_fifo_base #(T)) type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + typedef uvm_tlm_fifo_base #(T) this_type; + uvm_put_imp #(T, this_type) put_export; + uvm_get_peek_imp #(T, this_type) get_peek_export; + uvm_analysis_port #(T) put_ap; + uvm_analysis_port #(T) get_ap; + uvm_put_imp #(T, this_type) blocking_put_export; + uvm_put_imp #(T, this_type) nonblocking_put_export; + uvm_get_peek_imp #(T, this_type) blocking_get_export; + uvm_get_peek_imp #(T, this_type) nonblocking_get_export; + uvm_get_peek_imp #(T, this_type) get_export; + uvm_get_peek_imp #(T, this_type) blocking_peek_export; + uvm_get_peek_imp #(T, this_type) nonblocking_peek_export; + uvm_get_peek_imp #(T, this_type) peek_export; + uvm_get_peek_imp #(T, this_type) blocking_get_peek_export; + uvm_get_peek_imp #(T, this_type) nonblocking_get_peek_export; + function new(string name, uvm_component parent = null); + super.new(name, parent); + put_export = new("put_export", this); + blocking_put_export = put_export; + nonblocking_put_export = put_export; + get_peek_export = new("get_peek_export", this); + blocking_get_peek_export = get_peek_export; + nonblocking_get_peek_export = get_peek_export; + blocking_get_export = get_peek_export; + nonblocking_get_export = get_peek_export; + get_export = get_peek_export; + blocking_peek_export = get_peek_export; + nonblocking_peek_export = get_peek_export; + peek_export = get_peek_export; + put_ap = new("put_ap", this); + get_ap = new("get_ap", this); + endfunction + virtual function bit use_automatic_config(); + return 0; + endfunction : use_automatic_config + virtual function void flush(); + uvm_report_error("flush", "fifo channel function not implemented", UVM_NONE); + endfunction + virtual function int size(); + uvm_report_error("size", "fifo channel function not implemented", UVM_NONE); + return 0; + endfunction + virtual task put(T t); + uvm_report_error("put", "fifo channel task not implemented", UVM_NONE); + endtask + virtual task get(output T t); + uvm_report_error("get", "fifo channel task not implemented", UVM_NONE); + endtask + virtual task peek(output T t); + uvm_report_error("peek", "fifo channel task not implemented", UVM_NONE); + endtask + virtual function bit try_put(T t); + uvm_report_error("try_put", "fifo channel function not implemented", UVM_NONE); + return 0; + endfunction + virtual function bit try_get(output T t); + uvm_report_error("try_get", "fifo channel function not implemented", UVM_NONE); + return 0; + endfunction + virtual function bit try_peek(output T t); + uvm_report_error("try_peek", "fifo channel function not implemented", UVM_NONE); + return 0; + endfunction + virtual function bit can_put(); + uvm_report_error("can_put", "fifo channel function not implemented", UVM_NONE); + return 0; + endfunction + virtual function bit can_get(); + uvm_report_error("can_get", "fifo channel function not implemented", UVM_NONE); + return 0; + endfunction + virtual function bit can_peek(); + uvm_report_error("can_peek", "fifo channel function not implemented", UVM_NONE); + return 0; + endfunction + virtual function uvm_tlm_event ok_to_put(); + uvm_report_error("ok_to_put", "fifo channel function not implemented", UVM_NONE); + return null; + endfunction + virtual function uvm_tlm_event ok_to_get(); + uvm_report_error("ok_to_get", "fifo channel function not implemented", UVM_NONE); + return null; + endfunction + virtual function uvm_tlm_event ok_to_peek(); + uvm_report_error("ok_to_peek", "fifo channel function not implemented", UVM_NONE); + return null; + endfunction + virtual function bit is_empty(); + uvm_report_error("is_empty", "fifo channel function not implemented", UVM_NONE); + return 0; + endfunction + virtual function bit is_full(); + uvm_report_error("is_full", "fifo channel function not implemented"); + return 0; + endfunction + virtual function int used(); + uvm_report_error("used", "fifo channel function not implemented", UVM_NONE); + return 0; + endfunction +endclass +typedef class uvm_tlm_event; +class uvm_tlm_fifo #(type T=int) extends uvm_tlm_fifo_base #(T); + typedef uvm_component_registry #(uvm_tlm_fifo#(T)) type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_tlm_fifo #(T)"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_tlm_fifo #(T)"; + endfunction : get_type_name + local mailbox #( T ) m; + local int m_size; + protected int m_pending_blocked_gets; + function new(string name, uvm_component parent = null, int size = 1); + super.new(name, parent); + m = new( size ); + m_size = size; + endfunction + virtual function int size(); + return m_size; + endfunction + virtual function int used(); + return m.num(); + endfunction + virtual function bit is_empty(); + return (m.num() == 0); + endfunction + virtual function bit is_full(); + return (m_size != 0) && (m.num() == m_size); + endfunction + virtual task put( input T t ); + m.put( t ); + put_ap.write( t ); + endtask + virtual task get( output T t ); + m_pending_blocked_gets++; + m.get( t ); + m_pending_blocked_gets--; + get_ap.write( t ); + endtask + virtual task peek( output T t ); + m.peek( t ); + endtask + virtual function bit try_get( output T t ); + if( !m.try_get( t ) ) begin + return 0; + end + get_ap.write( t ); + return 1; + endfunction + virtual function bit try_peek( output T t ); + if( !m.try_peek( t ) ) begin + return 0; + end + return 1; + endfunction + virtual function bit try_put( input T t ); + if( !m.try_put( t ) ) begin + return 0; + end + put_ap.write( t ); + return 1; + endfunction + virtual function bit can_put(); + return m_size == 0 || m.num() < m_size; + endfunction + virtual function bit can_get(); + return m.num() > 0 && m_pending_blocked_gets == 0; + endfunction + virtual function bit can_peek(); + return m.num() > 0; + endfunction + virtual function void flush(); + T t; + bit r; + r = 1; + while( r ) r = try_get( t ) ; + if( m.num() > 0 && m_pending_blocked_gets != 0 ) begin + uvm_report_error("flush failed" , + "there are blocked gets preventing the flush", UVM_NONE); + end + endfunction +endclass +class uvm_tlm_analysis_fifo #(type T = int) extends uvm_tlm_fifo #(T); + typedef uvm_component_registry #(uvm_tlm_analysis_fifo#(T)) type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_tlm_analysis_fifo #(T)"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_tlm_analysis_fifo #(T)"; + endfunction : get_type_name + uvm_analysis_imp #(T, uvm_tlm_analysis_fifo #(T)) analysis_export; + function new(string name , uvm_component parent = null); + super.new(name, parent, 0); + analysis_export = new("analysis_export", this); + endfunction + function void write(input T t); + void'(this.try_put(t)); + endfunction +endclass +class uvm_tlm_req_rsp_channel #(type REQ=int, type RSP=REQ) extends uvm_component; + typedef uvm_tlm_req_rsp_channel #(REQ, RSP) this_type; + typedef uvm_component_registry #(uvm_tlm_req_rsp_channel#(REQ,RSP)) type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_tlm_req_rsp_channel #(REQ,RSP)"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_tlm_req_rsp_channel #(REQ,RSP)"; + endfunction : get_type_name + uvm_put_export #(REQ) put_request_export; + uvm_get_peek_export #(RSP) get_peek_response_export; + uvm_get_peek_export #(REQ) get_peek_request_export; + uvm_put_export #(RSP) put_response_export; + uvm_analysis_port #(REQ) request_ap; + uvm_analysis_port #(RSP) response_ap; + uvm_master_imp #(REQ, RSP, this_type, uvm_tlm_fifo #(REQ), uvm_tlm_fifo #(RSP)) master_export; + uvm_slave_imp #(REQ, RSP, this_type, uvm_tlm_fifo #(REQ), uvm_tlm_fifo #(RSP)) slave_export; + uvm_put_export #(REQ) blocking_put_request_export, + nonblocking_put_request_export; + uvm_get_peek_export #(REQ) get_request_export, + blocking_get_request_export, + nonblocking_get_request_export, + peek_request_export, + blocking_peek_request_export, + nonblocking_peek_request_export, + blocking_get_peek_request_export, + nonblocking_get_peek_request_export; + uvm_put_export #(RSP) blocking_put_response_export, + nonblocking_put_response_export; + uvm_get_peek_export #(RSP) get_response_export, + blocking_get_response_export, + nonblocking_get_response_export, + peek_response_export, + blocking_peek_response_export, + nonblocking_peek_response_export, + blocking_get_peek_response_export, + nonblocking_get_peek_response_export; + uvm_master_imp #(REQ, RSP, this_type, uvm_tlm_fifo #(REQ), uvm_tlm_fifo #(RSP)) + blocking_master_export, + nonblocking_master_export; + uvm_slave_imp #(REQ, RSP, this_type, uvm_tlm_fifo #(REQ), uvm_tlm_fifo #(RSP)) + blocking_slave_export, + nonblocking_slave_export; + protected uvm_tlm_fifo #(REQ) m_request_fifo; + protected uvm_tlm_fifo #(RSP) m_response_fifo; + function new (string name, uvm_component parent=null, + int request_fifo_size=1, + int response_fifo_size=1); + super.new (name, parent); + m_request_fifo = new ("request_fifo", this, request_fifo_size); + m_response_fifo = new ("response_fifo", this, response_fifo_size); + request_ap = new ("request_ap", this); + response_ap = new ("response_ap", this); + put_request_export = new ("put_request_export", this); + get_peek_request_export = new ("get_peek_request_export", this); + put_response_export = new ("put_response_export", this); + get_peek_response_export = new ("get_peek_response_export", this); + master_export = new ("master_export", this, m_request_fifo, m_response_fifo); + slave_export = new ("slave_export", this, m_request_fifo, m_response_fifo); + create_aliased_exports(); + set_report_id_action_hier(s_connection_error_id, UVM_NO_ACTION); + endfunction + virtual function void connect_phase(uvm_phase phase); + put_request_export.connect (m_request_fifo.put_export); + get_peek_request_export.connect (m_request_fifo.get_peek_export); + m_request_fifo.put_ap.connect (request_ap); + put_response_export.connect (m_response_fifo.put_export); + get_peek_response_export.connect (m_response_fifo.get_peek_export); + m_response_fifo.put_ap.connect (response_ap); + endfunction + function void create_aliased_exports(); + blocking_put_request_export = put_request_export; + nonblocking_put_request_export = put_request_export; + get_request_export = get_peek_request_export; + blocking_get_request_export = get_peek_request_export; + nonblocking_get_request_export = get_peek_request_export; + peek_request_export = get_peek_request_export; + blocking_peek_request_export = get_peek_request_export; + nonblocking_peek_request_export = get_peek_request_export; + blocking_get_peek_request_export = get_peek_request_export; + nonblocking_get_peek_request_export = get_peek_request_export; + blocking_put_response_export = put_response_export; + nonblocking_put_response_export = put_response_export; + get_response_export = get_peek_response_export; + blocking_get_response_export = get_peek_response_export; + nonblocking_get_response_export = get_peek_response_export; + peek_response_export = get_peek_response_export; + blocking_peek_response_export = get_peek_response_export; + nonblocking_peek_response_export = get_peek_response_export; + blocking_get_peek_response_export = get_peek_response_export; + nonblocking_get_peek_response_export = get_peek_response_export; + blocking_master_export = master_export; + nonblocking_master_export = master_export; + blocking_slave_export = slave_export; + nonblocking_slave_export = slave_export; + endfunction +endclass +class uvm_tlm_transport_channel #(type REQ=int, type RSP=REQ) + extends uvm_tlm_req_rsp_channel #(REQ, RSP); + typedef uvm_component_registry #(uvm_tlm_transport_channel#(REQ,RSP)) type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_tlm_transport_channel #(REQ,RSP)"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_tlm_transport_channel #(REQ,RSP)"; + endfunction : get_type_name + typedef uvm_tlm_transport_channel #(REQ, RSP) this_type; + uvm_transport_imp #(REQ, RSP, this_type) transport_export; + function new (string name, uvm_component parent=null); + super.new(name, parent, 1, 1); + transport_export = new("transport_export", this); + endfunction + task transport (REQ request, output RSP response ); + this.m_request_fifo.put( request ); + this.m_response_fifo.get( response ); + endtask + function bit nb_transport (REQ req, output RSP rsp ); + if(this.m_request_fifo.try_put(req)) + return this.m_response_fifo.try_get(rsp); + else + return 0; + endfunction +endclass +class uvm_seq_item_pull_port #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_sqr_if_base #(REQ, RSP)); + function new (string name, uvm_component parent, + int min_size=0, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = ((1<<0) | (1<<1) | + (1<<2) | (1<<3) | + (1<<4) | (1<<5) | + (1<<6) | (1<<7) | (1<<8)); + endfunction + virtual function string get_type_name(); + return "uvm_seq_item_pull_port"; + endfunction + function void disable_auto_item_recording(); this.m_if.disable_auto_item_recording(); endfunction + function bit is_auto_item_recording_enabled(); return this.m_if.is_auto_item_recording_enabled(); endfunction + task get_next_item(output REQ t); this.m_if.get_next_item(t); endtask + task try_next_item(output REQ t); this.m_if.try_next_item(t); endtask + function void item_done(input RSP t = null); this.m_if.item_done(t); endfunction + task wait_for_sequences(); this.m_if.wait_for_sequences(); endtask + function bit has_do_available(); return this.m_if.has_do_available(); endfunction + function void put_response(input RSP t); this.m_if.put_response(t); endfunction + task get(output REQ t); this.m_if.get(t); endtask + task peek(output REQ t); this.m_if.peek(t); endtask + task put(input RSP t); this.m_if.put(t); endtask + bit print_enabled; +endclass +class uvm_seq_item_pull_export #(type REQ=int, type RSP=REQ) + extends uvm_port_base #(uvm_sqr_if_base #(REQ, RSP)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = ((1<<0) | (1<<1) | + (1<<2) | (1<<3) | + (1<<4) | (1<<5) | + (1<<6) | (1<<7) | (1<<8)); + endfunction + virtual function string get_type_name(); + return "uvm_seq_item_pull_export"; + endfunction + function void disable_auto_item_recording(); this.m_if.disable_auto_item_recording(); endfunction + function bit is_auto_item_recording_enabled(); return this.m_if.is_auto_item_recording_enabled(); endfunction + task get_next_item(output REQ t); this.m_if.get_next_item(t); endtask + task try_next_item(output REQ t); this.m_if.try_next_item(t); endtask + function void item_done(input RSP t = null); this.m_if.item_done(t); endfunction + task wait_for_sequences(); this.m_if.wait_for_sequences(); endtask + function bit has_do_available(); return this.m_if.has_do_available(); endfunction + function void put_response(input RSP t); this.m_if.put_response(t); endfunction + task get(output REQ t); this.m_if.get(t); endtask + task peek(output REQ t); this.m_if.peek(t); endtask + task put(input RSP t); this.m_if.put(t); endtask +endclass +class uvm_seq_item_pull_imp #(type REQ=int, type RSP=REQ, type IMP=int) + extends uvm_port_base #(uvm_sqr_if_base #(REQ, RSP)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = ((1<<0) | (1<<1) | + (1<<2) | (1<<3) | + (1<<4) | (1<<5) | + (1<<6) | (1<<7) | (1<<8)); + endfunction + virtual function string get_type_name(); + return "uvm_seq_item_pull_imp"; + endfunction + function void disable_auto_item_recording(); m_imp.disable_auto_item_recording(); endfunction + function bit is_auto_item_recording_enabled(); return m_imp.is_auto_item_recording_enabled(); endfunction + task get_next_item(output REQ t); m_imp.get_next_item(t); endtask + task try_next_item(output REQ t); m_imp.try_next_item(t); endtask + function void item_done(input RSP t = null); m_imp.item_done(t); endfunction + task wait_for_sequences(); m_imp.wait_for_sequences(); endtask + function bit has_do_available(); return m_imp.has_do_available(); endfunction + function void put_response(input RSP t); m_imp.put_response(t); endfunction + task get(output REQ t); m_imp.get(t); endtask + task peek(output REQ t); m_imp.peek(t); endtask + task put(input RSP t); m_imp.put(t); endtask +endclass +class uvm_class_pair #(type T1=int, T2=T1) extends uvm_object; + typedef uvm_class_pair #(T1, T2 ) this_type; + typedef uvm_object_registry #(this_type) type_id; + static function this_type type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + this_type tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_class_pair #(T1,T2)"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_class_pair #(T1,T2)"; + endfunction : get_type_name + T1 first; + T2 second; + function new (string name="", T1 f=null, T2 s=null); + super.new(name); + if (f == null) + first = new; + else + first = f; + if (s == null) + second = new; + else + second = s; + endfunction + virtual function string convert2string; + string s; + $sformat(s, "pair : %s, %s", + first.convert2string(), second.convert2string()); + return s; + endfunction + virtual function bit do_compare(uvm_object rhs, uvm_comparer comparer); + this_type rhs_; + if(!$cast(rhs_,rhs)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"WRONG_TYPE")) + uvm_report_error ("WRONG_TYPE", {"do_compare: rhs argument is not of type '",get_type_name(),"'"}, UVM_NONE, "t/uvm/src/comps/uvm_pair.svh", 88, "", 1); + end + return 0; + end + return first.compare(rhs_.first) && second.compare(rhs_.second); + endfunction + virtual function void do_copy (uvm_object rhs); + this_type rhs_; + if(!$cast(rhs_,rhs)) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"WRONG_TYPE")) + uvm_report_fatal ("WRONG_TYPE", {"do_copy: rhs argument is not of type '",get_type_name(),"'"}, UVM_NONE, "t/uvm/src/comps/uvm_pair.svh", 97, "", 1); + end + first.copy(rhs_.first); + second.copy(rhs_.second); + endfunction +endclass +class uvm_built_in_pair #(type T1=int, T2=T1) extends uvm_object; + typedef uvm_built_in_pair #(T1,T2) this_type; + typedef uvm_object_registry #(this_type) type_id; + static function this_type type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + this_type tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_built_in_pair #(T1,T2)"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_built_in_pair #(T1,T2)"; + endfunction : get_type_name + T1 first; + T2 second; + function new (string name=""); + super.new(name); + endfunction + virtual function string convert2string; + return $sformatf("built-in pair : %p, %p", first, second); + endfunction + virtual function bit do_compare(uvm_object rhs, uvm_comparer comparer); + this_type rhs_; + if(!$cast(rhs_,rhs)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"WRONG_TYPE")) + uvm_report_error ("WRONG_TYPE", {"do_compare: rhs argument is not of type '",get_type_name(),"'"}, UVM_NONE, "t/uvm/src/comps/uvm_pair.svh", 146, "", 1); + end + return 0; + end + return first == rhs_.first && second == rhs_.second; + endfunction + function void do_copy (uvm_object rhs); + this_type rhs_; + if(!$cast(rhs_,rhs)) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"WRONG_TYPE")) + uvm_report_fatal ("WRONG_TYPE", {"do_copy: rhs argument is not of type '",get_type_name(),"'"}, UVM_NONE, "t/uvm/src/comps/uvm_pair.svh", 155, "", 1); + end + first = rhs_.first; + second = rhs_.second; + endfunction +endclass +class uvm_built_in_comp #(type T=int); + static function bit comp(T a, T b); + return a == b; + endfunction +endclass +class uvm_built_in_converter #(type T=int); + static function string convert2string(input T t); + return $sformatf("%p" , t ); + endfunction +endclass +class uvm_built_in_clone #(type T=int); + static function T clone(input T from); + return from; + endfunction +endclass +class uvm_class_comp #(type T=int); + static function bit comp(input T a, input T b); + return a.compare(b); + endfunction +endclass +class uvm_class_converter #(type T=int); + static function string convert2string(input T t); + return t.convert2string(); + endfunction +endclass +class uvm_class_clone #(type T=int); + static function uvm_object clone(input T from); + return from.clone(); + endfunction +endclass +class uvm_in_order_comparator + #( type T = int , + type comp_type = uvm_built_in_comp #( T ) , + type convert = uvm_built_in_converter #( T ) , + type pair_type = uvm_built_in_pair #( T ) ) + extends uvm_component; + typedef uvm_in_order_comparator #(T,comp_type,convert,pair_type) this_type; + typedef uvm_component_registry #(this_type) type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_in_order_comparator #(T,comp_type,convert,pair_type)"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_in_order_comparator #(T,comp_type,convert,pair_type)"; + endfunction : get_type_name + uvm_analysis_export #(T) before_export; + uvm_analysis_export #(T) after_export; + uvm_analysis_port #(pair_type) pair_ap; + local uvm_tlm_analysis_fifo #(T) m_before_fifo; + local uvm_tlm_analysis_fifo #(T) m_after_fifo; + int m_matches, m_mismatches; + function new(string name, uvm_component parent); + super.new(name, parent); + before_export = new("before_export", this); + after_export = new("after_export", this); + pair_ap = new("pair_ap", this); + m_before_fifo = new("before", this); + m_after_fifo = new("after", this); + m_matches = 0; + m_mismatches = 0; + endfunction + virtual function void connect_phase(uvm_phase phase); + before_export.connect(m_before_fifo.analysis_export); + after_export.connect(m_after_fifo.analysis_export); + endfunction + virtual task run_phase(uvm_phase phase); + pair_type pair; + T b; + T a; + string s; + super.run_phase(phase); + forever begin + m_before_fifo.get(b); + m_after_fifo.get(a); + if(!comp_type::comp(b, a)) begin + $sformat(s, "%s differs from %s", convert::convert2string(a), + convert::convert2string(b)); + uvm_report_warning("Comparator Mismatch", s); + m_mismatches++; + end + else begin + s = convert::convert2string(b); + uvm_report_info("Comparator Match", s); + m_matches++; + end + pair = new("after/before"); + pair.first = a; + pair.second = b; + pair_ap.write(pair); + end + endtask + virtual function void flush(); + m_matches = 0; + m_mismatches = 0; + endfunction +endclass +class uvm_in_order_built_in_comparator #(type T=int) + extends uvm_in_order_comparator #(T); + typedef uvm_in_order_built_in_comparator #(T) this_type; + typedef uvm_component_registry #(this_type) type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_in_order_built_in_comparator #(T)"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_in_order_built_in_comparator #(T)"; + endfunction : get_type_name + function new(string name, uvm_component parent); + super.new(name, parent); + endfunction +endclass +class uvm_in_order_class_comparator #( type T = int ) + extends uvm_in_order_comparator #( T , + uvm_class_comp #( T ) , + uvm_class_converter #( T ) , + uvm_class_pair #( T, T ) ); + typedef uvm_in_order_class_comparator #(T) this_type; + typedef uvm_component_registry #(this_type) type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_in_order_class_comparator #(T)"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_in_order_class_comparator #(T)"; + endfunction : get_type_name + function new( string name , uvm_component parent); + super.new( name, parent ); + endfunction +endclass +class uvm_algorithmic_comparator #( type BEFORE=int, + type AFTER=int, + type TRANSFORMER=int) extends uvm_component; + typedef uvm_algorithmic_comparator #( BEFORE , + AFTER , + TRANSFORMER ) this_type; + typedef uvm_component_registry #(this_type) type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_algorithmic_comparator #(BEFORE,AFTER,TRANSFORMER)"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_algorithmic_comparator #(BEFORE,AFTER,TRANSFORMER)"; + endfunction : get_type_name + uvm_analysis_imp #(BEFORE, this_type) before_export; + uvm_analysis_export #(AFTER) after_export; + local uvm_in_order_class_comparator #(AFTER) comp; + local TRANSFORMER m_transformer; + function new(string name, uvm_component parent=null, TRANSFORMER transformer=null); + super.new( name , parent ); + m_transformer = transformer; + comp = new("comp", this ); + before_export = new("before_analysis_export" , this ); + after_export = new("after_analysis_export" , this ); + endfunction + virtual function void connect_phase(uvm_phase phase); + after_export.connect( comp.after_export ); + endfunction + function void write( input BEFORE b ); + comp.before_export.write( m_transformer.transform( b ) ); + endfunction +endclass +virtual class uvm_subscriber #(type T=int) extends uvm_component; + typedef uvm_subscriber #(T) this_type; + uvm_analysis_imp #(T, this_type) analysis_export; + function new (string name, uvm_component parent); + super.new(name, parent); + analysis_export = new("analysis_imp", this); + endfunction + pure virtual function void write(T t); +endclass +virtual class uvm_monitor extends uvm_component; + typedef uvm_abstract_component_registry #(uvm_monitor,"uvm_monitor") type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_monitor"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_monitor"; + endfunction : get_type_name + function new (string name, uvm_component parent); + super.new(name, parent); + endfunction +endclass +typedef class uvm_sequence_item; +class uvm_driver #(type REQ=uvm_sequence_item, + type RSP=REQ) extends uvm_component; + typedef uvm_component_registry #(uvm_driver#(REQ,RSP)) type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_driver #(REQ,RSP)"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_driver #(REQ,RSP)"; + endfunction : get_type_name + uvm_seq_item_pull_port #(REQ, RSP) seq_item_port; + uvm_seq_item_pull_port #(REQ, RSP) seq_item_prod_if; + uvm_analysis_port #(RSP) rsp_port; + REQ req; + RSP rsp; + function new (string name, uvm_component parent); + super.new(name, parent); + seq_item_port = new("seq_item_port", this); + rsp_port = new("rsp_port", this); + seq_item_prod_if = seq_item_port; + endfunction + virtual function void end_of_elaboration_phase(uvm_phase phase); + if(seq_item_port.size<1) + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"DRVCONNECT")) + uvm_report_warning ("DRVCONNECT", "the driver is not connected to a sequencer via the standard mechanisms enabled by connect()", UVM_NONE, "t/uvm/src/comps/uvm_driver.svh", 90, "", 1); + end + endfunction +endclass +class uvm_push_driver #(type REQ=uvm_sequence_item, + type RSP=REQ) extends uvm_component; + typedef uvm_component_registry #(uvm_push_driver#(REQ,RSP)) type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_push_driver #(REQ,RSP)"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_push_driver #(REQ,RSP)"; + endfunction : get_type_name + uvm_blocking_put_imp #(REQ, uvm_push_driver #(REQ,RSP)) req_export; + uvm_analysis_port #(RSP) rsp_port; + REQ req; + RSP rsp; + function new (string name, uvm_component parent); + super.new(name, parent); + req_export = new("req_export", this); + rsp_port = new("rsp_port", this); + endfunction + function void check_port_connections(); + if (req_export.size() != 1) + uvm_report_fatal("Connection Error", + $sformatf("Must connect to seq_item_port(%0d)", + req_export.size()), UVM_NONE); + endfunction + virtual function void end_of_elaboration_phase(uvm_phase phase); + super.end_of_elaboration_phase(phase); + check_port_connections(); + endfunction + virtual task put(REQ item); + uvm_report_fatal("UVM_PUSH_DRIVER", "Put task for push driver is not implemented", UVM_NONE); + endtask +endclass +virtual class uvm_scoreboard extends uvm_component; + typedef uvm_abstract_component_registry #(uvm_scoreboard,"uvm_scoreboard") type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_scoreboard"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_scoreboard"; + endfunction : get_type_name + function new (string name, uvm_component parent); + super.new(name, parent); + endfunction +endclass +virtual class uvm_agent extends uvm_component; + uvm_active_passive_enum is_active = UVM_ACTIVE; + typedef uvm_abstract_component_registry #(uvm_agent,"uvm_agent") type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_agent"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_agent"; + endfunction : get_type_name + function new (string name, uvm_component parent); + super.new(name, parent); + endfunction + function void build_phase(uvm_phase phase); + int active; + uvm_resource_pool rp; + uvm_resource_types::rsrc_q_t rq; + bit found; + super.build_phase(phase); + rp = uvm_resource_pool::get(); + rq = rp.lookup_name(get_full_name(), "is_active", null, 0); + uvm_resource_pool::sort_by_precedence(rq); + for (int i = 0; i < rq.size() && !found; i++) begin + uvm_resource_base rsrc = rq.get(i); +begin +begin + uvm_resource#(uvm_active_passive_enum) __tmp_rsrc__; + found = $cast(__tmp_rsrc__, rsrc); + if (found) begin + is_active = __tmp_rsrc__.read(this); + end +end + if (!found) begin + uvm_active_passive_enum __tmp_val__; + string __tmp_string_val__; + bit __tmp_success_val__; +begin + uvm_resource#(string) __tmp_rsrc__; + __tmp_success_val__ = $cast(__tmp_rsrc__, rsrc); + if (__tmp_success_val__) begin + __tmp_string_val__ = __tmp_rsrc__.read(this); + end +end + if (__tmp_success_val__ && + uvm_enum_wrapper#(uvm_active_passive_enum)::from_name(__tmp_string_val__, + __tmp_val__)) begin + is_active = __tmp_val__; + found = __tmp_success_val__; + end + end + if (!found) begin + typedef bit [$bits(uvm_active_passive_enum)-1:0] __tmp_int_t__; + __tmp_int_t__ __tmp_int_val__; + bit __tmp_success_val__; +begin +begin + uvm_resource#(__tmp_int_t__) __tmp_rsrc__; + __tmp_success_val__ = $cast(__tmp_rsrc__, rsrc); + if (__tmp_success_val__) begin + __tmp_int_val__ = __tmp_rsrc__.read(this); + end +end + if (!__tmp_success_val__) +begin +begin + uvm_resource#(uvm_integral_t) __tmp_rsrc__; + __tmp_success_val__ = $cast(__tmp_rsrc__, rsrc); + if (__tmp_success_val__) begin + __tmp_int_val__ = __tmp_rsrc__.read(this); + end +end + if (!__tmp_success_val__) +begin + uvm_resource#(uvm_bitstream_t) __tmp_rsrc__; + __tmp_success_val__ = $cast(__tmp_rsrc__, rsrc); + if (__tmp_success_val__) begin + __tmp_int_val__ = __tmp_rsrc__.read(this); + end +end + if (!__tmp_success_val__) +begin + uvm_resource#(int) __tmp_rsrc__; + __tmp_success_val__ = $cast(__tmp_rsrc__, rsrc); + if (__tmp_success_val__) begin + __tmp_int_val__ = __tmp_rsrc__.read(this); + end +end + if (!__tmp_success_val__) +begin + uvm_resource#(int unsigned) __tmp_rsrc__; + __tmp_success_val__ = $cast(__tmp_rsrc__, rsrc); + if (__tmp_success_val__) begin + __tmp_int_val__ = __tmp_rsrc__.read(this); + end +end +end +end + if (__tmp_success_val__) begin + is_active = uvm_active_passive_enum'(__tmp_int_val__); + found = __tmp_success_val__; + end + end +end + end + endfunction + virtual function uvm_active_passive_enum get_is_active(); + return is_active; + endfunction +endclass +virtual class uvm_env extends uvm_component; + typedef uvm_abstract_component_registry #(uvm_env,"uvm_env") type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_env"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_env"; + endfunction : get_type_name + function new (string name="env", uvm_component parent=null); + super.new(name,parent); + endfunction +endclass +virtual class uvm_test extends uvm_component; + typedef uvm_abstract_component_registry #(uvm_test,"uvm_test") type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_test"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_test"; + endfunction : get_type_name + function new (string name, uvm_component parent); + super.new(name,parent); + endfunction +endclass +typedef class uvm_sequence_base; +typedef class uvm_sequencer_base; +class uvm_sequence_item extends uvm_transaction; + local int m_sequence_id = -1; + protected bit m_use_sequence_info; + protected int m_depth = -1; + protected uvm_sequencer_base m_sequencer; + protected uvm_sequence_base m_parent_sequence; + static bit issued1,issued2; + bit print_sequence_info; + function new (string name = "uvm_sequence_item"); + super.new(name); + endfunction + function string get_type_name(); + return "uvm_sequence_item"; + endfunction + typedef uvm_object_registry#(uvm_sequence_item,"uvm_sequence_item") type_id; + static function uvm_sequence_item type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function void set_sequence_id(int id); + m_sequence_id = id; + endfunction + function int get_sequence_id(); + return (m_sequence_id); + endfunction + function void set_item_context(uvm_sequence_base parent_seq, + uvm_sequencer_base sequencer = null); + set_use_sequence_info(1); + if (parent_seq != null) set_parent_sequence(parent_seq); + if (sequencer == null && m_parent_sequence != null) sequencer = m_parent_sequence.get_sequencer(); + set_sequencer(sequencer); + if (m_parent_sequence != null) set_depth(m_parent_sequence.get_depth() + 1); + reseed(); + endfunction + function void set_use_sequence_info(bit value); + m_use_sequence_info = value; + endfunction + function bit get_use_sequence_info(); + return (m_use_sequence_info); + endfunction + function void set_id_info(uvm_sequence_item item); + if (item == null) begin + uvm_report_fatal(get_full_name(), "set_id_info called with null parameter", UVM_NONE); + end + this.set_transaction_id(item.get_transaction_id()); + this.set_sequence_id(item.get_sequence_id()); + endfunction + virtual function void set_sequencer(uvm_sequencer_base sequencer); + m_sequencer = sequencer; + m_set_p_sequencer(); + endfunction + function uvm_sequencer_base get_sequencer(); + return m_sequencer; + endfunction + function void set_parent_sequence(uvm_sequence_base parent); + m_parent_sequence = parent; + endfunction + function uvm_sequence_base get_parent_sequence(); + return (m_parent_sequence); + endfunction + function void set_depth(int value); + m_depth = value; + endfunction + function int get_depth(); + if (m_depth != -1) begin + return (m_depth); + end + if (m_parent_sequence == null) begin + m_depth = 1; + end else begin + m_depth = m_parent_sequence.get_depth() + 1; + end + return (m_depth); + endfunction + virtual function bit is_item(); + return(1); + endfunction + function string get_full_name(); + if(m_parent_sequence != null) + get_full_name = {m_parent_sequence.get_full_name(), "."}; + else if(m_sequencer!=null) + get_full_name = {m_sequencer.get_full_name(), "."}; + if(get_name() != "") + get_full_name = {get_full_name, get_name()}; + else begin + get_full_name = {get_full_name, "_item"}; + end + endfunction + function string get_root_sequence_name(); + uvm_sequence_base root_seq; + root_seq = get_root_sequence(); + if (root_seq == null) + return ""; + else + return root_seq.get_name(); + endfunction + virtual function void m_set_p_sequencer(); + return; + endfunction + function uvm_sequence_base get_root_sequence(); + uvm_sequence_item root_seq_base; + uvm_sequence_base root_seq; + root_seq_base = this; + while(1) begin + if(root_seq_base.get_parent_sequence()!=null) begin + root_seq_base = root_seq_base.get_parent_sequence(); + $cast(root_seq, root_seq_base); + end + else + return root_seq; + end + endfunction + function string get_sequence_path(); + uvm_sequence_item this_item; + string seq_path; + this_item = this; + seq_path = this.get_name(); + while(1) begin + if(this_item.get_parent_sequence()!=null) begin + this_item = this_item.get_parent_sequence(); + seq_path = {this_item.get_name(), ".", seq_path}; + end + else + return seq_path; + end + endfunction + virtual function uvm_report_object uvm_get_report_object(); + if(m_sequencer == null) begin + uvm_coreservice_t cs = uvm_coreservice_t::get(); + return cs.get_root(); + end else + return m_sequencer; + endfunction + function int uvm_report_enabled(int verbosity, + uvm_severity severity=UVM_INFO, string id=""); + uvm_report_object l_report_object = uvm_get_report_object(); + if (l_report_object.get_report_verbosity_level(severity, id) < verbosity) + return 0; + return 1; + endfunction + 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, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + uvm_report_message l_report_message; + if (report_enabled_checked == 0) begin + if (!uvm_report_enabled(verbosity, severity, id)) + return; + end + l_report_message = uvm_report_message::new_report_message(); + l_report_message.set_report_message(severity, id, message, + verbosity, filename, line, context_name); + uvm_process_report_message(l_report_message); + endfunction + virtual function void uvm_report_info( string id, + string message, + int verbosity = UVM_MEDIUM, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + this.uvm_report(UVM_INFO, id, message, verbosity, filename, line, + context_name, report_enabled_checked); + endfunction + virtual function void uvm_report_warning( string id, + string message, + int verbosity = UVM_MEDIUM, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + this.uvm_report(UVM_WARNING, id, message, verbosity, filename, line, + context_name, report_enabled_checked); + endfunction + virtual function void uvm_report_error( string id, + string message, + int verbosity = UVM_NONE, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + this.uvm_report(UVM_ERROR, id, message, verbosity, filename, line, + context_name, report_enabled_checked); + endfunction + virtual function void uvm_report_fatal( string id, + string message, + int verbosity = UVM_NONE, + string filename = "", + int line = 0, + string context_name = "", + bit report_enabled_checked = 0); + this.uvm_report(UVM_FATAL, id, message, verbosity, filename, line, + context_name, report_enabled_checked); + endfunction + virtual function void uvm_process_report_message (uvm_report_message report_message); + uvm_report_object l_report_object = uvm_get_report_object(); + report_message.set_report_object(l_report_object); + if (report_message.get_context() == "") + report_message.set_context(get_sequence_path()); + l_report_object.m_rh.process_report_message(report_message); + endfunction + function void do_print (uvm_printer printer); + string temp_str0, temp_str1; + int depth = get_depth(); + super.do_print(printer); + if(print_sequence_info || m_use_sequence_info) begin + printer.print_field_int("depth", depth, $bits(depth), UVM_DEC, ".", "int"); + if(m_parent_sequence != null) begin + temp_str0 = m_parent_sequence.get_name(); + temp_str1 = m_parent_sequence.get_full_name(); + end + printer.print_string("parent sequence (name)", temp_str0); + printer.print_string("parent sequence (full name)", temp_str1); + temp_str1 = ""; + if(m_sequencer != null) begin + temp_str1 = m_sequencer.get_full_name(); + end + printer.print_string("sequencer", temp_str1); + end + endfunction +endclass +typedef uvm_config_db#(uvm_sequence_base) uvm_config_seq; +typedef class uvm_sequence_request; +class uvm_sequence_process_wrapper; + process pid; + uvm_sequence_base seq; +endclass : uvm_sequence_process_wrapper +virtual +class uvm_sequencer_base extends uvm_component; + typedef enum {SEQ_TYPE_REQ, + SEQ_TYPE_LOCK} seq_req_t; + protected uvm_sequence_request arb_sequence_q[$]; + protected bit arb_completed[int]; + protected uvm_sequence_base lock_list[$]; + protected uvm_sequence_base reg_sequences[int]; + protected int m_sequencer_id; + protected int m_lock_arb_size; + protected int m_arb_size; + protected int m_wait_for_item_sequence_id, + m_wait_for_item_transaction_id; + protected int m_wait_relevant_count = 0 ; + protected int m_max_zero_time_wait_relevant_count = 10; + protected time m_last_wait_relevant_time = 0 ; + local uvm_sequencer_arb_mode m_arbitration = UVM_SEQ_ARB_FIFO; + local static int g_request_id; + local static int g_sequence_id = 1; + local static int g_sequencer_id = 1; + extern function new (string name, uvm_component parent); + extern function bit is_child (uvm_sequence_base parent, uvm_sequence_base child); + extern virtual function int user_priority_arbitration(int avail_sequences[$]); + extern virtual task execute_item(uvm_sequence_item item); + protected uvm_sequence_process_wrapper m_default_sequences[uvm_phase]; + extern virtual function void start_phase_sequence(uvm_phase phase); + extern virtual function void stop_phase_sequence(uvm_phase phase); + extern virtual task wait_for_grant(uvm_sequence_base sequence_ptr, + int item_priority = -1, + bit lock_request = 0); + extern virtual task wait_for_item_done(uvm_sequence_base sequence_ptr, + int transaction_id); + extern function bit is_blocked(uvm_sequence_base sequence_ptr); + extern function bit has_lock(uvm_sequence_base sequence_ptr); + extern virtual task lock(uvm_sequence_base sequence_ptr); + extern virtual task grab(uvm_sequence_base sequence_ptr); + extern virtual function void unlock(uvm_sequence_base sequence_ptr); + extern virtual function void ungrab(uvm_sequence_base sequence_ptr); + extern virtual function void stop_sequences(); + extern virtual function bit is_grabbed(); + extern virtual function uvm_sequence_base current_grabber(); + extern virtual function bit has_do_available(); + extern function void set_arbitration(UVM_SEQ_ARB_TYPE val); + extern function UVM_SEQ_ARB_TYPE get_arbitration(); + extern virtual task wait_for_sequences(); + extern virtual function void send_request(uvm_sequence_base sequence_ptr, + uvm_sequence_item t, + bit rerandomize = 0); + extern virtual function void set_max_zero_time_wait_relevant_count(int new_val) ; + extern virtual function uvm_sequence_base get_arbitration_sequence( int index ); + extern protected function void grant_queued_locks(); + extern protected task m_select_sequence(); + extern protected function int m_choose_next_request(); + extern task m_wait_for_arbitration_completed(int request_id); + extern function void m_set_arbitration_completed(int request_id); + extern local task m_lock_req(uvm_sequence_base sequence_ptr, bit lock); + extern function void m_unlock_req(uvm_sequence_base sequence_ptr); + extern local function void remove_sequence_from_queues(uvm_sequence_base sequence_ptr); + extern function void m_sequence_exiting(uvm_sequence_base sequence_ptr); + extern function void kill_sequence(uvm_sequence_base sequence_ptr); + extern virtual function void analysis_write(uvm_sequence_item t); + extern function void do_print (uvm_printer printer); + extern virtual function int m_register_sequence(uvm_sequence_base sequence_ptr); + extern protected + virtual function void m_unregister_sequence(int sequence_id); + extern protected function + uvm_sequence_base m_find_sequence(int sequence_id); + extern protected function void m_update_lists(); + extern function string convert2string(); + extern protected + virtual function int m_find_number_driver_connections(); + extern protected task m_wait_arb_not_equal(); + extern protected task m_wait_for_available_sequence(); + extern protected function int m_get_seq_item_priority(uvm_sequence_request seq_q_entry); + int m_is_relevant_completed; + local bit m_auto_item_recording = 1; + virtual function void disable_auto_item_recording(); + m_auto_item_recording = 0; + endfunction + virtual function bit is_auto_item_recording_enabled(); + return m_auto_item_recording; + endfunction + static uvm_sequencer_base all_sequencer_insts[int unsigned]; +endclass +function uvm_sequencer_base::new (string name, uvm_component parent); + super.new(name, parent); + m_sequencer_id = g_sequencer_id++; + m_lock_arb_size = -1; + all_sequencer_insts[m_sequencer_id]=this; +endfunction +function void uvm_sequencer_base::do_print (uvm_printer printer); + super.do_print(printer); + printer.print_array_header("arbitration_queue", arb_sequence_q.size()); + foreach (arb_sequence_q[i]) + printer.print_string($sformatf("[%0d]", i), + $sformatf("%s@seqid%0d",arb_sequence_q[i].request.name(),arb_sequence_q[i].sequence_id), "["); + printer.print_array_footer(arb_sequence_q.size()); + printer.print_array_header("lock_queue", lock_list.size()); + foreach(lock_list[i]) + printer.print_string($sformatf("[%0d]", i), + $sformatf("%s@seqid%0d",lock_list[i].get_full_name(),lock_list[i].get_sequence_id()), "["); + printer.print_array_footer(lock_list.size()); +endfunction +function void uvm_sequencer_base::m_update_lists(); + m_lock_arb_size++; +endfunction +function string uvm_sequencer_base::convert2string(); + string s; + $sformat(s, " -- arb i/id/type: "); + foreach (arb_sequence_q[i]) begin + $sformat(s, "%s %0d/%0d/%s ", s, i, arb_sequence_q[i].sequence_id, arb_sequence_q[i].request.name()); + end + $sformat(s, "%s\n -- lock_list i/id: ", s); + foreach (lock_list[i]) begin + $sformat(s, "%s %0d/%0d",s, i, lock_list[i].get_sequence_id()); + end + return(s); +endfunction +function int uvm_sequencer_base::m_find_number_driver_connections(); + return 0; +endfunction +function int uvm_sequencer_base::m_register_sequence(uvm_sequence_base sequence_ptr); + if (sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 1) > 0) + return sequence_ptr.get_sequence_id(); + sequence_ptr.m_set_sqr_sequence_id(m_sequencer_id, g_sequence_id++); + reg_sequences[sequence_ptr.get_sequence_id()] = sequence_ptr; + return sequence_ptr.get_sequence_id(); +endfunction +function uvm_sequence_base uvm_sequencer_base::m_find_sequence(int sequence_id); + uvm_sequence_base seq_ptr; + int i; + if (sequence_id == -1) begin + if (reg_sequences.first(i)) begin + return(reg_sequences[i]); + end + return(null); + end + if (!reg_sequences.exists(sequence_id)) + return null; + return reg_sequences[sequence_id]; +endfunction +function void uvm_sequencer_base::m_unregister_sequence(int sequence_id); + if (!reg_sequences.exists(sequence_id)) + return; + reg_sequences.delete(sequence_id); +endfunction +function int uvm_sequencer_base::user_priority_arbitration(int avail_sequences[$]); + return avail_sequences[0]; +endfunction +function void uvm_sequencer_base::grant_queued_locks(); + begin + uvm_sequence_request zombies[$]; + zombies = arb_sequence_q.find(item) with (item.request==SEQ_TYPE_LOCK && item.process_id.status inside {process::KILLED,process::FINISHED}); + foreach(zombies[idx]) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"SEQLCKZMB")) + uvm_report_error ("SEQLCKZMB", $sformatf("The task responsible for requesting a lock on sequencer '%s' for sequence '%s' has been killed, to avoid a deadlock the sequence will be removed from the arbitration queues", this.get_full_name(), zombies[idx].sequence_ptr.get_full_name()), UVM_NONE, "t/uvm/src/seq/uvm_sequencer_base.svh", 557, "", 1); + end + remove_sequence_from_queues(zombies[idx].sequence_ptr); + end + end + begin + int lock_req_indices[$]; + lock_req_indices = arb_sequence_q.find_first_index(item) with (item.request==SEQ_TYPE_LOCK && is_blocked(item.sequence_ptr) == 0); + if(lock_req_indices.size()) begin + uvm_sequence_request lock_req = arb_sequence_q[lock_req_indices[0]]; + lock_list.push_back(lock_req.sequence_ptr); + m_set_arbitration_completed(lock_req.request_id); + arb_sequence_q.delete(lock_req_indices[0]); + m_update_lists(); + end + end +endfunction +task uvm_sequencer_base::m_select_sequence(); + int selected_sequence; + do begin + wait_for_sequences(); + selected_sequence = m_choose_next_request(); + if (selected_sequence == -1) begin + m_wait_for_available_sequence(); + end + end while (selected_sequence == -1); + if (selected_sequence >= 0) begin + m_set_arbitration_completed(arb_sequence_q[selected_sequence].request_id); + arb_sequence_q.delete(selected_sequence); + m_update_lists(); + end +endtask +function int uvm_sequencer_base::m_choose_next_request(); + int i, temp; + int avail_sequence_count; + int sum_priority_val; + int avail_sequences[$]; + int highest_sequences[$]; + int highest_pri; + string s; + avail_sequence_count = 0; + grant_queued_locks(); + i = 0; + while (i < arb_sequence_q.size()) begin + if ((arb_sequence_q[i].process_id.status == process::KILLED) || + (arb_sequence_q[i].process_id.status == process::FINISHED)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"SEQREQZMB")) + uvm_report_error ("SEQREQZMB", $sformatf("The task responsible for requesting a wait_for_grant on sequencer '%s' for sequence '%s' has been killed, to avoid a deadlock the sequence will be removed from the arbitration queues", this.get_full_name(), arb_sequence_q[i].sequence_ptr.get_full_name()), UVM_NONE, "t/uvm/src/seq/uvm_sequencer_base.svh", 625, "", 1); + end + remove_sequence_from_queues(arb_sequence_q[i].sequence_ptr); + continue; + end + if (i < arb_sequence_q.size()) + if (arb_sequence_q[i].request == SEQ_TYPE_REQ) + if (is_blocked(arb_sequence_q[i].sequence_ptr) == 0) + if (arb_sequence_q[i].sequence_ptr.is_relevant() == 1) begin + if (m_arbitration == UVM_SEQ_ARB_FIFO) begin + return i; + end + else avail_sequences.push_back(i); + end + i++; + end + if (m_arbitration == UVM_SEQ_ARB_FIFO) begin + return -1; + end + if (avail_sequences.size() < 1) begin + return -1; + end + if (avail_sequences.size() == 1) begin + return avail_sequences[0]; + end + if (lock_list.size() > 0) begin + for (i = 0; i < avail_sequences.size(); i++) begin + if (is_blocked(arb_sequence_q[avail_sequences[i]].sequence_ptr) != 0) begin + avail_sequences.delete(i); + i--; + end + end + if (avail_sequences.size() < 1) + return -1; + if (avail_sequences.size() == 1) + return avail_sequences[0]; + end + if (m_arbitration == UVM_SEQ_ARB_WEIGHTED) begin + sum_priority_val = 0; + for (i = 0; i < avail_sequences.size(); i++) begin + sum_priority_val += m_get_seq_item_priority(arb_sequence_q[avail_sequences[i]]); + end + temp = $urandom_range(sum_priority_val-1, 0); + sum_priority_val = 0; + for (i = 0; i < avail_sequences.size(); i++) begin + if ((m_get_seq_item_priority(arb_sequence_q[avail_sequences[i]]) + + sum_priority_val) > temp) begin + return avail_sequences[i]; + end + sum_priority_val += m_get_seq_item_priority(arb_sequence_q[avail_sequences[i]]); + end + uvm_report_fatal("Sequencer", "UVM Internal error in weighted arbitration code", UVM_NONE); + end + if (m_arbitration == UVM_SEQ_ARB_RANDOM) begin + i = $urandom_range(avail_sequences.size()-1, 0); + return avail_sequences[i]; + end + if ((m_arbitration == UVM_SEQ_ARB_STRICT_FIFO) || m_arbitration == UVM_SEQ_ARB_STRICT_RANDOM) begin + highest_pri = 0; + for (i = 0; i < avail_sequences.size(); i++) begin + if (m_get_seq_item_priority(arb_sequence_q[avail_sequences[i]]) > highest_pri) begin + highest_sequences.delete(); + highest_sequences.push_back(avail_sequences[i]); + highest_pri = m_get_seq_item_priority(arb_sequence_q[avail_sequences[i]]); + end + else if (m_get_seq_item_priority(arb_sequence_q[avail_sequences[i]]) == highest_pri) begin + highest_sequences.push_back(avail_sequences[i]); + end + end + if (m_arbitration == UVM_SEQ_ARB_STRICT_FIFO) begin + return(highest_sequences[0]); + end + i = $urandom_range(highest_sequences.size()-1, 0); + return highest_sequences[i]; + end + if (m_arbitration == UVM_SEQ_ARB_USER) begin + i = user_priority_arbitration( avail_sequences); + highest_sequences = avail_sequences.find with (item == i); + if (highest_sequences.size() == 0) begin + uvm_report_fatal("Sequencer", + $sformatf("Error in User arbitration, sequence %0d not available\n%s", + i, convert2string()), UVM_NONE); + end + return(i); + end + uvm_report_fatal("Sequencer", "Internal error: Failed to choose sequence", UVM_NONE); +endfunction +task uvm_sequencer_base::m_wait_arb_not_equal(); + wait (m_arb_size != m_lock_arb_size); +endtask +task uvm_sequencer_base::m_wait_for_available_sequence(); + int i; + int is_relevant_entries[$]; + m_arb_size = m_lock_arb_size; + for (i = 0; i < arb_sequence_q.size(); i++) begin + if (arb_sequence_q[i].request == SEQ_TYPE_REQ) begin + if (is_blocked(arb_sequence_q[i].sequence_ptr) == 0) begin + if (arb_sequence_q[i].sequence_ptr.is_relevant() == 0) begin + is_relevant_entries.push_back(i); + end + end + end + end + if (is_relevant_entries.size() == 0) begin + m_wait_arb_not_equal(); + return; + end + fork + begin + fork + begin + fork + begin + m_is_relevant_completed = 0; + for(i = 0; i < is_relevant_entries.size(); i++) begin + fork + automatic int k = i; + begin +//TODO issue #4493 - Fix UVM fork..join_none local variable can't locate varref scope +//TODO %Error: Internal Error: t/t_uvm_pkg_todo.vh:19203:56: ../V3Scope.cpp:80: Can't locate varref scope +//TODO arb_sequence_q[is_relevant_entries[k]].sequence_ptr.wait_for_relevant(); + if ($realtime != m_last_wait_relevant_time) begin + m_last_wait_relevant_time = $realtime ; + m_wait_relevant_count = 0 ; + end + else begin + m_wait_relevant_count++ ; + if (m_wait_relevant_count > m_max_zero_time_wait_relevant_count) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"SEQRELEVANTLOOP")) + uvm_report_fatal ("SEQRELEVANTLOOP", $sformatf("Zero time loop detected, passed wait_for_relevant %0d times without time advancing",m_wait_relevant_count), UVM_NONE, "t/uvm/src/seq/uvm_sequencer_base.svh", 798, "", 1); + end + end + end + m_is_relevant_completed = 1; + end + join_none + end + wait (m_is_relevant_completed > 0); + end + begin + m_wait_arb_not_equal(); + end + join_any + end + join_any +//TODO issue #4125 - Support disable fork +//TODO %Error-UNSUPPORTED: t/t_uvm_pkg_todo.vh:19213:12: Unsupported: disable fork statements +//TODO disable fork; + end + join +endtask +function int uvm_sequencer_base::m_get_seq_item_priority(uvm_sequence_request seq_q_entry); + if (seq_q_entry.item_priority != -1) begin + if (seq_q_entry.item_priority <= 0) begin + uvm_report_fatal("SEQITEMPRI", + $sformatf("Sequence item from %s has illegal priority: %0d", + seq_q_entry.sequence_ptr.get_full_name(), + seq_q_entry.item_priority), UVM_NONE); + end + return seq_q_entry.item_priority; + end + if (seq_q_entry.sequence_ptr.get_priority() < 0) begin + uvm_report_fatal("SEQDEFPRI", + $sformatf("Sequence %s has illegal priority: %0d", + seq_q_entry.sequence_ptr.get_full_name(), + seq_q_entry.sequence_ptr.get_priority()), UVM_NONE); + end + return seq_q_entry.sequence_ptr.get_priority(); +endfunction +task uvm_sequencer_base::m_wait_for_arbitration_completed(int request_id); + int lock_arb_size; + forever + begin + lock_arb_size = m_lock_arb_size; + if (arb_completed.exists(request_id)) begin + arb_completed.delete(request_id); + return; + end + wait (lock_arb_size != m_lock_arb_size); + end +endtask +function void uvm_sequencer_base::m_set_arbitration_completed(int request_id); + arb_completed[request_id] = 1; +endfunction +function bit uvm_sequencer_base::is_child (uvm_sequence_base parent, + uvm_sequence_base child); + uvm_sequence_base child_parent; + if (child == null) begin + uvm_report_fatal("uvm_sequencer", "is_child passed null child", UVM_NONE); + end + if (parent == null) begin + uvm_report_fatal("uvm_sequencer", "is_child passed null parent", UVM_NONE); + end + child_parent = child.get_parent_sequence(); + while (child_parent != null) begin + if (child_parent.get_inst_id() == parent.get_inst_id()) begin + return 1; + end + child_parent = child_parent.get_parent_sequence(); + end + return 0; +endfunction +class m_uvm_sqr_seq_base extends uvm_sequence_base; + function new(string name="unnamed-m_uvm_sqr_seq_base"); + super.new(name); + endfunction : new +endclass : m_uvm_sqr_seq_base +task uvm_sequencer_base::execute_item(uvm_sequence_item item); + m_uvm_sqr_seq_base seq; + seq = new("execute_item_seq"); + item.set_sequencer(this); + item.set_parent_sequence(seq); + seq.set_sequencer(this); + seq.start_item(item); + seq.finish_item(item); +endtask +task uvm_sequencer_base::wait_for_grant(uvm_sequence_base sequence_ptr, + int item_priority = -1, + bit lock_request = 0); + uvm_sequence_request req_s; + int my_seq_id; + if (sequence_ptr == null) + uvm_report_fatal("uvm_sequencer", + "wait_for_grant passed null sequence_ptr", UVM_NONE); + my_seq_id = m_register_sequence(sequence_ptr); + if (lock_request == 1) begin + req_s = new(); + req_s.grant = 0; + req_s.sequence_id = my_seq_id; + req_s.request = SEQ_TYPE_LOCK; + req_s.sequence_ptr = sequence_ptr; + req_s.request_id = g_request_id++; + req_s.process_id = process::self(); + arb_sequence_q.push_back(req_s); + end + req_s = new(); + req_s.grant = 0; + req_s.request = SEQ_TYPE_REQ; + req_s.sequence_id = my_seq_id; + req_s.item_priority = item_priority; + req_s.sequence_ptr = sequence_ptr; + req_s.request_id = g_request_id++; + req_s.process_id = process::self(); + arb_sequence_q.push_back(req_s); + m_update_lists(); + m_wait_for_arbitration_completed(req_s.request_id); + req_s.sequence_ptr.m_wait_for_grant_semaphore++; +endtask +task uvm_sequencer_base::wait_for_item_done(uvm_sequence_base sequence_ptr, + int transaction_id); + int sequence_id; + sequence_id = sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 1); + m_wait_for_item_sequence_id = -1; + m_wait_for_item_transaction_id = -1; + if (transaction_id == -1) + wait (m_wait_for_item_sequence_id == sequence_id); + else + wait ((m_wait_for_item_sequence_id == sequence_id && + m_wait_for_item_transaction_id == transaction_id)); +endtask +function bit uvm_sequencer_base::is_blocked(uvm_sequence_base sequence_ptr); + if (sequence_ptr == null) + uvm_report_fatal("uvm_sequence_controller", + "is_blocked passed null sequence_ptr", UVM_NONE); + foreach (lock_list[i]) begin + if ((lock_list[i].get_inst_id() != + sequence_ptr.get_inst_id()) && + (is_child(lock_list[i], sequence_ptr) == 0)) begin + return 1; + end + end + return 0; +endfunction +function bit uvm_sequencer_base::has_lock(uvm_sequence_base sequence_ptr); + int my_seq_id; + if (sequence_ptr == null) + uvm_report_fatal("uvm_sequence_controller", + "has_lock passed null sequence_ptr", UVM_NONE); + my_seq_id = m_register_sequence(sequence_ptr); + foreach (lock_list[i]) begin + if (lock_list[i].get_inst_id() == sequence_ptr.get_inst_id()) begin + return 1; + end + end + return 0; +endfunction +task uvm_sequencer_base::m_lock_req(uvm_sequence_base sequence_ptr, bit lock); + int my_seq_id; + uvm_sequence_request new_req; + if (sequence_ptr == null) + uvm_report_fatal("uvm_sequence_controller", + "lock_req passed null sequence_ptr", UVM_NONE); + my_seq_id = m_register_sequence(sequence_ptr); + new_req = new(); + new_req.grant = 0; + new_req.sequence_id = sequence_ptr.get_sequence_id(); + new_req.request = SEQ_TYPE_LOCK; + new_req.sequence_ptr = sequence_ptr; + new_req.request_id = g_request_id++; + new_req.process_id = process::self(); + if (lock == 1) begin + arb_sequence_q.push_back(new_req); + end else begin + arb_sequence_q.push_front(new_req); + m_update_lists(); + end + grant_queued_locks(); + m_wait_for_arbitration_completed(new_req.request_id); +endtask +function void uvm_sequencer_base::m_unlock_req(uvm_sequence_base sequence_ptr); + if (sequence_ptr == null) begin + uvm_report_fatal("uvm_sequencer", + "m_unlock_req passed null sequence_ptr", UVM_NONE); + end + begin + int q[$]; + int seqid=sequence_ptr.get_inst_id(); + q=lock_list.find_first_index(item) with (item.get_inst_id() == seqid); + if(q.size()==1) begin + lock_list.delete(q[0]); + grant_queued_locks(); + m_update_lists(); + end + else + uvm_report_warning("SQRUNL", + {"Sequence '", sequence_ptr.get_full_name(), + "' called ungrab / unlock, but didn't have lock"}, UVM_NONE); + end +endfunction +task uvm_sequencer_base::lock(uvm_sequence_base sequence_ptr); + m_lock_req(sequence_ptr, 1); +endtask +task uvm_sequencer_base::grab(uvm_sequence_base sequence_ptr); + m_lock_req(sequence_ptr, 0); +endtask +function void uvm_sequencer_base::unlock(uvm_sequence_base sequence_ptr); + m_unlock_req(sequence_ptr); +endfunction +function void uvm_sequencer_base::ungrab(uvm_sequence_base sequence_ptr); + m_unlock_req(sequence_ptr); +endfunction +function void uvm_sequencer_base::remove_sequence_from_queues( + uvm_sequence_base sequence_ptr); + int i; + int seq_id; + seq_id = sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 0); + i = 0; + do + begin + if (arb_sequence_q.size() > i) begin + if ((arb_sequence_q[i].sequence_id == seq_id) || + (is_child(sequence_ptr, arb_sequence_q[i].sequence_ptr))) begin + if (sequence_ptr.get_sequence_state() == UVM_FINISHED) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"SEQFINERR")) + uvm_report_error ("SEQFINERR", $sformatf("Parent sequence '%s' should not finish before all items from itself and items from descendent sequences are processed. The item request from the sequence '%s' is being removed.", sequence_ptr.get_full_name(), arb_sequence_q[i].sequence_ptr.get_full_name()), UVM_NONE, "t/uvm/src/seq/uvm_sequencer_base.svh", 1153, "", 1); + end + arb_sequence_q.delete(i); + m_update_lists(); + end + else begin + i++; + end + end + end + while (i < arb_sequence_q.size()); + i = 0; + do + begin + if (lock_list.size() > i) begin + if ((lock_list[i].get_inst_id() == sequence_ptr.get_inst_id()) || + (is_child(sequence_ptr, lock_list[i]))) begin + if (sequence_ptr.get_sequence_state() == UVM_FINISHED) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"SEQFINERR")) + uvm_report_error ("SEQFINERR", $sformatf("Parent sequence '%s' should not finish before locks from itself and descedent sequences are removed. The lock held by the child sequence '%s' is being removed.",sequence_ptr.get_full_name(), lock_list[i].get_full_name()), UVM_NONE, "t/uvm/src/seq/uvm_sequencer_base.svh", 1172, "", 1); + end + lock_list.delete(i); + m_update_lists(); + end + else begin + i++; + end + end + end + while (i < lock_list.size()); + m_unregister_sequence(sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 1)); +endfunction +function void uvm_sequencer_base::stop_sequences(); + uvm_sequence_base seq_ptr; + seq_ptr = m_find_sequence(-1); + while (seq_ptr != null) + begin + kill_sequence(seq_ptr); + seq_ptr = m_find_sequence(-1); + end +endfunction +function void uvm_sequencer_base::m_sequence_exiting(uvm_sequence_base sequence_ptr); + remove_sequence_from_queues(sequence_ptr); +endfunction +function void uvm_sequencer_base::kill_sequence(uvm_sequence_base sequence_ptr); + remove_sequence_from_queues(sequence_ptr); + sequence_ptr.m_kill(); +endfunction +function bit uvm_sequencer_base::is_grabbed(); + return (lock_list.size() != 0); +endfunction +function uvm_sequence_base uvm_sequencer_base::current_grabber(); + if (lock_list.size() == 0) begin + return null; + end + return lock_list[lock_list.size()-1]; +endfunction +function bit uvm_sequencer_base::has_do_available(); + foreach (arb_sequence_q[i]) begin + if ((arb_sequence_q[i].sequence_ptr.is_relevant() == 1) && + (is_blocked(arb_sequence_q[i].sequence_ptr) == 0)) begin + return 1; + end + end + return 0; +endfunction +function void uvm_sequencer_base::set_arbitration(UVM_SEQ_ARB_TYPE val); + m_arbitration = val; +endfunction +function UVM_SEQ_ARB_TYPE uvm_sequencer_base::get_arbitration(); + return m_arbitration; +endfunction +function uvm_sequence_base uvm_sequencer_base::get_arbitration_sequence( int index); + return arb_sequence_q[index].sequence_ptr; +endfunction +function void uvm_sequencer_base::analysis_write(uvm_sequence_item t); + return; +endfunction +task uvm_sequencer_base::wait_for_sequences(); + uvm_wait_for_nba_region(); +endtask +function void uvm_sequencer_base::send_request(uvm_sequence_base sequence_ptr, + uvm_sequence_item t, + bit rerandomize = 0); + return; +endfunction +function void uvm_sequencer_base::set_max_zero_time_wait_relevant_count(int new_val) ; + m_max_zero_time_wait_relevant_count = new_val ; +endfunction +function void uvm_sequencer_base::start_phase_sequence(uvm_phase phase); + uvm_resource_pool rp = uvm_resource_pool::get(); + uvm_resource_types::rsrc_q_t rq; + uvm_sequence_base seq; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory f = cs.get_factory(); + rq = rp.lookup_name({get_full_name(), ".", phase.get_name(), "_phase"}, + "default_sequence", null, 0); + uvm_resource_pool::sort_by_precedence(rq); + for (int i = 0; seq == null && i < rq.size(); i++) begin + uvm_resource_base rsrc = rq.get(i); + uvm_resource#(uvm_sequence_base) sbr; + uvm_resource#(uvm_object_wrapper) owr; + if ($cast(sbr, rsrc) && sbr != null) begin + seq = sbr.read(this); + if (seq == null) begin + begin + if (uvm_report_enabled(UVM_FULL,UVM_INFO,"UVM/SQR/PH/DEF/SB/NULL")) + uvm_report_info ("UVM/SQR/PH/DEF/SB/NULL", {"Default phase sequence for phase '", phase.get_name(),"' explicitly disabled"}, UVM_FULL, "t/uvm/src/seq/uvm_sequencer_base.svh", 1341, "", 1); + end + return; + end + end + else if ($cast(owr, rsrc) && owr != null) begin + uvm_object_wrapper wrapper; + wrapper = owr.read(this); + if (wrapper == null) begin + begin + if (uvm_report_enabled(UVM_FULL,UVM_INFO,"UVM/SQR/PH/DEF/OW/NULL")) + uvm_report_info ("UVM/SQR/PH/DEF/OW/NULL", {"Default phase sequence for phase '", phase.get_name(),"' explicitly disabled"}, UVM_FULL, "t/uvm/src/seq/uvm_sequencer_base.svh", 1353, "", 1); + end + return; + end + if (!$cast(seq, f.create_object_by_type(wrapper, get_full_name(), + wrapper.get_type_name())) + || seq == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"PHASESEQ")) + uvm_report_warning ("PHASESEQ", {"Default sequence for phase '", phase.get_name(),"' %s is not a sequence type"}, UVM_NONE, "t/uvm/src/seq/uvm_sequencer_base.svh", 1361, "", 1); + end + return; + end + end + end + if (seq == null) begin + begin + if (uvm_report_enabled(UVM_FULL,UVM_INFO,"PHASESEQ")) + uvm_report_info ("PHASESEQ", {"No default phase sequence for phase '", phase.get_name(),"'"}, UVM_FULL, "t/uvm/src/seq/uvm_sequencer_base.svh", 1369, "", 1); + end + return; + end + begin + if (uvm_report_enabled(UVM_FULL,UVM_INFO,"PHASESEQ")) + uvm_report_info ("PHASESEQ", {"Starting default sequence '", seq.get_type_name(),"' for phase '", phase.get_name(),"'"}, UVM_FULL, "t/uvm/src/seq/uvm_sequencer_base.svh", 1374, "", 1); + end + seq.print_sequence_info = 1; + seq.set_sequencer(this); + seq.reseed(); + seq.set_starting_phase(phase); + if (seq.get_randomize_enabled() && !seq.randomize()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"STRDEFSEQ")) + uvm_report_warning ("STRDEFSEQ", {"Randomization failed for default sequence '", seq.get_type_name(),"' for phase '", phase.get_name(),"'"}, UVM_NONE, "t/uvm/src/seq/uvm_sequencer_base.svh", 1383, "", 1); + end + return; + end + fork begin + uvm_sequence_process_wrapper w = new(); + w.pid = process::self(); + w.seq = seq; + w.pid.srandom(uvm_create_random_seed(seq.get_type_name(), this.get_full_name())); + m_default_sequences[phase] = w; + seq.start(this); + m_default_sequences.delete(phase); + end + join_none +endfunction +function void uvm_sequencer_base::stop_phase_sequence(uvm_phase phase); + if (m_default_sequences.exists(phase)) begin + begin + if (uvm_report_enabled(UVM_FULL,UVM_INFO,"PHASESEQ")) + uvm_report_info ("PHASESEQ", {"Killing default sequence '", m_default_sequences[phase].seq.get_type_name(), "' for phase '", phase.get_name(), "'"}, UVM_FULL, "t/uvm/src/seq/uvm_sequencer_base.svh", 1409, "", 1); + end + m_default_sequences[phase].seq.kill(); + end + else begin + begin + if (uvm_report_enabled(UVM_FULL,UVM_INFO,"PHASESEQ")) + uvm_report_info ("PHASESEQ", {"No default sequence to kill for phase '", phase.get_name(), "'"}, UVM_FULL, "t/uvm/src/seq/uvm_sequencer_base.svh", 1415, "", 1); + end + end +endfunction : stop_phase_sequence +class uvm_sequence_request; + bit grant; + int sequence_id; + int request_id; + int item_priority; + process process_id; + uvm_sequencer_base::seq_req_t request; + uvm_sequence_base sequence_ptr; +endclass +class uvm_sequencer_analysis_fifo #(type RSP = uvm_sequence_item) extends uvm_tlm_fifo #(RSP); + uvm_analysis_imp #(RSP, uvm_sequencer_analysis_fifo #(RSP)) analysis_export; + uvm_sequencer_base sequencer_ptr; + function new (string name, uvm_component parent = null); + super.new(name, parent, 0); + analysis_export = new ("analysis_export", this); + endfunction + function void write(input RSP t); + if (sequencer_ptr == null) + uvm_report_fatal ("SEQRNULL", "The sequencer pointer is null when attempting a write", UVM_NONE); + sequencer_ptr.analysis_write(t); + endfunction +endclass +virtual + class uvm_sequencer_param_base #(type REQ = uvm_sequence_item, + type RSP = REQ) extends uvm_sequencer_base; + typedef uvm_sequencer_param_base #( REQ , RSP) this_type; + typedef REQ req_type; + typedef RSP rsp_type; + REQ m_last_req_buffer[$]; + RSP m_last_rsp_buffer[$]; + protected int m_num_last_reqs = 1; + protected int num_last_items = m_num_last_reqs; + protected int m_num_last_rsps = 1; + protected int m_num_reqs_sent; + protected int m_num_rsps_received; + uvm_sequencer_analysis_fifo #(RSP) sqr_rsp_analysis_fifo; + extern function new (string name, uvm_component parent); + extern virtual function void send_request(uvm_sequence_base sequence_ptr, + uvm_sequence_item t, + bit rerandomize = 0); + function REQ get_current_item(); + REQ t; + if (m_req_fifo.try_peek(t) == 0) + return null; + return t; + endfunction + extern function int get_num_reqs_sent(); + extern function void set_num_last_reqs(int unsigned max); + extern function int unsigned get_num_last_reqs(); + function REQ last_req(int unsigned n = 0); + if(n > m_num_last_reqs) begin + uvm_report_warning("HSTOB", + $sformatf("Invalid last access (%0d), the max history is %0d", n, + m_num_last_reqs)); + return null; + end + if(n == m_last_req_buffer.size()) + return null; + return m_last_req_buffer[n]; + endfunction + uvm_analysis_export #(RSP) rsp_export; + extern function int get_num_rsps_received(); + extern function void set_num_last_rsps(int unsigned max); + extern function int unsigned get_num_last_rsps(); + function RSP last_rsp(int unsigned n = 0); + if(n > m_num_last_rsps) begin + uvm_report_warning("HSTOB", + $sformatf("Invalid last access (%0d), the max history is %0d", n, + m_num_last_rsps)); + return null; + end + if(n == m_last_rsp_buffer.size()) + return null; + return m_last_rsp_buffer[n]; + endfunction + extern function void m_last_rsp_push_front(RSP item); + extern function void put_response (RSP t); + extern virtual function void build_phase(uvm_phase phase); + extern virtual function void connect_phase(uvm_phase phase); + extern virtual function void do_print (uvm_printer printer); + extern virtual function void analysis_write(uvm_sequence_item t); + extern function void m_last_req_push_front(REQ item); + uvm_tlm_fifo #(REQ) m_req_fifo; +endclass +function uvm_sequencer_param_base::new (string name, uvm_component parent); + super.new(name, parent); + rsp_export = new("rsp_export", this); + sqr_rsp_analysis_fifo = new("sqr_rsp_analysis_fifo", this); + sqr_rsp_analysis_fifo.print_enabled = 0; + m_req_fifo = new("req_fifo", this); + m_req_fifo.print_enabled = 0; +endfunction +function void uvm_sequencer_param_base::do_print (uvm_printer printer); + super.do_print(printer); + printer.print_field_int("num_last_reqs", m_num_last_reqs, $bits(m_num_last_reqs), UVM_DEC); + printer.print_field_int("num_last_rsps", m_num_last_rsps, $bits(m_num_last_rsps), UVM_DEC); +endfunction +function void uvm_sequencer_param_base::connect_phase(uvm_phase phase); + super.connect_phase(phase); + rsp_export.connect(sqr_rsp_analysis_fifo.analysis_export); +endfunction +function void uvm_sequencer_param_base::build_phase(uvm_phase phase); + super.build_phase(phase); + sqr_rsp_analysis_fifo.sequencer_ptr = this; +endfunction +function void uvm_sequencer_param_base::send_request(uvm_sequence_base sequence_ptr, + uvm_sequence_item t, + bit rerandomize = 0); + REQ param_t; + if (sequence_ptr == null) begin + uvm_report_fatal("SNDREQ", "Send request sequence_ptr is null", UVM_NONE); + end + if (sequence_ptr.m_wait_for_grant_semaphore < 1) begin + uvm_report_fatal("SNDREQ", "Send request called without wait_for_grant", UVM_NONE); + end + sequence_ptr.m_wait_for_grant_semaphore--; + if ($cast(param_t, t)) begin + if (rerandomize == 1) begin + if (!param_t.randomize()) begin + uvm_report_warning("SQRSNDREQ", "Failed to rerandomize sequence item in send_request"); + end + end + if (param_t.get_transaction_id() == -1) begin + param_t.set_transaction_id(sequence_ptr.m_next_transaction_id++); + end + m_last_req_push_front(param_t); + end else begin + uvm_report_fatal("SQRSNDREQCAST",$sformatf("send_request failed to cast sequence item"), UVM_NONE); + end + param_t.set_sequence_id(sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 1)); + t.set_sequencer(this); + if (m_req_fifo.try_put(param_t) != 1) begin + uvm_report_fatal("SQRSNDREQGNI", "Concurrent calls to get_next_item() not supported. Consider using a semaphore to ensure that concurrent processes take turns in the driver", UVM_NONE); + end + m_num_reqs_sent++; + grant_queued_locks(); +endfunction +function void uvm_sequencer_param_base::put_response (RSP t); + uvm_sequence_base sequence_ptr; + if (t == null) begin + uvm_report_fatal("SQRPUT", "Driver put a null response", UVM_NONE); + end + m_last_rsp_push_front(t); + m_num_rsps_received++; + if (t.get_sequence_id() == -1) begin + uvm_report_fatal("SQRPUT", "Driver put a response with null sequence_id", UVM_NONE); + return; + end + sequence_ptr = m_find_sequence(t.get_sequence_id()); + if (sequence_ptr != null) begin + if (sequence_ptr.get_use_response_handler() == 1) begin + sequence_ptr.response_handler(t); + return; + end + sequence_ptr.put_response(t); + end + else begin + uvm_report_warning("Sequencer", + $sformatf("Dropping response for sequence %0d, sequence not found. Probable cause: sequence exited or has been killed", + t.get_sequence_id())); + end +endfunction +function void uvm_sequencer_param_base::analysis_write(uvm_sequence_item t); + RSP response; + if (!$cast(response, t)) begin + uvm_report_fatal("ANALWRT", "Failure to cast analysis port write item", UVM_NONE); + end + put_response(response); +endfunction +function int uvm_sequencer_param_base::get_num_reqs_sent(); + return m_num_reqs_sent; +endfunction +function int uvm_sequencer_param_base::get_num_rsps_received(); + return m_num_rsps_received; +endfunction +function void uvm_sequencer_param_base::set_num_last_reqs(int unsigned max); + if(max > 1024) begin + uvm_report_warning("HSTOB", + $sformatf("Invalid last size; 1024 is the maximum and will be used")); + max = 1024; + end + while((m_last_req_buffer.size() != 0) && (m_last_req_buffer.size() > max)) + void'(m_last_req_buffer.pop_back()); + m_num_last_reqs = max; + num_last_items = max; +endfunction +function int unsigned uvm_sequencer_param_base::get_num_last_reqs(); + return m_num_last_reqs; +endfunction +function void uvm_sequencer_param_base::m_last_req_push_front(REQ item); + if(!m_num_last_reqs) + return; + if(m_last_req_buffer.size() == m_num_last_reqs) + void'(m_last_req_buffer.pop_back()); + this.m_last_req_buffer.push_front(item); +endfunction +function void uvm_sequencer_param_base::set_num_last_rsps(int unsigned max); + if(max > 1024) begin + uvm_report_warning("HSTOB", + $sformatf("Invalid last size; 1024 is the maximum and will be used")); + max = 1024; + end + while((m_last_rsp_buffer.size() != 0) && (m_last_rsp_buffer.size() > max)) begin + void'(m_last_rsp_buffer.pop_back()); + end + m_num_last_rsps = max; +endfunction +function int unsigned uvm_sequencer_param_base::get_num_last_rsps(); + return m_num_last_rsps; +endfunction +function void uvm_sequencer_param_base::m_last_rsp_push_front(RSP item); + if(!m_num_last_rsps) + return; + if(m_last_rsp_buffer.size() == m_num_last_rsps) + void'(m_last_rsp_buffer.pop_back()); + this.m_last_rsp_buffer.push_front(item); +endfunction +class uvm_sequencer #(type REQ=uvm_sequence_item, RSP=REQ) + extends uvm_sequencer_param_base #(REQ, RSP); + typedef uvm_sequencer #( REQ , RSP) this_type; + bit sequence_item_requested; + bit get_next_item_called; + typedef uvm_component_registry #(this_type) type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + extern function new (string name, uvm_component parent=null); + extern virtual function void stop_sequences(); + extern virtual function string get_type_name(); + uvm_seq_item_pull_imp #(REQ, RSP, this_type) seq_item_export; + extern virtual task get_next_item (output REQ t); + extern virtual task try_next_item (output REQ t); + extern virtual function void item_done (RSP item = null); + extern virtual task put (RSP t); + extern task get (output REQ t); + extern task peek (output REQ t); + extern function void item_done_trigger(RSP item = null); + function RSP item_done_get_trigger_data(); + return last_rsp(0); + endfunction + extern protected virtual function int m_find_number_driver_connections(); +endclass +typedef uvm_sequencer #(uvm_sequence_item) uvm_virtual_sequencer; +function uvm_sequencer::new (string name, uvm_component parent=null); + super.new(name, parent); +//TODO issue #4497 - Fix uvm_sequencer wrong reference type +//TODO %Error: t/t_uvm_pkg_todo.vh:19869:21: Function Argument expects a CLASSREFDTYPE 'uvm_sequencer__Tz97_TBz97', got CLASSREFDTYPE 'uvm_sequencer__Tz97' +//TODO seq_item_export = new ("seq_item_export", this); +endfunction +function void uvm_sequencer::stop_sequences(); + REQ t; + super.stop_sequences(); + sequence_item_requested = 0; + get_next_item_called = 0; + if (m_req_fifo.used()) begin + uvm_report_info(get_full_name(), "Sequences stopped. Removing request from sequencer fifo"); + m_req_fifo.flush(); + end +endfunction +function string uvm_sequencer::get_type_name(); + return "uvm_sequencer"; +endfunction +function int uvm_sequencer::m_find_number_driver_connections(); + uvm_port_base #(uvm_sqr_if_base #(REQ, RSP)) provided_to_port_list[string]; + seq_item_export.get_provided_to(provided_to_port_list); + return provided_to_port_list.num(); +endfunction +task uvm_sequencer::get_next_item(output REQ t); + REQ req_item; + if (get_next_item_called == 1) + uvm_report_error(get_full_name(), + "Get_next_item called twice without item_done or get in between", UVM_NONE); + if (!sequence_item_requested) + m_select_sequence(); + sequence_item_requested = 1; + get_next_item_called = 1; + m_req_fifo.peek(t); +endtask +task uvm_sequencer::try_next_item(output REQ t); + int selected_sequence; + time arb_time; + uvm_sequence_base seq; + if (get_next_item_called == 1) begin + uvm_report_error(get_full_name(), "get_next_item/try_next_item called twice without item_done or get in between", UVM_NONE); + return; + end + wait_for_sequences(); + selected_sequence = m_choose_next_request(); + if (selected_sequence == -1) begin + t = null; + return; + end + m_set_arbitration_completed(arb_sequence_q[selected_sequence].request_id); + seq = arb_sequence_q[selected_sequence].sequence_ptr; + arb_sequence_q.delete(selected_sequence); + m_update_lists(); + sequence_item_requested = 1; + get_next_item_called = 1; + wait_for_sequences(); + if (!m_req_fifo.try_peek(t)) + uvm_report_error("TRY_NEXT_BLOCKED", {"try_next_item: the selected sequence '", + seq.get_full_name(), "' did not produce an item within an NBA delay. ", + "Sequences should not consume time between calls to start_item and finish_item. ", + "Returning null item."}, UVM_NONE); +endtask +function void uvm_sequencer::item_done(RSP item = null); + REQ t; + sequence_item_requested = 0; + get_next_item_called = 0; + if (m_req_fifo.try_get(t) == 0) begin + uvm_report_fatal("SQRBADITMDN", {"Item_done() called with no outstanding requests.", + " Each call to item_done() must be paired with a previous call to get_next_item()."}); + end else begin + m_wait_for_item_sequence_id = t.get_sequence_id(); + m_wait_for_item_transaction_id = t.get_transaction_id(); + end + if (item != null) begin + seq_item_export.put_response(item); + end + grant_queued_locks(); +endfunction +task uvm_sequencer::put (RSP t); + put_response(t); +endtask +task uvm_sequencer::get(output REQ t); + if (sequence_item_requested == 0) begin + m_select_sequence(); + end + sequence_item_requested = 1; + m_req_fifo.peek(t); + item_done(); +endtask +task uvm_sequencer::peek(output REQ t); + if (sequence_item_requested == 0) begin + m_select_sequence(); + end + sequence_item_requested = 1; + m_req_fifo.peek(t); +endtask +function void uvm_sequencer::item_done_trigger(RSP item = null); + item_done(item); +endfunction +class uvm_push_sequencer #(type REQ=uvm_sequence_item, RSP=REQ) + extends uvm_sequencer_param_base #(REQ, RSP); + typedef uvm_push_sequencer #( REQ , RSP) this_type; + uvm_blocking_put_port #(REQ) req_port; + function new (string name, uvm_component parent=null); + super.new(name, parent); + req_port = new ("req_port", this); + endfunction + task run_phase(uvm_phase phase); + REQ t; + int selected_sequence; + fork + super.run_phase(phase); + forever + begin + m_select_sequence(); + m_req_fifo.get(t); + req_port.put(t); + m_wait_for_item_sequence_id = t.get_sequence_id(); + m_wait_for_item_transaction_id = t.get_transaction_id(); + end + join + endtask + protected virtual function int m_find_number_driver_connections(); + return req_port.size(); + endfunction +endclass +virtual class uvm_sequence_base extends uvm_sequence_item; + typedef uvm_abstract_object_registry#(uvm_sequence_base,"uvm_sequence_base") type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_sequence_base"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_sequence_base"; + endfunction : get_type_name + protected uvm_sequence_state m_sequence_state; + int m_next_transaction_id = 1; + local int m_priority = -1; + uvm_recorder m_tr_recorder; + int m_wait_for_grant_semaphore; + protected int m_sqr_seq_ids[int]; + protected bit children_array[uvm_sequence_base]; + protected uvm_sequence_item response_queue[$]; + protected int response_queue_depth = 8; + protected bit response_queue_error_report_enabled; + local bit do_not_randomize; + protected process m_sequence_process; + local bit m_use_response_handler; + local bit is_rel_default; + local bit wait_rel_default; + function new (string name = "uvm_sequence"); + super.new(name); + m_sequence_state = UVM_CREATED; + m_wait_for_grant_semaphore = 0; + m_init_phase_daps(1); + endfunction + virtual function bit get_randomize_enabled(); + return (do_not_randomize == 0); + endfunction : get_randomize_enabled + virtual function void set_randomize_enabled(bit enable); + do_not_randomize = !enable; + endfunction : set_randomize_enabled + virtual function bit is_item(); + return 0; + endfunction + function uvm_sequence_state_enum get_sequence_state(); + return m_sequence_state; + endfunction + task wait_for_sequence_state(int unsigned state_mask); + wait (m_sequence_state & state_mask); + endtask + function int get_tr_handle(); + if (m_tr_recorder != null) + return m_tr_recorder.get_handle(); + else + return 0; + endfunction + virtual task start (uvm_sequencer_base sequencer, + uvm_sequence_base parent_sequence = null, + int this_priority = -1, + bit call_pre_post = 1); + bit old_automatic_phase_objection; + set_item_context(parent_sequence, sequencer); + if (!(m_sequence_state inside {UVM_CREATED,UVM_STOPPED,UVM_FINISHED})) begin + uvm_report_fatal("SEQ_NOT_DONE", + {"Sequence ", get_full_name(), " already started"},UVM_NONE); + end + if (m_parent_sequence != null) begin + m_parent_sequence.children_array[this] = 1; + end + if (this_priority < -1) begin + uvm_report_fatal("SEQPRI", $sformatf("Sequence %s start has illegal priority: %0d", + get_full_name(), + this_priority), UVM_NONE); + end + if (this_priority < 0) begin + if (parent_sequence == null) this_priority = 100; + else this_priority = parent_sequence.get_priority(); + end + clear_response_queue(); + m_priority = this_priority; + if (m_sequencer != null) begin + int handle; + if (m_parent_sequence == null) begin + handle = m_sequencer.begin_tr(this, get_name()); + m_tr_recorder = uvm_recorder::get_recorder_from_handle(handle); + end else begin + handle = m_sequencer.begin_tr(.tr(this), .stream_name(get_root_sequence_name()), + .parent_handle((m_parent_sequence.m_tr_recorder == null) ? 0 : m_parent_sequence.m_tr_recorder.get_handle())); + m_tr_recorder = uvm_recorder::get_recorder_from_handle(handle); + end + end + set_sequence_id(-1); + if (m_sequencer != null) begin + void'(m_sequencer.m_register_sequence(this)); + end + m_sequence_state = UVM_PRE_START; + fork + begin + m_sequence_process = process::self(); + #0; + if (get_automatic_phase_objection()) begin + m_safe_raise_starting_phase("automatic phase objection"); + end + pre_start(); + if (call_pre_post == 1) begin + m_sequence_state = UVM_PRE_BODY; + #0; + pre_body(); + end + if (parent_sequence != null) begin + parent_sequence.pre_do(0); + parent_sequence.mid_do(this); + end + m_sequence_state = UVM_BODY; + #0; + body(); + m_sequence_state = UVM_ENDED; + #0; + if (parent_sequence != null) begin + parent_sequence.post_do(this); + end + if (call_pre_post == 1) begin + m_sequence_state = UVM_POST_BODY; + #0; + post_body(); + end + m_sequence_state = UVM_POST_START; + #0; + post_start(); + if (get_automatic_phase_objection()) begin + m_safe_drop_starting_phase("automatic phase objection"); + end + m_sequence_state = UVM_FINISHED; + #0; + end + join + if (m_sequencer != null) begin + m_sequencer.end_tr(this); + end + if (m_sequence_state != UVM_STOPPED) begin + clean_exit_sequence(); + end + #0; + if ((m_parent_sequence != null) && (m_parent_sequence.children_array.exists(this))) begin + m_parent_sequence.children_array.delete(this); + end + old_automatic_phase_objection = get_automatic_phase_objection(); + m_init_phase_daps(1); + set_automatic_phase_objection(old_automatic_phase_objection); + endtask + function void clean_exit_sequence(); + if (m_sequencer != null) + m_sequencer.m_sequence_exiting(this); + else + foreach(m_sqr_seq_ids[seqrID]) begin + uvm_sequencer_base s = uvm_sequencer_base::all_sequencer_insts[seqrID]; + s.m_sequence_exiting(this); + end + m_sqr_seq_ids.delete(); + endfunction + virtual task pre_start(); + return; + endtask + virtual task pre_body(); + return; + endtask + virtual task pre_do(bit is_item); + return; + endtask + virtual function void mid_do(uvm_sequence_item this_item); + return; + endfunction + virtual task body(); + uvm_report_warning("uvm_sequence_base", "Body definition undefined"); + return; + endtask + virtual function void post_do(uvm_sequence_item this_item); + return; + endfunction + virtual task post_body(); + return; + endtask + virtual task post_start(); + return; + endtask + local uvm_get_to_lock_dap#(bit) m_automatic_phase_objection_dap; + local uvm_get_to_lock_dap#(uvm_phase) m_starting_phase_dap; + function void m_init_phase_daps(bit create); + string apo_name = $sformatf("%s.automatic_phase_objection", get_full_name()); + string sp_name = $sformatf("%s.starting_phase", get_full_name()); + if (create) begin + m_automatic_phase_objection_dap = uvm_get_to_lock_dap#(bit)::type_id_create(apo_name, get_sequencer()); + m_starting_phase_dap = uvm_get_to_lock_dap#(uvm_phase)::type_id_create(sp_name, get_sequencer()); + end + else begin + m_automatic_phase_objection_dap.set_name(apo_name); + m_starting_phase_dap.set_name(sp_name); + end + endfunction : m_init_phase_daps + function uvm_phase get_starting_phase(); + return m_starting_phase_dap.get(); + endfunction : get_starting_phase + function void set_starting_phase(uvm_phase phase); + m_starting_phase_dap.set(phase); + endfunction : set_starting_phase + function void set_automatic_phase_objection(bit value); + m_automatic_phase_objection_dap.set(value); + endfunction : set_automatic_phase_objection + function bit get_automatic_phase_objection(); + return m_automatic_phase_objection_dap.get(); + endfunction : get_automatic_phase_objection + function void m_safe_raise_starting_phase(string description = "", + int count = 1); + uvm_phase starting_phase = get_starting_phase(); + if (starting_phase != null) + starting_phase.raise_objection(this, description, count); + endfunction : m_safe_raise_starting_phase + function void m_safe_drop_starting_phase(string description = "", + int count = 1); + uvm_phase starting_phase = get_starting_phase(); + if (starting_phase != null) + starting_phase.drop_objection(this, description, count); + endfunction : m_safe_drop_starting_phase + function void set_priority (int value); + m_priority = value; + endfunction + function int get_priority(); + return m_priority; + endfunction + virtual function bit is_relevant(); + is_rel_default = 1; + return 1; + endfunction + virtual task wait_for_relevant(); + event e; + wait_rel_default = 1; + if (is_rel_default != wait_rel_default) + uvm_report_fatal("RELMSM", + "is_relevant() was implemented without defining wait_for_relevant()", UVM_NONE); +//TODO issue #4495 - unsupported local event - may want to model the larger context where is used - might be case where edit upstream? +//TODO %Error-UNSUPPORTED: t/t_uvm_pkg_todo.vh:20247:5: Unsupported: waiting on local event variables +//TODO @e; + endtask + task lock(uvm_sequencer_base sequencer = null); + if (sequencer == null) + sequencer = m_sequencer; + if (sequencer == null) + uvm_report_fatal("LOCKSEQR", "Null m_sequencer reference", UVM_NONE); + sequencer.lock(this); + endtask + task grab(uvm_sequencer_base sequencer = null); + if (sequencer == null) begin + if (m_sequencer == null) begin + uvm_report_fatal("GRAB", "Null m_sequencer reference", UVM_NONE); + end + m_sequencer.grab(this); + end + else begin + sequencer.grab(this); + end + endtask + function void unlock(uvm_sequencer_base sequencer = null); + if (sequencer == null) begin + if (m_sequencer == null) begin + uvm_report_fatal("UNLOCK", "Null m_sequencer reference", UVM_NONE); + end + m_sequencer.unlock(this); + end else begin + sequencer.unlock(this); + end + endfunction + function void ungrab(uvm_sequencer_base sequencer = null); + unlock(sequencer); + endfunction + function bit is_blocked(); + return m_sequencer.is_blocked(this); + endfunction + function bit has_lock(); + return m_sequencer.has_lock(this); + endfunction + function void kill(); + if (m_sequence_process != null) begin + if (m_sequencer == null) begin + m_kill(); + if (get_automatic_phase_objection()) begin + m_safe_drop_starting_phase("automatic phase objection"); + end + return; + end + m_sequencer.kill_sequence(this); + if (get_automatic_phase_objection()) begin + m_safe_drop_starting_phase("automatic phase objection"); + end + return; + end + endfunction + virtual function void do_kill(); + return; + endfunction + function void m_kill(); + do_kill(); + foreach(children_array[i]) begin + i.kill(); + end + if (m_sequence_process != null) begin + m_sequence_process.kill; + m_sequence_process = null; + end + m_sequence_state = UVM_STOPPED; + if ((m_parent_sequence != null) && (m_parent_sequence.children_array.exists(this))) + m_parent_sequence.children_array.delete(this); + clean_exit_sequence(); + endfunction + protected function uvm_sequence_item create_item(uvm_object_wrapper type_var, + uvm_sequencer_base l_sequencer, string name); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory=cs.get_factory(); + $cast(create_item, factory.create_object_by_type( type_var, this.get_full_name(), name )); + create_item.set_item_context(this, l_sequencer); + endfunction + virtual task start_item (uvm_sequence_item item, + int set_priority = -1, + uvm_sequencer_base sequencer=null); + if(item == null) begin + uvm_report_fatal("NULLITM", + {"attempting to start a null item from sequence '", + get_full_name(), "'"}, UVM_NONE); + return; + end + if ( ! item.is_item() ) begin + uvm_report_fatal("SEQNOTITM", + {"attempting to start a sequence using start_item() from sequence '", + get_full_name(), "'. Use seq.start() instead."}, UVM_NONE); + return; + end + if (sequencer == null) + sequencer = item.get_sequencer(); + if(sequencer == null) + sequencer = get_sequencer(); + if(sequencer == null) begin + uvm_report_fatal("SEQ",{"neither the item's sequencer nor dedicated sequencer has been supplied to start item in ",get_full_name()},UVM_NONE); + return; + end + item.set_item_context(this, sequencer); + if (set_priority < 0) + set_priority = get_priority(); + sequencer.wait_for_grant(this, set_priority); + if (sequencer.is_auto_item_recording_enabled()) begin + void'(sequencer.begin_tr(.tr(item), .stream_name(item.get_root_sequence_name()), .label("Transactions"), + .parent_handle((m_tr_recorder == null) ? 0 : m_tr_recorder.get_handle()))); + end + pre_do(1); + endtask + virtual task finish_item (uvm_sequence_item item, + int set_priority = -1); + uvm_sequencer_base sequencer; + sequencer = item.get_sequencer(); + if (sequencer == null) begin + uvm_report_fatal("STRITM", "sequence_item has null sequencer", UVM_NONE); + end + mid_do(item); + sequencer.send_request(this, item); + sequencer.wait_for_item_done(this, -1); + if (sequencer.is_auto_item_recording_enabled()) begin + sequencer.end_tr(item); + end + post_do(item); + endtask + virtual task wait_for_grant(int item_priority = -1, bit lock_request = 0); + if (m_sequencer == null) begin + uvm_report_fatal("WAITGRANT", "Null m_sequencer reference", UVM_NONE); + end + m_sequencer.wait_for_grant(this, item_priority, lock_request); + endtask + virtual function void send_request(uvm_sequence_item request, bit rerandomize = 0); + if (m_sequencer == null) begin + uvm_report_fatal("SENDREQ", "Null m_sequencer reference", UVM_NONE); + end + m_sequencer.send_request(this, request, rerandomize); + endfunction + virtual task wait_for_item_done(int transaction_id = -1); + if (m_sequencer == null) begin + uvm_report_fatal("WAITITEMDONE", "Null m_sequencer reference", UVM_NONE); + end + m_sequencer.wait_for_item_done(this, transaction_id); + endtask + function void use_response_handler(bit enable); + m_use_response_handler = enable; + endfunction + function bit get_use_response_handler(); + return m_use_response_handler; + endfunction + virtual function void response_handler(uvm_sequence_item response); + return; + endfunction + function void set_response_queue_error_report_enabled(bit value); + response_queue_error_report_enabled = value; + endfunction : set_response_queue_error_report_enabled + function bit get_response_queue_error_report_enabled(); + return response_queue_error_report_enabled; + endfunction : get_response_queue_error_report_enabled + function void set_response_queue_depth(int value); + response_queue_depth = value; + endfunction + function int get_response_queue_depth(); + return response_queue_depth; + endfunction + virtual function void clear_response_queue(); + response_queue.delete(); + endfunction + virtual function void put_base_response(input uvm_sequence_item response); + if ((response_queue_depth == -1) || + (response_queue.size() < response_queue_depth)) begin + response_queue.push_back(response); + return; + end + if (response_queue_error_report_enabled) begin + uvm_report_error(get_full_name(), "Response queue overflow, response was dropped", UVM_NONE); + end + endfunction + virtual function void put_response (uvm_sequence_item response_item); + put_base_response(response_item); + endfunction + virtual task get_base_response(output uvm_sequence_item response, input int transaction_id = -1); + int queue_size, i; + if (response_queue.size() == 0) + wait (response_queue.size() != 0); + if (transaction_id == -1) begin + response = response_queue.pop_front(); + return; + end + forever begin + queue_size = response_queue.size(); + for (i = 0; i < queue_size; i++) begin + if (response_queue[i].get_transaction_id() == transaction_id) + begin + $cast(response,response_queue[i]); + response_queue.delete(i); + return; + end + end + wait (response_queue.size() != queue_size); + end + endtask + function int m_get_sqr_sequence_id(int sequencer_id, bit update_sequence_id); + if (m_sqr_seq_ids.exists(sequencer_id)) begin + if (update_sequence_id == 1) begin + set_sequence_id(m_sqr_seq_ids[sequencer_id]); + end + return m_sqr_seq_ids[sequencer_id]; + end + if (update_sequence_id == 1) + set_sequence_id(-1); + return -1; + endfunction + function void m_set_sqr_sequence_id(int sequencer_id, int sequence_id); + m_sqr_seq_ids[sequencer_id] = sequence_id; + set_sequence_id(sequence_id); + endfunction +endclass +virtual class uvm_sequence #(type REQ = uvm_sequence_item, + type RSP = REQ) extends uvm_sequence_base; + typedef uvm_sequencer_param_base #(REQ, RSP) sequencer_t; + sequencer_t param_sequencer; + REQ req; + RSP rsp; + function new (string name = "uvm_sequence"); + super.new(name); + endfunction + function void send_request(uvm_sequence_item request, bit rerandomize = 0); + REQ m_request; + if (m_sequencer == null) begin + uvm_report_fatal("SSENDREQ", "Null m_sequencer reference", UVM_NONE); + end + if (!$cast(m_request, request)) begin + uvm_report_fatal("SSENDREQ", "Failure to cast uvm_sequence_item to request", UVM_NONE); + end + m_sequencer.send_request(this, m_request, rerandomize); + endfunction + function REQ get_current_item(); + if (!$cast(param_sequencer, m_sequencer)) + uvm_report_fatal("SGTCURR", "Failure to cast m_sequencer to the parameterized sequencer", UVM_NONE); + return (param_sequencer.get_current_item()); + endfunction + virtual task get_response(output RSP response, input int transaction_id = -1); + uvm_sequence_item rsp; + get_base_response( rsp, transaction_id); + $cast(response,rsp); + endtask + virtual function void put_response(uvm_sequence_item response_item); + RSP response; + if (!$cast(response, response_item)) begin + uvm_report_fatal("PUTRSP", "Failure to cast response in put_response", UVM_NONE); + end + put_base_response(response_item); + endfunction + function void do_print (uvm_printer printer); + super.do_print(printer); + printer.print_object("req", req); + printer.print_object("rsp", rsp); + endfunction +endclass +typedef class uvm_sequence_library_cfg; +class uvm_sequence_library #(type REQ=uvm_sequence_item,RSP=REQ) extends uvm_sequence #(REQ,RSP); + typedef uvm_object_registry #(uvm_sequence_library#(REQ,RSP)) type_id; + static function uvm_sequence_library#(REQ,RSP) type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_sequence_library#(REQ,RSP) tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_sequence_library #(REQ,RSP)"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_sequence_library #(REQ,RSP)"; + endfunction : get_type_name + extern function new(string name=""); + uvm_sequence_lib_mode selection_mode; + int unsigned min_random_count=10; + int unsigned max_random_count=10; + protected int unsigned sequences_executed; + rand int unsigned sequence_count = 10; + rand int unsigned select_rand; + randc bit [15:0] select_randc; + protected int seqs_distrib[string] = '{default:0}; + protected uvm_object_wrapper sequences[$]; + constraint valid_rand_selection { + select_rand inside {[0:sequences.size()-1]}; + } + constraint valid_randc_selection { + select_randc inside {[0:sequences.size()-1]}; + } + constraint valid_sequence_count { + sequence_count inside {[min_random_count:max_random_count]}; + } + extern virtual function int unsigned select_sequence(int unsigned max); + extern static function void add_typewide_sequence(uvm_object_wrapper seq_type); + extern static function void add_typewide_sequences(uvm_object_wrapper seq_types[$]); + extern function void add_sequence(uvm_object_wrapper seq_type); + extern virtual function void add_sequences(uvm_object_wrapper seq_types[$]); + extern virtual function void remove_sequence(uvm_object_wrapper seq_type); + extern virtual function void get_sequences(ref uvm_object_wrapper seq_types[$]); + extern virtual function uvm_object_wrapper get_sequence(int unsigned idx); + extern function void init_sequence_library(); + typedef uvm_sequence_library #(REQ,RSP) this_type; + static protected uvm_object_wrapper m_typewide_sequences[$]; + bit m_abort; + extern static function bit m_static_check(uvm_object_wrapper seq_type); + extern static function bit m_check(uvm_object_wrapper seq_type, this_type lib); + extern function bit m_dyn_check(uvm_object_wrapper seq_type); + extern function void m_get_config(); + extern static function bit m_add_typewide_sequence(uvm_object_wrapper seq_type); + extern virtual task execute(uvm_object_wrapper wrap); + extern virtual task body(); + extern virtual function void do_print(uvm_printer printer); + extern function void pre_randomize(); +endclass +class uvm_sequence_library_cfg extends uvm_object; + typedef uvm_object_registry#(uvm_sequence_library_cfg,"uvm_sequence_library_cfg") type_id; + static function uvm_sequence_library_cfg type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_sequence_library_cfg tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_sequence_library_cfg"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_sequence_library_cfg"; + endfunction : get_type_name + uvm_sequence_lib_mode selection_mode; + int unsigned min_random_count; + int unsigned max_random_count; + function new(string name="", + uvm_sequence_lib_mode mode=UVM_SEQ_LIB_RAND, + int unsigned min=1, + int unsigned max=10); + super.new(name); + selection_mode = mode; + min_random_count = min; + max_random_count = max; + endfunction +endclass +function uvm_sequence_library::new(string name=""); + super.new(name); + init_sequence_library(); + valid_rand_selection.constraint_mode(0); + valid_randc_selection.constraint_mode(0); +endfunction +function bit uvm_sequence_library::m_add_typewide_sequence(uvm_object_wrapper seq_type); + this_type::add_typewide_sequence(seq_type); + return 1; +endfunction +function void uvm_sequence_library::add_typewide_sequence(uvm_object_wrapper seq_type); + if (m_static_check(seq_type)) + m_typewide_sequences.push_back(seq_type); +endfunction +function void uvm_sequence_library::add_typewide_sequences(uvm_object_wrapper seq_types[$]); + foreach (seq_types[i]) + add_typewide_sequence(seq_types[i]); +endfunction +function void uvm_sequence_library::add_sequence(uvm_object_wrapper seq_type); + if (m_dyn_check(seq_type)) + sequences.push_back(seq_type); +endfunction +function void uvm_sequence_library::add_sequences(uvm_object_wrapper seq_types[$]); + foreach (seq_types[i]) + add_sequence(seq_types[i]); +endfunction +function void uvm_sequence_library::remove_sequence(uvm_object_wrapper seq_type); + foreach (sequences[i]) + if (sequences[i] == seq_type) begin + sequences.delete(i); + return; + end +endfunction +function void uvm_sequence_library::get_sequences(ref uvm_object_wrapper seq_types[$]); + foreach (sequences[i]) + seq_types.push_back(sequences[i]); +endfunction +function uvm_object_wrapper uvm_sequence_library::get_sequence(int unsigned idx); + if(idx < sequences.size()) + return sequences[idx]; + else begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"SEQ_LIB/GET_SEQ")) + uvm_report_error ("SEQ_LIB/GET_SEQ", $sformatf("idx %0d > number of sequences in library", idx), UVM_NONE, "t/uvm/src/seq/uvm_sequence_library.svh", 453, "", 1); + end + return null; + end +endfunction +function int unsigned uvm_sequence_library::select_sequence(int unsigned max); + static int unsigned counter; + select_sequence = counter; + counter++; + if (counter >= max) + counter = 0; +endfunction +function void uvm_sequence_library::init_sequence_library(); + foreach (this_type::m_typewide_sequences[i]) + sequences.push_back(this_type::m_typewide_sequences[i]); +endfunction +function bit uvm_sequence_library::m_static_check(uvm_object_wrapper seq_type); + if (!m_check(seq_type,null)) + return 0; + foreach (m_typewide_sequences[i]) + if (m_typewide_sequences[i] == seq_type) + return 0; + return 1; +endfunction +function bit uvm_sequence_library::m_dyn_check(uvm_object_wrapper seq_type); + if (!m_check(seq_type,this)) + return 0; + foreach (sequences[i]) + if (sequences[i] == seq_type) + return 0; + return 1; +endfunction +function bit uvm_sequence_library::m_check(uvm_object_wrapper seq_type, this_type lib); + uvm_object obj; + uvm_sequence_base seq; + uvm_root top; + uvm_coreservice_t cs; + string name; + string typ; + obj = seq_type.create_object(); + name = (lib == null) ? type_name() : lib.get_full_name(); + typ = (lib == null) ? type_name() : lib.get_type_name(); + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + if (!$cast(seq, obj)) begin + begin + if (top.uvm_report_enabled(UVM_NONE,UVM_ERROR,"SEQLIB/BAD_SEQ_TYPE")) + top.uvm_report_error ("SEQLIB/BAD_SEQ_TYPE", {"Object '",obj.get_type_name(), "' is not a sequence. Cannot add to sequence library '",name, "'"}, UVM_NONE, "t/uvm/src/seq/uvm_sequence_library.svh", 538, "", 1); + end + return 0; + end + return 1; +endfunction +function void uvm_sequence_library::pre_randomize(); + m_get_config(); +endfunction +function void uvm_sequence_library::m_get_config(); + uvm_sequence_library_cfg cfg; + string phase_name; + uvm_phase starting_phase = get_starting_phase(); + if (starting_phase != null) begin + phase_name = {starting_phase.get_name(),"_phase"}; + end + if (uvm_config_db #(uvm_sequence_library_cfg)::get(m_sequencer, + phase_name, + "default_sequence.config", + cfg) ) begin + selection_mode = cfg.selection_mode; + min_random_count = cfg.min_random_count; + max_random_count = cfg.max_random_count; + end + else begin + void'(uvm_config_db #(int unsigned)::get(m_sequencer, + phase_name, + "default_sequence.min_random_count", + min_random_count) ); + void'(uvm_config_db #(int unsigned)::get(m_sequencer, + phase_name, + "default_sequence.max_random_count", + max_random_count) ); + void'(uvm_config_db #(uvm_sequence_lib_mode)::get(m_sequencer, + phase_name, + "default_sequence.selection_mode", + selection_mode) ); + end + if (max_random_count == 0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"SEQLIB/MAX_ZERO")) + uvm_report_warning ("SEQLIB/MAX_ZERO", $sformatf("max_random_count (%0d) zero. Nothing will be done.", max_random_count), UVM_NONE, "t/uvm/src/seq/uvm_sequence_library.svh", 593, "", 1); + end + if (min_random_count > max_random_count) + min_random_count = max_random_count; + end + else if (min_random_count > max_random_count) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"SEQLIB/MIN_GT_MAX")) + uvm_report_error ("SEQLIB/MIN_GT_MAX", $sformatf("min_random_count (%0d) greater than max_random_count (%0d). Setting min to max.", min_random_count,max_random_count), UVM_NONE, "t/uvm/src/seq/uvm_sequence_library.svh", 600, "", 1); + end + min_random_count = max_random_count; + end + else begin + if (selection_mode == UVM_SEQ_LIB_ITEM) begin + uvm_sequencer #(REQ,RSP) seqr; + uvm_object_wrapper lhs = REQ::get_type(); + uvm_object_wrapper rhs = uvm_sequence_item::get_type(); + if (lhs == rhs) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"SEQLIB/BASE_ITEM")) + uvm_report_error ("SEQLIB/BASE_ITEM", {"selection_mode cannot be UVM_SEQ_LIB_ITEM when ", "the REQ type is the base uvm_sequence_item. Using UVM_SEQ_LIB_RAND mode"}, UVM_NONE, "t/uvm/src/seq/uvm_sequence_library.svh", 610, "", 1); + end + selection_mode = UVM_SEQ_LIB_RAND; + end + if (m_sequencer == null || !$cast(seqr,m_sequencer)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"SEQLIB/VIRT_SEQ")) + uvm_report_error ("SEQLIB/VIRT_SEQ", {"selection_mode cannot be UVM_SEQ_LIB_ITEM when ", "running as a virtual sequence. Using UVM_SEQ_LIB_RAND mode"}, UVM_NONE, "t/uvm/src/seq/uvm_sequence_library.svh", 615, "", 1); + end + selection_mode = UVM_SEQ_LIB_RAND; + end + end + end +endfunction +task uvm_sequence_library::body(); + uvm_object_wrapper wrap; + uvm_phase starting_phase = get_starting_phase(); + if (m_sequencer == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"SEQLIB/VIRT_SEQ")) + uvm_report_fatal ("SEQLIB/VIRT_SEQ", {"Sequence library 'm_sequencer' handle is null ", " no current support for running as a virtual sequence."}, UVM_NONE, "t/uvm/src/seq/uvm_sequence_library.svh", 634, "", 1); + end + return; + end + if (sequences.size() == 0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"SEQLIB/NOSEQS")) + uvm_report_error ("SEQLIB/NOSEQS", "Sequence library does not contain any sequences. Did you forget to call init_sequence_library() in the constructor?", UVM_NONE, "t/uvm/src/seq/uvm_sequence_library.svh", 639, "", 1); + end + return; + end + if (!get_randomize_enabled()) + m_get_config(); + m_safe_raise_starting_phase({"starting sequence library ",get_full_name()," (", get_type_name(),")"}); + begin + if (uvm_report_enabled(UVM_LOW,UVM_INFO,"SEQLIB/START")) + uvm_report_info ("SEQLIB/START", $sformatf("Starting sequence library %s in %s phase: %0d iterations in mode %s", get_type_name(), (starting_phase != null ? starting_phase.get_name() : "unknown"), sequence_count, selection_mode.name()), UVM_LOW, "t/uvm/src/seq/uvm_sequence_library.svh", 652, "", 1); + end + begin + if (uvm_report_enabled(UVM_FULL,UVM_INFO,"SEQLIB/SPRINT")) + uvm_report_info ("SEQLIB/SPRINT", {"\n",sprint(uvm_table_printer::get_default())}, UVM_FULL, "t/uvm/src/seq/uvm_sequence_library.svh", 654, "", 1); + end + case (selection_mode) + UVM_SEQ_LIB_RAND: begin + valid_rand_selection.constraint_mode(1); + valid_sequence_count.constraint_mode(0); + for (int i=1; i<=sequence_count; i++) begin + if (!randomize(select_rand)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"SEQLIB/RAND_FAIL")) + uvm_report_error ("SEQLIB/RAND_FAIL", "Random sequence selection failed", UVM_NONE, "t/uvm/src/seq/uvm_sequence_library.svh", 663, "", 1); + end + break; + end + else begin + wrap = sequences[select_rand]; + end + execute(wrap); + end + valid_rand_selection.constraint_mode(0); + valid_sequence_count.constraint_mode(1); + end + UVM_SEQ_LIB_RANDC: begin + uvm_object_wrapper q[$]; + valid_randc_selection.constraint_mode(1); + valid_sequence_count.constraint_mode(0); + for (int i=1; i<=sequence_count; i++) begin + if (!randomize(select_randc)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"SEQLIB/RANDC_FAIL")) + uvm_report_error ("SEQLIB/RANDC_FAIL", "Random sequence selection failed", UVM_NONE, "t/uvm/src/seq/uvm_sequence_library.svh", 681, "", 1); + end + break; + end + else begin + wrap = sequences[select_randc]; + end + q.push_back(wrap); + end + valid_randc_selection.constraint_mode(0); + valid_sequence_count.constraint_mode(1); + foreach(q[i]) + execute(q[i]); + valid_randc_selection.constraint_mode(0); + valid_sequence_count.constraint_mode(1); + end + UVM_SEQ_LIB_ITEM: begin + for (int i=1; i<=sequence_count; i++) begin + wrap = REQ::get_type(); + execute(wrap); + end + end + UVM_SEQ_LIB_USER: begin + for (int i=1; i<=sequence_count; i++) begin + int user_selection; + user_selection = select_sequence(sequences.size()-1); + if (user_selection >= sequences.size()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"SEQLIB/USER_FAIL")) + uvm_report_error ("SEQLIB/USER_FAIL", "User sequence selection out of range", UVM_NONE, "t/uvm/src/seq/uvm_sequence_library.svh", 709, "", 1); + end + wrap = REQ::get_type(); + end + else begin + wrap = sequences[user_selection]; + end + execute(wrap); + end + end + default: begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"SEQLIB/RAND_MODE")) + uvm_report_fatal ("SEQLIB/RAND_MODE", $sformatf("Unknown random sequence selection mode: %0d",selection_mode), UVM_NONE, "t/uvm/src/seq/uvm_sequence_library.svh", 721, "", 1); + end + end + endcase + begin + if (uvm_report_enabled(UVM_LOW,UVM_INFO,"SEQLIB/END")) + uvm_report_info ("SEQLIB/END", {"Ending sequence library in phase ", (starting_phase != null ? starting_phase.get_name() : "unknown")}, UVM_LOW, "t/uvm/src/seq/uvm_sequence_library.svh", 726, "", 1); + end + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"SEQLIB/DSTRB")) + uvm_report_info ("SEQLIB/DSTRB", $sformatf("%p",seqs_distrib), UVM_HIGH, "t/uvm/src/seq/uvm_sequence_library.svh", 728, "", 1); + end + m_safe_drop_starting_phase({"starting sequence library ",get_full_name()," (", get_type_name(),")"}); +endtask +task uvm_sequence_library::execute(uvm_object_wrapper wrap); + uvm_object obj; + uvm_sequence_item seq_or_item; + uvm_sequence_base seq_base; + REQ req_item; + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_factory factory=cs.get_factory(); + obj = factory.create_object_by_type(wrap,get_full_name(), + $sformatf("%s:%0d",wrap.get_type_name(),sequences_executed+1)); + if (!$cast(seq_base, obj)) begin + if (!$cast(req_item, obj)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"SEQLIB/WRONG_ITEM_TYPE")) + uvm_report_error ("SEQLIB/WRONG_ITEM_TYPE", {"The item created by '", get_full_name(), "' when in 'UVM_SEQ_LIB_ITEM' mode doesn't match the REQ type which was passed in to the uvm_sequence_library#(REQ[,RSP]), this can happen if the REQ type which was passed in was a pure-virtual type. Either configure the factory overrides to properly generate items for this sequence library, or do not execute this sequence library in UVM_SEQ_LIB_ITEM mode."}, UVM_NONE, "t/uvm/src/seq/uvm_sequence_library.svh", 756, "", 1); + end + return; + end + end + void'($cast(seq_or_item,obj)); + begin + if (uvm_report_enabled(UVM_FULL,UVM_INFO,"SEQLIB/EXEC")) + uvm_report_info ("SEQLIB/EXEC", {"Executing ",(seq_or_item.is_item() ? "item " : "sequence "),seq_or_item.get_name(), " (",seq_or_item.get_type_name(),")"}, UVM_FULL, "t/uvm/src/seq/uvm_sequence_library.svh", 764, "", 1); + end + seq_or_item.print_sequence_info = 1; + begin + uvm_sequence_base __seq; + if ( seq_or_item.is_item() ) begin + start_item(seq_or_item, -1); + if ( ! seq_or_item.randomize() with {} ) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RNDFLD")) + uvm_report_warning ("RNDFLD", "Randomization failed in uvm_rand_send action", UVM_NONE, "t/uvm/src/seq/uvm_sequence_library.svh", 766, "", 1); + end + end + finish_item(seq_or_item, -1); + end + else if ( $cast( __seq, seq_or_item ) ) begin + __seq.set_item_context(this,seq_or_item.get_sequencer()); + if ( __seq.get_randomize_enabled() ) begin + if ( ! seq_or_item.randomize() with {} ) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RNDFLD")) + uvm_report_warning ("RNDFLD", "Randomization failed in uvm_rand_send action", UVM_NONE, "t/uvm/src/seq/uvm_sequence_library.svh", 766, "", 1); + end + end + end + __seq.start(__seq.get_sequencer(), this, -1, 0); + end + else begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"NOT_SEQ_OR_ITEM")) + uvm_report_warning ("NOT_SEQ_OR_ITEM", "Object passed uvm_rand_send appears to be neither a sequence or item.", UVM_NONE, "t/uvm/src/seq/uvm_sequence_library.svh", 766, "", 1); + end + end + end + seqs_distrib[seq_or_item.get_type_name()] = seqs_distrib[seq_or_item.get_type_name()]+1; + sequences_executed++; +endtask +function void uvm_sequence_library::do_print(uvm_printer printer); + printer.print_field_int("min_random_count",min_random_count,32,UVM_DEC,,"int unsigned"); + printer.print_field_int("max_random_count",max_random_count,32,UVM_DEC,,"int unsigned"); + printer.print_generic("selection_mode","uvm_sequence_lib_mode",32,selection_mode.name()); + printer.print_field_int("sequence_count",sequence_count,32,UVM_DEC,,"int unsigned"); + printer.print_array_header("typewide_sequences",m_typewide_sequences.size(),"queue_object_types"); + foreach (m_typewide_sequences[i]) + printer.print_generic($sformatf("[%0d]",i),"uvm_object_wrapper","-",m_typewide_sequences[i].get_type_name()); + printer.print_array_footer(); + printer.print_array_header("sequences",sequences.size(),"queue_object_types"); + foreach (sequences[i]) + printer.print_generic($sformatf("[%0d]",i),"uvm_object_wrapper","-",sequences[i].get_type_name()); + printer.print_array_footer(); + printer.print_array_header("seqs_distrib",seqs_distrib.num(),"as_int_string"); + foreach (seqs_distrib[typ]) begin + printer.print_field_int({"[",typ,"]"},seqs_distrib[typ],32,,UVM_DEC,"int unsigned"); + end + printer.print_array_footer(); +endfunction +typedef uvm_sequence #(uvm_sequence_item, uvm_sequence_item) uvm_default_sequence_type; +typedef uvm_sequencer #(uvm_sequence_item, uvm_sequence_item) uvm_default_sequencer_type; +typedef uvm_driver #(uvm_sequence_item, uvm_sequence_item) uvm_default_driver_type; +typedef uvm_sequencer_param_base #(uvm_sequence_item, uvm_sequence_item) uvm_default_sequencer_param_type; +class uvm_time; + static local real m_resolution = 1.0e-12; + local real m_res; + local time m_time; + local string m_name; + static function void set_time_resolution(real res); + m_resolution = res; + endfunction + function new(string name = "uvm_tlm_time", real res = 0); + m_name = name; + m_res = (res == 0) ? m_resolution : res; + reset(); + endfunction + function string get_name(); + return m_name; + endfunction + function void reset(); + m_time = 0; + endfunction + local function real to_m_res(real t, time scaled, real secs); + return t/real'(scaled) * (secs/m_res); + endfunction + function real get_realtime(time scaled, real secs = 1.0e-9); + return m_time*real'(scaled) * m_res/secs; + endfunction + function void incr(real t, time scaled, real secs = 1.0e-9); + if (t < 0.0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/TIMENEG")) + uvm_report_error ("UVM/TLM/TIMENEG", {"Cannot increment uvm_tlm_time variable ", m_name, " by a negative value"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm_time.svh", 134, "", 1); + end + return; + end + if (scaled == 0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"UVM/TLM/BADSCALE")) + uvm_report_fatal ("UVM/TLM/BADSCALE", "uvm_tlm_time::incr() called with a scaled time literal that is smaller than the current timescale", UVM_NONE, "t/uvm/src/tlm2/uvm_tlm_time.svh", 139, "", 1); + end + end + m_time += to_m_res(t, scaled, secs); + endfunction + function void decr(real t, time scaled, real secs); + if (t < 0.0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/TIMENEG")) + uvm_report_error ("UVM/TLM/TIMENEG", {"Cannot decrement uvm_tlm_time variable ", m_name, " by a negative value"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm_time.svh", 161, "", 1); + end + return; + end + if (scaled == 0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"UVM/TLM/BADSCALE")) + uvm_report_fatal ("UVM/TLM/BADSCALE", "uvm_tlm_time::decr() called with a scaled time literal that is smaller than the current timescale", UVM_NONE, "t/uvm/src/tlm2/uvm_tlm_time.svh", 166, "", 1); + end + end + m_time -= to_m_res(t, scaled, secs); + if (m_time < 0.0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/TOODECR")) + uvm_report_error ("UVM/TLM/TOODECR", {"Cannot decrement uvm_tlm_time variable ", m_name, " to a negative value"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm_time.svh", 172, "", 1); + end + reset(); + end + endfunction + function real get_abstime(real secs); + return m_time*m_res/secs; + endfunction + function void set_abstime(real t, real secs); + m_time = t*secs/m_res; + endfunction +endclass +typedef uvm_time uvm_tlm_time; +typedef enum +{ + UVM_TLM_READ_COMMAND, + UVM_TLM_WRITE_COMMAND, + UVM_TLM_IGNORE_COMMAND +} uvm_tlm_command_e; +typedef enum +{ + UVM_TLM_OK_RESPONSE = 1, + UVM_TLM_INCOMPLETE_RESPONSE = 0, + UVM_TLM_GENERIC_ERROR_RESPONSE = -1, + UVM_TLM_ADDRESS_ERROR_RESPONSE = -2, + UVM_TLM_COMMAND_ERROR_RESPONSE = -3, + UVM_TLM_BURST_ERROR_RESPONSE = -4, + UVM_TLM_BYTE_ENABLE_ERROR_RESPONSE = -5 +} uvm_tlm_response_status_e; +typedef class uvm_tlm_extension_base; +class uvm_tlm_generic_payload extends uvm_sequence_item; + rand bit [63:0] m_address; + rand uvm_tlm_command_e m_command; + rand byte unsigned m_data[]; + rand int unsigned m_length; + rand uvm_tlm_response_status_e m_response_status; + bit m_dmi; + rand byte unsigned m_byte_enable[]; + rand int unsigned m_byte_enable_length; + rand int unsigned m_streaming_width; + protected uvm_tlm_extension_base m_extensions [uvm_tlm_extension_base]; + local rand uvm_tlm_extension_base m_rand_exts[]; + typedef uvm_object_registry#(uvm_tlm_generic_payload,"uvm_tlm_generic_payload") type_id; + static function uvm_tlm_generic_payload type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_tlm_generic_payload tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_tlm_generic_payload"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_tlm_generic_payload"; + endfunction : get_type_name + function new(string name=""); + super.new(name); + m_address = 0; + m_command = UVM_TLM_IGNORE_COMMAND; + m_length = 0; + m_response_status = UVM_TLM_INCOMPLETE_RESPONSE; + m_dmi = 0; + m_byte_enable_length = 0; + m_streaming_width = 0; + endfunction + function void do_print(uvm_printer printer); + byte unsigned be; + super.do_print(printer); + printer.print_field_int ("address", m_address, 64, UVM_HEX); + printer.print_generic ("command", "uvm_tlm_command_e", 32, m_command.name()); + printer.print_generic ("response_status", "uvm_tlm_response_status_e", + 32, m_response_status.name()); + printer.print_field_int ("streaming_width", m_streaming_width, 32, UVM_HEX); + printer.print_array_header("data", m_length, "darray(byte)"); + for (int i=0; i < m_length && i < m_data.size(); i++) begin + if (m_byte_enable_length) begin + be = m_byte_enable[i % m_byte_enable_length]; + printer.print_generic ($sformatf("[%0d]",i), "byte", 8, + $sformatf("'h%h%s",m_data[i],((be=='hFF) ? "" : " x"))); + end + else + printer.print_generic ($sformatf("[%0d]",i), "byte", 8, + $sformatf("'h%h",m_data[i])); + end + printer.print_array_footer(); + begin + string name; + printer.print_array_header("extensions", m_extensions.num(), "aa(obj,obj)"); + foreach (m_extensions[ext_]) begin + uvm_tlm_extension_base ext = m_extensions[ext_]; + name = {"[",ext.get_name(),"]"}; + printer.print_object(name, ext, "["); + end + printer.print_array_footer(); + end + endfunction + function void do_copy(uvm_object rhs); + uvm_tlm_generic_payload gp; + super.do_copy(rhs); + $cast(gp, rhs); + m_address = gp.m_address; + m_command = gp.m_command; + m_data = gp.m_data; + m_dmi = gp.m_dmi; + m_length = gp.m_length; + m_response_status = gp.m_response_status; + m_byte_enable = gp.m_byte_enable; + m_streaming_width = gp.m_streaming_width; + m_byte_enable_length = gp.m_byte_enable_length; + m_extensions.delete(); + foreach (gp.m_extensions[ext]) + $cast(m_extensions[ext], gp.m_extensions[ext].clone()); + endfunction + function bit do_compare(uvm_object rhs, uvm_comparer comparer); + uvm_tlm_generic_payload gp; + do_compare = super.do_compare(rhs, comparer); + $cast(gp, rhs); + if ( (!comparer.get_threshold() || (comparer.get_result() < comparer.get_threshold())) && + ((m_address) != (gp.m_address)) ) begin + string name = ("" == "") ? "m_address" : ""; + void'(comparer.compare_field_int(name , m_address, gp.m_address, $bits(m_address), UVM_HEX)); + end + if ( (!comparer.get_threshold() || (comparer.get_result() < comparer.get_threshold())) && + ((m_command) != (gp.m_command)) ) begin + string name = ("" == "") ? "m_command" : ""; + void'( comparer.compare_string(name, + $sformatf("%s'(%s)", "uvm_tlm_command_e", m_command.name()), + $sformatf("%s'(%s)", "uvm_tlm_command_e", gp.m_command.name())) ); + end + if ( (!comparer.get_threshold() || (comparer.get_result() < comparer.get_threshold())) && + ((m_length) != (gp.m_length)) ) begin + string name = ("" == "") ? "m_length" : ""; + void'(comparer.compare_field_int(name , m_length, gp.m_length, $bits(m_length), UVM_UNSIGNED)); + end + if ( (!comparer.get_threshold() || (comparer.get_result() < comparer.get_threshold())) && + ((m_dmi) != (gp.m_dmi)) ) begin + string name = ("" == "") ? "m_dmi" : ""; + void'(comparer.compare_field_int(name , m_dmi, gp.m_dmi, $bits(m_dmi), UVM_BIN)); + end + if ( (!comparer.get_threshold() || (comparer.get_result() < comparer.get_threshold())) && + ((m_byte_enable_length) != (gp.m_byte_enable_length)) ) begin + string name = ("" == "") ? "m_byte_enable_length" : ""; + void'(comparer.compare_field_int(name , m_byte_enable_length, gp.m_byte_enable_length, $bits(m_byte_enable_length), UVM_UNSIGNED)); + end + if ( (!comparer.get_threshold() || (comparer.get_result() < comparer.get_threshold())) && + ((m_response_status) != (gp.m_response_status)) ) begin + string name = ("" == "") ? "m_response_status" : ""; + void'( comparer.compare_string(name, + $sformatf("%s'(%s)", "uvm_tlm_response_status_e", m_response_status.name()), + $sformatf("%s'(%s)", "uvm_tlm_response_status_e", gp.m_response_status.name())) ); + end + if ( (!comparer.get_threshold() || (comparer.get_result() < comparer.get_threshold())) && + ((m_streaming_width) != (gp.m_streaming_width)) ) begin + string name = ("" == "") ? "m_streaming_width" : ""; + void'(comparer.compare_field_int(name , m_streaming_width, gp.m_streaming_width, $bits(m_streaming_width), UVM_UNSIGNED)); + end + if ( (!comparer.get_threshold() || (comparer.get_result() < comparer.get_threshold())) && + m_byte_enable_length == gp.m_byte_enable_length ) begin + for (int i=0; i < m_byte_enable_length && i < m_byte_enable.size(); i++) begin + if ( (!comparer.get_threshold() || (comparer.get_result() < comparer.get_threshold())) && + ((m_byte_enable[i]) != (gp.m_byte_enable[i])) ) begin + string name = ($sformatf("m_byte_enable[%0d]", i) == "") ? "m_byte_enable[i]" : $sformatf("m_byte_enable[%0d]", i); + void'(comparer.compare_field_int(name , m_byte_enable[i], gp.m_byte_enable[i], $bits(m_byte_enable[i]), UVM_HEX)); + end + end + end + if ( (!comparer.get_threshold() || (comparer.get_result() < comparer.get_threshold())) && + m_length == gp.m_length ) begin + byte unsigned be; + for (int i=0; i < m_length && i < m_data.size(); i++) begin + if (m_byte_enable_length) begin + be = m_byte_enable[i % m_byte_enable_length]; + end + else begin + be = 8'hFF; + end + if ( (!comparer.get_threshold() || (comparer.get_result() < comparer.get_threshold())) && + ((m_data[i] & be) != (gp.m_data[i] & be)) ) begin + string name = ($sformatf("m_data[%0d] & %0x", i, be) == "") ? "m_data[i] & be" : $sformatf("m_data[%0d] & %0x", i, be); + void'(comparer.compare_field_int(name , m_data[i] & be, gp.m_data[i] & be, $bits(m_data[i] & be), UVM_HEX)); + end + end + end + if ( !comparer.get_threshold() || (comparer.get_result() < comparer.get_threshold()) ) + foreach (m_extensions[ext_]) begin + uvm_tlm_extension_base ext = ext_; + uvm_tlm_extension_base rhs_ext = gp.m_extensions.exists(ext) ? + gp.m_extensions[ext] : null; + void'(comparer.compare_object(ext.get_name(), + m_extensions[ext], rhs_ext)); + if ( !comparer.get_threshold() || (comparer.get_result() < comparer.get_threshold()) ) + break; + end + if (comparer.get_result()) begin + string msg = $sformatf("GP miscompare between '%s' and '%s':\nlhs = %s\nrhs = %s", + get_full_name(), gp.get_full_name(), + this.convert2string(), gp.convert2string()); + comparer.print_msg(msg); + end + return (comparer.get_result() == 0); + endfunction + function void do_pack(uvm_packer packer); + super.do_pack(packer); + if (m_length > m_data.size()) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PACK_DATA_ARR")) + uvm_report_fatal ("PACK_DATA_ARR", $sformatf("Data array m_length property (%0d) greater than m_data.size (%0d)", m_length,m_data.size()), UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_generic_payload.svh", 562, "", 1); + end + if (m_byte_enable_length > m_byte_enable.size()) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"PACK_DATA_ARR")) + uvm_report_fatal ("PACK_DATA_ARR", $sformatf("Data array m_byte_enable_length property (%0d) greater than m_byte_enable.size (%0d)", m_byte_enable_length,m_byte_enable.size()), UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_generic_payload.svh", 566, "", 1); + end + begin + bit __array[]; + { << bit { __array}} = m_address; + __array = new [64] (__array); + packer.pack_bits(__array, 64); + end + begin + bit __array[]; + { << bit { __array}} = m_command; + __array = new [32] (__array); + packer.pack_bits(__array, 32); + end + begin + bit __array[]; + { << bit { __array}} = m_length; + __array = new [32] (__array); + packer.pack_bits(__array, 32); + end + begin + bit __array[]; + { << bit { __array}} = m_dmi; + __array = new [1] (__array); + packer.pack_bits(__array, 1); + end + for (int i=0; i 64) + recorder.record_field("address", m_address, $bits(m_address), UVM_NORADIX); + else + recorder.record_field_int("address", m_address, $bits(m_address), UVM_NORADIX); + end + if (recorder != null && recorder.is_open()) begin + if (recorder.use_record_attribute()) + recorder.record_generic("command", $sformatf("%p", m_command.name())); + else + recorder.record_string("command",m_command.name()); + end + if (recorder != null && recorder.is_open()) begin + if (recorder.use_record_attribute()) + recorder.record_generic("data_length", $sformatf("%p", m_length)); + else + if ($bits(m_length) > 64) + recorder.record_field("data_length", m_length, $bits(m_length), UVM_NORADIX); + else + recorder.record_field_int("data_length", m_length, $bits(m_length), UVM_NORADIX); + end + if (recorder != null && recorder.is_open()) begin + if (recorder.use_record_attribute()) + recorder.record_generic("byte_enable_length", $sformatf("%p", m_byte_enable_length)); + else + if ($bits(m_byte_enable_length) > 64) + recorder.record_field("byte_enable_length", m_byte_enable_length, $bits(m_byte_enable_length), UVM_NORADIX); + else + recorder.record_field_int("byte_enable_length", m_byte_enable_length, $bits(m_byte_enable_length), UVM_NORADIX); + end + if (recorder != null && recorder.is_open()) begin + if (recorder.use_record_attribute()) + recorder.record_generic("response_status", $sformatf("%p", m_response_status.name())); + else + recorder.record_string("response_status",m_response_status.name()); + end + if (recorder != null && recorder.is_open()) begin + if (recorder.use_record_attribute()) + recorder.record_generic("streaming_width", $sformatf("%p", m_streaming_width)); + else + if ($bits(m_streaming_width) > 64) + recorder.record_field("streaming_width", m_streaming_width, $bits(m_streaming_width), UVM_NORADIX); + else + recorder.record_field_int("streaming_width", m_streaming_width, $bits(m_streaming_width), UVM_NORADIX); + end + for (int i=0; i < m_length; i++) + if (recorder != null && recorder.is_open()) begin + if (recorder.use_record_attribute()) + recorder.record_generic($sformatf("\\data[%0d] ", i), $sformatf("%p", m_data[i])); + else + if ($bits(m_data[i]) > 64) + recorder.record_field($sformatf("\\data[%0d] ", i), m_data[i], $bits(m_data[i]), UVM_NORADIX); + else + recorder.record_field_int($sformatf("\\data[%0d] ", i), m_data[i], $bits(m_data[i]), UVM_NORADIX); + end + for (int i=0; i < m_byte_enable_length; i++) + if (recorder != null && recorder.is_open()) begin + if (recorder.use_record_attribute()) + recorder.record_generic($sformatf("\\byte_en[%0d] ", i), $sformatf("%p", m_byte_enable[i])); + else + if ($bits(m_byte_enable[i]) > 64) + recorder.record_field($sformatf("\\byte_en[%0d] ", i), m_byte_enable[i], $bits(m_byte_enable[i]), UVM_NORADIX); + else + recorder.record_field_int($sformatf("\\byte_en[%0d] ", i), m_byte_enable[i], $bits(m_byte_enable[i]), UVM_NORADIX); + end + foreach (m_extensions[ext]) + recorder.record_object(ext.get_name(),m_extensions[ext]); + endfunction + function string convert2string(); + string msg; + string s; + $sformat(msg, "%s %s [0x%16x] =", super.convert2string(), + m_command.name(), m_address); + for(int unsigned i = 0; i < m_length; i++) begin + if (!m_byte_enable_length || (m_byte_enable[i % m_byte_enable_length] == 'hFF)) + $sformat(s, " %02x", m_data[i]); + else + $sformat(s, " --"); + msg = { msg , s }; + end + msg = { msg, " (status=", get_response_string(), ")" }; + return msg; + endfunction + virtual function uvm_tlm_command_e get_command(); + return m_command; + endfunction + virtual function void set_command(uvm_tlm_command_e command); + m_command = command; + endfunction + virtual function bit is_read(); + return (m_command == UVM_TLM_READ_COMMAND); + endfunction + virtual function void set_read(); + set_command(UVM_TLM_READ_COMMAND); + endfunction + virtual function bit is_write(); + return (m_command == UVM_TLM_WRITE_COMMAND); + endfunction + virtual function void set_write(); + set_command(UVM_TLM_WRITE_COMMAND); + endfunction + virtual function void set_address(bit [63:0] addr); + m_address = addr; + endfunction + virtual function bit [63:0] get_address(); + return m_address; + endfunction + virtual function void get_data (output byte unsigned p []); + p = m_data; + endfunction + virtual function void set_data(ref byte unsigned p []); + m_data = p; + endfunction + virtual function int unsigned get_data_length(); + return m_length; + endfunction + virtual function void set_data_length(int unsigned length); + m_length = length; + endfunction + virtual function int unsigned get_streaming_width(); + return m_streaming_width; + endfunction + virtual function void set_streaming_width(int unsigned width); + m_streaming_width = width; + endfunction + virtual function void get_byte_enable(output byte unsigned p[]); + p = m_byte_enable; + endfunction + virtual function void set_byte_enable(ref byte unsigned p[]); + m_byte_enable = p; + endfunction + virtual function int unsigned get_byte_enable_length(); + return m_byte_enable_length; + endfunction + virtual function void set_byte_enable_length(int unsigned length); + m_byte_enable_length = length; + endfunction + virtual function void set_dmi_allowed(bit dmi); + m_dmi = dmi; + endfunction + virtual function bit is_dmi_allowed(); + return m_dmi; + endfunction + virtual function uvm_tlm_response_status_e get_response_status(); + return m_response_status; + endfunction + virtual function void set_response_status(uvm_tlm_response_status_e status); + m_response_status = status; + endfunction + virtual function bit is_response_ok(); + return (int'(m_response_status) > 0); + endfunction + virtual function bit is_response_error(); + return !is_response_ok(); + endfunction + virtual function string get_response_string(); + case(m_response_status) + UVM_TLM_OK_RESPONSE : return "OK"; + UVM_TLM_INCOMPLETE_RESPONSE : return "INCOMPLETE"; + UVM_TLM_GENERIC_ERROR_RESPONSE : return "GENERIC_ERROR"; + UVM_TLM_ADDRESS_ERROR_RESPONSE : return "ADDRESS_ERROR"; + UVM_TLM_COMMAND_ERROR_RESPONSE : return "COMMAND_ERROR"; + UVM_TLM_BURST_ERROR_RESPONSE : return "BURST_ERROR"; + UVM_TLM_BYTE_ENABLE_ERROR_RESPONSE : return "BYTE_ENABLE_ERROR"; + endcase + return "UNKNOWN_RESPONSE"; + endfunction + function uvm_tlm_extension_base set_extension(uvm_tlm_extension_base ext); + uvm_tlm_extension_base ext_handle = ext.get_type_handle(); + if(!m_extensions.exists(ext_handle)) + set_extension = null; + else + set_extension = m_extensions[ext_handle]; + m_extensions[ext_handle] = ext; + endfunction + function int get_num_extensions(); + return m_extensions.num(); + endfunction: get_num_extensions + function uvm_tlm_extension_base get_extension(uvm_tlm_extension_base ext_handle); + if(!m_extensions.exists(ext_handle)) + return null; + return m_extensions[ext_handle]; + endfunction + function void clear_extension(uvm_tlm_extension_base ext_handle); + if(m_extensions.exists(ext_handle)) + m_extensions.delete(ext_handle); + else + begin + if (uvm_report_enabled(UVM_MEDIUM,UVM_INFO,"GP_EXT")) + uvm_report_info ("GP_EXT", $sformatf("Unable to find extension to clear"), UVM_MEDIUM, "t/uvm/src/tlm2/uvm_tlm2_generic_payload.svh", 965, "", 1); + end + endfunction + function void clear_extensions(); + m_extensions.delete(); + endfunction + function void pre_randomize(); + int i; + m_rand_exts = new [m_extensions.num()]; + foreach (m_extensions[ext_]) begin + uvm_tlm_extension_base ext = ext_; + m_rand_exts[i++] = m_extensions[ext]; + end + endfunction + function void post_randomize(); + m_rand_exts.delete(); + endfunction +endclass +typedef uvm_tlm_generic_payload uvm_tlm_gp; +virtual class uvm_tlm_extension_base extends uvm_object; + function new(string name = ""); + super.new(name); + endfunction + pure virtual function uvm_tlm_extension_base get_type_handle(); + pure virtual function string get_type_handle_name(); + virtual function void do_copy(uvm_object rhs); + super.do_copy(rhs); + endfunction + virtual function uvm_object create (string name=""); + return null; + endfunction +endclass +class uvm_tlm_extension #(type T=int) extends uvm_tlm_extension_base; + typedef uvm_tlm_extension#(T) this_type; + local static this_type m_my_tlm_ext_type = ID(); + function new(string name=""); + super.new(name); + endfunction + static function this_type ID(); + if (m_my_tlm_ext_type == null) + m_my_tlm_ext_type = new(); + return m_my_tlm_ext_type; + endfunction + virtual function uvm_tlm_extension_base get_type_handle(); + return ID(); + endfunction + virtual function string get_type_handle_name(); + return $typename(T); + endfunction + virtual function uvm_object create (string name=""); + return null; + endfunction +endclass +typedef class uvm_time; +typedef enum + { + UNINITIALIZED_PHASE, + BEGIN_REQ, + END_REQ, + BEGIN_RESP, + END_RESP + } uvm_tlm_phase_e; +typedef enum + { + UVM_TLM_ACCEPTED, + UVM_TLM_UPDATED, + UVM_TLM_COMPLETED + } uvm_tlm_sync_e; +class uvm_tlm_if #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e); + virtual function uvm_tlm_sync_e nb_transport_fw(T t, ref P p, input uvm_tlm_time delay); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"nb_transport_fw")) + uvm_report_error ("nb_transport_fw", "UVM TLM 2 interface function not implemented", UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_ifs.svh", 115, "", 1); + end + return UVM_TLM_ACCEPTED; + endfunction + virtual function uvm_tlm_sync_e nb_transport_bw(T t, ref P p, input uvm_tlm_time delay); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"nb_transport_bw")) + uvm_report_error ("nb_transport_bw", "UVM TLM 2 interface function not implemented", UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_ifs.svh", 158, "", 1); + end + return UVM_TLM_ACCEPTED; + endfunction + virtual task b_transport(T t, uvm_tlm_time delay); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"b_transport")) + uvm_report_error ("b_transport", "TLM-2 interface task not implemented", UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_ifs.svh", 182, "", 1); + end + endtask +endclass +class uvm_tlm_b_transport_imp #(type T=uvm_tlm_generic_payload, + type IMP=int) + extends uvm_port_base #(uvm_tlm_if #(T)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = (1<<2); + endfunction + virtual function string get_type_name(); + return "uvm_tlm_b_transport_imp"; + endfunction + task b_transport(T t, uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".b_transport() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_imps.svh", 173, "", 1); + end + return; + end + m_imp.b_transport(t, delay); + endtask +endclass +class uvm_tlm_nb_transport_fw_imp #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e, + type IMP=int) + extends uvm_port_base #(uvm_tlm_if #(T,P)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = (1<<0); + endfunction + virtual function string get_type_name(); + return "uvm_tlm_nb_transport_fw_imp"; + endfunction + function uvm_tlm_sync_e nb_transport_fw(T t, ref P p, input uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".nb_transport_fw() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_imps.svh", 190, "", 1); + end + return UVM_TLM_COMPLETED; + end + return m_imp.nb_transport_fw(t, p, delay); + endfunction +endclass +class uvm_tlm_nb_transport_bw_imp #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e, + type IMP=int) + extends uvm_port_base #(uvm_tlm_if #(T,P)); + local IMP m_imp; + function new (string name, IMP imp); + super.new (name, imp, UVM_IMPLEMENTATION, 1, 1); + m_imp = imp; + m_if_mask = (1<<1); + endfunction + virtual function string get_type_name(); + return "uvm_tlm_nb_transport_bw_imp"; + endfunction + function uvm_tlm_sync_e nb_transport_bw(T t, ref P p, input uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".nb_transport_bw() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_imps.svh", 207, "", 1); + end + return UVM_TLM_COMPLETED; + end + return m_imp.nb_transport_bw(t, p, delay); + endfunction +endclass +class uvm_tlm_b_transport_port #(type T=uvm_tlm_generic_payload) + extends uvm_port_base #(uvm_tlm_if #(T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = (1<<2); + endfunction + virtual function string get_type_name(); + return "uvm_tlm_b_transport_port"; + endfunction + task b_transport(T t, uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".b_transport() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_ports.svh", 41, "", 1); + end + return; + end + this.m_if.b_transport(t, delay); + endtask +endclass +class uvm_tlm_nb_transport_fw_port #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e) + extends uvm_port_base #(uvm_tlm_if #(T,P)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = (1<<0); + endfunction + virtual function string get_type_name(); + return "uvm_tlm_nb_transport_fw_port"; + endfunction + function uvm_tlm_sync_e nb_transport_fw(T t, ref P p, input uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".nb_transport_fw() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_ports.svh", 59, "", 1); + end + return UVM_TLM_COMPLETED; + end + return this.m_if.nb_transport_fw(t, p, delay); + endfunction +endclass +class uvm_tlm_nb_transport_bw_port #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e) + extends uvm_port_base #(uvm_tlm_if #(T,P)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = (1<<1); + endfunction + virtual function string get_type_name(); + return "uvm_tlm_nb_transport_bw_port"; + endfunction + function uvm_tlm_sync_e nb_transport_bw(T t, ref P p, input uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".nb_transport_bw() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_ports.svh", 78, "", 1); + end + return UVM_TLM_COMPLETED; + end + return this.m_if.nb_transport_bw(t, p, delay); + endfunction +endclass +class uvm_tlm_b_transport_export #(type T=uvm_tlm_generic_payload) + extends uvm_port_base #(uvm_tlm_if #(T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = (1<<2); + endfunction + virtual function string get_type_name(); + return "uvm_tlm_b_transport_export"; + endfunction + task b_transport(T t, uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".b_transport() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_exports.svh", 39, "", 1); + end + return; + end + this.m_if.b_transport(t, delay); + endtask +endclass +class uvm_tlm_nb_transport_fw_export #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e) + extends uvm_port_base #(uvm_tlm_if #(T,P)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = (1<<0); + endfunction + virtual function string get_type_name(); + return "uvm_tlm_nb_transport_fw_export"; + endfunction + function uvm_tlm_sync_e nb_transport_fw(T t, ref P p, input uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".nb_transport_fw() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_exports.svh", 53, "", 1); + end + return UVM_TLM_COMPLETED; + end + return this.m_if.nb_transport_fw(t, p, delay); + endfunction +endclass +class uvm_tlm_nb_transport_bw_export #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e) + extends uvm_port_base #(uvm_tlm_if #(T,P)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = (1<<1); + endfunction + virtual function string get_type_name(); + return "uvm_tlm_nb_transport_bw_export"; + endfunction + function uvm_tlm_sync_e nb_transport_bw(T t, ref P p, input uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".nb_transport_bw() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_exports.svh", 68, "", 1); + end + return UVM_TLM_COMPLETED; + end + return this.m_if.nb_transport_bw(t, p, delay); + endfunction +endclass +virtual +class uvm_tlm_b_target_socket_base #(type T=uvm_tlm_generic_payload) + extends uvm_port_base #(uvm_tlm_if #(T)); + function new (string name, uvm_component parent); + super.new (name, parent, UVM_IMPLEMENTATION, 1, 1); + m_if_mask = (1<<2); + endfunction + virtual function string get_type_name(); + return "uvm_tlm_b_target_socket"; + endfunction +endclass +virtual +class uvm_tlm_b_initiator_socket_base #(type T=uvm_tlm_generic_payload) + extends uvm_port_base #(uvm_tlm_if #(T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = (1<<2); + endfunction + virtual function string get_type_name(); + return "uvm_tlm_b_initiator_socket"; + endfunction + task b_transport(T t, uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".b_transport() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets_base.svh", 77, "", 1); + end + return; + end + this.m_if.b_transport(t, delay); + endtask +endclass +virtual +class uvm_tlm_nb_target_socket_base #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e) + extends uvm_port_base #(uvm_tlm_if #(T,P)); + uvm_tlm_nb_transport_bw_port #(T,P) bw_port; + function new (string name, uvm_component parent); + super.new (name, parent, UVM_IMPLEMENTATION, 1, 1); + m_if_mask = (1<<0); + endfunction + virtual function string get_type_name(); + return "uvm_tlm_nb_target_socket"; + endfunction + function uvm_tlm_sync_e nb_transport_bw(T t, ref P p, input uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".nb_transport_bw() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets_base.svh", 102, "", 1); + end + return UVM_TLM_COMPLETED; + end + return bw_port.nb_transport_bw(t, p, delay); + endfunction +endclass +virtual +class uvm_tlm_nb_initiator_socket_base #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e) + extends uvm_port_base #(uvm_tlm_if #(T,P)); + function new (string name, uvm_component parent); + super.new (name, parent, UVM_PORT, 1, 1); + m_if_mask = (1<<0); + endfunction + virtual function string get_type_name(); + return "uvm_tlm_nb_initiator_socket"; + endfunction + function uvm_tlm_sync_e nb_transport_fw(T t, ref P p, input uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".nb_transport_fw() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets_base.svh", 125, "", 1); + end + return UVM_TLM_COMPLETED; + end + return this.m_if.nb_transport_fw(t, p, delay); + endfunction +endclass +virtual +class uvm_tlm_nb_passthrough_initiator_socket_base #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e) + extends uvm_port_base #(uvm_tlm_if #(T,P)); + uvm_tlm_nb_transport_bw_export #(T,P) bw_export; + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = (1<<0); + bw_export = new("bw_export", get_comp()); + endfunction + virtual function string get_type_name(); + return "uvm_tlm_nb_passthrough_initiator_socket"; + endfunction + function uvm_tlm_sync_e nb_transport_fw(T t, ref P p, input uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".nb_transport_fw() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets_base.svh", 155, "", 1); + end + return UVM_TLM_COMPLETED; + end + return this.m_if.nb_transport_fw(t, p, delay); + endfunction + function uvm_tlm_sync_e nb_transport_bw(T t, ref P p, input uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".nb_transport_bw() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets_base.svh", 156, "", 1); + end + return UVM_TLM_COMPLETED; + end + return bw_export.nb_transport_bw(t, p, delay); + endfunction +endclass +virtual +class uvm_tlm_nb_passthrough_target_socket_base #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e) + extends uvm_port_base #(uvm_tlm_if #(T,P)); + uvm_tlm_nb_transport_bw_port #(T,P) bw_port; + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = (1<<0); + bw_port = new("bw_port", get_comp()); + endfunction + virtual function string get_type_name(); + return "uvm_tlm_nb_passthrough_target_socket"; + endfunction + function uvm_tlm_sync_e nb_transport_fw(T t, ref P p, input uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".nb_transport_fw() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets_base.svh", 183, "", 1); + end + return UVM_TLM_COMPLETED; + end + return this.m_if.nb_transport_fw(t, p, delay); + endfunction + function uvm_tlm_sync_e nb_transport_bw(T t, ref P p, input uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".nb_transport_bw() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets_base.svh", 184, "", 1); + end + return UVM_TLM_COMPLETED; + end + return bw_port.nb_transport_bw(t, p, delay); + endfunction +endclass +virtual +class uvm_tlm_b_passthrough_initiator_socket_base #(type T=uvm_tlm_generic_payload) + extends uvm_port_base #(uvm_tlm_if #(T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_PORT, min_size, max_size); + m_if_mask = (1<<2); + endfunction + virtual function string get_type_name(); + return "uvm_tlm_b_passthrough_initiator_socket"; + endfunction + task b_transport(T t, uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".b_transport() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets_base.svh", 200, "", 1); + end + return; + end + this.m_if.b_transport(t, delay); + endtask +endclass +virtual +class uvm_tlm_b_passthrough_target_socket_base #(type T=uvm_tlm_generic_payload) + extends uvm_port_base #(uvm_tlm_if #(T)); + function new (string name, uvm_component parent, + int min_size=1, int max_size=1); + super.new (name, parent, UVM_EXPORT, min_size, max_size); + m_if_mask = (1<<2); + endfunction + virtual function string get_type_name(); + return "uvm_tlm_b_passthrough_target_socket"; + endfunction + task b_transport(T t, uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".b_transport() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets_base.svh", 217, "", 1); + end + return; + end + this.m_if.b_transport(t, delay); + endtask + endclass +class uvm_tlm_b_initiator_socket #(type T=uvm_tlm_generic_payload) + extends uvm_tlm_b_initiator_socket_base #(T); + function new(string name, uvm_component parent); + super.new(name, parent); + endfunction + function void connect(this_type provider); + uvm_tlm_b_passthrough_initiator_socket_base #(T) initiator_pt_socket; + uvm_tlm_b_passthrough_target_socket_base #(T) target_pt_socket; + uvm_tlm_b_target_socket_base #(T) target_socket; + uvm_component c; + super.connect(provider); + if($cast(initiator_pt_socket, provider) || + $cast(target_pt_socket, provider) || + $cast(target_socket, provider)) + return; + c = get_comp(); + begin + if (c.uvm_report_enabled(UVM_NONE,UVM_ERROR,get_type_name())) + c.uvm_report_error (get_type_name(), "type mismatch in connect -- connection cannot be completed", UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets.svh", 87, "", 1); + end + endfunction +endclass +class uvm_tlm_b_target_socket #(type IMP=int, + type T=uvm_tlm_generic_payload) + extends uvm_tlm_b_target_socket_base #(T); + local IMP m_imp; + function new (string name, uvm_component parent, IMP imp = null); + super.new (name, parent); + if (imp == null) $cast(m_imp, parent); + else m_imp = imp; + if (m_imp == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM2/NOIMP")) + uvm_report_error ("UVM/TLM2/NOIMP", {"b_target socket ", name, " has no implementation"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets.svh", 121, "", 1); + end + endfunction + function void connect(this_type provider); + uvm_component c; + super.connect(provider); + c = get_comp(); + begin + if (c.uvm_report_enabled(UVM_NONE,UVM_ERROR,get_type_name())) + c.uvm_report_error (get_type_name(), "You cannot call connect() on a target termination socket", UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets.svh", 134, "", 1); + end + endfunction + task b_transport(T t, uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".b_transport() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets.svh", 137, "", 1); + end + return; + end + m_imp.b_transport(t, delay); + endtask +endclass +class uvm_tlm_nb_initiator_socket #(type IMP=int, + type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e) + extends uvm_tlm_nb_initiator_socket_base #(T,P); + uvm_tlm_nb_transport_bw_imp #(T,P,IMP) bw_imp; + function new(string name, uvm_component parent, IMP imp = null); + super.new (name, parent); + if (imp == null) $cast(imp, parent); + if (imp == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM2/NOIMP")) + uvm_report_error ("UVM/TLM2/NOIMP", {"nb_initiator socket ", name, " has no implementation"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets.svh", 168, "", 1); + end + bw_imp = new("bw_imp", imp); + endfunction + function void connect(this_type provider); + uvm_tlm_nb_passthrough_initiator_socket_base #(T,P) initiator_pt_socket; + uvm_tlm_nb_passthrough_target_socket_base #(T,P) target_pt_socket; + uvm_tlm_nb_target_socket_base #(T,P) target_socket; + uvm_component c; + super.connect(provider); + if($cast(initiator_pt_socket, provider)) begin + initiator_pt_socket.bw_export.connect(bw_imp); + return; + end + if($cast(target_pt_socket, provider)) begin + target_pt_socket.bw_port.connect(bw_imp); + return; + end + if($cast(target_socket, provider)) begin + target_socket.bw_port.connect(bw_imp); + return; + end + c = get_comp(); + begin + if (c.uvm_report_enabled(UVM_NONE,UVM_ERROR,get_type_name())) + c.uvm_report_error (get_type_name(), "type mismatch in connect -- connection cannot be completed", UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets.svh", 200, "", 1); + end + endfunction +endclass +class uvm_tlm_nb_target_socket #(type IMP=int, + type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e) + extends uvm_tlm_nb_target_socket_base #(T,P); + local IMP m_imp; + function new (string name, uvm_component parent, IMP imp = null); + super.new (name, parent); + if (imp == null) $cast(m_imp, parent); + else m_imp = imp; + bw_port = new("bw_port", get_comp()); + if (m_imp == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM2/NOIMP")) + uvm_report_error ("UVM/TLM2/NOIMP", {"nb_target socket ", name, " has no implementation"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets.svh", 236, "", 1); + end + endfunction + function void connect(this_type provider); + uvm_component c; + super.connect(provider); + c = get_comp(); + begin + if (c.uvm_report_enabled(UVM_NONE,UVM_ERROR,get_type_name())) + c.uvm_report_error (get_type_name(), "You cannot call connect() on a target termination socket", UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets.svh", 249, "", 1); + end + endfunction + function uvm_tlm_sync_e nb_transport_fw(T t, ref P p, input uvm_tlm_time delay); + if (delay == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/TLM/NULLDELAY")) + uvm_report_error ("UVM/TLM/NULLDELAY", {get_full_name(), ".nb_transport_fw() called with 'null' delay"}, UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets.svh", 252, "", 1); + end + return UVM_TLM_COMPLETED; + end + return m_imp.nb_transport_fw(t, p, delay); + endfunction +endclass +class uvm_tlm_b_passthrough_initiator_socket #(type T=uvm_tlm_generic_payload) + extends uvm_tlm_b_passthrough_initiator_socket_base #(T); + function new(string name, uvm_component parent); + super.new(name, parent); + endfunction + function void connect(this_type provider); + uvm_tlm_b_passthrough_initiator_socket_base #(T) initiator_pt_socket; + uvm_tlm_b_passthrough_target_socket_base #(T) target_pt_socket; + uvm_tlm_b_target_socket_base #(T) target_socket; + uvm_component c; + super.connect(provider); + if($cast(initiator_pt_socket, provider) || + $cast(target_pt_socket, provider) || + $cast(target_socket, provider)) + return; + c = get_comp(); + begin + if (c.uvm_report_enabled(UVM_NONE,UVM_ERROR,get_type_name())) + c.uvm_report_error (get_type_name(), "type mismatch in connect -- connection cannot be completed", UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets.svh", 290, "", 1); + end + endfunction +endclass +class uvm_tlm_b_passthrough_target_socket #(type T=uvm_tlm_generic_payload) + extends uvm_tlm_b_passthrough_target_socket_base #(T); + function new(string name, uvm_component parent); + super.new(name, parent); + endfunction + function void connect(this_type provider); + uvm_tlm_b_passthrough_target_socket_base #(T) target_pt_socket; + uvm_tlm_b_target_socket_base #(T) target_socket; + uvm_component c; + super.connect(provider); + if($cast(target_pt_socket, provider) || + $cast(target_socket, provider)) + return; + c = get_comp(); + begin + if (c.uvm_report_enabled(UVM_NONE,UVM_ERROR,get_type_name())) + c.uvm_report_error (get_type_name(), "type mismatch in connect -- connection cannot be completed", UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets.svh", 323, "", 1); + end + endfunction +endclass +class uvm_tlm_nb_passthrough_initiator_socket #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e) + extends uvm_tlm_nb_passthrough_initiator_socket_base #(T,P); + function new(string name, uvm_component parent); + super.new(name, parent); + endfunction + function void connect(this_type provider); + uvm_tlm_nb_passthrough_initiator_socket_base #(T,P) initiator_pt_socket; + uvm_tlm_nb_passthrough_target_socket_base #(T,P) target_pt_socket; + uvm_tlm_nb_target_socket_base #(T,P) target_socket; + uvm_component c; + super.connect(provider); + if($cast(initiator_pt_socket, provider)) begin + bw_export.connect(initiator_pt_socket.bw_export); + return; + end + if($cast(target_pt_socket, provider)) begin + target_pt_socket.bw_port.connect(bw_export); + return; + end + if($cast(target_socket, provider)) begin + target_socket.bw_port.connect(bw_export); + return; + end + c = get_comp(); + begin + if (c.uvm_report_enabled(UVM_NONE,UVM_ERROR,get_type_name())) + c.uvm_report_error (get_type_name(), "type mismatch in connect -- connection cannot be completed", UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets.svh", 375, "", 1); + end + endfunction +endclass +class uvm_tlm_nb_passthrough_target_socket #(type T=uvm_tlm_generic_payload, + type P=uvm_tlm_phase_e) + extends uvm_tlm_nb_passthrough_target_socket_base #(T,P); + function new(string name, uvm_component parent); + super.new(name, parent); + endfunction + function void connect(this_type provider); + uvm_tlm_nb_passthrough_target_socket_base #(T,P) target_pt_socket; + uvm_tlm_nb_target_socket_base #(T,P) target_socket; + uvm_component c; + super.connect(provider); + if($cast(target_pt_socket, provider)) begin + target_pt_socket.bw_port.connect(bw_port); + return; + end + if($cast(target_socket, provider)) begin + target_socket.bw_port.connect(bw_port); + return; + end + c = get_comp(); + begin + if (c.uvm_report_enabled(UVM_NONE,UVM_ERROR,get_type_name())) + c.uvm_report_error (get_type_name(), "type mismatch in connect -- connection cannot be completed", UVM_NONE, "t/uvm/src/tlm2/uvm_tlm2_sockets.svh", 419, "", 1); + end + endfunction +endclass +typedef class uvm_reg_field; +typedef class uvm_vreg_field; +typedef class uvm_reg; +typedef class uvm_reg_file; +typedef class uvm_vreg; +typedef class uvm_reg_block; +typedef class uvm_mem; +typedef class uvm_reg_item; +typedef class uvm_reg_map; +typedef class uvm_reg_map_info; +typedef class uvm_reg_sequence; +typedef class uvm_reg_adapter; +typedef class uvm_reg_indirect_data; +typedef bit unsigned [64-1:0] uvm_reg_data_t ; +typedef logic unsigned [64-1:0] uvm_reg_data_logic_t ; +typedef bit unsigned [64-1:0] uvm_reg_addr_t ; +typedef logic unsigned [64-1:0] uvm_reg_addr_logic_t ; +typedef bit unsigned [((64-1)/8+1)-1:0] uvm_reg_byte_en_t ; +typedef bit [32-1:0] uvm_reg_cvr_t ; +typedef struct { + string path; + int offset; + int size; +} uvm_hdl_path_slice; +typedef uvm_resource_db#(uvm_reg_cvr_t) uvm_reg_cvr_rsrc_db; + typedef enum { + UVM_IS_OK, + UVM_NOT_OK, + UVM_HAS_X + } uvm_status_e; + typedef enum { + UVM_FRONTDOOR, + UVM_BACKDOOR, + UVM_PREDICT, + UVM_DEFAULT_DOOR + } uvm_door_e; + typedef enum { + UVM_NO_CHECK, + UVM_CHECK + } uvm_check_e; + typedef enum { + UVM_NO_ENDIAN, + UVM_LITTLE_ENDIAN, + UVM_BIG_ENDIAN, + UVM_LITTLE_FIFO, + UVM_BIG_FIFO + } uvm_endianness_e; + typedef enum { + UVM_REG, + UVM_FIELD, + UVM_MEM + } uvm_elem_kind_e; + typedef enum { + UVM_READ, + UVM_WRITE, + UVM_BURST_READ, + UVM_BURST_WRITE + } uvm_access_e; + typedef enum { + UVM_NO_HIER, + UVM_HIER + } uvm_hier_e; + typedef enum { + UVM_PREDICT_DIRECT, + UVM_PREDICT_READ, + UVM_PREDICT_WRITE + } uvm_predict_e; + typedef enum uvm_reg_cvr_t { + UVM_NO_COVERAGE = 'h0000, + UVM_CVR_REG_BITS = 'h0001, + UVM_CVR_ADDR_MAP = 'h0002, + UVM_CVR_FIELD_VALS = 'h0004, + UVM_CVR_ALL = -1 + } uvm_coverage_model_e; +typedef enum bit [63:0] { + UVM_DO_REG_HW_RESET = 64'h0000_0000_0000_0001, + UVM_DO_REG_BIT_BASH = 64'h0000_0000_0000_0002, + UVM_DO_REG_ACCESS = 64'h0000_0000_0000_0004, + UVM_DO_MEM_ACCESS = 64'h0000_0000_0000_0008, + UVM_DO_SHARED_ACCESS = 64'h0000_0000_0000_0010, + UVM_DO_MEM_WALK = 64'h0000_0000_0000_0020, + UVM_DO_ALL_REG_MEM_TESTS = 64'hffff_ffff_ffff_ffff +} uvm_reg_mem_tests_e; +class uvm_hdl_path_concat; + uvm_hdl_path_slice slices[]; + function void set(uvm_hdl_path_slice t[]); + slices = t; + endfunction + function void add_slice(uvm_hdl_path_slice slice); + slices = new [slices.size()+1] (slices); + slices[slices.size()-1] = slice; + endfunction + function void add_path(string path, + int unsigned offset = -1, + int unsigned size = -1); + uvm_hdl_path_slice t; + t.offset = offset; + t.path = path; + t.size = size; + add_slice(t); + endfunction +endclass +function automatic string uvm_hdl_concat2string(uvm_hdl_path_concat concat); + string image = "{"; + if (concat.slices.size() == 1 && + concat.slices[0].offset == -1 && + concat.slices[0].size == -1) + return concat.slices[0].path; + foreach (concat.slices[i]) begin + uvm_hdl_path_slice slice=concat.slices[i]; + image = { image, (i == 0) ? "" : ", ", slice.path }; + if (slice.offset >= 0) + image = { image, "@", $sformatf("[%0d +: %0d]", slice.offset, slice.size) }; + end + image = { image, "}" }; + return image; +endfunction +typedef struct packed { + uvm_reg_addr_t min; + uvm_reg_addr_t max; + int unsigned stride; + } uvm_reg_map_addr_range; +class uvm_reg_item extends uvm_sequence_item; + typedef uvm_object_registry#(uvm_reg_item,"uvm_reg_item") type_id; + static function uvm_reg_item type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_reg_item tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_reg_item"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_reg_item"; + endfunction : get_type_name + uvm_elem_kind_e element_kind; + uvm_object element; + rand uvm_access_e kind; + rand uvm_reg_data_t value[]; + constraint max_values { value.size() > 0 && value.size() < 1000; } + rand uvm_reg_addr_t offset; + uvm_status_e status; + uvm_reg_map local_map; + uvm_reg_map map; + uvm_door_e path; + rand uvm_sequence_base parent; + int prior = -1; + rand uvm_object extension; + string bd_kind; + string fname; + int lineno; + function new(string name=""); + super.new(name); + value = new[1]; + endfunction + virtual function string convert2string(); + string s,value_s; + s = {"kind=",kind.name(), + " ele_kind=",element_kind.name(), + " ele_name=",element==null?"null":element.get_full_name() }; + if (value.size() > 1 && uvm_report_enabled(UVM_HIGH, UVM_INFO, "RegModel")) begin + value_s = "'{"; + foreach (value[i]) + value_s = {value_s,$sformatf("%0h,",value[i])}; + value_s[value_s.len()-1]="}"; + end + else + value_s = $sformatf("%0h",value[0]); + s = {s, " value=",value_s}; + if (element_kind == UVM_MEM) + s = {s, $sformatf(" offset=%0h",offset)}; + s = {s," map=",(map==null?"null":map.get_full_name())," path=",path.name()}; + s = {s," status=",status.name()}; + return s; + endfunction + virtual function void do_copy(uvm_object rhs); + uvm_reg_item rhs_; + if (rhs == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"REG/NULL")) + uvm_report_fatal ("REG/NULL", "do_copy: rhs argument is null", UVM_NONE, "t/uvm/src/reg/uvm_reg_item.svh", 215, "", 1); + end + if (!$cast(rhs_,rhs)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"WRONG_TYPE")) + uvm_report_error ("WRONG_TYPE", "Provided rhs is not of type uvm_reg_item", UVM_NONE, "t/uvm/src/reg/uvm_reg_item.svh", 218, "", 1); + end + return; + end + super.do_copy(rhs); + element_kind = rhs_.element_kind; + element = rhs_.element; + kind = rhs_.kind; + value = rhs_.value; + offset = rhs_.offset; + status = rhs_.status; + local_map = rhs_.local_map; + map = rhs_.map; + path = rhs_.path; + extension = rhs_.extension; + bd_kind = rhs_.bd_kind; + parent = rhs_.parent; + prior = rhs_.prior; + fname = rhs_.fname; + lineno = rhs_.lineno; + endfunction +endclass +typedef struct { + uvm_access_e kind; + uvm_reg_addr_t addr; + uvm_reg_data_t data; + int n_bits; + uvm_reg_byte_en_t byte_en; + uvm_status_e status; +} uvm_reg_bus_op; +virtual class uvm_reg_adapter extends uvm_object; + typedef uvm_abstract_object_registry#(uvm_reg_adapter,"uvm_reg_adapter") type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_reg_adapter"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_reg_adapter"; + endfunction : get_type_name + function new(string name=""); + super.new(name); + endfunction + bit supports_byte_enable; + bit provides_responses; + uvm_sequence_base parent_sequence; + pure virtual function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw); + pure virtual function void bus2reg(uvm_sequence_item bus_item, + ref uvm_reg_bus_op rw); + local uvm_reg_item m_item; + virtual function uvm_reg_item get_item(); + return m_item; + endfunction + virtual function void m_set_item(uvm_reg_item item); + m_item = item; + endfunction +endclass +class uvm_reg_tlm_adapter extends uvm_reg_adapter; + typedef uvm_object_registry#(uvm_reg_tlm_adapter,"uvm_reg_tlm_adapter") type_id; + static function uvm_reg_tlm_adapter type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_reg_tlm_adapter tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_reg_tlm_adapter"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_reg_tlm_adapter"; + endfunction : get_type_name + function new(string name = "uvm_reg_tlm_adapter"); + super.new(name); + endfunction + virtual function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw); + uvm_tlm_gp gp = uvm_tlm_gp::type_id_create("tlm_gp",, this.get_full_name()); + int nbytes = (rw.n_bits-1)/8+1; + uvm_reg_addr_t addr=rw.addr; + if (rw.kind == UVM_WRITE) + gp.set_command(UVM_TLM_WRITE_COMMAND); + else + gp.set_command(UVM_TLM_READ_COMMAND); + gp.set_address(addr); + gp.m_byte_enable = new [nbytes]; + gp.m_byte_enable_length = nbytes; + gp.set_streaming_width (nbytes); + gp.m_data = new [gp.get_streaming_width()]; + gp.m_length = nbytes; + for (int i = 0; i < nbytes; i++) begin + gp.m_data[i] = rw.data[i*8+:8]; + gp.m_byte_enable[i] = (i > nbytes) ? 8'h00 : (rw.byte_en[i] ? 8'hFF : 8'h00); + end + return gp; + endfunction + virtual function void bus2reg(uvm_sequence_item bus_item, + ref uvm_reg_bus_op rw); + uvm_tlm_gp gp; + int nbytes; + if (bus_item == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"REG/NULL_ITEM")) + uvm_report_fatal ("REG/NULL_ITEM", "bus2reg: bus_item argument is null", UVM_NONE, "t/uvm/src/reg/uvm_reg_adapter.svh", 232, "", 1); + end + if (!$cast(gp,bus_item)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"WRONG_TYPE")) + uvm_report_error ("WRONG_TYPE", "Provided bus_item is not of type uvm_tlm_gp", UVM_NONE, "t/uvm/src/reg/uvm_reg_adapter.svh", 235, "", 1); + end + return; + end + if (gp.get_command() == UVM_TLM_WRITE_COMMAND) + rw.kind = UVM_WRITE; + else + rw.kind = UVM_READ; + rw.addr = gp.get_address(); + rw.byte_en = 0; + foreach (gp.m_byte_enable[i]) + rw.byte_en[i] = gp.m_byte_enable[i]; + rw.data = 0; + foreach (gp.m_data[i]) + rw.data[i*8+:8] = gp.m_data[i]; + rw.status = (gp.is_response_ok()) ? UVM_IS_OK : UVM_NOT_OK; + endfunction +endclass +class uvm_predict_s; + bit addr[uvm_reg_addr_t]; + uvm_reg_item reg_item; +endclass +class uvm_reg_predictor #(type BUSTYPE=int) extends uvm_component; + typedef uvm_component_registry #(uvm_reg_predictor#(BUSTYPE)) type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + uvm_analysis_imp #(BUSTYPE, uvm_reg_predictor #(BUSTYPE)) bus_in; + uvm_analysis_port #(uvm_reg_item) reg_ap; + uvm_reg_map map; + uvm_reg_adapter adapter; + function new (string name, uvm_component parent); + super.new(name, parent); + bus_in = new("bus_in", this); + reg_ap = new("reg_ap", this); + endfunction + static function string type_name(); + static string m_type_name; + if (m_type_name == "") begin + BUSTYPE t; + t = BUSTYPE::type_id_create("t"); + m_type_name = {"uvm_reg_predictor #(", t.get_type_name(), ")"}; + end + return m_type_name; + endfunction + virtual function string get_type_name(); + return type_name(); + endfunction : get_type_name + virtual function void pre_predict(uvm_reg_item rw); + endfunction + local uvm_predict_s m_pending[uvm_reg]; + virtual function void write(BUSTYPE tr); + uvm_reg rg; + uvm_reg_bus_op rw; + if (adapter == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"REG/WRITE/NULL")) + uvm_report_fatal ("REG/WRITE/NULL", "write: adapter handle is null", UVM_NONE, "t/uvm/src/reg/uvm_reg_predictor.svh", 168, "", 1); + end + rw.byte_en = -1; + adapter.bus2reg(tr,rw); + rg = map.get_reg_by_offset(rw.addr, (rw.kind == UVM_READ)); + if (rg != null) begin + bit found; + uvm_reg_item reg_item; + uvm_reg_map local_map; + uvm_reg_map_info map_info; + uvm_predict_s predict_info; + uvm_reg_indirect_data ireg; + uvm_reg ir; + if (!m_pending.exists(rg)) begin + uvm_reg_item item = new; + predict_info =new; + item.element_kind = UVM_REG; + item.element = rg; + item.path = UVM_PREDICT; + item.map = map; + item.kind = rw.kind; + predict_info.reg_item = item; + m_pending[rg] = predict_info; + end + predict_info = m_pending[rg]; + reg_item = predict_info.reg_item; + if (predict_info.addr.exists(rw.addr)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"REG_PREDICT_COLLISION")) + uvm_report_error ("REG_PREDICT_COLLISION", {"Collision detected for register '", rg.get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_predictor.svh", 202, "", 1); + end + m_pending.delete(rg); + end + local_map = rg.get_local_map(map); + map_info = local_map.get_reg_map_info(rg); + ir=($cast(ireg, rg))?ireg.get_indirect_reg():rg; + foreach (map_info.addr[i]) begin + if (rw.addr == map_info.addr[i]) begin + found = 1; + reg_item.value[0] |= rw.data << (i * map.get_n_bytes()*8); + predict_info.addr[rw.addr] = 1; + if (predict_info.addr.num() == map_info.addr.size()) begin + uvm_predict_e predict_kind = + (reg_item.kind == UVM_WRITE) ? UVM_PREDICT_WRITE : UVM_PREDICT_READ; + if (reg_item.kind == UVM_READ && + local_map.get_check_on_read() && + reg_item.status != UVM_NOT_OK) begin + void'(rg.do_check(ir.get_mirrored_value(), reg_item.value[0], local_map)); + end + pre_predict(reg_item); + ir.XsampleX(reg_item.value[0], rw.byte_en, + reg_item.kind == UVM_READ, local_map); + begin + uvm_reg_block blk = rg.get_parent(); + blk.XsampleX(map_info.offset, + reg_item.kind == UVM_READ, + local_map); + end + rg.do_predict(reg_item, predict_kind, rw.byte_en); + if(reg_item.kind == UVM_WRITE) + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"REG_PREDICT")) + uvm_report_info ("REG_PREDICT", {"Observed WRITE transaction to register ", ir.get_full_name(), ": value='h", $sformatf("%0h",reg_item.value[0]), " : updated value = 'h", $sformatf("%0h",ir.get())}, UVM_HIGH, "t/uvm/src/reg/uvm_reg_predictor.svh", 243, "", 1); + end + else + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"REG_PREDICT")) + uvm_report_info ("REG_PREDICT", {"Observed READ transaction to register ", ir.get_full_name(), ": value='h", $sformatf("%0h",reg_item.value[0])}, UVM_HIGH, "t/uvm/src/reg/uvm_reg_predictor.svh", 247, "", 1); + end + reg_ap.write(reg_item); + m_pending.delete(rg); + end + break; + end + end + if (!found) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"REG_PREDICT_INTERNAL")) + uvm_report_error ("REG_PREDICT_INTERNAL", {"Unexpected failed address lookup for register '", rg.get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_predictor.svh", 256, "", 1); + end + end + else begin + begin + if (uvm_report_enabled(UVM_FULL,UVM_INFO,"REG_PREDICT_NOT_FOR_ME")) + uvm_report_info ("REG_PREDICT_NOT_FOR_ME", {"Observed transaction does not target a register: ", $sformatf("%p",tr)}, UVM_FULL, "t/uvm/src/reg/uvm_reg_predictor.svh", 261, "", 1); + end + end + endfunction + virtual function void check_phase(uvm_phase phase); + string q[$]; + super.check_phase(phase); + foreach (m_pending[l]) begin + uvm_reg rg=l; + q.push_back($sformatf("\n%s",rg.get_full_name())); + end + if (m_pending.num() > 0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"PENDING REG ITEMS")) + uvm_report_error ("PENDING REG ITEMS", $sformatf("There are %0d incomplete register transactions still pending completion:%s",m_pending.num(),uvm_pkg::m_uvm_string_queue_join(q)), UVM_NONE, "t/uvm/src/reg/uvm_reg_predictor.svh", 282, "", 1); + end + end + endfunction +endclass +class uvm_reg_sequence #(type BASE=uvm_sequence #(uvm_reg_item)) extends BASE; + typedef uvm_object_registry #(uvm_reg_sequence #(BASE)) type_id; + static function uvm_reg_sequence #(BASE) type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_reg_sequence #(BASE) tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + uvm_reg_block model; + uvm_reg_adapter adapter; + uvm_sequencer #(uvm_reg_item) reg_seqr; + function new (string name="uvm_reg_sequence_inst"); + super.new(name); + endfunction + virtual task body(); + if (m_sequencer == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"NO_SEQR")) + uvm_report_fatal ("NO_SEQR", {"Sequence executing as translation sequence, ", "but is not associated with a sequencer (m_sequencer == null)"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_sequence.svh", 127, "", 1); + end + end + if (reg_seqr == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"REG_XLATE_NO_SEQR")) + uvm_report_warning ("REG_XLATE_NO_SEQR", {"Executing RegModel translation sequence on sequencer ", m_sequencer.get_full_name(),"' does not have an upstream sequencer defined. ", "Execution of register items available only via direct calls to 'do_reg_item'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_sequence.svh", 133, "", 1); + end + wait(0); + end + begin + if (uvm_report_enabled(UVM_LOW,UVM_INFO,"REG_XLATE_SEQ_START")) + uvm_report_info ("REG_XLATE_SEQ_START", {"Starting RegModel translation sequence on sequencer ", m_sequencer.get_full_name(),"'"}, UVM_LOW, "t/uvm/src/reg/uvm_reg_sequence.svh", 138, "", 1); + end + forever begin + uvm_reg_item reg_item; + reg_seqr.peek(reg_item); + do_reg_item(reg_item); + reg_seqr.get(reg_item); + #0; + end + endtask + typedef enum { LOCAL, UPSTREAM } seq_parent_e; + seq_parent_e parent_select = LOCAL; + uvm_sequence_base upstream_parent; + virtual task do_reg_item(uvm_reg_item rw); + string rws=rw.convert2string(); + if (m_sequencer == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"REG/DO_ITEM/NULL")) + uvm_report_fatal ("REG/DO_ITEM/NULL", "do_reg_item: m_sequencer is null", UVM_NONE, "t/uvm/src/reg/uvm_reg_sequence.svh", 161, "", 1); + end + if (adapter == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"REG/DO_ITEM/NULL")) + uvm_report_fatal ("REG/DO_ITEM/NULL", "do_reg_item: adapter handle is null", UVM_NONE, "t/uvm/src/reg/uvm_reg_sequence.svh", 163, "", 1); + end + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"DO_RW_ACCESS")) + uvm_report_info ("DO_RW_ACCESS", {"Doing transaction: ",rws}, UVM_HIGH, "t/uvm/src/reg/uvm_reg_sequence.svh", 165, "", 1); + end + if (parent_select == LOCAL) begin + upstream_parent = rw.parent; + rw.parent = this; + end + if (rw.kind == UVM_WRITE) + rw.local_map.do_bus_write(rw, m_sequencer, adapter); + else + rw.local_map.do_bus_read(rw, m_sequencer, adapter); + if (parent_select == LOCAL) + rw.parent = upstream_parent; + endtask + virtual task write_reg(input uvm_reg rg, + output uvm_status_e status, + input uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + if (rg == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"NO_REG")) + uvm_report_error ("NO_REG", "Register argument is null", UVM_NONE, "t/uvm/src/reg/uvm_reg_sequence.svh", 211, "", 1); + end + else + rg.write(status,value,path,map,this,prior,extension,fname,lineno); + endtask + virtual task read_reg(input uvm_reg rg, + output uvm_status_e status, + output uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + if (rg == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"NO_REG")) + uvm_report_error ("NO_REG", "Register argument is null", UVM_NONE, "t/uvm/src/reg/uvm_reg_sequence.svh", 229, "", 1); + end + else + rg.read(status,value,path,map,this,prior,extension,fname,lineno); + endtask + virtual task poke_reg(input uvm_reg rg, + output uvm_status_e status, + input uvm_reg_data_t value, + input string kind = "", + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + if (rg == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"NO_REG")) + uvm_report_error ("NO_REG", "Register argument is null", UVM_NONE, "t/uvm/src/reg/uvm_reg_sequence.svh", 246, "", 1); + end + else + rg.poke(status,value,kind,this,extension,fname,lineno); + endtask + virtual task peek_reg(input uvm_reg rg, + output uvm_status_e status, + output uvm_reg_data_t value, + input string kind = "", + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + if (rg == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"NO_REG")) + uvm_report_error ("NO_REG", "Register argument is null", UVM_NONE, "t/uvm/src/reg/uvm_reg_sequence.svh", 263, "", 1); + end + else + rg.peek(status,value,kind,this,extension,fname,lineno); + endtask + virtual task update_reg(input uvm_reg rg, + output uvm_status_e status, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + if (rg == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"NO_REG")) + uvm_report_error ("NO_REG", "Register argument is null", UVM_NONE, "t/uvm/src/reg/uvm_reg_sequence.svh", 281, "", 1); + end + else + rg.update(status,path,map,this,prior,extension,fname,lineno); + endtask + virtual task mirror_reg(input uvm_reg rg, + output uvm_status_e status, + input uvm_check_e check = UVM_NO_CHECK, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + if (rg == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"NO_REG")) + uvm_report_error ("NO_REG", "Register argument is null", UVM_NONE, "t/uvm/src/reg/uvm_reg_sequence.svh", 300, "", 1); + end + else + rg.mirror(status,check,path,map,this,prior,extension,fname,lineno); + endtask + virtual task write_mem(input uvm_mem mem, + output uvm_status_e status, + input uvm_reg_addr_t offset, + input uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + if (mem == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"NO_MEM")) + uvm_report_error ("NO_MEM", "Memory argument is null", UVM_NONE, "t/uvm/src/reg/uvm_reg_sequence.svh", 320, "", 1); + end + else + mem.write(status,offset,value,path,map,this,prior,extension,fname,lineno); + endtask + virtual task read_mem(input uvm_mem mem, + output uvm_status_e status, + input uvm_reg_addr_t offset, + output uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + if (mem == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"NO_MEM")) + uvm_report_error ("NO_MEM", "Memory argument is null", UVM_NONE, "t/uvm/src/reg/uvm_reg_sequence.svh", 339, "", 1); + end + else + mem.read(status,offset,value,path,map,this,prior,extension,fname,lineno); + endtask + virtual task poke_mem(input uvm_mem mem, + output uvm_status_e status, + input uvm_reg_addr_t offset, + input uvm_reg_data_t value, + input string kind = "", + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + if (mem == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"NO_MEM")) + uvm_report_error ("NO_MEM", "Memory argument is null", UVM_NONE, "t/uvm/src/reg/uvm_reg_sequence.svh", 357, "", 1); + end + else + mem.poke(status,offset,value,kind,this,extension,fname,lineno); + endtask + virtual task peek_mem(input uvm_mem mem, + output uvm_status_e status, + input uvm_reg_addr_t offset, + output uvm_reg_data_t value, + input string kind = "", + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + if (mem == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"NO_MEM")) + uvm_report_error ("NO_MEM", "Memory argument is null", UVM_NONE, "t/uvm/src/reg/uvm_reg_sequence.svh", 375, "", 1); + end + else + mem.peek(status,offset,value,kind,this,extension,fname,lineno); + endtask + virtual function void put_response(uvm_sequence_item response_item); + put_base_response(response_item); + endfunction +endclass +virtual class uvm_reg_frontdoor extends uvm_reg_sequence #(uvm_sequence #(uvm_sequence_item)); + typedef uvm_abstract_object_registry#(uvm_reg_frontdoor,"uvm_reg_frontdoor") type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_reg_frontdoor"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_reg_frontdoor"; + endfunction : get_type_name + uvm_reg_item rw_info; + uvm_sequencer_base sequencer; + function new(string name=""); + super.new(name); + endfunction + string fname; + int lineno; +endclass: uvm_reg_frontdoor +typedef class uvm_reg; +typedef class uvm_mem; +typedef class uvm_reg_backdoor; +class uvm_reg_cbs extends uvm_callback; + typedef uvm_object_registry#(uvm_reg_cbs,"uvm_reg_cbs") type_id; + static function uvm_reg_cbs type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_reg_cbs tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_reg_cbs"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_reg_cbs"; + endfunction : get_type_name + function new(string name = "uvm_reg_cbs"); + super.new(name); + endfunction + virtual task pre_write(uvm_reg_item rw); endtask + virtual task post_write(uvm_reg_item rw); endtask + virtual task pre_read(uvm_reg_item rw); endtask + virtual task post_read(uvm_reg_item rw); endtask + virtual function void post_predict(input uvm_reg_field fld, + input uvm_reg_data_t previous, + inout uvm_reg_data_t value, + input uvm_predict_e kind, + input uvm_door_e path, + input uvm_reg_map map); + endfunction + virtual function void encode(ref uvm_reg_data_t data[]); + endfunction + virtual function void decode(ref uvm_reg_data_t data[]); + endfunction +endclass +typedef uvm_callbacks#(uvm_reg, uvm_reg_cbs) uvm_reg_cb ; +typedef uvm_callback_iter#(uvm_reg, uvm_reg_cbs) uvm_reg_cb_iter ; +typedef uvm_callbacks#(uvm_reg_backdoor, uvm_reg_cbs) uvm_reg_bd_cb ; +typedef uvm_callback_iter#(uvm_reg_backdoor, uvm_reg_cbs) uvm_reg_bd_cb_iter ; +typedef uvm_callbacks#(uvm_mem, uvm_reg_cbs) uvm_mem_cb ; +typedef uvm_callback_iter#(uvm_mem, uvm_reg_cbs) uvm_mem_cb_iter ; +typedef uvm_callbacks#(uvm_reg_field, uvm_reg_cbs) uvm_reg_field_cb ; +typedef uvm_callback_iter#(uvm_reg_field, uvm_reg_cbs) uvm_reg_field_cb_iter ; +class uvm_reg_read_only_cbs extends uvm_reg_cbs; + function new(string name = "uvm_reg_read_only_cbs"); + super.new(name); + endfunction + typedef uvm_object_registry#(uvm_reg_read_only_cbs,"uvm_reg_read_only_cbs") type_id; + static function uvm_reg_read_only_cbs type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_reg_read_only_cbs tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_reg_read_only_cbs"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_reg_read_only_cbs"; + endfunction : get_type_name + virtual task pre_write(uvm_reg_item rw); + string name = rw.element.get_full_name(); + if (rw.status != UVM_IS_OK) + return; + if (rw.element_kind == UVM_FIELD) begin + uvm_reg_field fld; + uvm_reg rg; + $cast(fld, rw.element); + rg = fld.get_parent(); + name = rg.get_full_name(); + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/REG/READONLY")) + uvm_report_error ("UVM/REG/READONLY", {name, " is read-only. Cannot call write() method."}, UVM_NONE, "t/uvm/src/reg/uvm_reg_cbs.svh", 232, "", 1); + end + rw.status = UVM_NOT_OK; + endtask + local static uvm_reg_read_only_cbs m_me; + local static function uvm_reg_read_only_cbs get(); + if (m_me == null) m_me = new; + return m_me; + endfunction + static function void add(uvm_reg rg); + uvm_reg_field flds[$]; + uvm_reg_cb::add(rg, get()); + rg.get_fields(flds); + foreach (flds[i]) begin + uvm_reg_field_cb::add(flds[i], get()); + end + endfunction + static function void remove(uvm_reg rg); + uvm_reg_cb_iter cbs = new(rg); + uvm_reg_field flds[$]; + void'(cbs.first()); + while (cbs.get_cb() != get()) begin + if (cbs.get_cb() == null) + return; + void'(cbs.next()); + end + uvm_reg_cb::delete(rg, get()); + rg.get_fields(flds); + foreach (flds[i]) begin + uvm_reg_field_cb::delete(flds[i], get()); + end + endfunction +endclass +class uvm_reg_write_only_cbs extends uvm_reg_cbs; + function new(string name = "uvm_reg_write_only_cbs"); + super.new(name); + endfunction + typedef uvm_object_registry#(uvm_reg_write_only_cbs,"uvm_reg_write_only_cbs") type_id; + static function uvm_reg_write_only_cbs type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_reg_write_only_cbs tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_reg_write_only_cbs"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_reg_write_only_cbs"; + endfunction : get_type_name + virtual task pre_read(uvm_reg_item rw); + string name = rw.element.get_full_name(); + if (rw.status != UVM_IS_OK) + return; + if (rw.element_kind == UVM_FIELD) begin + uvm_reg_field fld; + uvm_reg rg; + $cast(fld, rw.element); + rg = fld.get_parent(); + name = rg.get_full_name(); + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/REG/WRTEONLY")) + uvm_report_error ("UVM/REG/WRTEONLY", {name, " is write-only. Cannot call read() method."}, UVM_NONE, "t/uvm/src/reg/uvm_reg_cbs.svh", 316, "", 1); + end + rw.status = UVM_NOT_OK; + endtask + local static uvm_reg_write_only_cbs m_me; + local static function uvm_reg_write_only_cbs get(); + if (m_me == null) m_me = new; + return m_me; + endfunction + static function void add(uvm_reg rg); + uvm_reg_field flds[$]; + uvm_reg_cb::add(rg, get()); + rg.get_fields(flds); + foreach (flds[i]) begin + uvm_reg_field_cb::add(flds[i], get()); + end + endfunction + static function void remove(uvm_reg rg); + uvm_reg_cb_iter cbs = new(rg); + uvm_reg_field flds[$]; + void'(cbs.first()); + while (cbs.get_cb() != get()) begin + if (cbs.get_cb() == null) + return; + void'(cbs.next()); + end + uvm_reg_cb::delete(rg, get()); + rg.get_fields(flds); + foreach (flds[i]) begin + uvm_reg_field_cb::delete(flds[i], get()); + end + endfunction +endclass +typedef class uvm_reg_cbs; +virtual class uvm_reg_backdoor extends uvm_object; + typedef uvm_abstract_object_registry#(uvm_reg_backdoor,"uvm_reg_backdoor") type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_reg_backdoor"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_reg_backdoor"; + endfunction : get_type_name + function new(string name = ""); + super.new(name); + endfunction: new + protected task do_pre_read(uvm_reg_item rw); + pre_read(rw); + begin + uvm_callback_iter#(uvm_reg_backdoor,uvm_reg_cbs) iter = new(this); + uvm_reg_cbs cb = iter.first(); + while(cb != null) begin + cb.pre_read(rw); + cb = iter.next(); + end + end + endtask + protected task do_post_read(uvm_reg_item rw); + uvm_callback_iter#(uvm_reg_backdoor, uvm_reg_cbs) iter = new(this); + for(uvm_reg_cbs cb = iter.last(); cb != null; cb=iter.prev()) + cb.decode(rw.value); + begin + uvm_callback_iter#(uvm_reg_backdoor,uvm_reg_cbs) iter = new(this); + uvm_reg_cbs cb = iter.first(); + while(cb != null) begin + cb.post_read(rw); + cb = iter.next(); + end + end + post_read(rw); + endtask + protected task do_pre_write(uvm_reg_item rw); + uvm_callback_iter#(uvm_reg_backdoor, uvm_reg_cbs) iter = new(this); + pre_write(rw); + begin + uvm_callback_iter#(uvm_reg_backdoor,uvm_reg_cbs) iter = new(this); + uvm_reg_cbs cb = iter.first(); + while(cb != null) begin + cb.pre_write(rw); + cb = iter.next(); + end + end + for(uvm_reg_cbs cb = iter.first(); cb != null; cb = iter.next()) + cb.encode(rw.value); + endtask + protected task do_post_write(uvm_reg_item rw); + begin + uvm_callback_iter#(uvm_reg_backdoor,uvm_reg_cbs) iter = new(this); + uvm_reg_cbs cb = iter.first(); + while(cb != null) begin + cb.post_write(rw); + cb = iter.next(); + end + end + post_write(rw); + endtask + extern virtual task write(uvm_reg_item rw); + extern virtual task read(uvm_reg_item rw); + extern virtual function void read_func(uvm_reg_item rw); + extern virtual function bit is_auto_updated(uvm_reg_field field); + extern virtual local task wait_for_change(uvm_object element); + extern function void start_update_thread(uvm_object element); + extern function void kill_update_thread(uvm_object element); + extern function bit has_update_threads(); + virtual task pre_read(uvm_reg_item rw); endtask + virtual task post_read(uvm_reg_item rw); endtask + virtual task pre_write(uvm_reg_item rw); endtask + virtual task post_write(uvm_reg_item rw); endtask + string fname; + int lineno; + local process m_update_thread[uvm_object]; + static local bit m_register_cb_uvm_reg_cbs = uvm_callbacks#(uvm_reg_backdoor,uvm_reg_cbs)::m_register_pair("uvm_reg_backdoor","uvm_reg_cbs"); +endclass: uvm_reg_backdoor +function bit uvm_reg_backdoor::is_auto_updated(uvm_reg_field field); + return 0; +endfunction +task uvm_reg_backdoor::wait_for_change(uvm_object element); + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"RegModel")) + uvm_report_fatal ("RegModel", "uvm_reg_backdoor::wait_for_change() method has not been overloaded", UVM_NONE, "t/uvm/src/reg/uvm_reg_backdoor.svh", 171, "", 1); + end +endtask +function void uvm_reg_backdoor::start_update_thread(uvm_object element); + uvm_reg rg; + if (this.m_update_thread.exists(element)) begin + this.kill_update_thread(element); + end + if (!$cast(rg,element)) + return; + fork + begin + uvm_reg_field fields[$]; + this.m_update_thread[element] = process::self(); + rg.get_fields(fields); + forever begin + uvm_status_e status; + uvm_reg_data_t val; + uvm_reg_item r_item = new("bd_r_item"); + r_item.element = rg; + r_item.element_kind = UVM_REG; + this.read(r_item); + val = r_item.value[0]; + if (r_item.status != UVM_IS_OK) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Backdoor read of register '%s' failed.", rg.get_name()), UVM_NONE, "t/uvm/src/reg/uvm_reg_backdoor.svh", 206, "", 1); + end + end + foreach (fields[i]) begin + if (this.is_auto_updated(fields[i])) begin + r_item.value[0] = (val >> fields[i].get_lsb_pos()) & + ((1 << fields[i].get_n_bits())-1); + fields[i].do_predict(r_item); + end + end + this.wait_for_change(element); + end + end + join_none +endfunction +function void uvm_reg_backdoor::kill_update_thread(uvm_object element); + if (this.m_update_thread.exists(element)) begin + this.m_update_thread[element].kill(); + this.m_update_thread.delete(element); + end +endfunction +function bit uvm_reg_backdoor::has_update_threads(); + return this.m_update_thread.num() > 0; +endfunction +task uvm_reg_backdoor::write(uvm_reg_item rw); + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"RegModel")) + uvm_report_fatal ("RegModel", "uvm_reg_backdoor::write() method has not been overloaded", UVM_NONE, "t/uvm/src/reg/uvm_reg_backdoor.svh", 248, "", 1); + end +endtask +task uvm_reg_backdoor::read(uvm_reg_item rw); + do_pre_read(rw); + read_func(rw); + do_post_read(rw); +endtask +function void uvm_reg_backdoor::read_func(uvm_reg_item rw); + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"RegModel")) + uvm_report_fatal ("RegModel", "uvm_reg_backdoor::read_func() method has not been overloaded", UVM_NONE, "t/uvm/src/reg/uvm_reg_backdoor.svh", 264, "", 1); + end + rw.status = UVM_NOT_OK; +endfunction +typedef class uvm_reg_cbs; +class uvm_reg_field extends uvm_object; + rand uvm_reg_data_t value; + local uvm_reg_data_t m_mirrored; + local uvm_reg_data_t m_desired; + local string m_access; + local uvm_reg m_parent; + local int unsigned m_lsb; + local int unsigned m_size; + local bit m_volatile; + local uvm_reg_data_t m_reset[string]; + local bit m_written; + local bit m_read_in_progress; + local bit m_write_in_progress; + local string m_fname; + local int m_lineno; + local int m_cover_on; + local bit m_individually_accessible; + local uvm_check_e m_check; + local static int m_max_size; + local static bit m_policy_names[string]; + constraint uvm_reg_field_valid { + if (64 > m_size) { + value < (64'h1 << m_size); + } + } + typedef uvm_object_registry#(uvm_reg_field,"uvm_reg_field") type_id; + static function uvm_reg_field type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_reg_field tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_reg_field"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_reg_field"; + endfunction : get_type_name + extern function new(string name = "uvm_reg_field"); + extern function void configure(uvm_reg parent, + int unsigned size, + int unsigned lsb_pos, + string access, + bit volatile, + uvm_reg_data_t reset, + bit has_reset, + bit is_rand, + bit individually_accessible); + extern virtual function string get_full_name(); + extern virtual function uvm_reg get_parent(); + extern virtual function uvm_reg get_register(); + extern virtual function int unsigned get_lsb_pos(); + extern virtual function int unsigned get_n_bits(); + extern static function int unsigned get_max_size(); + extern virtual function string set_access(string mode); + extern static function bit define_access(string name); + local static bit m_predefined = m_predefine_policies(); + extern local static function bit m_predefine_policies(); + extern virtual function string get_access(uvm_reg_map map = null); + extern virtual function bit is_known_access(uvm_reg_map map = null); + extern virtual function void set_volatility(bit volatile); + extern virtual function bit is_volatile(); + extern virtual function void set(uvm_reg_data_t value, + string fname = "", + int lineno = 0); + extern virtual function uvm_reg_data_t get(string fname = "", + int lineno = 0); + extern virtual function uvm_reg_data_t get_mirrored_value(string fname = "", + int lineno = 0); + extern virtual function void reset(string kind = "HARD"); + extern virtual function uvm_reg_data_t get_reset(string kind = "HARD"); + extern virtual function bit has_reset(string kind = "HARD", + bit delete = 0); + extern virtual function void set_reset(uvm_reg_data_t value, + string kind = "HARD"); + extern virtual function bit needs_update(); + extern virtual task write (output uvm_status_e status, + input uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + extern virtual task read (output uvm_status_e status, + output uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + extern virtual task poke (output uvm_status_e status, + input uvm_reg_data_t value, + input string kind = "", + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + extern virtual task peek (output uvm_status_e status, + output uvm_reg_data_t value, + input string kind = "", + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + extern virtual task mirror(output uvm_status_e status, + input uvm_check_e check = UVM_NO_CHECK, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + extern function void set_compare(uvm_check_e check=UVM_CHECK); + extern function uvm_check_e get_compare(); + extern function bit is_indv_accessible (uvm_door_e path, + uvm_reg_map local_map); + extern function bit predict (uvm_reg_data_t value, + uvm_reg_byte_en_t be = -1, + uvm_predict_e kind = UVM_PREDICT_DIRECT, + uvm_door_e path = UVM_FRONTDOOR, + uvm_reg_map map = null, + string fname = "", + int lineno = 0); + extern virtual function uvm_reg_data_t XpredictX (uvm_reg_data_t cur_val, + uvm_reg_data_t wr_val, + uvm_reg_map map); + extern virtual function uvm_reg_data_t XupdateX(); + extern function bit Xcheck_accessX (input uvm_reg_item rw, + output uvm_reg_map_info map_info); + extern virtual task do_write(uvm_reg_item rw); + extern virtual task do_read(uvm_reg_item rw); + extern virtual function void do_predict + (uvm_reg_item rw, + uvm_predict_e kind=UVM_PREDICT_DIRECT, + uvm_reg_byte_en_t be = -1); + extern function void pre_randomize(); + extern function void post_randomize(); + static local bit m_register_cb_uvm_reg_cbs = uvm_callbacks#(uvm_reg_field,uvm_reg_cbs)::m_register_pair("uvm_reg_field","uvm_reg_cbs"); + virtual task pre_write (uvm_reg_item rw); endtask + virtual task post_write (uvm_reg_item rw); endtask + virtual task pre_read (uvm_reg_item rw); endtask + virtual task post_read (uvm_reg_item rw); endtask + extern virtual function void do_print (uvm_printer printer); + extern virtual function string convert2string; + extern virtual function uvm_object clone(); + extern virtual function void do_copy (uvm_object rhs); + extern virtual function bit do_compare (uvm_object rhs, + uvm_comparer comparer); + extern virtual function void do_pack (uvm_packer packer); + extern virtual function void do_unpack (uvm_packer packer); +endclass: uvm_reg_field +function uvm_reg_field::new(string name = "uvm_reg_field"); + super.new(name); +endfunction: new +function void uvm_reg_field::configure(uvm_reg parent, + int unsigned size, + int unsigned lsb_pos, + string access, + bit volatile, + uvm_reg_data_t reset, + bit has_reset, + bit is_rand, + bit individually_accessible); + m_parent = parent; + if (size == 0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Field \"%s\" cannot have 0 bits", get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_reg_field.svh", 416, "", 1); + end + size = 1; + end + m_size = size; + m_volatile = volatile; + m_access = access.toupper(); + m_lsb = lsb_pos; + m_cover_on = UVM_NO_COVERAGE; + m_written = 0; + m_check = volatile ? UVM_NO_CHECK : UVM_CHECK; + m_individually_accessible = individually_accessible; + if (has_reset) + set_reset(reset); + m_parent.add_field(this); + if (!m_policy_names.exists(m_access)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Access policy '",access, "' for field '",get_full_name(),"' is not defined. Setting to RW"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_field.svh", 436, "", 1); + end + m_access = "RW"; + end + if (size > m_max_size) + m_max_size = size; + case (access) + "RO", "RC", "RS", "WC", "WS", + "W1C", "W1S", "W1T", "W0C", "W0S", "W0T", + "W1SRC", "W1CRS", "W0SRC", "W0CRS", "WSRC", "WCRS", + "WOC", "WOS": is_rand = 0; + endcase + if (!is_rand) + value.rand_mode(0); +endfunction: configure +function uvm_reg uvm_reg_field::get_parent(); + return m_parent; +endfunction: get_parent +function string uvm_reg_field::get_full_name(); + return {m_parent.get_full_name(), ".", get_name()}; +endfunction: get_full_name +function uvm_reg uvm_reg_field::get_register(); + return m_parent; +endfunction: get_register +function int unsigned uvm_reg_field::get_lsb_pos(); + return m_lsb; +endfunction: get_lsb_pos +function int unsigned uvm_reg_field::get_n_bits(); + return m_size; +endfunction: get_n_bits +function int unsigned uvm_reg_field::get_max_size(); + return m_max_size; +endfunction: get_max_size +function bit uvm_reg_field::is_known_access(uvm_reg_map map = null); + string acc = get_access(map); + case (acc) + "RO", "RW", "RC", "RS", "WC", "WS", + "W1C", "W1S", "W1T", "W0C", "W0S", "W0T", + "WRC", "WRS", "W1SRC", "W1CRS", "W0SRC", "W0CRS", "WSRC", "WCRS", + "WO", "WOC", "WOS", "W1", "WO1" : return 1; + endcase + return 0; +endfunction +function string uvm_reg_field::get_access(uvm_reg_map map = null); + string field_access = m_access; + if (map == uvm_reg_map::backdoor()) + return field_access; + case (m_parent.get_rights(map)) + "RW": + return field_access; + "RO": + case (field_access) + "RW", "RO", "WC", "WS", + "W1C", "W1S", "W1T", "W0C", "W0S", "W0T", + "W1" + : field_access = "RO"; + "RC", "WRC", "W1SRC", "W0SRC", "WSRC" + : field_access = "RC"; + "RS", "WRS", "W1CRS", "W0CRS", "WCRS" + : field_access = "RS"; + "WO", "WOC", "WOS", "WO1": begin + field_access = "NOACCESS"; + end + endcase + "WO": + case (field_access) + "RW","WRC","WRS" : field_access = "WO"; + "W1SRC" : field_access = "W1S"; + "W0SRC": field_access = "W0S"; + "W1CRS": field_access = "W1C"; + "W0CRS": field_access = "W0C"; + "WCRS": field_access = "WC"; + "W1" : field_access = "W1"; + "WO1" : field_access = "WO1"; + "WSRC" : field_access = "WS"; + "RO","RC","RS": field_access = "NOACCESS"; + endcase + default: + begin + field_access = "NOACCESS"; + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Register '",m_parent.get_full_name(), "' containing field '",get_name(),"' is mapped in map '", map.get_full_name(),"' with unknown access right '", m_parent.get_rights(map), "'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_field.svh", 570, "", 1); + end + end + endcase + return field_access; +endfunction: get_access +function string uvm_reg_field::set_access(string mode); + set_access = m_access; + m_access = mode.toupper(); + if (!m_policy_names.exists(m_access)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Access policy '",m_access, "' is not a defined field access policy"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_field.svh", 584, "", 1); + end + m_access = set_access; + end +endfunction: set_access +function bit uvm_reg_field::define_access(string name); + if (!m_predefined) m_predefined = m_predefine_policies(); + name = name.toupper(); + if (m_policy_names.exists(name)) return 0; + m_policy_names[name] = 1; + return 1; +endfunction +function bit uvm_reg_field::m_predefine_policies(); + if (m_predefined) return 1; + m_predefined = 1; + void'(define_access("RO")); + void'(define_access("RW")); + void'(define_access("RC")); + void'(define_access("RS")); + void'(define_access("WRC")); + void'(define_access("WRS")); + void'(define_access("WC")); + void'(define_access("WS")); + void'(define_access("WSRC")); + void'(define_access("WCRS")); + void'(define_access("W1C")); + void'(define_access("W1S")); + void'(define_access("W1T")); + void'(define_access("W0C")); + void'(define_access("W0S")); + void'(define_access("W0T")); + void'(define_access("W1SRC")); + void'(define_access("W1CRS")); + void'(define_access("W0SRC")); + void'(define_access("W0CRS")); + void'(define_access("WO")); + void'(define_access("WOC")); + void'(define_access("WOS")); + void'(define_access("W1")); + void'(define_access("WO1")); + return 1; +endfunction +function void uvm_reg_field::set_volatility(bit volatile); + m_volatile = volatile; +endfunction +function bit uvm_reg_field::is_volatile(); + return m_volatile; +endfunction +function uvm_reg_data_t uvm_reg_field::XpredictX (uvm_reg_data_t cur_val, + uvm_reg_data_t wr_val, + uvm_reg_map map); + uvm_reg_data_t mask = ('b1 << m_size)-1; + case (get_access(map)) + "RO": return cur_val; + "RW": return wr_val; + "RC": return cur_val; + "RS": return cur_val; + "WC": return '0; + "WS": return mask; + "WRC": return wr_val; + "WRS": return wr_val; + "WSRC": return mask; + "WCRS": return '0; + "W1C": return cur_val & (~wr_val); + "W1S": return cur_val | wr_val; + "W1T": return cur_val ^ wr_val; + "W0C": return cur_val & wr_val; + "W0S": return cur_val | (~wr_val & mask); + "W0T": return cur_val ^ (~wr_val & mask); + "W1SRC": return cur_val | wr_val; + "W1CRS": return cur_val & (~wr_val); + "W0SRC": return cur_val | (~wr_val & mask); + "W0CRS": return cur_val & wr_val; + "WO": return wr_val; + "WOC": return '0; + "WOS": return mask; + "W1": return (m_written) ? cur_val : wr_val; + "WO1": return (m_written) ? cur_val : wr_val; + "NOACCESS": return cur_val; + default: return wr_val; + endcase + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"RegModel")) + uvm_report_fatal ("RegModel", "uvm_reg_field::XpredictX(): Internal error", UVM_NONE, "t/uvm/src/reg/uvm_reg_field.svh", 691, "", 1); + end + return 0; +endfunction: XpredictX +function bit uvm_reg_field::predict (uvm_reg_data_t value, + uvm_reg_byte_en_t be = -1, + uvm_predict_e kind = UVM_PREDICT_DIRECT, + uvm_door_e path = UVM_FRONTDOOR, + uvm_reg_map map = null, + string fname = "", + int lineno = 0); + uvm_reg_item rw = new; + rw.value[0] = value; + rw.path = path; + rw.map = map; + rw.fname = fname; + rw.lineno = lineno; + do_predict(rw, kind, be); + predict = (rw.status == UVM_NOT_OK) ? 0 : 1; +endfunction: predict +function void uvm_reg_field::do_predict(uvm_reg_item rw, + uvm_predict_e kind = UVM_PREDICT_DIRECT, + uvm_reg_byte_en_t be = -1); + uvm_reg_data_t field_val = rw.value[0] & ((1 << m_size)-1); + if (rw.status != UVM_NOT_OK) + rw.status = UVM_IS_OK; + if (!be[0]) + return; + m_fname = rw.fname; + m_lineno = rw.lineno; + case (kind) + UVM_PREDICT_WRITE: + begin + uvm_reg_field_cb_iter cbs = new(this); + if (rw.path == UVM_FRONTDOOR || rw.path == UVM_PREDICT) + field_val = XpredictX(m_mirrored, field_val, rw.map); + m_written = 1; + for (uvm_reg_cbs cb = cbs.first(); cb != null; cb = cbs.next()) + cb.post_predict(this, m_mirrored, field_val, + UVM_PREDICT_WRITE, rw.path, rw.map); + field_val &= ('b1 << m_size)-1; + end + UVM_PREDICT_READ: + begin + uvm_reg_field_cb_iter cbs = new(this); + if (rw.path == UVM_FRONTDOOR || rw.path == UVM_PREDICT) begin + string acc = get_access(rw.map); + if (acc == "RC" || + acc == "WRC" || + acc == "WSRC" || + acc == "W1SRC" || + acc == "W0SRC") + field_val = 0; + else if (acc == "RS" || + acc == "WRS" || + acc == "WCRS" || + acc == "W1CRS" || + acc == "W0CRS") + field_val = ('b1 << m_size)-1; + else if (acc == "WO" || + acc == "WOC" || + acc == "WOS" || + acc == "WO1" || + acc == "NOACCESS") + return; + end + for (uvm_reg_cbs cb = cbs.first(); cb != null; cb = cbs.next()) + cb.post_predict(this, m_mirrored, field_val, + UVM_PREDICT_READ, rw.path, rw.map); + field_val &= ('b1 << m_size)-1; + end + UVM_PREDICT_DIRECT: + begin + if (m_parent.is_busy()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Trying to predict value of field '", get_name(),"' while register '",m_parent.get_full_name(), "' is being accessed"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_field.svh", 797, "", 1); + end + rw.status = UVM_NOT_OK; + end + end + endcase + m_mirrored = field_val; + m_desired = field_val; + this.value = field_val; +endfunction: do_predict +function uvm_reg_data_t uvm_reg_field::XupdateX(); + XupdateX = 0; + case (m_access) + "RO": XupdateX = m_desired; + "RW": XupdateX = m_desired; + "RC": XupdateX = m_desired; + "RS": XupdateX = m_desired; + "WRC": XupdateX = m_desired; + "WRS": XupdateX = m_desired; + "WC": XupdateX = m_desired; + "WS": XupdateX = m_desired; + "WSRC": XupdateX = m_desired; + "WCRS": XupdateX = m_desired; + "W1C": XupdateX = ~m_desired; + "W1S": XupdateX = m_desired; + "W1T": XupdateX = m_desired ^ m_mirrored; + "W0C": XupdateX = m_desired; + "W0S": XupdateX = ~m_desired; + "W0T": XupdateX = ~(m_desired ^ m_mirrored); + "W1SRC": XupdateX = m_desired; + "W1CRS": XupdateX = ~m_desired; + "W0SRC": XupdateX = ~m_desired; + "W0CRS": XupdateX = m_desired; + "WO": XupdateX = m_desired; + "WOC": XupdateX = m_desired; + "WOS": XupdateX = m_desired; + "W1": XupdateX = m_desired; + "WO1": XupdateX = m_desired; + default: XupdateX = m_desired; + endcase + XupdateX &= (1 << m_size) - 1; +endfunction: XupdateX +function void uvm_reg_field::set(uvm_reg_data_t value, + string fname = "", + int lineno = 0); + uvm_reg_data_t mask = ('b1 << m_size)-1; + m_fname = fname; + m_lineno = lineno; + if (value >> m_size) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", $sformatf("Specified value (0x%h) greater than field \"%s\" size (%0d bits)", value, get_name(), m_size), UVM_NONE, "t/uvm/src/reg/uvm_reg_field.svh", 863, "", 1); + end + value &= mask; + end + if (m_parent.is_busy()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/FLD/SET/BSY")) + uvm_report_warning ("UVM/FLD/SET/BSY", $sformatf("Setting the value of field \"%s\" while containing register \"%s\" is being accessed may result in loss of desired field value. A race condition between threads concurrently accessing the register model is the likely cause of the problem.", get_name(), m_parent.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_reg_field.svh", 870, "", 1); + end + end + case (m_access) + "RO": m_desired = m_desired; + "RW": m_desired = value; + "RC": m_desired = m_desired; + "RS": m_desired = m_desired; + "WC": m_desired = '0; + "WS": m_desired = mask; + "WRC": m_desired = value; + "WRS": m_desired = value; + "WSRC": m_desired = mask; + "WCRS": m_desired = '0; + "W1C": m_desired = m_desired & (~value); + "W1S": m_desired = m_desired | value; + "W1T": m_desired = m_desired ^ value; + "W0C": m_desired = m_desired & value; + "W0S": m_desired = m_desired | (~value & mask); + "W0T": m_desired = m_desired ^ (~value & mask); + "W1SRC": m_desired = m_desired | value; + "W1CRS": m_desired = m_desired & (~value); + "W0SRC": m_desired = m_desired | (~value & mask); + "W0CRS": m_desired = m_desired & value; + "WO": m_desired = value; + "WOC": m_desired = '0; + "WOS": m_desired = mask; + "W1": m_desired = (m_written) ? m_desired : value; + "WO1": m_desired = (m_written) ? m_desired : value; + default: m_desired = value; + endcase + this.value = m_desired; +endfunction: set +function uvm_reg_data_t uvm_reg_field::get(string fname = "", + int lineno = 0); + m_fname = fname; + m_lineno = lineno; + get = m_desired; +endfunction: get +function uvm_reg_data_t uvm_reg_field::get_mirrored_value(string fname = "", + int lineno = 0); + m_fname = fname; + m_lineno = lineno; + get_mirrored_value = m_mirrored; +endfunction: get_mirrored_value +function void uvm_reg_field::reset(string kind = "HARD"); + if (!m_reset.exists(kind)) + return; + m_mirrored = m_reset[kind]; + m_desired = m_mirrored; + value = m_mirrored; + if (kind == "HARD") + m_written = 0; +endfunction: reset +function bit uvm_reg_field::has_reset(string kind = "HARD", + bit delete = 0); + if (!m_reset.exists(kind)) return 0; + if (delete) m_reset.delete(kind); + return 1; +endfunction: has_reset +function uvm_reg_data_t + uvm_reg_field::get_reset(string kind = "HARD"); + if (!m_reset.exists(kind)) + return m_desired; + return m_reset[kind]; +endfunction: get_reset +function void uvm_reg_field::set_reset(uvm_reg_data_t value, + string kind = "HARD"); + m_reset[kind] = value & ((1<> m_size) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"uvm_reg_field::write(): Value greater than field '", get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_field.svh", 1096, "", 1); + end + rw.value[0] &= ((1<> m_lsb) & ((1<0) begin + prev_lsb = fields[fld_idx-1].get_lsb_pos(); + prev_sz = fields[fld_idx-1].get_n_bits(); + end + if (fld_idx < fields.size()-1) begin + next_lsb = fields[fld_idx+1].get_lsb_pos(); + next_sz = fields[fld_idx+1].get_n_bits(); + end + if (fld_idx == 0 && + ((next_lsb % bus_sz) == 0 || + (next_lsb - this_sz) > (next_lsb % bus_sz))) + return 1; + else if (fld_idx == (fields.size()-1) && + ((this_lsb % bus_sz) == 0 || + (this_lsb - (prev_lsb + prev_sz)) >= (this_lsb % bus_sz))) + return 1; + else begin + if ((this_lsb % bus_sz) == 0) begin + if ((next_lsb % bus_sz) == 0 || + (next_lsb - (this_lsb + this_sz)) >= (next_lsb % bus_sz)) + return 1; + end + else begin + if ( (next_lsb - (this_lsb + this_sz)) >= (next_lsb % bus_sz) && + ((this_lsb - (prev_lsb + prev_sz)) >= (this_lsb % bus_sz)) ) + return 1; + end + end + end + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Target bus does not support byte enabling, and the field '", get_full_name(),"' is not the only field within the entire bus width. ", "Individual field access will not be available. ", "Accessing complete register instead."}, UVM_NONE, "t/uvm/src/reg/uvm_reg_field.svh", 1430, "", 1); + end + return 0; +endfunction +task uvm_reg_field::poke(output uvm_status_e status, + input uvm_reg_data_t value, + input string kind = "", + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_data_t tmp; + m_fname = fname; + m_lineno = lineno; + if (value >> m_size) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"uvm_reg_field::poke(): Value exceeds size of field '", get_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_field.svh", 1454, "", 1); + end + value &= value & ((1<> m_lsb) & ((1< 64) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Virtual field \"%s\" cannot have more than %0d bits", this.get_full_name(), 64), UVM_NONE, "t/uvm/src/reg/uvm_vreg_field.svh", 327, "", 1); + end + size = 64; + end + this.size = size; + this.lsb = lsb_pos; + this.parent.add_field(this); +endfunction: configure +function string uvm_vreg_field::get_full_name(); + get_full_name = {this.parent.get_full_name(), ".", this.get_name()}; +endfunction: get_full_name +function uvm_vreg uvm_vreg_field::get_register(); + get_register = this.parent; +endfunction: get_register +function uvm_vreg uvm_vreg_field::get_parent(); + get_parent = this.parent; +endfunction: get_parent +function int unsigned uvm_vreg_field::get_lsb_pos_in_register(); + get_lsb_pos_in_register = this.lsb; +endfunction: get_lsb_pos_in_register +function int unsigned uvm_vreg_field::get_n_bits(); + get_n_bits = this.size; +endfunction: get_n_bits +function string uvm_vreg_field::get_access(uvm_reg_map map = null); + if (this.parent.get_memory() == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot call uvm_vreg_field::get_rights() on unimplemented virtual field \"%s\"", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg_field.svh", 368, "", 1); + end + return "RW"; + end + return this.parent.get_access(map); +endfunction: get_access +task uvm_vreg_field::write(input longint unsigned idx, + output uvm_status_e status, + input uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_data_t tmp; + uvm_reg_data_t segval; + uvm_reg_addr_t segoff; + uvm_status_e st; + int flsb, fmsb, rmwbits; + int segsiz, segn; + uvm_mem mem; + uvm_door_e rm_path; + uvm_vreg_field_cb_iter cbs = new(this); + this.fname = fname; + this.lineno = lineno; + write_in_progress = 1'b1; + mem = this.parent.get_memory(); + if (mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot call uvm_vreg_field::write() on unimplemented virtual register \"%s\"", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg_field.svh", 404, "", 1); + end + status = UVM_NOT_OK; + return; + end + if (path == UVM_DEFAULT_DOOR) begin + uvm_reg_block blk = this.parent.get_block(); + path = blk.get_default_door(); + end + status = UVM_IS_OK; + this.parent.XatomicX(1); + if (value >> this.size) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", $sformatf("Writing value 'h%h that is greater than field \"%s\" size (%0d bits)", value, this.get_full_name(), this.get_n_bits()), UVM_NONE, "t/uvm/src/reg/uvm_vreg_field.svh", 419, "", 1); + end + value &= value & ((1< 0) begin + uvm_reg_addr_t segn; + mem.read(st, segoff, tmp, rm_path, map, parent, , extension, fname, lineno); + if (st != UVM_IS_OK && st != UVM_HAS_X) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Unable to read LSB bits in %s[%0d] to for RMW cycle on virtual field %s.", mem.get_full_name(), segoff, this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg_field.svh", 453, "", 1); + end + status = UVM_NOT_OK; + this.parent.XatomicX(0); + return; + end + value = (value << rmwbits) | (tmp & ((1< 0) begin + if (segn > 0) begin + mem.read(st, segoff + segn - 1, tmp, rm_path, map, parent,, extension, fname, lineno); + if (st != UVM_IS_OK && st != UVM_HAS_X) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Unable to read MSB bits in %s[%0d] to for RMW cycle on virtual field %s.", mem.get_full_name(), segoff+segn-1, this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg_field.svh", 472, "", 1); + end + status = UVM_NOT_OK; + this.parent.XatomicX(0); + return; + end + end + value |= (tmp & ~((1<> segsiz; + end + this.post_write(idx, value, path, map, status); + for (uvm_vreg_field_cbs cb = cbs.first(); cb != null; + cb = cbs.next()) begin + cb.fname = this.fname; + cb.lineno = this.lineno; + cb.post_write(this, idx, value, path, map, status); + end + this.parent.XatomicX(0); + begin + if (uvm_report_enabled(UVM_MEDIUM,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", $sformatf("Wrote virtual field \"%s\"[%0d] via %s with: 'h%h", this.get_full_name(), idx, (path == UVM_FRONTDOOR) ? "frontdoor" : "backdoor", value), UVM_MEDIUM, "t/uvm/src/reg/uvm_vreg_field.svh", 505, "", 1); + end + write_in_progress = 1'b0; + this.fname = ""; + this.lineno = 0; +endtask: write +task uvm_vreg_field::read(input longint unsigned idx, + output uvm_status_e status, + output uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_data_t tmp; + uvm_reg_data_t segval; + uvm_reg_addr_t segoff; + uvm_status_e st; + int flsb, lsb; + int segsiz, segn; + uvm_mem mem; + uvm_vreg_field_cb_iter cbs = new(this); + this.fname = fname; + this.lineno = lineno; + read_in_progress = 1'b1; + mem = this.parent.get_memory(); + if (mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot call uvm_vreg_field::read() on unimplemented virtual register \"%s\"", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg_field.svh", 540, "", 1); + end + status = UVM_NOT_OK; + return; + end + if (path == UVM_DEFAULT_DOOR) begin + uvm_reg_block blk = this.parent.get_block(); + path = blk.get_default_door(); + end + status = UVM_IS_OK; + this.parent.XatomicX(1); + value = 0; + this.pre_read(idx, path, map); + for (uvm_vreg_field_cbs cb = cbs.first(); cb != null; + cb = cbs.next()) begin + cb.fname = this.fname; + cb.lineno = this.lineno; + cb.pre_read(this, idx, path, map); + end + segsiz = mem.get_n_bytes() * 8; + flsb = this.get_lsb_pos_in_register(); + segoff = this.parent.get_offset_in_memory(idx) + (flsb / segsiz); + lsb = flsb % segsiz; + segn = (lsb + this.get_n_bits() - 1) / segsiz + 1; + segoff += segn - 1; + repeat (segn) begin + value = value << segsiz; + mem.read(st, segoff, tmp, path, map, parent, , extension, fname, lineno); + if (st != UVM_IS_OK && st != UVM_HAS_X) status = UVM_NOT_OK; + segoff--; + value |= tmp; + end + value = value >> lsb; + value &= (1<> this.size) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", $sformatf("Writing value 'h%h that is greater than field \"%s\" size (%0d bits)", value, this.get_full_name(), this.get_n_bits()), UVM_NONE, "t/uvm/src/reg/uvm_vreg_field.svh", 644, "", 1); + end + value &= value & ((1< 0) begin + uvm_reg_addr_t segn; + mem.peek(st, segoff, tmp, "", parent, extension, fname, lineno); + if (st != UVM_IS_OK && st != UVM_HAS_X) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Unable to read LSB bits in %s[%0d] to for RMW cycle on virtual field %s.", mem.get_full_name(), segoff, this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg_field.svh", 666, "", 1); + end + status = UVM_NOT_OK; + this.parent.XatomicX(0); + return; + end + value = (value << rmwbits) | (tmp & ((1< 0) begin + if (segn > 0) begin + mem.peek(st, segoff + segn - 1, tmp, "", parent, extension, fname, lineno); + if (st != UVM_IS_OK && st != UVM_HAS_X) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Unable to read MSB bits in %s[%0d] to for RMW cycle on virtual field %s.", mem.get_full_name(), segoff+segn-1, this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg_field.svh", 685, "", 1); + end + status = UVM_NOT_OK; + this.parent.XatomicX(0); + return; + end + end + value |= (tmp & ~((1<> segsiz; + end + this.parent.XatomicX(0); + begin + if (uvm_report_enabled(UVM_MEDIUM,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", $sformatf("Wrote virtual field \"%s\"[%0d] with: 'h%h", this.get_full_name(), idx, value), UVM_MEDIUM, "t/uvm/src/reg/uvm_vreg_field.svh", 707, "", 1); + end + this.fname = ""; + this.lineno = 0; +endtask: poke +task uvm_vreg_field::peek(input longint unsigned idx, + output uvm_status_e status, + output uvm_reg_data_t value, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_data_t tmp; + uvm_reg_data_t segval; + uvm_reg_addr_t segoff; + uvm_status_e st; + int flsb, lsb; + int segsiz, segn; + uvm_mem mem; + this.fname = fname; + this.lineno = lineno; + mem = this.parent.get_memory(); + if (mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot call uvm_vreg_field::peek() on unimplemented virtual register \"%s\"", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg_field.svh", 735, "", 1); + end + status = UVM_NOT_OK; + return; + end + status = UVM_IS_OK; + this.parent.XatomicX(1); + value = 0; + segsiz = mem.get_n_bytes() * 8; + flsb = this.get_lsb_pos_in_register(); + segoff = this.parent.get_offset_in_memory(idx) + (flsb / segsiz); + lsb = flsb % segsiz; + segn = (lsb + this.get_n_bits() - 1) / segsiz + 1; + segoff += segn - 1; + repeat (segn) begin + value = value << segsiz; + mem.peek(st, segoff, tmp, "", parent, extension, fname, lineno); + if (st != UVM_IS_OK && st != UVM_HAS_X) status = UVM_NOT_OK; + segoff--; + value |= tmp; + end + value = value >> lsb; + value &= (1< m_max_size) + m_max_size = n_bits; +endfunction: new +function void uvm_reg::configure (uvm_reg_block blk_parent, + uvm_reg_file regfile_parent=null, + string hdl_path = ""); + if (blk_parent == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/REG/CFG/NOBLK")) + uvm_report_error ("UVM/REG/CFG/NOBLK", {"uvm_reg::configure() called without a parent block for instance \"", get_name(), "\" of register type \"", get_type_name(), "\"."}, UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 623, "", 1); + end + return; + end + m_parent = blk_parent; + m_parent.add_reg(this); + m_regfile_parent = regfile_parent; + if (hdl_path != "") + add_hdl_path_slice(hdl_path, -1, -1); +endfunction: configure +function void uvm_reg::add_field(uvm_reg_field field); + int offset; + int idx; + if (m_locked) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", "Cannot add field to locked register model", UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 642, "", 1); + end + return; + end + if (field == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"RegModel")) + uvm_report_fatal ("RegModel", "Attempting to register NULL field", UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 646, "", 1); + end + offset = field.get_lsb_pos(); + idx = -1; + foreach (m_fields[i]) begin + if (offset < m_fields[i].get_lsb_pos()) begin + int j = i; + m_fields.insert(j, field); + idx = i; + break; + end + end + if (idx < 0) begin + m_fields.push_back(field); + idx = m_fields.size()-1; + end + m_n_used_bits += field.get_n_bits(); + if (m_n_used_bits > m_n_bits) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Fields use more bits (%0d) than available in register \"%s\" (%0d)", m_n_used_bits, get_name(), m_n_bits), UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 671, "", 1); + end + end + if (idx > 0) begin + if (m_fields[idx-1].get_lsb_pos() + + m_fields[idx-1].get_n_bits() > offset) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Field %s overlaps field %s in register \"%s\"", m_fields[idx-1].get_name(), field.get_name(), get_name()), UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 680, "", 1); + end + end + end + if (idx < m_fields.size()-1) begin + if (offset + field.get_n_bits() > + m_fields[idx+1].get_lsb_pos()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Field %s overlaps field %s in register \"%s\"", field.get_name(), m_fields[idx+1].get_name(), get_name()), UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 689, "", 1); + end + end + end +endfunction: add_field +function void uvm_reg::Xlock_modelX(); + if (m_locked) + return; + m_locked = 1; +endfunction +function void uvm_reg::set_frontdoor(uvm_reg_frontdoor ftdr, + uvm_reg_map map = null, + string fname = "", + int lineno = 0); + uvm_reg_map_info map_info; + ftdr.fname = m_fname; + ftdr.lineno = m_lineno; + map = get_local_map(map); + if (map == null) + return; + map_info = map.get_reg_map_info(this); + if (map_info == null) + map.add_reg(this, -1, "RW", 1, ftdr); + else begin + map_info.frontdoor = ftdr; + end +endfunction: set_frontdoor +function uvm_reg_frontdoor uvm_reg::get_frontdoor(uvm_reg_map map = null); + uvm_reg_map_info map_info; + map = get_local_map(map); + if (map == null) + return null; + map_info = map.get_reg_map_info(this); + return map_info.frontdoor; +endfunction: get_frontdoor +function void uvm_reg::set_backdoor(uvm_reg_backdoor bkdr, + string fname = "", + int lineno = 0); + bkdr.fname = fname; + bkdr.lineno = lineno; + if (m_backdoor != null && + m_backdoor.has_update_threads()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", "Previous register backdoor still has update threads running. Backdoors with active mirroring should only be set before simulation starts.", UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 750, "", 1); + end + end + m_backdoor = bkdr; +endfunction: set_backdoor +function uvm_reg_backdoor uvm_reg::get_backdoor(bit inherited = 1); + if (m_backdoor == null && inherited) begin + uvm_reg_block blk = get_parent(); + uvm_reg_backdoor bkdr; + while (blk != null) begin + bkdr = blk.get_backdoor(); + if (bkdr != null) begin + m_backdoor = bkdr; + break; + end + blk = blk.get_parent(); + end + end + return m_backdoor; +endfunction: get_backdoor +function void uvm_reg::clear_hdl_path(string kind = "RTL"); + if (kind == "ALL") begin + m_hdl_paths_pool = new("hdl_paths"); + return; + end + if (kind == "") begin + if (m_regfile_parent != null) + kind = m_regfile_parent.get_default_hdl_path(); + else + kind = m_parent.get_default_hdl_path(); + end + if (!m_hdl_paths_pool.exists(kind)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Unknown HDL Abstraction '",kind,"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 793, "", 1); + end + return; + end + m_hdl_paths_pool.delete(kind); +endfunction +function void uvm_reg::add_hdl_path(uvm_hdl_path_slice slices[], + string kind = "RTL"); + uvm_queue #(uvm_hdl_path_concat) paths = m_hdl_paths_pool.get(kind); + uvm_hdl_path_concat concat = new(); + concat.set(slices); + paths.push_back(concat); +endfunction +function void uvm_reg::add_hdl_path_slice(string name, + int offset, + int size, + bit first = 0, + string kind = "RTL"); + uvm_queue #(uvm_hdl_path_concat) paths = m_hdl_paths_pool.get(kind); + uvm_hdl_path_concat concat; + if (first || paths.size() == 0) begin + concat = new(); + paths.push_back(concat); + end + else + concat = paths.get(paths.size()-1); + concat.add_path(name, offset, size); +endfunction +function bit uvm_reg::has_hdl_path(string kind = ""); + if (kind == "") begin + if (m_regfile_parent != null) + kind = m_regfile_parent.get_default_hdl_path(); + else + kind = m_parent.get_default_hdl_path(); + end + return m_hdl_paths_pool.exists(kind); +endfunction +function void uvm_reg::get_hdl_path_kinds (ref string kinds[$]); + string kind; + kinds.delete(); + if (!m_hdl_paths_pool.first(kind)) + return; + do + kinds.push_back(kind); + while (m_hdl_paths_pool.next(kind)); +endfunction +function void uvm_reg::get_hdl_path(ref uvm_hdl_path_concat paths[$], + input string kind = ""); + uvm_queue #(uvm_hdl_path_concat) hdl_paths; + if (kind == "") begin + if (m_regfile_parent != null) + kind = m_regfile_parent.get_default_hdl_path(); + else + kind = m_parent.get_default_hdl_path(); + end + if (!has_hdl_path(kind)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Register does not have hdl path defined for abstraction '",kind,"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 877, "", 1); + end + return; + end + hdl_paths = m_hdl_paths_pool.get(kind); + for (int i=0; i 1 && map == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"set_offset requires a non-null map when register '", get_full_name(),"' belongs to more than one map."}, UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 949, "", 1); + end + return; + end + map = get_local_map(map); + if (map == null) + return; + map.m_set_reg_offset(this, offset, unmapped); +endfunction +function void uvm_reg::set_parent(uvm_reg_block blk_parent, + uvm_reg_file regfile_parent); + if (m_parent != null) begin + end + m_parent = blk_parent; + m_regfile_parent = regfile_parent; +endfunction +function uvm_reg_block uvm_reg::get_parent(); + return get_block(); +endfunction +function uvm_reg_file uvm_reg::get_regfile(); + return m_regfile_parent; +endfunction +function string uvm_reg::get_full_name(); + if (m_regfile_parent != null) + return {m_regfile_parent.get_full_name(), ".", get_name()}; + if (m_parent != null) + return {m_parent.get_full_name(), ".", get_name()}; + return get_name(); +endfunction: get_full_name +function void uvm_reg::add_map(uvm_reg_map map); + m_maps[map] = 1; +endfunction +function void uvm_reg::get_maps(ref uvm_reg_map maps[$]); + foreach (m_maps[map]) + maps.push_back(map); +endfunction +function int uvm_reg::get_n_maps(); + return m_maps.num(); +endfunction +function bit uvm_reg::is_in_map(uvm_reg_map map); + if (m_maps.exists(map)) + return 1; + foreach (m_maps[l]) begin + uvm_reg_map local_map = l; + uvm_reg_map parent_map = local_map.get_parent_map(); + while (parent_map != null) begin + if (parent_map == map) + return 1; + parent_map = parent_map.get_parent_map(); + end + end + return 0; +endfunction +function uvm_reg_map uvm_reg::get_local_map(uvm_reg_map map); + if (map == null) + return get_default_map(); + if (m_maps.exists(map)) + return map; + foreach (m_maps[l]) begin + uvm_reg_map local_map=l; + uvm_reg_map parent_map = local_map.get_parent_map(); + while (parent_map != null) begin + if (parent_map == map) + return local_map; + parent_map = parent_map.get_parent_map(); + end + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Register '",get_full_name(),"' is not contained within map '",map.get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 1062, "", 1); + end + return null; +endfunction +function uvm_reg_map uvm_reg::get_default_map(); + if (m_maps.num() == 0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Register '",get_full_name(),"' is not registered with any map"}, UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 1075, "", 1); + end + return null; + end + if (m_maps.num() == 1) begin + uvm_reg_map map; + void'(m_maps.first(map)); + return map; + end + foreach (m_maps[l]) begin + uvm_reg_map map = l; + uvm_reg_block blk = map.get_parent(); + uvm_reg_map default_map = blk.get_default_map(); + if (default_map != null) begin + uvm_reg_map local_map = get_local_map(default_map); + if (local_map != null) + return local_map; + end + end + begin + uvm_reg_map map; + void'(m_maps.first(map)); + return map; + end +endfunction +function string uvm_reg::get_rights(uvm_reg_map map = null); + uvm_reg_map_info info; + map = get_local_map(map); + if (map == null) + return "RW"; + info = map.get_reg_map_info(this); + return info.rights; +endfunction +function uvm_reg_block uvm_reg::get_block(); + get_block = m_parent; +endfunction +function uvm_reg_addr_t uvm_reg::get_offset(uvm_reg_map map = null); + uvm_reg_map_info map_info; + uvm_reg_map orig_map = map; + map = get_local_map(map); + if (map == null) + return -1; + map_info = map.get_reg_map_info(this); + if (map_info.unmapped) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Register '",get_name(), "' is unmapped in map '", ((orig_map == null) ? map.get_full_name() : orig_map.get_full_name()),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 1151, "", 1); + end + return -1; + end + return map_info.offset; +endfunction +function int uvm_reg::get_addresses(uvm_reg_map map=null, ref uvm_reg_addr_t addr[]); + uvm_reg_map_info map_info; + uvm_reg_map orig_map = map; + map = get_local_map(map); + if (map == null) + return -1; + map_info = map.get_reg_map_info(this); + if (map_info.unmapped) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Register '",get_name(), "' is unmapped in map '", ((orig_map == null) ? map.get_full_name() : orig_map.get_full_name()),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 1177, "", 1); + end + return -1; + end + addr = map_info.addr; + return map.get_n_bytes(); +endfunction +function uvm_reg_addr_t uvm_reg::get_address(uvm_reg_map map = null); + uvm_reg_addr_t addr[]; + void'(get_addresses(map,addr)); + return addr[0]; +endfunction +function int unsigned uvm_reg::get_n_bits(); + return m_n_bits; +endfunction +function int unsigned uvm_reg::get_n_bytes(); + return ((m_n_bits-1) / 8) + 1; +endfunction +function int unsigned uvm_reg::get_max_size(); + return m_max_size; +endfunction: get_max_size +function void uvm_reg::get_fields(ref uvm_reg_field fields[$]); + foreach(m_fields[i]) + fields.push_back(m_fields[i]); +endfunction +function uvm_reg_field uvm_reg::get_field_by_name(string name); + foreach (m_fields[i]) + if (m_fields[i].get_name() == name) + return m_fields[i]; + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Unable to locate field '",name, "' in register '",get_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 1232, "", 1); + end + return null; +endfunction +function string uvm_reg::Xget_fields_accessX(uvm_reg_map map); + bit is_R; + bit is_W; + foreach(m_fields[i]) begin + case (m_fields[i].get_access(map)) + "RO", + "RC", + "RS": + is_R = 1; + "WO", + "WOC", + "WOS", + "WO1": + is_W = 1; + default: + return "RW"; + endcase + if (is_R && is_W) return "RW"; + end + case ({is_R, is_W}) + 2'b01: return "WO"; + 2'b10: return "RO"; + endcase + return "RW"; +endfunction +function void uvm_reg::include_coverage(string scope, + uvm_reg_cvr_t models, + uvm_object accessor = null); + uvm_reg_cvr_rsrc_db::set({"uvm_reg::", scope}, + "include_coverage", + models, accessor); +endfunction +function uvm_reg_cvr_t uvm_reg::build_coverage(uvm_reg_cvr_t models); + build_coverage = UVM_NO_COVERAGE; + void'(uvm_reg_cvr_rsrc_db::read_by_name({"uvm_reg::", get_full_name()}, + "include_coverage", + build_coverage, this)); + return build_coverage & models; +endfunction: build_coverage +function void uvm_reg::add_coverage(uvm_reg_cvr_t models); + m_has_cover |= models; +endfunction: add_coverage +function bit uvm_reg::has_coverage(uvm_reg_cvr_t models); + return ((m_has_cover & models) == models); +endfunction: has_coverage +function uvm_reg_cvr_t uvm_reg::set_coverage(uvm_reg_cvr_t is_on); + if (is_on == uvm_reg_cvr_t'(UVM_NO_COVERAGE)) begin + m_cover_on = is_on; + return m_cover_on; + end + m_cover_on = m_has_cover & is_on; + return m_cover_on; +endfunction: set_coverage +function bit uvm_reg::get_coverage(uvm_reg_cvr_t is_on); + if (has_coverage(is_on) == 0) + return 0; + return ((m_cover_on & is_on) == is_on); +endfunction: get_coverage +function void uvm_reg::set(uvm_reg_data_t value, + string fname = "", + int lineno = 0); + m_fname = fname; + m_lineno = lineno; + foreach (m_fields[i]) + m_fields[i].set((value >> m_fields[i].get_lsb_pos()) & + ((1 << m_fields[i].get_n_bits()) - 1)); +endfunction: set +function bit uvm_reg::predict (uvm_reg_data_t value, + uvm_reg_byte_en_t be = -1, + uvm_predict_e kind = UVM_PREDICT_DIRECT, + uvm_door_e path = UVM_FRONTDOOR, + uvm_reg_map map = null, + string fname = "", + int lineno = 0); + uvm_reg_item rw = new; + rw.value[0] = value; + rw.path = path; + rw.map = map; + rw.fname = fname; + rw.lineno = lineno; + do_predict(rw, kind, be); + predict = (rw.status == UVM_NOT_OK) ? 0 : 1; +endfunction: predict +function void uvm_reg::do_predict(uvm_reg_item rw, + uvm_predict_e kind = UVM_PREDICT_DIRECT, + uvm_reg_byte_en_t be = -1); + uvm_reg_data_t reg_value = rw.value[0]; + m_fname = rw.fname; + m_lineno = rw.lineno; +if (rw.status ==UVM_IS_OK ) + rw.status = UVM_IS_OK; + if (m_is_busy && kind == UVM_PREDICT_DIRECT) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Trying to predict value of register '", get_full_name(),"' while it is being accessed"}, UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 1395, "", 1); + end + rw.status = UVM_NOT_OK; + return; + end + foreach (m_fields[i]) begin + rw.value[0] = (reg_value >> m_fields[i].get_lsb_pos()) & + ((1 << m_fields[i].get_n_bits())-1); + m_fields[i].do_predict(rw, kind, be>>(m_fields[i].get_lsb_pos()/8)); + end + rw.value[0] = reg_value; +endfunction: do_predict +function uvm_reg_data_t uvm_reg::get(string fname = "", + int lineno = 0); + m_fname = fname; + m_lineno = lineno; + get = 0; + foreach (m_fields[i]) + get |= m_fields[i].get() << m_fields[i].get_lsb_pos(); +endfunction: get +function uvm_reg_data_t uvm_reg::get_mirrored_value(string fname = "", + int lineno = 0); + m_fname = fname; + m_lineno = lineno; + get_mirrored_value = 0; + foreach (m_fields[i]) + get_mirrored_value |= m_fields[i].get_mirrored_value() << m_fields[i].get_lsb_pos(); +endfunction: get_mirrored_value +function void uvm_reg::reset(string kind = "HARD"); + foreach (m_fields[i]) + m_fields[i].reset(kind); + void'(m_atomic.try_get(1)); + m_atomic.put(1); + m_process = null; + Xset_busyX(0); +endfunction: reset +function uvm_reg_data_t uvm_reg::get_reset(string kind = "HARD"); + get_reset = 0; + foreach (m_fields[i]) + get_reset |= m_fields[i].get_reset(kind) << m_fields[i].get_lsb_pos(); +endfunction: get_reset +function bit uvm_reg::has_reset(string kind = "HARD", + bit delete = 0); + has_reset = 0; + foreach (m_fields[i]) begin + has_reset |= m_fields[i].has_reset(kind, delete); + if (!delete && has_reset) + return 1; + end +endfunction: has_reset +function void uvm_reg::set_reset(uvm_reg_data_t value, + string kind = "HARD"); + foreach (m_fields[i]) begin + m_fields[i].set_reset(value >> m_fields[i].get_lsb_pos(), kind); + end +endfunction: set_reset +function bit uvm_reg::needs_update(); + needs_update = 0; + foreach (m_fields[i]) begin + if (m_fields[i].needs_update()) begin + return 1; + end + end +endfunction: needs_update +task uvm_reg::update(output uvm_status_e status, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_data_t upd; + status = UVM_IS_OK; + if (!needs_update()) return; + upd = 0; + foreach (m_fields[i]) + upd |= m_fields[i].XupdateX() << m_fields[i].get_lsb_pos(); + write(status, upd, path, map, parent, prior, extension, fname, lineno); +endtask: update +task uvm_reg::write(output uvm_status_e status, + input uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_item rw; + XatomicX(1); + set(value); + rw = uvm_reg_item::type_id_create("write_item",,get_full_name()); + rw.element = this; + rw.element_kind = UVM_REG; + rw.kind = UVM_WRITE; + rw.value[0] = value; + rw.path = path; + rw.map = map; + rw.parent = parent; + rw.prior = prior; + rw.extension = extension; + rw.fname = fname; + rw.lineno = lineno; + do_write(rw); + status = rw.status; + XatomicX(0); +endtask +task uvm_reg::do_write (uvm_reg_item rw); + uvm_reg_cb_iter cbs = new(this); + uvm_reg_map_info map_info; + uvm_reg_data_t value; + m_fname = rw.fname; + m_lineno = rw.lineno; + if (!Xcheck_accessX(rw,map_info)) + return; + XatomicX(1); + m_write_in_progress = 1'b1; + rw.value[0] &= ((1 << m_n_bits)-1); + value = rw.value[0]; + rw.status = UVM_IS_OK; + begin : pre_write_callbacks + uvm_reg_data_t msk; + int lsb; + foreach (m_fields[i]) begin + uvm_reg_field_cb_iter cbs = new(m_fields[i]); + uvm_reg_field f = m_fields[i]; + lsb = f.get_lsb_pos(); + msk = ((1<> lsb; + f.pre_write(rw); + for (uvm_reg_cbs cb=cbs.first(); cb!=null; cb=cbs.next()) begin + rw.element = f; + rw.element_kind = UVM_FIELD; + cb.pre_write(rw); + end + value = (value & ~msk) | (rw.value[0] << lsb); + end + end + rw.element = this; + rw.element_kind = UVM_REG; + rw.value[0] = value; + pre_write(rw); + for (uvm_reg_cbs cb=cbs.first(); cb!=null; cb=cbs.next()) + cb.pre_write(rw); + if (rw.status != UVM_IS_OK) begin + m_write_in_progress = 1'b0; + XatomicX(0); + return; + end + case (rw.path) + UVM_BACKDOOR: begin + uvm_reg_data_t final_val; + uvm_reg_backdoor bkdr = get_backdoor(); + if (rw.map != null) + rw.local_map = rw.map; + else + rw.local_map = get_default_map(); + value = rw.value[0]; + rw.kind = UVM_READ; + if (bkdr != null) + bkdr.read(rw); + else + backdoor_read(rw); + if (rw.status == UVM_NOT_OK) begin + m_write_in_progress = 1'b0; + return; + end + begin + foreach (m_fields[i]) begin + uvm_reg_data_t field_val; + int lsb = m_fields[i].get_lsb_pos(); + int sz = m_fields[i].get_n_bits(); + field_val = m_fields[i].XpredictX((rw.value[0] >> lsb) & ((1<> lsb) & ((1<> f.get_lsb_pos()) & ((1<> f.get_lsb_pos()) & ((1<> hdl_concat.slices[j].offset; + slice &= (1 << hdl_concat.slices[j].size)-1; + ok &= uvm_hdl_deposit(hdl_concat.slices[j].path, slice); + end + end + end + rw.status = (ok ? UVM_IS_OK : UVM_NOT_OK); +endtask +task uvm_reg::backdoor_read (uvm_reg_item rw); + rw.status = backdoor_read_func(rw); +endtask +function uvm_status_e uvm_reg::backdoor_read_func(uvm_reg_item rw); + uvm_hdl_path_concat paths[$]; + uvm_reg_data_t val; + bit ok=1; + get_full_hdl_path(paths,rw.bd_kind); + foreach (paths[i]) begin + uvm_hdl_path_concat hdl_concat = paths[i]; + val = 0; + foreach (hdl_concat.slices[j]) begin + begin + if (uvm_report_enabled(UVM_DEBUG,UVM_INFO,"RegMem")) + uvm_report_info ("RegMem", $sformatf("backdoor_read from %s ", hdl_concat.slices[j].path), UVM_DEBUG, "t/uvm/src/reg/uvm_reg.svh", 2192, "", 1); + end + if (hdl_concat.slices[j].offset < 0) begin +//TODO issue #4467 - Fix UVM function output width reassignment +//TODO %Error-UNSUPPORTED: t/t_uvm_pkg_todo.vh:26297:57: Unsupported: Function output argument 'value' requires 1024 bits, but connection's VARREF 'val' generates 64 bits. +//TODO ok &= uvm_hdl_read(hdl_concat.slices[j].path,val); + continue; + end + begin + uvm_reg_data_t slice; + int k = hdl_concat.slices[j].offset; +//TODO issue #4467 - Fix UVM function output width reassignment +//TODO %Error-UNSUPPORTED: t/t_uvm_pkg_todo.vh:26303:58: Unsupported: Function output argument 'value' requires 1024 bits, but connection's VARREF 'slice' generates 64 bits. +//TODO ok &= uvm_hdl_read(hdl_concat.slices[j].path, slice); + repeat (hdl_concat.slices[j].size) begin + val[k++] = slice[0]; + slice >>= 1; + end + end + end + val &= (1 << m_n_bits)-1; + if (i == 0) + rw.value[0] = val; + if (val != rw.value[0]) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Backdoor read of register %s with multiple HDL copies: values are not the same: %0h at path '%s', and %0h at path '%s'. Returning first value.", get_full_name(), rw.value[0], uvm_hdl_concat2string(paths[0]), val, uvm_hdl_concat2string(paths[i])), UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 2220, "", 1); + end + return UVM_NOT_OK; + end + begin + if (uvm_report_enabled(UVM_DEBUG,UVM_INFO,"RegMem")) + uvm_report_info ("RegMem", $sformatf("returned backdoor value 0x%0x",rw.value[0]), UVM_DEBUG, "t/uvm/src/reg/uvm_reg.svh", 2224, "", 1); + end + end + rw.status = (ok) ? UVM_IS_OK : UVM_NOT_OK; + return rw.status; +endfunction +task uvm_reg::poke(output uvm_status_e status, + input uvm_reg_data_t value, + input string kind = "", + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_backdoor bkdr = get_backdoor(); + uvm_reg_item rw; + m_fname = fname; + m_lineno = lineno; + if (bkdr == null && !has_hdl_path(kind)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"No backdoor access available to poke register '",get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 2252, "", 1); + end + status = UVM_NOT_OK; + return; + end + if (!m_is_locked_by_field) + XatomicX(1); + rw = uvm_reg_item::type_id_create("reg_poke_item",,get_full_name()); + rw.element = this; + rw.path = UVM_BACKDOOR; + rw.element_kind = UVM_REG; + rw.kind = UVM_WRITE; + rw.bd_kind = kind; + rw.value[0] = value & ((1 << m_n_bits)-1); + rw.parent = parent; + rw.extension = extension; + rw.fname = fname; + rw.lineno = lineno; + if (bkdr != null) + bkdr.write(rw); + else + backdoor_write(rw); + status = rw.status; + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", $sformatf("Poked register \"%s\": 'h%h", get_full_name(), value), UVM_HIGH, "t/uvm/src/reg/uvm_reg.svh", 2285, "", 1); + end + do_predict(rw, UVM_PREDICT_WRITE); + if (!m_is_locked_by_field) + XatomicX(0); +endtask: poke +task uvm_reg::peek(output uvm_status_e status, + output uvm_reg_data_t value, + input string kind = "", + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_backdoor bkdr = get_backdoor(); + uvm_reg_item rw; + m_fname = fname; + m_lineno = lineno; + if (bkdr == null && !has_hdl_path(kind)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("No backdoor access available to peek register \"%s\"", get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 2313, "", 1); + end + status = UVM_NOT_OK; + return; + end + if(!m_is_locked_by_field) + XatomicX(1); + rw = uvm_reg_item::type_id_create("mem_peek_item",,get_full_name()); + rw.element = this; + rw.path = UVM_BACKDOOR; + rw.element_kind = UVM_REG; + rw.kind = UVM_READ; + rw.bd_kind = kind; + rw.parent = parent; + rw.extension = extension; + rw.fname = fname; + rw.lineno = lineno; + if (bkdr != null) + bkdr.read(rw); + else + backdoor_read(rw); + status = rw.status; + value = rw.value[0]; + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", $sformatf("Peeked register \"%s\": 'h%h", get_full_name(), value), UVM_HIGH, "t/uvm/src/reg/uvm_reg.svh", 2346, "", 1); + end + do_predict(rw, UVM_PREDICT_READ); + if (!m_is_locked_by_field) + XatomicX(0); +endtask: peek +function bit uvm_reg::do_check(input uvm_reg_data_t expected, + input uvm_reg_data_t actual, + uvm_reg_map map); + uvm_reg_data_t valid_bits_mask = 0; + foreach(m_fields[i]) begin + string acc = m_fields[i].get_access(map); + acc = acc.substr(0, 1); + if (!(m_fields[i].get_compare() == UVM_NO_CHECK ||acc == "WO")) begin + valid_bits_mask |= ((1 << m_fields[i].get_n_bits())-1)<< m_fields[i].get_lsb_pos(); + end + end + if ((actual&valid_bits_mask) === (expected&valid_bits_mask)) return 1; + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Register \"%s\" value read from DUT (0x%h) does not match mirrored value (0x%h) (valid bit mask = 0x%h)", get_full_name(), actual, expected,valid_bits_mask), UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 2373, "", 1); + end + foreach(m_fields[i]) begin + string acc = m_fields[i].get_access(map); + acc = acc.substr(0, 1); + if (!(m_fields[i].get_compare() == UVM_NO_CHECK || + acc == "WO")) begin + uvm_reg_data_t mask = ((1 << m_fields[i].get_n_bits())-1); + uvm_reg_data_t val = actual >> m_fields[i].get_lsb_pos() & mask; + uvm_reg_data_t exp = expected >> m_fields[i].get_lsb_pos() & mask; + if (val !== exp) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", $sformatf("Field %s (%s[%0d:%0d]) mismatch read=%0d'h%0h mirrored=%0d'h%0h ", m_fields[i].get_name(), get_full_name(), m_fields[i].get_lsb_pos() + m_fields[i].get_n_bits() - 1, m_fields[i].get_lsb_pos(), m_fields[i].get_n_bits(), val, m_fields[i].get_n_bits(), exp), UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 2392, "", 1); + end + end + end + end + return 0; +endfunction +task uvm_reg::mirror(output uvm_status_e status, + input uvm_check_e check = UVM_NO_CHECK, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_data_t v; + uvm_reg_data_t exp; + uvm_reg_backdoor bkdr = get_backdoor(); + XatomicX(1); + m_fname = fname; + m_lineno = lineno; + if (path == UVM_DEFAULT_DOOR) + path = m_parent.get_default_door(); + if (path == UVM_BACKDOOR && (bkdr != null || has_hdl_path())) + map = uvm_reg_map::backdoor(); + else + map = get_local_map(map); + if (map == null) + return; + if (check == UVM_CHECK) + exp = get_mirrored_value(); + XreadX(status, v, path, map, parent, prior, extension, fname, lineno); + if (status == UVM_NOT_OK) begin + XatomicX(0); + return; + end + if (check == UVM_CHECK) void'(do_check(exp, v, map)); + XatomicX(0); +endtask: mirror +task uvm_reg::XatomicX(bit on); + process m_reg_process; + m_reg_process=process::self(); + if (on) begin + if (m_reg_process == m_process) + return; + m_atomic.get(1); + m_process = m_reg_process; + end + else begin + void'(m_atomic.try_get(1)); + m_atomic.put(1); + m_process = null; + end +endtask: XatomicX +function string uvm_reg::convert2string(); + string res_str; + string t_str; + bit with_debug_info; + string prefix; + $sformat(convert2string, "Register %s -- %0d bytes, mirror value:'h%h", + get_full_name(), get_n_bytes(),get()); + if (m_maps.num()==0) + convert2string = {convert2string, " (unmapped)\n"}; + else + convert2string = {convert2string, "\n"}; + foreach (m_maps[map]) begin + uvm_reg_map parent_map = map; + int unsigned offset; + while (parent_map != null) begin + uvm_reg_map this_map = parent_map; + parent_map = this_map.get_parent_map(); + offset = parent_map == null ? this_map.get_base_addr(UVM_NO_HIER) : + parent_map.get_submap_offset(this_map); + prefix = {prefix, " "}; + begin + uvm_endianness_e e = this_map.get_endian(); + $sformat(convert2string, + "%sMapped in '%s' -- %d bytes, %s, offset 'h%0h\n", + prefix, this_map.get_full_name(), this_map.get_n_bytes(), + e.name(), offset); + end + end + end + prefix = " "; + foreach(m_fields[i]) begin + $sformat(convert2string, "%s\n%s", convert2string, + m_fields[i].convert2string()); + end + if (m_read_in_progress == 1'b1) begin + if (m_fname != "" && m_lineno != 0) + $sformat(res_str, "%s:%0d ",m_fname, m_lineno); + convert2string = {convert2string, "\n", res_str, + "currently executing read method"}; + end + if ( m_write_in_progress == 1'b1) begin + if (m_fname != "" && m_lineno != 0) + $sformat(res_str, "%s:%0d ",m_fname, m_lineno); + convert2string = {convert2string, "\n", res_str, + "currently executing write method"}; + end +endfunction: convert2string +function void uvm_reg::do_print (uvm_printer printer); + uvm_reg_field f[$]; + super.do_print(printer); + get_fields(f); + foreach(f[i]) printer.print_generic(f[i].get_name(),f[i].get_type_name(),-2,f[i].convert2string()); +endfunction +function uvm_object uvm_reg::clone(); + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"RegModel")) + uvm_report_fatal ("RegModel", "RegModel registers cannot be cloned", UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 2544, "", 1); + end + return null; +endfunction +function void uvm_reg::do_copy(uvm_object rhs); + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"RegModel")) + uvm_report_fatal ("RegModel", "RegModel registers cannot be copied", UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 2551, "", 1); + end +endfunction +function bit uvm_reg::do_compare (uvm_object rhs, + uvm_comparer comparer); + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", "RegModel registers cannot be compared", UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 2559, "", 1); + end + return 0; +endfunction +function void uvm_reg::do_pack (uvm_packer packer); + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", "RegModel registers cannot be packed", UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 2567, "", 1); + end +endfunction +function void uvm_reg::do_unpack (uvm_packer packer); + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", "RegModel registers cannot be unpacked", UVM_NONE, "t/uvm/src/reg/uvm_reg.svh", 2574, "", 1); + end +endfunction +typedef class uvm_reg_indirect_ftdr_seq; +class uvm_reg_indirect_data extends uvm_reg; + protected uvm_reg m_idx; + protected uvm_reg m_tbl[]; + function new(string name = "uvm_reg_indirect", + int unsigned n_bits, + int has_cover); + super.new(name,n_bits,has_cover); + endfunction: new + virtual function void build(); + endfunction: build + function void configure (uvm_reg idx, + uvm_reg reg_a[], + uvm_reg_block blk_parent, + uvm_reg_file regfile_parent = null); + super.configure(blk_parent, regfile_parent, ""); + m_idx = idx; + m_tbl = reg_a; + uvm_resource_db#(bit)::set({"REG::", get_full_name()}, + "NO_REG_TESTS", 1); + foreach (m_maps[map]) begin + add_frontdoors(map); + end + endfunction + virtual function void add_map(uvm_reg_map map); + super.add_map(map); + add_frontdoors(map); + endfunction + local function void add_frontdoors(uvm_reg_map map); + foreach (m_tbl[i]) begin + uvm_reg_indirect_ftdr_seq fd; + if (m_tbl[i] == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,get_full_name())) + uvm_report_error (get_full_name(), $sformatf("Indirect register #%0d is NULL", i), UVM_NONE, "t/uvm/src/reg/uvm_reg_indirect.svh", 90, "", 1); + end + continue; + end + fd = new(m_idx, i, this); + if (m_tbl[i].is_in_map(map)) + m_tbl[i].set_frontdoor(fd, map); + else + map.add_reg(m_tbl[i], -1, "RW", 1, fd); + end + endfunction + virtual function void do_predict (uvm_reg_item rw, + uvm_predict_e kind = UVM_PREDICT_DIRECT, + uvm_reg_byte_en_t be = -1); + if (m_idx.get() >= m_tbl.size()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,get_full_name())) + uvm_report_error (get_full_name(), $sformatf("Address register %s has a value (%0d) greater than the maximum indirect register array size (%0d)", m_idx.get_full_name(), m_idx.get(), m_tbl.size()), UVM_NONE, "t/uvm/src/reg/uvm_reg_indirect.svh", 105, "", 1); + end + rw.status = UVM_NOT_OK; + return; + end + begin + int unsigned idx = m_idx.get(); + m_tbl[idx].do_predict(rw, kind, be); + end + endfunction + virtual function uvm_reg_map get_local_map(uvm_reg_map map); + return m_idx.get_local_map(map); + endfunction + virtual function void add_field (uvm_reg_field field); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,get_full_name())) + uvm_report_error (get_full_name(), "Cannot add field to an indirect data access register", UVM_NONE, "t/uvm/src/reg/uvm_reg_indirect.svh", 126, "", 1); + end + endfunction + virtual function void set (uvm_reg_data_t value, + string fname = "", + int lineno = 0); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,get_full_name())) + uvm_report_error (get_full_name(), "Cannot set() an indirect data access register", UVM_NONE, "t/uvm/src/reg/uvm_reg_indirect.svh", 132, "", 1); + end + endfunction + virtual function uvm_reg_data_t get(string fname = "", + int lineno = 0); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,get_full_name())) + uvm_report_error (get_full_name(), "Cannot get() an indirect data access register", UVM_NONE, "t/uvm/src/reg/uvm_reg_indirect.svh", 137, "", 1); + end + return 0; + endfunction + virtual function uvm_reg get_indirect_reg(string fname = "", + int lineno = 0); + int unsigned idx = m_idx.get_mirrored_value(); + return(m_tbl[idx]); + endfunction + virtual function bit needs_update(); + return 0; + endfunction + virtual task write(output uvm_status_e status, + input uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + if (path == UVM_DEFAULT_DOOR) begin + uvm_reg_block blk = get_parent(); + path = blk.get_default_door(); + end + if (path == UVM_BACKDOOR) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,get_full_name())) + uvm_report_warning (get_full_name(), "Cannot backdoor-write an indirect data access register. Switching to frontdoor.", UVM_NONE, "t/uvm/src/reg/uvm_reg_indirect.svh", 167, "", 1); + end + path = UVM_FRONTDOOR; + end + begin + uvm_reg_item rw; + XatomicX(1); + rw = uvm_reg_item::type_id_create("write_item",,get_full_name()); + rw.element = this; + rw.element_kind = UVM_REG; + rw.kind = UVM_WRITE; + rw.value[0] = value; + rw.path = path; + rw.map = map; + rw.parent = parent; + rw.prior = prior; + rw.extension = extension; + rw.fname = fname; + rw.lineno = lineno; + do_write(rw); + status = rw.status; + XatomicX(0); + end + endtask + virtual task read(output uvm_status_e status, + output uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + if (path == UVM_DEFAULT_DOOR) begin + uvm_reg_block blk = get_parent(); + path = blk.get_default_door(); + end + if (path == UVM_BACKDOOR) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,get_full_name())) + uvm_report_warning (get_full_name(), "Cannot backdoor-read an indirect data access register. Switching to frontdoor.", UVM_NONE, "t/uvm/src/reg/uvm_reg_indirect.svh", 218, "", 1); + end + path = UVM_FRONTDOOR; + end + super.read(status, value, path, map, parent, prior, extension, fname, lineno); + endtask + virtual task poke(output uvm_status_e status, + input uvm_reg_data_t value, + input string kind = "", + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,get_full_name())) + uvm_report_error (get_full_name(), "Cannot poke() an indirect data access register", UVM_NONE, "t/uvm/src/reg/uvm_reg_indirect.svh", 232, "", 1); + end + status = UVM_NOT_OK; + endtask + virtual task peek(output uvm_status_e status, + output uvm_reg_data_t value, + input string kind = "", + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,get_full_name())) + uvm_report_error (get_full_name(), "Cannot peek() an indirect data access register", UVM_NONE, "t/uvm/src/reg/uvm_reg_indirect.svh", 243, "", 1); + end + status = UVM_NOT_OK; + endtask + virtual task update(output uvm_status_e status, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + status = UVM_IS_OK; + endtask + virtual task mirror(output uvm_status_e status, + input uvm_check_e check = UVM_NO_CHECK, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + status = UVM_IS_OK; + endtask +endclass : uvm_reg_indirect_data +class uvm_reg_indirect_ftdr_seq extends uvm_reg_frontdoor; + local uvm_reg m_addr_reg; + local uvm_reg m_data_reg; + local int m_idx; + function new(uvm_reg addr_reg, + int idx, + uvm_reg data_reg); + super.new("uvm_reg_indirect_ftdr_seq"); + m_addr_reg = addr_reg; + m_idx = idx; + m_data_reg = data_reg; + endfunction: new + virtual task body(); + uvm_reg_item rw; + $cast(rw,rw_info.clone()); + rw.element = m_addr_reg; + rw.kind = UVM_WRITE; + rw.value[0]= m_idx; + m_addr_reg.XatomicX(1); + m_data_reg.XatomicX(1); + m_addr_reg.do_write(rw); + if (rw.status == UVM_NOT_OK) + return; + $cast(rw,rw_info.clone()); + rw.element = m_data_reg; + if (rw_info.kind == UVM_WRITE) + m_data_reg.do_write(rw); + else begin + m_data_reg.do_read(rw); + rw_info.value[0] = rw.value[0]; + end + m_addr_reg.XatomicX(0); + m_data_reg.XatomicX(0); + rw_info.status = rw.status; + endtask +endclass +class uvm_reg_fifo extends uvm_reg; + local uvm_reg_field value; + local int m_set_cnt; + local int unsigned m_size; + rand uvm_reg_data_t fifo[$]; + constraint valid_fifo_size { + fifo.size() <= m_size; + } + function new(string name = "reg_fifo", + int unsigned size, + int unsigned n_bits, + int has_cover); + super.new(name,n_bits,has_cover); + m_size = size; + endfunction + virtual function void build(); + value = uvm_reg_field::type_id_create("value"); + value.configure(this, get_n_bits(), 0, "RW", 0, 32'h0, 1, 0, 1); + endfunction + function void set_compare(uvm_check_e check=UVM_CHECK); + value.set_compare(check); + endfunction + function int unsigned size(); + return fifo.size(); + endfunction + function int unsigned capacity(); + return m_size; + endfunction + virtual function void set(uvm_reg_data_t value, + string fname = "", + int lineno = 0); + value &= ((1 << get_n_bits())-1); + if (fifo.size() == m_size) begin + return; + end + super.set(value,fname,lineno); + m_set_cnt++; + fifo.push_back(this.value.value); + endfunction + virtual task update(output uvm_status_e status, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_data_t upd; + if (!m_set_cnt || fifo.size() == 0) + return; + m_update_in_progress = 1; + for (int i=fifo.size()-m_set_cnt; m_set_cnt > 0; i++, m_set_cnt--) begin + if (i >= 0) begin + write(status,fifo[i],path,map,parent,prior,extension,fname,lineno); + end + end + m_update_in_progress = 0; + endtask + virtual function uvm_reg_data_t get(string fname="", int lineno=0); + return fifo[0]; + endfunction + virtual function void do_predict(uvm_reg_item rw, + uvm_predict_e kind = UVM_PREDICT_DIRECT, + uvm_reg_byte_en_t be = -1); + super.do_predict(rw,kind,be); + if (rw.status == UVM_NOT_OK) + return; + case (kind) + UVM_PREDICT_WRITE, + UVM_PREDICT_DIRECT: + begin + if (fifo.size() != m_size && !m_update_in_progress) + fifo.push_back(this.value.value); + end + UVM_PREDICT_READ: + begin + uvm_reg_data_t value = rw.value[0] & ((1 << get_n_bits())-1); + uvm_reg_data_t mirror_val; + if (fifo.size() == 0) begin + return; + end + mirror_val = fifo.pop_front(); + if (this.value.get_compare() == UVM_CHECK && mirror_val != value) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"MIRROR_MISMATCH")) + uvm_report_warning ("MIRROR_MISMATCH", $sformatf("Observed DUT read value 'h%0h != mirror value 'h%0h",value,mirror_val), UVM_NONE, "t/uvm/src/reg/uvm_reg_fifo.svh", 241, "", 1); + end + end + end + endcase + endfunction + virtual task pre_write(uvm_reg_item rw); + if (m_set_cnt && !m_update_in_progress) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"Needs Update")) + uvm_report_error ("Needs Update", "Must call update() after set() and before write()", UVM_NONE, "t/uvm/src/reg/uvm_reg_fifo.svh", 263, "", 1); + end + rw.status = UVM_NOT_OK; + return; + end + if (fifo.size() >= m_size && !m_update_in_progress) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"FIFO Full")) + uvm_report_error ("FIFO Full", "Write to full FIFO ignored", UVM_NONE, "t/uvm/src/reg/uvm_reg_fifo.svh", 268, "", 1); + end + rw.status = UVM_NOT_OK; + return; + end + endtask + virtual task pre_read(uvm_reg_item rw); + if (fifo.size() == 0) begin + rw.status = UVM_NOT_OK; + return; + end + endtask + function void post_randomize(); + m_set_cnt = 0; + endfunction +endclass +class uvm_reg_file extends uvm_object; + local uvm_reg_block parent; + local uvm_reg_file m_rf; + local string default_hdl_path = "RTL"; + local uvm_object_string_pool #(uvm_queue #(string)) hdl_paths_pool; + typedef uvm_object_registry#(uvm_reg_file,"uvm_reg_file") type_id; + static function uvm_reg_file type_id_create (string name="", + uvm_component parent=null, + string contxt=""); + return type_id::create(name, parent, contxt); + endfunction + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + function uvm_object create (string name=""); + uvm_reg_file tmp; + if (name=="") tmp = new(); + else tmp = new(name); + return tmp; + endfunction + static function string type_name(); + return "uvm_reg_file"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_reg_file"; + endfunction : get_type_name + extern function new (string name=""); + extern function void configure (uvm_reg_block blk_parent, + uvm_reg_file regfile_parent, + string hdl_path = ""); + extern virtual function string get_full_name(); + extern virtual function uvm_reg_block get_parent (); + extern virtual function uvm_reg_block get_block (); + extern virtual function uvm_reg_file get_regfile (); + extern function void clear_hdl_path (string kind = "RTL"); + extern function void add_hdl_path (string path, string kind = "RTL"); + extern function bit has_hdl_path (string kind = ""); + extern function void get_hdl_path (ref string paths[$], input string kind = ""); + extern function void get_full_hdl_path (ref string paths[$], + input string kind = "", + input string separator = "."); + extern function void set_default_hdl_path (string kind); + extern function string get_default_hdl_path (); + extern virtual function void do_print (uvm_printer printer); + extern virtual function string convert2string(); + extern virtual function uvm_object clone (); + extern virtual function void do_copy (uvm_object rhs); + extern virtual function bit do_compare (uvm_object rhs, + uvm_comparer comparer); + extern virtual function void do_pack (uvm_packer packer); + extern virtual function void do_unpack (uvm_packer packer); +endclass: uvm_reg_file +function uvm_reg_file::new(string name=""); + super.new(name); + hdl_paths_pool = new("hdl_paths"); +endfunction: new +function void uvm_reg_file::configure(uvm_reg_block blk_parent, uvm_reg_file regfile_parent, string hdl_path = ""); + if (blk_parent == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/RFILE/CFG/NOBLK")) + uvm_report_error ("UVM/RFILE/CFG/NOBLK", {"uvm_reg_file::configure() called without a parent block for instance \"", get_name(), "\" of register file type \"", get_type_name(), "\"."}, UVM_NONE, "t/uvm/src/reg/uvm_reg_file.svh", 148, "", 1); + end + return; + end + this.parent = blk_parent; + this.m_rf = regfile_parent; + this.add_hdl_path(hdl_path); +endfunction: configure +function uvm_reg_block uvm_reg_file::get_block(); + get_block = this.parent; +endfunction: get_block +function uvm_reg_file uvm_reg_file::get_regfile(); + return m_rf; +endfunction +function void uvm_reg_file::clear_hdl_path(string kind = "RTL"); + if (kind == "ALL") begin + hdl_paths_pool = new("hdl_paths"); + return; + end + if (kind == "") begin + if (m_rf != null) + kind = m_rf.get_default_hdl_path(); + else + kind = parent.get_default_hdl_path(); + end + if (!hdl_paths_pool.exists(kind)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Unknown HDL Abstraction '",kind,"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_file.svh", 188, "", 1); + end + return; + end + hdl_paths_pool.delete(kind); +endfunction +function void uvm_reg_file::add_hdl_path(string path, string kind = "RTL"); + uvm_queue #(string) paths; + paths = hdl_paths_pool.get(kind); + paths.push_back(path); +endfunction +function bit uvm_reg_file::has_hdl_path(string kind = ""); + if (kind == "") begin + if (m_rf != null) + kind = m_rf.get_default_hdl_path(); + else + kind = parent.get_default_hdl_path(); + end + return hdl_paths_pool.exists(kind); +endfunction +function void uvm_reg_file::get_hdl_path(ref string paths[$], input string kind = ""); + uvm_queue #(string) hdl_paths; + if (kind == "") begin + if (m_rf != null) + kind = m_rf.get_default_hdl_path(); + else + kind = parent.get_default_hdl_path(); + end + if (!has_hdl_path(kind)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Register does not have hdl path defined for abstraction '",kind,"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_file.svh", 237, "", 1); + end + return; + end + hdl_paths = hdl_paths_pool.get(kind); + for (int i=0; i= min_offset; + start_offset <= max_offset - len + 1; + } + constraint uvm_mem_mam_policy_no_overlap { + foreach (in_use[i]) { + !(start_offset <= in_use[i].Xend_offsetX && + start_offset + len - 1 >= in_use[i].Xstart_offsetX); + } + } +endclass +class uvm_mem_mam_cfg; + rand int unsigned n_bytes; + rand bit [63:0] start_offset; + rand bit [63:0] end_offset; + rand uvm_mem_mam::alloc_mode_e mode; + rand uvm_mem_mam::locality_e locality; + constraint uvm_mem_mam_cfg_valid { + end_offset > start_offset; + n_bytes < 64; + } +endclass +function uvm_mem_region::new(bit [63:0] start_offset, + bit [63:0] end_offset, + int unsigned len, + int unsigned n_bytes, + uvm_mem_mam parent); + this.Xstart_offsetX = start_offset; + this.Xend_offsetX = end_offset; + this.len = len; + this.n_bytes = n_bytes; + this.parent = parent; + this.XvregX = null; +endfunction: new +function bit [63:0] uvm_mem_region::get_start_offset(); + return this.Xstart_offsetX; +endfunction: get_start_offset +function bit [63:0] uvm_mem_region::get_end_offset(); + return this.Xend_offsetX; +endfunction: get_end_offset +function int unsigned uvm_mem_region::get_len(); + return this.len; +endfunction: get_len +function int unsigned uvm_mem_region::get_n_bytes(); + return this.n_bytes; +endfunction: get_n_bytes +function string uvm_mem_region::convert2string(); + $sformat(convert2string, "['h%h:'h%h]", + this.Xstart_offsetX, this.Xend_offsetX); +endfunction: convert2string +function void uvm_mem_region::release_region(); + this.parent.release_region(this); +endfunction +function uvm_mem uvm_mem_region::get_memory(); + return this.parent.get_memory(); +endfunction: get_memory +function uvm_vreg uvm_mem_region::get_virtual_registers(); + return this.XvregX; +endfunction: get_virtual_registers +function uvm_mem_mam::new(string name, + uvm_mem_mam_cfg cfg, + uvm_mem mem = null); + this.cfg = cfg; + this.memory = mem; + this.default_alloc = new; +endfunction: new +function uvm_mem_mam_cfg uvm_mem_mam::reconfigure(uvm_mem_mam_cfg cfg = null); + uvm_root top; + uvm_coreservice_t cs; + if (cfg == null) + return this.cfg; + cs = uvm_coreservice_t::get(); + top = cs.get_root(); + if (cfg.n_bytes !== this.cfg.n_bytes) begin + top.uvm_report_error("uvm_mem_mam", + $sformatf("Cannot reconfigure Memory Allocation Manager with a different number of bytes (%0d !== %0d)", + cfg.n_bytes, this.cfg.n_bytes), UVM_LOW); + return this.cfg; + end + foreach (this.in_use[i]) begin + if (this.in_use[i].get_start_offset() < cfg.start_offset || + this.in_use[i].get_end_offset() > cfg.end_offset) begin + top.uvm_report_error("uvm_mem_mam", + $sformatf("Cannot reconfigure Memory Allocation Manager with a currently allocated region outside of the managed address range ([%0d:%0d] outside of [%0d:%0d])", + this.in_use[i].get_start_offset(), + this.in_use[i].get_end_offset(), + cfg.start_offset, cfg.end_offset), UVM_LOW); + return this.cfg; + end + end + reconfigure = this.cfg; + this.cfg = cfg; +endfunction: reconfigure +function uvm_mem_region uvm_mem_mam::reserve_region(bit [63:0] start_offset, + int unsigned n_bytes, + string fname = "", + int lineno = 0); + bit [63:0] end_offset; + this.fname = fname; + this.lineno = lineno; + if (n_bytes == 0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", "Cannot reserve 0 bytes", UVM_NONE, "t/uvm/src/reg/uvm_mem_mam.svh", 638, "", 1); + end + return null; + end + if (start_offset < this.cfg.start_offset) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot reserve before start of memory space: 'h%h < 'h%h", start_offset, this.cfg.start_offset), UVM_NONE, "t/uvm/src/reg/uvm_mem_mam.svh", 644, "", 1); + end + return null; + end + end_offset = start_offset + ((n_bytes-1) / this.cfg.n_bytes); + n_bytes = (end_offset - start_offset + 1) * this.cfg.n_bytes; + if (end_offset > this.cfg.end_offset) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot reserve past end of memory space: 'h%h > 'h%h", end_offset, this.cfg.end_offset), UVM_NONE, "t/uvm/src/reg/uvm_mem_mam.svh", 653, "", 1); + end + return null; + end + begin + if (uvm_report_enabled(UVM_MEDIUM,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", $sformatf("Attempting to reserve ['h%h:'h%h]...", start_offset, end_offset), UVM_MEDIUM, "t/uvm/src/reg/uvm_mem_mam.svh", 658, "", 1); + end + foreach (this.in_use[i]) begin + if (start_offset <= this.in_use[i].get_end_offset() && + end_offset >= this.in_use[i].get_start_offset()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot reserve ['h%h:'h%h] because it overlaps with %s", start_offset, end_offset, this.in_use[i].convert2string()), UVM_NONE, "t/uvm/src/reg/uvm_mem_mam.svh", 669, "", 1); + end + return null; + end + if (start_offset > this.in_use[i].get_start_offset()) begin + reserve_region = new(start_offset, end_offset, + end_offset - start_offset + 1, n_bytes, this); + this.in_use.insert(i, reserve_region); + return reserve_region; + end + end + reserve_region = new(start_offset, end_offset, + end_offset - start_offset + 1, n_bytes, this); + this.in_use.push_back(reserve_region); +endfunction: reserve_region +function uvm_mem_region uvm_mem_mam::request_region(int unsigned n_bytes, + uvm_mem_mam_policy alloc = null, + string fname = "", + int lineno = 0); + this.fname = fname; + this.lineno = lineno; + if (alloc == null) alloc = this.default_alloc; + alloc.len = (n_bytes-1) / this.cfg.n_bytes + 1; + alloc.min_offset = this.cfg.start_offset; + alloc.max_offset = this.cfg.end_offset; + alloc.in_use = this.in_use; + if (!alloc.randomize()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", "Unable to randomize policy", UVM_NONE, "t/uvm/src/reg/uvm_mem_mam.svh", 702, "", 1); + end + return null; + end + return reserve_region(alloc.start_offset, n_bytes); +endfunction: request_region +function void uvm_mem_mam::release_region(uvm_mem_region region); + if (region == null) return; + foreach (this.in_use[i]) begin + if (this.in_use[i] == region) begin + this.in_use.delete(i); + return; + end + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Attempting to release unallocated region\n", region.convert2string()}, UVM_NONE, "t/uvm/src/reg/uvm_mem_mam.svh", 721, "", 1); + end +endfunction: release_region +function void uvm_mem_mam::release_all_regions(); + in_use.delete(); +endfunction: release_all_regions +function string uvm_mem_mam::convert2string(); + convert2string = "Allocated memory regions:\n"; + foreach (this.in_use[i]) begin + $sformat(convert2string, "%s %s\n", convert2string, + this.in_use[i].convert2string()); + end +endfunction: convert2string +function uvm_mem_region uvm_mem_mam::for_each(bit reset = 0); + if (reset) this.for_each_idx = -1; + this.for_each_idx++; + if (this.for_each_idx >= this.in_use.size()) begin + return null; + end + return this.in_use[this.for_each_idx]; +endfunction: for_each +function uvm_mem uvm_mem_mam::get_memory(); + return this.memory; +endfunction: get_memory +task uvm_mem_region::write(output uvm_status_e status, + input uvm_reg_addr_t offset, + input uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_mem mem = this.parent.get_memory(); + this.fname = fname; + this.lineno = lineno; + if (mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", "Cannot use uvm_mem_region::write() on a region that was allocated by a Memory Allocation Manager that was not associated with a uvm_mem instance", UVM_NONE, "t/uvm/src/reg/uvm_mem_mam.svh", 773, "", 1); + end + status = UVM_NOT_OK; + return; + end + if (offset > this.len) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Attempting to write to an offset outside of the allocated region (%0d > %0d)", offset, this.len), UVM_NONE, "t/uvm/src/reg/uvm_mem_mam.svh", 781, "", 1); + end + status = UVM_NOT_OK; + return; + end + mem.write(status, offset + this.get_start_offset(), value, + path, map, parent, prior, extension); +endtask: write +task uvm_mem_region::read(output uvm_status_e status, + input uvm_reg_addr_t offset, + output uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_mem mem = this.parent.get_memory(); + this.fname = fname; + this.lineno = lineno; + if (mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", "Cannot use uvm_mem_region::read() on a region that was allocated by a Memory Allocation Manager that was not associated with a uvm_mem instance", UVM_NONE, "t/uvm/src/reg/uvm_mem_mam.svh", 806, "", 1); + end + status = UVM_NOT_OK; + return; + end + if (offset > this.len) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Attempting to read from an offset outside of the allocated region (%0d > %0d)", offset, this.len), UVM_NONE, "t/uvm/src/reg/uvm_mem_mam.svh", 814, "", 1); + end + status = UVM_NOT_OK; + return; + end + mem.read(status, offset + this.get_start_offset(), value, + path, map, parent, prior, extension); +endtask: read +task uvm_mem_region::burst_write(output uvm_status_e status, + input uvm_reg_addr_t offset, + input uvm_reg_data_t value[], + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_mem mem = this.parent.get_memory(); + this.fname = fname; + this.lineno = lineno; + if (mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", "Cannot use uvm_mem_region::burst_write() on a region that was allocated by a Memory Allocation Manager that was not associated with a uvm_mem instance", UVM_NONE, "t/uvm/src/reg/uvm_mem_mam.svh", 839, "", 1); + end + status = UVM_NOT_OK; + return; + end + if (offset + value.size() > this.len) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Attempting to burst-write to an offset outside of the allocated region (burst to [%0d:%0d] > mem_size %0d)", offset,offset+value.size(),this.len), UVM_NONE, "t/uvm/src/reg/uvm_mem_mam.svh", 847, "", 1); + end + status = UVM_NOT_OK; + return; + end + mem.burst_write(status, offset + get_start_offset(), value, + path, map, parent, prior, extension); +endtask: burst_write +task uvm_mem_region::burst_read(output uvm_status_e status, + input uvm_reg_addr_t offset, + output uvm_reg_data_t value[], + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_mem mem = this.parent.get_memory(); + this.fname = fname; + this.lineno = lineno; + if (mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", "Cannot use uvm_mem_region::burst_read() on a region that was allocated by a Memory Allocation Manager that was not associated with a uvm_mem instance", UVM_NONE, "t/uvm/src/reg/uvm_mem_mam.svh", 873, "", 1); + end + status = UVM_NOT_OK; + return; + end + if (offset + value.size() > this.len) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Attempting to burst-read to an offset outside of the allocated region (burst to [%0d:%0d] > mem_size %0d)", offset,offset+value.size(),this.len), UVM_NONE, "t/uvm/src/reg/uvm_mem_mam.svh", 881, "", 1); + end + status = UVM_NOT_OK; + return; + end + mem.burst_read(status, offset + get_start_offset(), value, + path, map, parent, prior, extension); +endtask: burst_read +task uvm_mem_region::poke(output uvm_status_e status, + input uvm_reg_addr_t offset, + input uvm_reg_data_t value, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_mem mem = this.parent.get_memory(); + this.fname = fname; + this.lineno = lineno; + if (mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", "Cannot use uvm_mem_region::poke() on a region that was allocated by a Memory Allocation Manager that was not associated with a uvm_mem instance", UVM_NONE, "t/uvm/src/reg/uvm_mem_mam.svh", 904, "", 1); + end + status = UVM_NOT_OK; + return; + end + if (offset > this.len) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Attempting to poke to an offset outside of the allocated region (%0d > %0d)", offset, this.len), UVM_NONE, "t/uvm/src/reg/uvm_mem_mam.svh", 912, "", 1); + end + status = UVM_NOT_OK; + return; + end + mem.poke(status, offset + this.get_start_offset(), value, "", parent, extension); +endtask: poke +task uvm_mem_region::peek(output uvm_status_e status, + input uvm_reg_addr_t offset, + output uvm_reg_data_t value, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_mem mem = this.parent.get_memory(); + this.fname = fname; + this.lineno = lineno; + if (mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", "Cannot use uvm_mem_region::peek() on a region that was allocated by a Memory Allocation Manager that was not associated with a uvm_mem instance", UVM_NONE, "t/uvm/src/reg/uvm_mem_mam.svh", 933, "", 1); + end + status = UVM_NOT_OK; + return; + end + if (offset > this.len) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Attempting to peek from an offset outside of the allocated region (%0d > %0d)", offset, this.len), UVM_NONE, "t/uvm/src/reg/uvm_mem_mam.svh", 941, "", 1); + end + status = UVM_NOT_OK; + return; + end + mem.peek(status, offset + this.get_start_offset(), value, "", parent, extension); +endtask: peek +typedef class uvm_mem_region; +typedef class uvm_mem_mam; +typedef class uvm_vreg_cbs; +class uvm_vreg extends uvm_object; + static local bit m_register_cb_uvm_vreg_cbs = uvm_callbacks#(uvm_vreg,uvm_vreg_cbs)::m_register_pair("uvm_vreg","uvm_vreg_cbs"); + local bit locked; + local uvm_reg_block parent; + local int unsigned n_bits; + local int unsigned n_used_bits; + local uvm_vreg_field fields[$]; + local uvm_mem mem; + local uvm_reg_addr_t offset; + local int unsigned incr; + local longint unsigned size; + local bit is_static; + local uvm_mem_region region; + local semaphore atomic; + local string fname; + local int lineno; + local bit read_in_progress; + local bit write_in_progress; + extern function new(string name, + int unsigned n_bits); + extern function void configure(uvm_reg_block parent, + uvm_mem mem = null, + longint unsigned size = 0, + uvm_reg_addr_t offset = 0, + int unsigned incr = 0); + extern virtual function bit implement(longint unsigned n, + uvm_mem mem = null, + uvm_reg_addr_t offset = 0, + int unsigned incr = 0); + extern virtual function uvm_mem_region allocate(longint unsigned n, + uvm_mem_mam mam, + uvm_mem_mam_policy alloc = null); + extern virtual function uvm_mem_region get_region(); + extern virtual function void release_region(); + extern virtual function void set_parent(uvm_reg_block parent); + extern function void Xlock_modelX(); + extern function void add_field(uvm_vreg_field field); + extern task XatomicX(bit on); + extern virtual function string get_full_name(); + extern virtual function uvm_reg_block get_parent(); + extern virtual function uvm_reg_block get_block(); + extern virtual function uvm_mem get_memory(); + extern virtual function int get_n_maps (); + extern function bit is_in_map (uvm_reg_map map); + extern virtual function void get_maps (ref uvm_reg_map maps[$]); + extern virtual function string get_rights(uvm_reg_map map = null); + extern virtual function string get_access(uvm_reg_map map = null); + extern virtual function int unsigned get_size(); + extern virtual function int unsigned get_n_bytes(); + extern virtual function int unsigned get_n_memlocs(); + extern virtual function int unsigned get_incr(); + extern virtual function void get_fields(ref uvm_vreg_field fields[$]); + extern virtual function uvm_vreg_field get_field_by_name(string name); + extern virtual function uvm_reg_addr_t get_offset_in_memory(longint unsigned idx); + extern virtual function uvm_reg_addr_t get_address(longint unsigned idx, + uvm_reg_map map = null); + extern virtual task write(input longint unsigned idx, + output uvm_status_e status, + input uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + extern virtual task read(input longint unsigned idx, + output uvm_status_e status, + output uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + extern virtual task poke(input longint unsigned idx, + output uvm_status_e status, + input uvm_reg_data_t value, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + extern virtual task peek(input longint unsigned idx, + output uvm_status_e status, + output uvm_reg_data_t value, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + extern function void reset(string kind = "HARD"); + virtual task pre_write(longint unsigned idx, + ref uvm_reg_data_t wdat, + ref uvm_door_e path, + ref uvm_reg_map map); + endtask: pre_write + virtual task post_write(longint unsigned idx, + uvm_reg_data_t wdat, + uvm_door_e path, + uvm_reg_map map, + ref uvm_status_e status); + endtask: post_write + virtual task pre_read(longint unsigned idx, + ref uvm_door_e path, + ref uvm_reg_map map); + endtask: pre_read + virtual task post_read(longint unsigned idx, + ref uvm_reg_data_t rdat, + input uvm_door_e path, + input uvm_reg_map map, + ref uvm_status_e status); + endtask: post_read + extern virtual function void do_print (uvm_printer printer); + extern virtual function string convert2string; + extern virtual function uvm_object clone(); + extern virtual function void do_copy (uvm_object rhs); + extern virtual function bit do_compare (uvm_object rhs, + uvm_comparer comparer); + extern virtual function void do_pack (uvm_packer packer); + extern virtual function void do_unpack (uvm_packer packer); +endclass: uvm_vreg +virtual class uvm_vreg_cbs extends uvm_callback; + typedef uvm_abstract_object_registry#(uvm_vreg_cbs,"uvm_vreg_cbs") type_id; + static function type_id get_type(); + return type_id::get(); + endfunction + virtual function uvm_object_wrapper get_object_type(); + return type_id::get(); + endfunction + static function string type_name(); + return "uvm_vreg_cbs"; + endfunction : type_name + virtual function string get_type_name(); + return "uvm_vreg_cbs"; + endfunction : get_type_name + string fname; + int lineno; + function new(string name = "uvm_reg_cbs"); + super.new(name); + endfunction + virtual task pre_write(uvm_vreg rg, + longint unsigned idx, + ref uvm_reg_data_t wdat, + ref uvm_door_e path, + ref uvm_reg_map map); + endtask: pre_write + virtual task post_write(uvm_vreg rg, + longint unsigned idx, + uvm_reg_data_t wdat, + uvm_door_e path, + uvm_reg_map map, + ref uvm_status_e status); + endtask: post_write + virtual task pre_read(uvm_vreg rg, + longint unsigned idx, + ref uvm_door_e path, + ref uvm_reg_map map); + endtask: pre_read + virtual task post_read(uvm_vreg rg, + longint unsigned idx, + ref uvm_reg_data_t rdat, + input uvm_door_e path, + input uvm_reg_map map, + ref uvm_status_e status); + endtask: post_read +endclass: uvm_vreg_cbs +typedef uvm_callbacks#(uvm_vreg, uvm_vreg_cbs) uvm_vreg_cb ; +typedef uvm_callback_iter#(uvm_vreg, uvm_vreg_cbs) uvm_vreg_cb_iter ; +function uvm_vreg::new(string name, + int unsigned n_bits); + super.new(name); + if (n_bits == 0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Virtual register \"%s\" cannot have 0 bits", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 425, "", 1); + end + n_bits = 1; + end + if (n_bits > 64) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Virtual register \"%s\" cannot have more than %0d bits (%0d)", this.get_full_name(), 64, n_bits), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 429, "", 1); + end + n_bits = 64; + end + this.n_bits = n_bits; + this.locked = 0; +endfunction: new +function void uvm_vreg::configure(uvm_reg_block parent, + uvm_mem mem = null, + longint unsigned size = 0, + uvm_reg_addr_t offset = 0, + int unsigned incr = 0); + this.parent = parent; + this.n_used_bits = 0; + if (mem != null) begin + void'(this.implement(size, mem, offset, incr)); + this.is_static = 1; + end + else begin + this.mem = null; + this.is_static = 0; + end + this.parent.add_vreg(this); + this.atomic = new(1); +endfunction: configure +function void uvm_vreg::Xlock_modelX(); + if (this.locked) return; + this.locked = 1; +endfunction: Xlock_modelX +function void uvm_vreg::add_field(uvm_vreg_field field); + int offset; + int idx; + if (this.locked) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", "Cannot add virtual field to locked virtual register model", UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 473, "", 1); + end + return; + end + if (field == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"RegModel")) + uvm_report_fatal ("RegModel", "Attempting to register NULL virtual field", UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 477, "", 1); + end + offset = field.get_lsb_pos_in_register(); + idx = -1; + foreach (this.fields[i]) begin + if (offset < this.fields[i].get_lsb_pos_in_register()) begin + int j = i; + this.fields.insert(j, field); + idx = i; + break; + end + end + if (idx < 0) begin + this.fields.push_back(field); + idx = this.fields.size()-1; + end + this.n_used_bits += field.get_n_bits(); + if (this.n_used_bits > this.n_bits) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Virtual fields use more bits (%0d) than available in virtual register \"%s\" (%0d)", this.n_used_bits, this.get_full_name(), this.n_bits), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 501, "", 1); + end + end + if (idx > 0) begin + if (this.fields[idx-1].get_lsb_pos_in_register() + + this.fields[idx-1].get_n_bits() > offset) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Field %s overlaps field %s in virtual register \"%s\"", this.fields[idx-1].get_name(), field.get_name(), this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 511, "", 1); + end + end + end + if (idx < this.fields.size()-1) begin + if (offset + field.get_n_bits() > + this.fields[idx+1].get_lsb_pos_in_register()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Field %s overlaps field %s in virtual register \"%s\"", field.get_name(), this.fields[idx+1].get_name(), this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 520, "", 1); + end + end + end +endfunction: add_field +task uvm_vreg::XatomicX(bit on); + if (on) this.atomic.get(1); + else begin + void'(this.atomic.try_get(1)); + this.atomic.put(1); + end +endtask: XatomicX +function void uvm_vreg::reset(string kind = "HARD"); + void'(this.atomic.try_get(1)); + this.atomic.put(1); +endfunction: reset +function string uvm_vreg::get_full_name(); + uvm_reg_block blk; + get_full_name = this.get_name(); + blk = this.get_block(); + if (blk == null) return get_full_name; + if (blk.get_parent() == null) return get_full_name; + get_full_name = {this.parent.get_full_name(), ".", get_full_name}; +endfunction: get_full_name +function void uvm_vreg::set_parent(uvm_reg_block parent); + this.parent = parent; +endfunction: set_parent +function uvm_reg_block uvm_vreg::get_parent(); + get_parent = this.parent; +endfunction: get_parent +function uvm_reg_block uvm_vreg::get_block(); + get_block = this.parent; +endfunction: get_block +function bit uvm_vreg::implement(longint unsigned n, + uvm_mem mem = null, + uvm_reg_addr_t offset = 0, + int unsigned incr = 0); + uvm_mem_region region; + if(n < 1) + begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Attempting to implement virtual register \"%s\" with a subscript less than one doesn't make sense",this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 579, "", 1); + end + return 0; + end + if (mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Attempting to implement virtual register \"%s\" using a NULL uvm_mem reference", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 584, "", 1); + end + return 0; + end + if (this.is_static) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Virtual register \"%s\" is static and cannot be dynamically implemented", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 589, "", 1); + end + return 0; + end + if (mem.get_block() != this.parent) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Attempting to implement virtual register \"%s\" on memory \"%s\" in a different block", this.get_full_name(), mem.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 596, "", 1); + end + return 0; + end + begin + int min_incr = (this.get_n_bytes()-1) / mem.get_n_bytes() + 1; + if (incr == 0) incr = min_incr; + if (min_incr > incr) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Virtual register \"%s\" increment is too small (%0d): Each virtual register requires at least %0d locations in memory \"%s\".", this.get_full_name(), incr, min_incr, mem.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 606, "", 1); + end + return 0; + end + end + if (offset + (n * incr) > mem.get_size()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Given Offset for Virtual register \"%s[%0d]\" is too big for memory %s@'h%0h", this.get_full_name(), n, mem.get_full_name(), offset), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 613, "", 1); + end + return 0; + end + region = mem.mam.reserve_region(offset,n*incr*mem.get_n_bytes()); + if (region == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Could not allocate a memory region for virtual register \"%s\"", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 620, "", 1); + end + return 0; + end + if (this.mem != null) begin + begin + if (uvm_report_enabled(UVM_MEDIUM,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", $sformatf("Virtual register \"%s\" is being moved re-implemented from %s@'h%0h to %s@'h%0h", this.get_full_name(), this.mem.get_full_name(), this.offset, mem.get_full_name(), offset), UVM_MEDIUM, "t/uvm/src/reg/uvm_vreg.svh", 629, "", 1); + end + this.release_region(); + end + this.region = region; + this.mem = mem; + this.size = n; + this.offset = offset; + this.incr = incr; + this.mem.Xadd_vregX(this); + return 1; +endfunction: implement +function uvm_mem_region uvm_vreg::allocate(longint unsigned n, + uvm_mem_mam mam, + uvm_mem_mam_policy alloc=null); + uvm_mem mem; + if(n < 1) + begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Attempting to implement virtual register \"%s\" with a subscript less than one doesn't make sense",this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 652, "", 1); + end + return null; + end + if (mam == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Attempting to implement virtual register \"%s\" using a NULL uvm_mem_mam reference", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 657, "", 1); + end + return null; + end + if (this.is_static) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Virtual register \"%s\" is static and cannot be dynamically allocated", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 662, "", 1); + end + return null; + end + mem = mam.get_memory(); + if (mem.get_block() != this.parent) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Attempting to allocate virtual register \"%s\" on memory \"%s\" in a different block", this.get_full_name(), mem.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 670, "", 1); + end + return null; + end + begin + int min_incr = (this.get_n_bytes()-1) / mem.get_n_bytes() + 1; + if (incr == 0) incr = min_incr; + if (min_incr < incr) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Virtual register \"%s\" increment is too small (%0d): Each virtual register requires at least %0d locations in memory \"%s\".", this.get_full_name(), incr, min_incr, mem.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 680, "", 1); + end + return null; + end + end + allocate = mam.request_region(n*incr*mem.get_n_bytes(), alloc); + if (allocate == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Could not allocate a memory region for virtual register \"%s\"", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 688, "", 1); + end + return null; + end + if (this.mem != null) begin + begin + if (uvm_report_enabled(UVM_MEDIUM,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", $sformatf("Virtual register \"%s\" is being moved from %s@'h%0h to %s@'h%0h", this.get_full_name(), this.mem.get_full_name(), this.offset, mem.get_full_name(), allocate.get_start_offset()), UVM_MEDIUM, "t/uvm/src/reg/uvm_vreg.svh", 698, "", 1); + end + this.release_region(); + end + this.region = allocate; + this.mem = mam.get_memory(); + this.offset = allocate.get_start_offset(); + this.size = n; + this.incr = incr; + this.mem.Xadd_vregX(this); +endfunction: allocate +function uvm_mem_region uvm_vreg::get_region(); + return this.region; +endfunction: get_region +function void uvm_vreg::release_region(); + if (this.is_static) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Virtual register \"%s\" is static and cannot be dynamically released", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 721, "", 1); + end + return; + end + if (this.mem != null) + this.mem.Xdelete_vregX(this); + if (this.region != null) begin + this.region.release_region(); + end + this.region = null; + this.mem = null; + this.size = 0; + this.offset = 0; + this.reset(); +endfunction: release_region +function uvm_mem uvm_vreg::get_memory(); + return this.mem; +endfunction: get_memory +function uvm_reg_addr_t uvm_vreg::get_offset_in_memory(longint unsigned idx); + if (this.mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot call uvm_vreg::get_offset_in_memory() on unimplemented virtual register \"%s\"", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 749, "", 1); + end + return 0; + end + return this.offset + idx * this.incr; +endfunction +function uvm_reg_addr_t uvm_vreg::get_address(longint unsigned idx, + uvm_reg_map map = null); + if (this.mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot get address of of unimplemented virtual register \"%s\".", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 760, "", 1); + end + return 0; + end + return this.mem.get_address(this.get_offset_in_memory(idx), map); +endfunction: get_address +function int unsigned uvm_vreg::get_size(); + if (this.size == 0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot call uvm_vreg::get_size() on unimplemented virtual register \"%s\"", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 771, "", 1); + end + return 0; + end + return this.size; +endfunction: get_size +function int unsigned uvm_vreg::get_n_bytes(); + return ((this.n_bits-1) / 8) + 1; +endfunction: get_n_bytes +function int unsigned uvm_vreg::get_n_memlocs(); + if (this.mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot call uvm_vreg::get_n_memlocs() on unimplemented virtual register \"%s\"", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 787, "", 1); + end + return 0; + end + return (this.get_n_bytes()-1) / this.mem.get_n_bytes() + 1; +endfunction: get_n_memlocs +function int unsigned uvm_vreg::get_incr(); + if (this.incr == 0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot call uvm_vreg::get_incr() on unimplemented virtual register \"%s\"", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 798, "", 1); + end + return 0; + end + return this.incr; +endfunction: get_incr +function int uvm_vreg::get_n_maps(); + if (this.mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot call uvm_vreg::get_n_maps() on unimplemented virtual register \"%s\"", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 809, "", 1); + end + return 0; + end + return this.mem.get_n_maps(); +endfunction: get_n_maps +function void uvm_vreg::get_maps(ref uvm_reg_map maps[$]); + if (this.mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot call uvm_vreg::get_maps() on unimplemented virtual register \"%s\"", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 820, "", 1); + end + return; + end + this.mem.get_maps(maps); +endfunction: get_maps +function bit uvm_vreg::is_in_map(uvm_reg_map map); + if (this.mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot call uvm_vreg::is_in_map() on unimplemented virtual register \"%s\"", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 831, "", 1); + end + return 0; + end + return this.mem.is_in_map(map); +endfunction +function string uvm_vreg::get_access(uvm_reg_map map = null); + if (this.mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot call uvm_vreg::get_rights() on unimplemented virtual register \"%s\"", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 842, "", 1); + end + return "RW"; + end + return this.mem.get_access(map); +endfunction: get_access +function string uvm_vreg::get_rights(uvm_reg_map map = null); + if (this.mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot call uvm_vreg::get_rights() on unimplemented virtual register \"%s\"", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 853, "", 1); + end + return "RW"; + end + return this.mem.get_rights(map); +endfunction: get_rights +function void uvm_vreg::get_fields(ref uvm_vreg_field fields[$]); + foreach(this.fields[i]) + fields.push_back(this.fields[i]); +endfunction: get_fields +function uvm_vreg_field uvm_vreg::get_field_by_name(string name); + foreach (this.fields[i]) begin + if (this.fields[i].get_name() == name) begin + return this.fields[i]; + end + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", $sformatf("Unable to locate field \"%s\" in virtual register \"%s\".", name, this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 874, "", 1); + end + get_field_by_name = null; +endfunction: get_field_by_name +task uvm_vreg::write(input longint unsigned idx, + output uvm_status_e status, + input uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_vreg_cb_iter cbs = new(this); + uvm_reg_addr_t addr; + uvm_reg_data_t tmp; + uvm_reg_data_t msk; + int lsb; + this.write_in_progress = 1'b1; + this.fname = fname; + this.lineno = lineno; + if (this.mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot write to unimplemented virtual register \"%s\".", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 899, "", 1); + end + status = UVM_NOT_OK; + return; + end + if (path == UVM_DEFAULT_DOOR) + path = this.parent.get_default_door(); + foreach (fields[i]) begin + uvm_vreg_field_cb_iter cbs = new(fields[i]); + uvm_vreg_field f = fields[i]; + lsb = f.get_lsb_pos_in_register(); + msk = ((1<> lsb; + f.pre_write(idx, tmp, path, map); + for (uvm_vreg_field_cbs cb = cbs.first(); cb != null; + cb = cbs.next()) begin + cb.fname = this.fname; + cb.lineno = this.lineno; + cb.pre_write(f, idx, tmp, path, map); + end + value = (value & ~msk) | (tmp << lsb); + end + this.pre_write(idx, value, path, map); + for (uvm_vreg_cbs cb = cbs.first(); cb != null; + cb = cbs.next()) begin + cb.fname = this.fname; + cb.lineno = this.lineno; + cb.pre_write(this, idx, value, path, map); + end + addr = this.offset + (idx * this.incr); + lsb = 0; + status = UVM_IS_OK; + for (int i = 0; i < this.get_n_memlocs(); i++) begin + uvm_status_e s; + msk = ((1<<(this.mem.get_n_bytes()*8))-1) << lsb; + tmp = (value & msk) >> lsb; + this.mem.write(s, addr + i, tmp, path, map , parent, , extension, fname, lineno); + if (s != UVM_IS_OK && s != UVM_HAS_X) status = s; + lsb += this.mem.get_n_bytes() * 8; + end + for (uvm_vreg_cbs cb = cbs.first(); cb != null; + cb = cbs.next()) begin + cb.fname = this.fname; + cb.lineno = this.lineno; + cb.post_write(this, idx, value, path, map, status); + end + this.post_write(idx, value, path, map, status); + foreach (fields[i]) begin + uvm_vreg_field_cb_iter cbs = new(fields[i]); + uvm_vreg_field f = fields[i]; + lsb = f.get_lsb_pos_in_register(); + msk = ((1<> lsb; + for (uvm_vreg_field_cbs cb = cbs.first(); cb != null; + cb = cbs.next()) begin + cb.fname = this.fname; + cb.lineno = this.lineno; + cb.post_write(f, idx, tmp, path, map, status); + end + f.post_write(idx, tmp, path, map, status); + value = (value & ~msk) | (tmp << lsb); + end + begin + if (uvm_report_enabled(UVM_MEDIUM,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", $sformatf("Wrote virtual register \"%s\"[%0d] via %s with: 'h%h", this.get_full_name(), idx, (path == UVM_FRONTDOOR) ? "frontdoor" : "backdoor", value), UVM_MEDIUM, "t/uvm/src/reg/uvm_vreg.svh", 976, "", 1); + end + this.write_in_progress = 1'b0; + this.fname = ""; + this.lineno = 0; +endtask: write +task uvm_vreg::read(input longint unsigned idx, + output uvm_status_e status, + output uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_vreg_cb_iter cbs = new(this); + uvm_reg_addr_t addr; + uvm_reg_data_t tmp; + uvm_reg_data_t msk; + int lsb; + this.read_in_progress = 1'b1; + this.fname = fname; + this.lineno = lineno; + if (this.mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot read from unimplemented virtual register \"%s\".", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 1005, "", 1); + end + status = UVM_NOT_OK; + return; + end + if (path == UVM_DEFAULT_DOOR) + path = this.parent.get_default_door(); + foreach (fields[i]) begin + uvm_vreg_field_cb_iter cbs = new(fields[i]); + uvm_vreg_field f = fields[i]; + f.pre_read(idx, path, map); + for (uvm_vreg_field_cbs cb = cbs.first(); cb != null; + cb = cbs.next()) begin + cb.fname = this.fname; + cb.lineno = this.lineno; + cb.pre_read(f, idx, path, map); + end + end + this.pre_read(idx, path, map); + for (uvm_vreg_cbs cb = cbs.first(); cb != null; + cb = cbs.next()) begin + cb.fname = this.fname; + cb.lineno = this.lineno; + cb.pre_read(this, idx, path, map); + end + addr = this.offset + (idx * this.incr); + lsb = 0; + value = 0; + status = UVM_IS_OK; + for (int i = 0; i < this.get_n_memlocs(); i++) begin + uvm_status_e s; + this.mem.read(s, addr + i, tmp, path, map, parent, , extension, fname, lineno); + if (s != UVM_IS_OK && s != UVM_HAS_X) status = s; + value |= tmp << lsb; + lsb += this.mem.get_n_bytes() * 8; + end + for (uvm_vreg_cbs cb = cbs.first(); cb != null; + cb = cbs.next()) begin + cb.fname = this.fname; + cb.lineno = this.lineno; + cb.post_read(this, idx, value, path, map, status); + end + this.post_read(idx, value, path, map, status); + foreach (fields[i]) begin + uvm_vreg_field_cb_iter cbs = new(fields[i]); + uvm_vreg_field f = fields[i]; + lsb = f.get_lsb_pos_in_register(); + msk = ((1<> lsb; + for (uvm_vreg_field_cbs cb = cbs.first(); cb != null; + cb = cbs.next()) begin + cb.fname = this.fname; + cb.lineno = this.lineno; + cb.post_read(f, idx, tmp, path, map, status); + end + f.post_read(idx, tmp, path, map, status); + value = (value & ~msk) | (tmp << lsb); + end + begin + if (uvm_report_enabled(UVM_MEDIUM,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", $sformatf("Read virtual register \"%s\"[%0d] via %s: 'h%h", this.get_full_name(), idx, (path == UVM_FRONTDOOR) ? "frontdoor" : "backdoor", value), UVM_MEDIUM, "t/uvm/src/reg/uvm_vreg.svh", 1078, "", 1); + end + this.read_in_progress = 1'b0; + this.fname = ""; + this.lineno = 0; +endtask: read +task uvm_vreg::poke(input longint unsigned idx, + output uvm_status_e status, + input uvm_reg_data_t value, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_addr_t addr; + uvm_reg_data_t tmp; + uvm_reg_data_t msk; + int lsb; + this.fname = fname; + this.lineno = lineno; + if (this.mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot poke in unimplemented virtual register \"%s\".", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 1101, "", 1); + end + status = UVM_NOT_OK; + return; + end + addr = this.offset + (idx * this.incr); + lsb = 0; + status = UVM_IS_OK; + for (int i = 0; i < this.get_n_memlocs(); i++) begin + uvm_status_e s; + msk = ((1<<(this.mem.get_n_bytes() * 8))-1) << lsb; + tmp = (value & msk) >> lsb; + this.mem.poke(status, addr + i, tmp, "", parent, extension, fname, lineno); + if (s != UVM_IS_OK && s != UVM_HAS_X) status = s; + lsb += this.mem.get_n_bytes() * 8; + end + begin + if (uvm_report_enabled(UVM_MEDIUM,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", $sformatf("Poked virtual register \"%s\"[%0d] with: 'h%h", this.get_full_name(), idx, value), UVM_MEDIUM, "t/uvm/src/reg/uvm_vreg.svh", 1123, "", 1); + end + this.fname = ""; + this.lineno = 0; +endtask: poke +task uvm_vreg::peek(input longint unsigned idx, + output uvm_status_e status, + output uvm_reg_data_t value, + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_addr_t addr; + uvm_reg_data_t tmp; + uvm_reg_data_t msk; + int lsb; + this.fname = fname; + this.lineno = lineno; + if (this.mem == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot peek in from unimplemented virtual register \"%s\".", this.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_vreg.svh", 1145, "", 1); + end + status = UVM_NOT_OK; + return; + end + addr = this.offset + (idx * this.incr); + lsb = 0; + value = 0; + status = UVM_IS_OK; + for (int i = 0; i < this.get_n_memlocs(); i++) begin + uvm_status_e s; + this.mem.peek(status, addr + i, tmp, "", parent, extension, fname, lineno); + if (s != UVM_IS_OK && s != UVM_HAS_X) status = s; + value |= tmp << lsb; + lsb += this.mem.get_n_bytes() * 8; + end + begin + if (uvm_report_enabled(UVM_MEDIUM,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", $sformatf("Peeked virtual register \"%s\"[%0d]: 'h%h", this.get_full_name(), idx, value), UVM_MEDIUM, "t/uvm/src/reg/uvm_vreg.svh", 1166, "", 1); + end + this.fname = ""; + this.lineno = 0; +endtask: peek +function void uvm_vreg::do_print (uvm_printer printer); + super.do_print(printer); + printer.print_generic("initiator", parent.get_type_name(), -1, convert2string()); +endfunction +function string uvm_vreg::convert2string(); + string res_str; + string t_str; + bit with_debug_info; + $sformat(convert2string, "Virtual register %s -- ", + this.get_full_name()); + if (this.size == 0) + $sformat(convert2string, "%sunimplemented", convert2string); + else begin + uvm_reg_map maps[$]; + mem.get_maps(maps); + $sformat(convert2string, "%s[%0d] in %0s['h%0h+'h%0h]\n", convert2string, + this.size, this.mem.get_full_name(), this.offset, this.incr); + foreach (maps[i]) begin + uvm_reg_addr_t addr0 = this.get_address(0, maps[i]); + $sformat(convert2string, " Address in map '%s' -- @'h%0h+%0h", + maps[i].get_full_name(), addr0, this.get_address(1, maps[i]) - addr0); + end + end + foreach(this.fields[i]) begin + $sformat(convert2string, "%s\n%s", convert2string, + this.fields[i].convert2string()); + end +endfunction: convert2string +function uvm_object uvm_vreg::clone(); + return null; +endfunction +function void uvm_vreg::do_copy (uvm_object rhs); +endfunction +function bit uvm_vreg::do_compare (uvm_object rhs, + uvm_comparer comparer); + return 0; +endfunction +function void uvm_vreg::do_pack (uvm_packer packer); +endfunction +function void uvm_vreg::do_unpack (uvm_packer packer); +endfunction +class uvm_mem extends uvm_object; + typedef enum {UNKNOWNS, ZEROES, ONES, ADDRESS, VALUE, INCR, DECR} init_e; + local bit m_locked; + local bit m_read_in_progress; + local bit m_write_in_progress; + local string m_access; + local longint unsigned m_size; + local uvm_reg_block m_parent; + local bit m_maps[uvm_reg_map]; + local int unsigned m_n_bits; + local uvm_reg_backdoor m_backdoor; + local bit m_is_powered_down; + local int m_has_cover; + local int m_cover_on; + local string m_fname; + local int m_lineno; + local bit m_vregs[uvm_vreg]; + local uvm_object_string_pool + #(uvm_queue #(uvm_hdl_path_concat)) m_hdl_paths_pool; + local static int unsigned m_max_size; + extern function new (string name, + longint unsigned size, + int unsigned n_bits, + string access = "RW", + int has_coverage = UVM_NO_COVERAGE); + extern function void configure (uvm_reg_block parent, + string hdl_path = ""); + extern virtual function void set_offset (uvm_reg_map map, + uvm_reg_addr_t offset, + bit unmapped = 0); + extern virtual function void set_parent(uvm_reg_block parent); + extern function void add_map(uvm_reg_map map); + extern function void Xlock_modelX(); + extern function void Xadd_vregX(uvm_vreg vreg); + extern function void Xdelete_vregX(uvm_vreg vreg); + uvm_mem_mam mam; + extern virtual function string get_full_name(); + extern virtual function uvm_reg_block get_parent (); + extern virtual function uvm_reg_block get_block (); + extern virtual function int get_n_maps (); + extern function bit is_in_map (uvm_reg_map map); + extern virtual function void get_maps (ref uvm_reg_map maps[$]); + extern function uvm_reg_map get_local_map (uvm_reg_map map); + extern function uvm_reg_map get_default_map (); + extern virtual function string get_rights (uvm_reg_map map = null); + extern virtual function string get_access(uvm_reg_map map = null); + extern function longint unsigned get_size(); + extern function int unsigned get_n_bytes(); + extern function int unsigned get_n_bits(); + extern static function int unsigned get_max_size(); + extern virtual function void get_virtual_registers(ref uvm_vreg regs[$]); + extern virtual function void get_virtual_fields(ref uvm_vreg_field fields[$]); + extern virtual function uvm_vreg get_vreg_by_name(string name); + extern virtual function uvm_vreg_field get_vfield_by_name(string name); + extern virtual function uvm_vreg get_vreg_by_offset(uvm_reg_addr_t offset, + uvm_reg_map map = null); + extern virtual function uvm_reg_addr_t get_offset (uvm_reg_addr_t offset = 0, + uvm_reg_map map = null); + extern virtual function uvm_reg_addr_t get_address(uvm_reg_addr_t offset = 0, + uvm_reg_map map = null); + extern virtual function int get_addresses(uvm_reg_addr_t offset = 0, + uvm_reg_map map=null, + ref uvm_reg_addr_t addr[]); + extern virtual task write(output uvm_status_e status, + input uvm_reg_addr_t offset, + input uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + extern virtual task read(output uvm_status_e status, + input uvm_reg_addr_t offset, + output uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + extern virtual task burst_write(output uvm_status_e status, + input uvm_reg_addr_t offset, + input uvm_reg_data_t value[], + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + extern virtual task burst_read(output uvm_status_e status, + input uvm_reg_addr_t offset, + ref uvm_reg_data_t value[], + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + extern virtual task poke(output uvm_status_e status, + input uvm_reg_addr_t offset, + input uvm_reg_data_t value, + input string kind = "", + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + extern virtual task peek(output uvm_status_e status, + input uvm_reg_addr_t offset, + output uvm_reg_data_t value, + input string kind = "", + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + extern protected function bit Xcheck_accessX (input uvm_reg_item rw, + output uvm_reg_map_info map_info); + extern virtual task do_write (uvm_reg_item rw); + extern virtual task do_read (uvm_reg_item rw); + extern function void set_frontdoor(uvm_reg_frontdoor ftdr, + uvm_reg_map map = null, + string fname = "", + int lineno = 0); + extern function uvm_reg_frontdoor get_frontdoor(uvm_reg_map map = null); + extern function void set_backdoor (uvm_reg_backdoor bkdr, + string fname = "", + int lineno = 0); + extern function uvm_reg_backdoor get_backdoor(bit inherited = 1); + extern function void clear_hdl_path (string kind = "RTL"); + extern function void add_hdl_path (uvm_hdl_path_slice slices[], + string kind = "RTL"); + extern function void add_hdl_path_slice(string name, + int offset, + int size, + bit first = 0, + string kind = "RTL"); + extern function bit has_hdl_path (string kind = ""); + extern function void get_hdl_path (ref uvm_hdl_path_concat paths[$], + input string kind = ""); + extern function void get_full_hdl_path (ref uvm_hdl_path_concat paths[$], + input string kind = "", + input string separator = "."); + extern function void get_hdl_path_kinds (ref string kinds[$]); + extern virtual protected task backdoor_read(uvm_reg_item rw); + extern virtual task backdoor_write(uvm_reg_item rw); + extern virtual function uvm_status_e backdoor_read_func(uvm_reg_item rw); + static local bit m_register_cb_uvm_reg_cbs = uvm_callbacks#(uvm_mem,uvm_reg_cbs)::m_register_pair("uvm_mem","uvm_reg_cbs"); + virtual task pre_write(uvm_reg_item rw); endtask + virtual task post_write(uvm_reg_item rw); endtask + virtual task pre_read(uvm_reg_item rw); endtask + virtual task post_read(uvm_reg_item rw); endtask + extern protected function uvm_reg_cvr_t build_coverage(uvm_reg_cvr_t models); + extern virtual protected function void add_coverage(uvm_reg_cvr_t models); + extern virtual function bit has_coverage(uvm_reg_cvr_t models); + extern virtual function uvm_reg_cvr_t set_coverage(uvm_reg_cvr_t is_on); + extern virtual function bit get_coverage(uvm_reg_cvr_t is_on); + protected virtual function void sample(uvm_reg_addr_t offset, + bit is_read, + uvm_reg_map map); + endfunction + function void XsampleX(uvm_reg_addr_t addr, + bit is_read, + uvm_reg_map map); + sample(addr, is_read, map); + endfunction + extern virtual function void do_print (uvm_printer printer); + extern virtual function string convert2string(); + extern virtual function uvm_object clone(); + extern virtual function void do_copy (uvm_object rhs); + extern virtual function bit do_compare (uvm_object rhs, + uvm_comparer comparer); + extern virtual function void do_pack (uvm_packer packer); + extern virtual function void do_unpack (uvm_packer packer); +endclass: uvm_mem +function uvm_mem::new (string name, + longint unsigned size, + int unsigned n_bits, + string access = "RW", + int has_coverage = UVM_NO_COVERAGE); + super.new(name); + m_locked = 0; + if (n_bits == 0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Memory '",get_full_name(),"' cannot have 0 bits"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 537, "", 1); + end + n_bits = 1; + end + m_size = size; + m_n_bits = n_bits; + m_backdoor = null; + m_access = access.toupper(); + m_has_cover = has_coverage; + m_hdl_paths_pool = new("hdl_paths"); + if (n_bits > m_max_size) + m_max_size = n_bits; +endfunction: new +function void uvm_mem::configure(uvm_reg_block parent, + string hdl_path=""); + if (parent == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"REG/NULL_PARENT")) + uvm_report_fatal ("REG/NULL_PARENT", "configure: parent argument is null", UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 559, "", 1); + end + m_parent = parent; + if (m_access != "RW" && m_access != "RO") begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Memory '",get_full_name(),"' can only be RW or RO"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 564, "", 1); + end + m_access = "RW"; + end + begin + uvm_mem_mam_cfg cfg = new; + cfg.n_bytes = ((m_n_bits-1) / 8) + 1; + cfg.start_offset = 0; + cfg.end_offset = m_size-1; + cfg.mode = uvm_mem_mam::GREEDY; + cfg.locality = uvm_mem_mam::BROAD; + mam = new(get_full_name(), cfg, this); + end + m_parent.add_mem(this); + if (hdl_path != "") add_hdl_path_slice(hdl_path, -1, -1); +endfunction: configure +function void uvm_mem::set_offset (uvm_reg_map map, + uvm_reg_addr_t offset, + bit unmapped = 0); + uvm_reg_map orig_map = map; + if (m_maps.num() > 1 && map == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"set_offset requires a non-null map when memory '", get_full_name(),"' belongs to more than one map."}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 597, "", 1); + end + return; + end + map = get_local_map(map); + if (map == null) + return; + map.m_set_mem_offset(this, offset, unmapped); +endfunction +function void uvm_mem::add_map(uvm_reg_map map); + m_maps[map] = 1; +endfunction +function void uvm_mem::Xlock_modelX(); + m_locked = 1; +endfunction: Xlock_modelX +function string uvm_mem::get_full_name(); + if (m_parent == null) + return get_name(); + return {m_parent.get_full_name(), ".", get_name()}; +endfunction: get_full_name +function uvm_reg_block uvm_mem::get_block(); + return m_parent; +endfunction: get_block +function int uvm_mem::get_n_maps(); + return m_maps.num(); +endfunction: get_n_maps +function void uvm_mem::get_maps(ref uvm_reg_map maps[$]); + foreach (m_maps[map]) + maps.push_back(map); +endfunction +function bit uvm_mem::is_in_map(uvm_reg_map map); + if (m_maps.exists(map)) + return 1; + foreach (m_maps[l]) begin + uvm_reg_map local_map=l; + uvm_reg_map parent_map = local_map.get_parent_map(); + while (parent_map != null) begin + if (parent_map == map) + return 1; + parent_map = parent_map.get_parent_map(); + end + end + return 0; +endfunction +function uvm_reg_map uvm_mem::get_local_map(uvm_reg_map map); + if (map == null) + return get_default_map(); + if (m_maps.exists(map)) + return map; + foreach (m_maps[l]) begin + uvm_reg_map local_map = l; + uvm_reg_map parent_map = local_map.get_parent_map(); + while (parent_map != null) begin + if (parent_map == map) + return local_map; + parent_map = parent_map.get_parent_map(); + end + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Memory '",get_full_name(),"' is not contained within map '",map.get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 694, "", 1); + end + return null; +endfunction +function uvm_reg_map uvm_mem::get_default_map(); + if (m_maps.num() == 0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Memory '",get_full_name(),"' is not registered with any map"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 706, "", 1); + end + return null; + end + if (m_maps.num() == 1) begin + void'(m_maps.first(get_default_map)); + end + foreach (m_maps[l]) begin + uvm_reg_map map = l; + uvm_reg_block blk = map.get_parent(); + uvm_reg_map default_map = blk.get_default_map(); + if (default_map != null) begin + uvm_reg_map local_map = get_local_map(default_map); + if (local_map != null) + return local_map; + end + end + void'(m_maps.first(get_default_map)); +endfunction +function string uvm_mem::get_access(uvm_reg_map map = null); + get_access = m_access; + if (get_n_maps() == 1) return get_access; + map = get_local_map(map); + if (map == null) return get_access; + case (get_rights(map)) + "RW": + return get_access; + "RO": + case (get_access) + "RW", "RO": get_access = "RO"; + "WO": + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"WO memory '",get_full_name(), "' restricted to RO in map '",map.get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 754, "", 1); + end + default: + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Memory '",get_full_name(), "' has invalid access mode, '",get_access,"'"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 757, "", 1); + end + endcase + "WO": + case (get_access) + "RW", "WO": get_access = "WO"; + "RO": + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"RO memory '",get_full_name(), "' restricted to WO in map '",map.get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 765, "", 1); + end + default: + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Memory '",get_full_name(), "' has invalid access mode, '",get_access,"'"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 768, "", 1); + end + endcase + default: + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Shared memory '",get_full_name(), "' is not shared in map '",map.get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 772, "", 1); + end + endcase +endfunction: get_access +function string uvm_mem::get_rights(uvm_reg_map map = null); + uvm_reg_map_info info; + if (m_maps.num() <= 1) begin + return "RW"; + end + map = get_local_map(map); + if (map == null) + return "RW"; + info = map.get_mem_map_info(this); + return info.rights; +endfunction: get_rights +function uvm_reg_addr_t uvm_mem::get_offset(uvm_reg_addr_t offset = 0, + uvm_reg_map map = null); + uvm_reg_map_info map_info; + uvm_reg_map orig_map = map; + map = get_local_map(map); + if (map == null) + return -1; + map_info = map.get_mem_map_info(this); + if (map_info.unmapped) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Memory '",get_name(), "' is unmapped in map '", ((orig_map == null) ? map.get_full_name() : orig_map.get_full_name()),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 817, "", 1); + end + return -1; + end + return map_info.offset; +endfunction: get_offset +function void uvm_mem::get_virtual_registers(ref uvm_vreg regs[$]); + foreach (m_vregs[vreg]) + regs.push_back(vreg); +endfunction +function void uvm_mem::get_virtual_fields(ref uvm_vreg_field fields[$]); + foreach (m_vregs[l]) + begin + uvm_vreg vreg = l; + vreg.get_fields(fields); + end +endfunction: get_virtual_fields +function uvm_vreg_field uvm_mem::get_vfield_by_name(string name); + uvm_vreg_field vfields[$]; + get_virtual_fields(vfields); + foreach (vfields[i]) + if (vfields[i].get_name() == name) + return vfields[i]; + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Unable to find virtual field '",name, "' in memory '",get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 860, "", 1); + end + return null; +endfunction: get_vfield_by_name +function uvm_vreg uvm_mem::get_vreg_by_name(string name); + foreach (m_vregs[l]) + begin + uvm_vreg vreg = l; + if (vreg.get_name() == name) + return vreg; + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Unable to find virtual register '",name, "' in memory '",get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 877, "", 1); + end + return null; +endfunction: get_vreg_by_name +function uvm_vreg uvm_mem::get_vreg_by_offset(uvm_reg_addr_t offset, + uvm_reg_map map = null); + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", "uvm_mem::get_vreg_by_offset() not yet implemented", UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 887, "", 1); + end + return null; +endfunction: get_vreg_by_offset +function int uvm_mem::get_addresses(uvm_reg_addr_t offset = 0, + uvm_reg_map map=null, + ref uvm_reg_addr_t addr[]); + uvm_reg_map_info map_info; + uvm_reg_map system_map; + uvm_reg_map orig_map = map; + map = get_local_map(map); + if (map == null) + return 0; + map_info = map.get_mem_map_info(this); + if (map_info.unmapped) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Memory '",get_name(), "' is unmapped in map '", ((orig_map == null) ? map.get_full_name() : orig_map.get_full_name()),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 913, "", 1); + end + return 0; + end + addr = map_info.addr; + foreach (addr[i]) + addr[i] = addr[i] + map_info.mem_range.stride * offset; + return map.get_n_bytes(); +endfunction +function uvm_reg_addr_t uvm_mem::get_address(uvm_reg_addr_t offset = 0, + uvm_reg_map map = null); + uvm_reg_addr_t addr[]; + void'(get_addresses(offset, map, addr)); + return addr[0]; +endfunction +function longint unsigned uvm_mem::get_size(); + return m_size; +endfunction: get_size +function int unsigned uvm_mem::get_n_bits(); + return m_n_bits; +endfunction: get_n_bits +function int unsigned uvm_mem::get_max_size(); + return m_max_size; +endfunction: get_max_size +function int unsigned uvm_mem::get_n_bytes(); + return (m_n_bits - 1) / 8 + 1; +endfunction: get_n_bytes +function uvm_reg_cvr_t uvm_mem::build_coverage(uvm_reg_cvr_t models); + build_coverage = UVM_NO_COVERAGE; + void'(uvm_reg_cvr_rsrc_db::read_by_name({"uvm_reg::", get_full_name()}, + "include_coverage", + build_coverage, this)); + return build_coverage & models; +endfunction: build_coverage +function void uvm_mem::add_coverage(uvm_reg_cvr_t models); + m_has_cover |= models; +endfunction: add_coverage +function bit uvm_mem::has_coverage(uvm_reg_cvr_t models); + return ((m_has_cover & models) == models); +endfunction: has_coverage +function uvm_reg_cvr_t uvm_mem::set_coverage(uvm_reg_cvr_t is_on); + if (is_on == uvm_reg_cvr_t'(UVM_NO_COVERAGE)) begin + m_cover_on = is_on; + return m_cover_on; + end + m_cover_on = m_has_cover & is_on; + return m_cover_on; +endfunction: set_coverage +function bit uvm_mem::get_coverage(uvm_reg_cvr_t is_on); + if (has_coverage(is_on) == 0) return 0; + return ((m_cover_on & is_on) == is_on); +endfunction: get_coverage +task uvm_mem::write(output uvm_status_e status, + input uvm_reg_addr_t offset, + input uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_item rw = uvm_reg_item::type_id_create("mem_write",,get_full_name()); + rw.element = this; + rw.element_kind = UVM_MEM; + rw.kind = UVM_WRITE; + rw.offset = offset; + rw.value[0] = value; + rw.path = path; + rw.map = map; + rw.parent = parent; + rw.prior = prior; + rw.extension = extension; + rw.fname = fname; + rw.lineno = lineno; + do_write(rw); + status = rw.status; +endtask: write +task uvm_mem::read(output uvm_status_e status, + input uvm_reg_addr_t offset, + output uvm_reg_data_t value, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_item rw; + rw = uvm_reg_item::type_id_create("mem_read",,get_full_name()); + rw.element = this; + rw.element_kind = UVM_MEM; + rw.kind = UVM_READ; + rw.value[0] = 0; + rw.offset = offset; + rw.path = path; + rw.map = map; + rw.parent = parent; + rw.prior = prior; + rw.extension = extension; + rw.fname = fname; + rw.lineno = lineno; + do_read(rw); + status = rw.status; + value = rw.value[0]; +endtask: read +task uvm_mem::burst_write(output uvm_status_e status, + input uvm_reg_addr_t offset, + input uvm_reg_data_t value[], + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_item rw; + rw = uvm_reg_item::type_id_create("mem_burst_write",,get_full_name()); + rw.element = this; + rw.element_kind = UVM_MEM; + rw.kind = UVM_BURST_WRITE; + rw.offset = offset; + rw.value = value; + rw.path = path; + rw.map = map; + rw.parent = parent; + rw.prior = prior; + rw.extension = extension; + rw.fname = fname; + rw.lineno = lineno; + do_write(rw); + status = rw.status; +endtask: burst_write +task uvm_mem::burst_read(output uvm_status_e status, + input uvm_reg_addr_t offset, + ref uvm_reg_data_t value[], + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_item rw; + rw = uvm_reg_item::type_id_create("mem_burst_read",,get_full_name()); + rw.element = this; + rw.element_kind = UVM_MEM; + rw.kind = UVM_BURST_READ; + rw.offset = offset; + rw.value = value; + rw.path = path; + rw.map = map; + rw.parent = parent; + rw.prior = prior; + rw.extension = extension; + rw.fname = fname; + rw.lineno = lineno; + do_read(rw); + status = rw.status; + value = rw.value; +endtask: burst_read +task uvm_mem::do_write(uvm_reg_item rw); + uvm_mem_cb_iter cbs = new(this); + uvm_reg_map_info map_info; + m_fname = rw.fname; + m_lineno = rw.lineno; + if (!Xcheck_accessX(rw, map_info)) + return; + m_write_in_progress = 1'b1; + rw.status = UVM_IS_OK; + pre_write(rw); + for (uvm_reg_cbs cb=cbs.first(); cb!=null; cb=cbs.next()) + cb.pre_write(rw); + if (rw.status != UVM_IS_OK) begin + m_write_in_progress = 1'b0; + return; + end + rw.status = UVM_NOT_OK; + if (rw.path == UVM_FRONTDOOR) begin + uvm_reg_map system_map = rw.local_map.get_root_map(); + if (map_info.frontdoor != null) begin + uvm_reg_frontdoor fd = map_info.frontdoor; + fd.rw_info = rw; + if (fd.sequencer == null) + fd.sequencer = system_map.get_sequencer(); + fd.start(fd.sequencer, rw.parent); + end + else begin + rw.local_map.do_write(rw); + end + if (rw.status != UVM_NOT_OK) + for (uvm_reg_addr_t idx = rw.offset; + idx <= rw.offset + rw.value.size(); + idx++) begin + XsampleX(map_info.mem_range.stride * idx, 0, rw.map); + m_parent.XsampleX(map_info.offset + + (map_info.mem_range.stride * idx), + 0, rw.map); + end + end + else begin + if (get_access(rw.map) inside {"RW", "WO"}) begin + uvm_reg_backdoor bkdr = get_backdoor(); + if (bkdr != null) + bkdr.write(rw); + else + backdoor_write(rw); + end + else + rw.status = UVM_NOT_OK; + end + post_write(rw); + for (uvm_reg_cbs cb=cbs.first(); cb!=null; cb=cbs.next()) + cb.post_write(rw); + if (uvm_report_enabled(UVM_HIGH, UVM_INFO, "RegModel")) begin + string path_s,value_s,pre_s,range_s; + if (rw.path == UVM_FRONTDOOR) + path_s = (map_info.frontdoor != null) ? "user frontdoor" : + {"map ",rw.map.get_full_name()}; + else + path_s = (get_backdoor() != null) ? "user backdoor" : "DPI backdoor"; + if (rw.value.size() > 1) begin + value_s = "='{"; + pre_s = "Burst "; + foreach (rw.value[i]) + value_s = {value_s,$sformatf("%0h,",rw.value[i])}; + value_s[value_s.len()-1]="}"; + range_s = $sformatf("[%0d:%0d]",rw.offset,rw.offset+rw.value.size()); + end + else begin + value_s = $sformatf("=%0h",rw.value[0]); + range_s = $sformatf("[%0d]",rw.offset); + end + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", {pre_s,"Wrote memory via ",path_s,": ", get_full_name(),range_s,value_s}, UVM_HIGH, "t/uvm/src/reg/uvm_mem.svh", 1281, "", 1); + end + end + m_write_in_progress = 1'b0; +endtask: do_write +task uvm_mem::do_read(uvm_reg_item rw); + uvm_mem_cb_iter cbs = new(this); + uvm_reg_map_info map_info; + m_fname = rw.fname; + m_lineno = rw.lineno; + if (!Xcheck_accessX(rw, map_info)) + return; + m_read_in_progress = 1'b1; + rw.status = UVM_IS_OK; + pre_read(rw); + for (uvm_reg_cbs cb=cbs.first(); cb!=null; cb=cbs.next()) + cb.pre_read(rw); + if (rw.status != UVM_IS_OK) begin + m_read_in_progress = 1'b0; + return; + end + rw.status = UVM_NOT_OK; + if (rw.path == UVM_FRONTDOOR) begin + uvm_reg_map system_map = rw.local_map.get_root_map(); + if (map_info.frontdoor != null) begin + uvm_reg_frontdoor fd = map_info.frontdoor; + fd.rw_info = rw; + if (fd.sequencer == null) + fd.sequencer = system_map.get_sequencer(); + fd.start(fd.sequencer, rw.parent); + end + else begin + rw.local_map.do_read(rw); + end + if (rw.status != UVM_NOT_OK) + for (uvm_reg_addr_t idx = rw.offset; + idx <= rw.offset + rw.value.size(); + idx++) begin + XsampleX(map_info.mem_range.stride * idx, 1, rw.map); + m_parent.XsampleX(map_info.offset + + (map_info.mem_range.stride * idx), + 1, rw.map); + end + end + else begin + if (get_access(rw.map) inside {"RW", "RO"}) begin + uvm_reg_backdoor bkdr = get_backdoor(); + if (bkdr != null) + bkdr.read(rw); + else + backdoor_read(rw); + end + else + rw.status = UVM_NOT_OK; + end + post_read(rw); + for (uvm_reg_cbs cb=cbs.first(); cb!=null; cb=cbs.next()) + cb.post_read(rw); + if (uvm_report_enabled(UVM_HIGH, UVM_INFO, "RegModel")) begin + string path_s,value_s,pre_s,range_s; + if (rw.path == UVM_FRONTDOOR) + path_s = (map_info.frontdoor != null) ? "user frontdoor" : + {"map ",rw.map.get_full_name()}; + else + path_s = (get_backdoor() != null) ? "user backdoor" : "DPI backdoor"; + if (rw.value.size() > 1) begin + value_s = "='{"; + pre_s = "Burst "; + foreach (rw.value[i]) + value_s = {value_s,$sformatf("%0h,",rw.value[i])}; + value_s[value_s.len()-1]="}"; + range_s = $sformatf("[%0d:%0d]",rw.offset,(rw.offset+rw.value.size())); + end + else begin + value_s = $sformatf("=%0h",rw.value[0]); + range_s = $sformatf("[%0d]",rw.offset); + end + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", {pre_s,"Read memory via ",path_s,": ", get_full_name(),range_s,value_s}, UVM_HIGH, "t/uvm/src/reg/uvm_mem.svh", 1389, "", 1); + end + end + m_read_in_progress = 1'b0; +endtask: do_read +function bit uvm_mem::Xcheck_accessX(input uvm_reg_item rw, + output uvm_reg_map_info map_info); + if (rw.offset >= m_size) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,get_type_name())) + uvm_report_error (get_type_name(), $sformatf("Offset 'h%0h exceeds size of memory, 'h%0h", rw.offset, m_size), UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 1405, "", 1); + end + rw.status = UVM_NOT_OK; + return 0; + end + if (rw.path == UVM_DEFAULT_DOOR) + rw.path = m_parent.get_default_door(); + if (rw.path == UVM_BACKDOOR) begin + if (get_backdoor() == null && !has_hdl_path()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"No backdoor access available for memory '",get_full_name(), "' . Using frontdoor instead."}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 1417, "", 1); + end + rw.path = UVM_FRONTDOOR; + end + else if (rw.map == null) begin + if (get_default_map() != null) + rw.map = get_default_map(); + else + rw.map = uvm_reg_map::backdoor(); + end + end + if (rw.path != UVM_BACKDOOR) begin + rw.local_map = get_local_map(rw.map); + if (rw.local_map == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,get_type_name())) + uvm_report_error (get_type_name(), {"No transactor available to physically access memory from map '", rw.map.get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 1436, "", 1); + end + rw.status = UVM_NOT_OK; + return 0; + end + map_info = rw.local_map.get_mem_map_info(this); + if (map_info.frontdoor == null) begin + if (map_info.unmapped) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Memory '",get_full_name(), "' unmapped in map '", rw.map.get_full_name(), "' and does not have a user-defined frontdoor"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 1448, "", 1); + end + rw.status = UVM_NOT_OK; + return 0; + end + if ((rw.value.size() > 1)) begin + if (get_n_bits() > rw.local_map.get_n_bytes()*8) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot burst a %0d-bit memory through a narrower data path (%0d bytes)", get_n_bits(), rw.local_map.get_n_bytes()*8), UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 1457, "", 1); + end + rw.status = UVM_NOT_OK; + return 0; + end + if (rw.offset + rw.value.size() > m_size) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Burst of size 'd%0d starting at offset 'd%0d exceeds size of memory, 'd%0d", rw.value.size(), rw.offset, m_size), UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 1464, "", 1); + end + return 0; + end + end + end + if (rw.map == null) + rw.map = rw.local_map; + end + return 1; +endfunction +task uvm_mem::poke(output uvm_status_e status, + input uvm_reg_addr_t offset, + input uvm_reg_data_t value, + input string kind = "", + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_item rw; + uvm_reg_backdoor bkdr = get_backdoor(); + m_fname = fname; + m_lineno = lineno; + if (bkdr == null && !has_hdl_path(kind)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"No backdoor access available in memory '", get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 1500, "", 1); + end + status = UVM_NOT_OK; + return; + end + rw = uvm_reg_item::type_id_create("mem_poke_item",,get_full_name()); + rw.element = this; + rw.path = UVM_BACKDOOR; + rw.element_kind = UVM_MEM; + rw.kind = UVM_WRITE; + rw.offset = offset; + rw.value[0] = value & ((1 << m_n_bits)-1); + rw.bd_kind = kind; + rw.parent = parent; + rw.extension = extension; + rw.fname = fname; + rw.lineno = lineno; + if (bkdr != null) + bkdr.write(rw); + else + backdoor_write(rw); + status = rw.status; + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", $sformatf("Poked memory '%s[%0d]' with value 'h%h", get_full_name(), offset, value), UVM_HIGH, "t/uvm/src/reg/uvm_mem.svh", 1531, "", 1); + end +endtask: poke +task uvm_mem::peek(output uvm_status_e status, + input uvm_reg_addr_t offset, + output uvm_reg_data_t value, + input string kind = "", + input uvm_sequence_base parent = null, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg_backdoor bkdr = get_backdoor(); + uvm_reg_item rw; + m_fname = fname; + m_lineno = lineno; + if (bkdr == null && !has_hdl_path(kind)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"No backdoor access available in memory '", get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 1554, "", 1); + end + status = UVM_NOT_OK; + return; + end + rw = uvm_reg_item::type_id_create("mem_peek_item",,get_full_name()); + rw.element = this; + rw.path = UVM_BACKDOOR; + rw.element_kind = UVM_MEM; + rw.kind = UVM_READ; + rw.offset = offset; + rw.bd_kind = kind; + rw.parent = parent; + rw.extension = extension; + rw.fname = fname; + rw.lineno = lineno; + if (bkdr != null) + bkdr.read(rw); + else + backdoor_read(rw); + status = rw.status; + value = rw.value[0]; + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", $sformatf("Peeked memory '%s[%0d]' has value 'h%h", get_full_name(), offset, value), UVM_HIGH, "t/uvm/src/reg/uvm_mem.svh", 1585, "", 1); + end +endtask: peek +function void uvm_mem::set_frontdoor(uvm_reg_frontdoor ftdr, + uvm_reg_map map = null, + string fname = "", + int lineno = 0); + uvm_reg_map_info map_info; + m_fname = fname; + m_lineno = lineno; + map = get_local_map(map); + if (map == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Memory '",get_full_name(), "' not found in map '", map.get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 1607, "", 1); + end + return; + end + map_info = map.get_mem_map_info(this); + map_info.frontdoor = ftdr; +endfunction: set_frontdoor +function uvm_reg_frontdoor uvm_mem::get_frontdoor(uvm_reg_map map = null); + uvm_reg_map_info map_info; + map = get_local_map(map); + if (map == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Memory '",get_full_name(), "' not found in map '", map.get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 1626, "", 1); + end + return null; + end + map_info = map.get_mem_map_info(this); + return map_info.frontdoor; +endfunction: get_frontdoor +function void uvm_mem::set_backdoor(uvm_reg_backdoor bkdr, + string fname = "", + int lineno = 0); + m_fname = fname; + m_lineno = lineno; + m_backdoor = bkdr; +endfunction: set_backdoor +function uvm_reg_backdoor uvm_mem::get_backdoor(bit inherited = 1); + if (m_backdoor == null && inherited) begin + uvm_reg_block blk = get_parent(); + uvm_reg_backdoor bkdr; + while (blk != null) begin + bkdr = blk.get_backdoor(); + if (bkdr != null) begin + m_backdoor = bkdr; + break; + end + blk = blk.get_parent(); + end + end + return m_backdoor; +endfunction: get_backdoor +function uvm_status_e uvm_mem::backdoor_read_func(uvm_reg_item rw); + uvm_hdl_path_concat paths[$]; + uvm_hdl_data_t val; + bit ok=1; + get_full_hdl_path(paths,rw.bd_kind); + foreach (rw.value[mem_idx]) begin + string idx; + idx.itoa(rw.offset + mem_idx); + foreach (paths[i]) begin + uvm_hdl_path_concat hdl_concat = paths[i]; + val = 0; + foreach (hdl_concat.slices[j]) begin + string hdl_path = {hdl_concat.slices[j].path, "[", idx, "]"}; + begin + if (uvm_report_enabled(UVM_DEBUG,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", {"backdoor_read from ",hdl_path}, UVM_DEBUG, "t/uvm/src/reg/uvm_mem.svh", 1691, "", 1); + end + if (hdl_concat.slices[j].offset < 0) begin +//TODO issue #4467 - Fix UVM function output width reassignment +//TODO %Error-UNSUPPORTED: t/t_uvm_pkg_todo.vh:29567:44: Unsupported: Function output argument 'value' requires 1024 bits, but connection's VARREF 'slice' generates 64 bits. +//TODO ok &= uvm_hdl_read(hdl_path, val); + continue; + end + begin + uvm_reg_data_t slice; + int k = hdl_concat.slices[j].offset; +//TODO issue #4467 - Fix UVM function output width reassignment +//TODO %Error-UNSUPPORTED: t/t_uvm_pkg_todo.vh:34181:38: Unsupported: Function output argument 'value' requires 1024 bits, but connection's VARREF 'd' generates 64 bits. +//TODO ok &= uvm_hdl_read(hdl_path, slice); + repeat (hdl_concat.slices[j].size) begin + val[k++] = slice[0]; + slice >>= 1; + end + end + end + val &= (1 << m_n_bits)-1; + if (i == 0) + rw.value[mem_idx] = val; + if (val != rw.value[mem_idx]) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Backdoor read of register %s with multiple HDL copies: values are not the same: %0h at path '%s', and %0h at path '%s'. Returning first value.", get_full_name(), rw.value[mem_idx], uvm_hdl_concat2string(paths[0]), val, uvm_hdl_concat2string(paths[i])), UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 1716, "", 1); + end + return UVM_NOT_OK; + end + end + end + rw.status = (ok) ? UVM_IS_OK : UVM_NOT_OK; + return rw.status; +endfunction +task uvm_mem::backdoor_read(uvm_reg_item rw); + rw.status = backdoor_read_func(rw); +endtask +task uvm_mem::backdoor_write(uvm_reg_item rw); + uvm_hdl_path_concat paths[$]; + bit ok=1; + get_full_hdl_path(paths,rw.bd_kind); + foreach (rw.value[mem_idx]) begin + string idx; + idx.itoa(rw.offset + mem_idx); + foreach (paths[i]) begin + uvm_hdl_path_concat hdl_concat = paths[i]; + foreach (hdl_concat.slices[j]) begin + begin + if (uvm_report_enabled(UVM_DEBUG,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", $sformatf("backdoor_write to %s ",hdl_concat.slices[j].path), UVM_DEBUG, "t/uvm/src/reg/uvm_mem.svh", 1751, "", 1); + end + if (hdl_concat.slices[j].offset < 0) begin + ok &= uvm_hdl_deposit({hdl_concat.slices[j].path,"[", idx, "]"},rw.value[mem_idx]); + continue; + end + begin + uvm_reg_data_t slice; + slice = rw.value[mem_idx] >> hdl_concat.slices[j].offset; + slice &= (1 << hdl_concat.slices[j].size)-1; + ok &= uvm_hdl_deposit({hdl_concat.slices[j].path, "[", idx, "]"}, slice); + end + end + end + end + rw.status = (ok ? UVM_IS_OK : UVM_NOT_OK); +endtask +function void uvm_mem::clear_hdl_path(string kind = "RTL"); + if (kind == "ALL") begin + m_hdl_paths_pool = new("hdl_paths"); + return; + end + if (kind == "") + kind = m_parent.get_default_hdl_path(); + if (!m_hdl_paths_pool.exists(kind)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Unknown HDL Abstraction '",kind,"'"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 1784, "", 1); + end + return; + end + m_hdl_paths_pool.delete(kind); +endfunction +function void uvm_mem::add_hdl_path(uvm_hdl_path_slice slices[], string kind = "RTL"); + uvm_queue #(uvm_hdl_path_concat) paths = m_hdl_paths_pool.get(kind); + uvm_hdl_path_concat concat = new(); + concat.set(slices); + paths.push_back(concat); +endfunction +function void uvm_mem::add_hdl_path_slice(string name, + int offset, + int size, + bit first = 0, + string kind = "RTL"); + uvm_queue #(uvm_hdl_path_concat) paths=m_hdl_paths_pool.get(kind); + uvm_hdl_path_concat concat; + if (first || paths.size() == 0) begin + concat = new(); + paths.push_back(concat); + end + else + concat = paths.get(paths.size()-1); + concat.add_path(name, offset, size); +endfunction +function bit uvm_mem::has_hdl_path(string kind = ""); + if (kind == "") + kind = m_parent.get_default_hdl_path(); + return m_hdl_paths_pool.exists(kind); +endfunction +function void uvm_mem::get_hdl_path(ref uvm_hdl_path_concat paths[$], + input string kind = ""); + uvm_queue #(uvm_hdl_path_concat) hdl_paths; + if (kind == "") + kind = m_parent.get_default_hdl_path(); + if (!has_hdl_path(kind)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Memory does not have hdl path defined for abstraction '",kind,"'"}, UVM_NONE, "t/uvm/src/reg/uvm_mem.svh", 1846, "", 1); + end + return; + end + hdl_paths = m_hdl_paths_pool.get(kind); + for (int i=0; i= range.min && addrs[i] <= range.max) begin + string a; + a = $sformatf("%0h",addrs[i]); + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"In map '",get_full_name(),"' register '", rg.get_full_name(), "' overlaps with address range of memory '", top_map.m_mems_by_offset[range].get_full_name(),"': 'h",a}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 716, "", 1); + end + end + end + end + info.addr = addrs; + end + end + if (unmapped) begin + info.offset = -1; + info.unmapped = 1; + end + else begin + info.offset = offset; + info.unmapped = 0; + end + end +endfunction +function void uvm_reg_map::add_mem(uvm_mem mem, + uvm_reg_addr_t offset, + string rights = "RW", + bit unmapped=0, + uvm_reg_frontdoor frontdoor=null); + if (m_mems_info.exists(mem)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Memory '",mem.get_name(), "' has already been added to map '",get_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 746, "", 1); + end + return; + end + if (mem.get_parent() != get_parent()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Memory '",mem.get_full_name(),"' may not be added to address map '", get_full_name(),"' : they are not in the same block"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 753, "", 1); + end + return; + end + mem.add_map(this); + begin + uvm_reg_map_info info = new; + info.offset = offset; + info.rights = rights; + info.unmapped = unmapped; + info.frontdoor = frontdoor; + m_mems_info[mem] = info; + end +endfunction: add_mem +function void uvm_reg_map::m_set_mem_offset(uvm_mem mem, + uvm_reg_addr_t offset, + bit unmapped); + if (!m_mems_info.exists(mem)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Cannot modify offset of memory '",mem.get_full_name(), "' in address map '",get_full_name(), "' : memory not mapped in that address map"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 781, "", 1); + end + return; + end + begin + uvm_reg_map_info info = m_mems_info[mem]; + uvm_reg_block blk = get_parent(); + uvm_reg_map top_map = get_root_map(); + uvm_reg_addr_t addrs[]; + if (blk.is_locked()) begin + if (!info.unmapped) begin + foreach (top_map.m_mems_by_offset[range]) begin + if (top_map.m_mems_by_offset[range] == mem) + top_map.m_mems_by_offset.delete(range); + end + end + if (!unmapped) begin + uvm_reg_addr_t addrs[],addrs_max[]; + uvm_reg_addr_t min, max, min2, max2; + int unsigned stride; + void'(get_physical_addresses(offset,0,mem.get_n_bytes(),addrs)); + min = (addrs[0] < addrs[addrs.size()-1]) ? addrs[0] : addrs[addrs.size()-1]; + min2 = addrs[0]; + void'(get_physical_addresses(offset,(mem.get_size()-1), + mem.get_n_bytes(),addrs_max)); + max = (addrs_max[0] > addrs_max[addrs_max.size()-1]) ? + addrs_max[0] : addrs_max[addrs_max.size()-1]; + max2 = addrs_max[0]; + stride = mem.get_n_bytes()/get_addr_unit_bytes(); + foreach (top_map.m_regs_by_offset[reg_addr]) begin + if (reg_addr >= min && reg_addr <= max) begin + string a,b; + a = $sformatf("[%0h:%0h]",min,max); + b = $sformatf("%0h",reg_addr); + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"In map '",get_full_name(),"' memory '", mem.get_full_name(), "' with range ",a, " overlaps with address of existing register '", top_map.m_regs_by_offset[reg_addr].get_full_name(),"': 'h",b}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 829, "", 1); + end + end + end + foreach (top_map.m_mems_by_offset[range]) begin + if (min <= range.max && max >= range.max || + min <= range.min && max >= range.min || + min >= range.min && max <= range.max) begin + string a,b; + a = $sformatf("[%0h:%0h]",min,max); + b = $sformatf("[%0h:%0h]",range.min,range.max); + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"In map '",get_full_name(),"' memory '", mem.get_full_name(), "' with range ",a, " overlaps existing memory with range '", top_map.m_mems_by_offset[range].get_full_name(),"': ",b}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 843, "", 1); + end + end + end + begin + uvm_reg_map_addr_range range = '{ min, max, stride}; + top_map.m_mems_by_offset[range] = mem; + info.addr = addrs; + info.mem_range = range; + end + end + end + if (unmapped) begin + info.offset = -1; + info.unmapped = 1; + end + else begin + info.offset = offset; + info.unmapped = 0; + end + end +endfunction +function void uvm_reg_map::add_submap (uvm_reg_map child_map, + uvm_reg_addr_t offset); + uvm_reg_map parent_map; + if (child_map == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Attempting to add NULL map to map '",get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 877, "", 1); + end + return; + end + parent_map = child_map.get_parent_map(); + if (parent_map != null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Map '", child_map.get_full_name(), "' is already a child of map '", parent_map.get_full_name(), "'. Cannot also be a child of map '", get_full_name(), "'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 890, "", 1); + end + return; + end + begin : n_bytes_match_check + if (m_n_bytes > child_map.get_n_bytes(UVM_NO_HIER)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", $sformatf("Adding %0d-byte submap '%s' to %0d-byte parent map '%s'", child_map.get_n_bytes(UVM_NO_HIER), child_map.get_full_name(), m_n_bytes, get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 900, "", 1); + end + end + end + child_map.add_parent_map(this,offset); + set_submap_offset(child_map, offset); +endfunction: add_submap +function void uvm_reg_map::reset(string kind = "SOFT"); + uvm_reg regs[$]; + get_registers(regs); + foreach (regs[i]) begin + regs[i].reset(kind); + end +endfunction +function void uvm_reg_map::add_parent_map(uvm_reg_map parent_map, uvm_reg_addr_t offset); + if (parent_map == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Attempting to add NULL parent map to map '",get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 930, "", 1); + end + return; + end + if (m_parent_map != null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Map \"%s\" already a submap of map \"%s\" at offset 'h%h", get_full_name(), m_parent_map.get_full_name(), m_parent_map.get_submap_offset(this)), UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 938, "", 1); + end + return; + end + m_parent_map = parent_map; + parent_map.m_submaps[this] = offset; +endfunction: add_parent_map +function void uvm_reg_map::set_sequencer(uvm_sequencer_base sequencer, + uvm_reg_adapter adapter=null); + if (sequencer == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"REG_NULL_SQR")) + uvm_report_error ("REG_NULL_SQR", "Null reference specified for bus sequencer", UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 954, "", 1); + end + return; + end + if (adapter == null) begin + begin + if (uvm_report_enabled(UVM_MEDIUM,UVM_INFO,"REG_NO_ADAPT")) + uvm_report_info ("REG_NO_ADAPT", {"Adapter not specified for map '",get_full_name(), "'. Accesses via this map will send abstract 'uvm_reg_item' items to sequencer '", sequencer.get_full_name(),"'"}, UVM_MEDIUM, "t/uvm/src/reg/uvm_reg_map.svh", 961, "", 1); + end + end + m_sequencer = sequencer; + m_adapter = adapter; +endfunction +function uvm_reg_block uvm_reg_map::get_parent(); + return m_parent; +endfunction +function uvm_reg_map uvm_reg_map::get_parent_map(); + return m_parent_map; +endfunction +function uvm_reg_map uvm_reg_map::get_root_map(); + return (m_parent_map == null) ? this : m_parent_map.get_root_map(); +endfunction: get_root_map +function uvm_reg_addr_t uvm_reg_map::get_base_addr(uvm_hier_e hier=UVM_HIER); + uvm_reg_map child = this; + if (hier == UVM_NO_HIER || m_parent_map == null) + return m_base_addr; + get_base_addr = m_parent_map.get_submap_offset(this); + get_base_addr += m_parent_map.get_base_addr(UVM_HIER); +endfunction +function int unsigned uvm_reg_map::get_n_bytes(uvm_hier_e hier=UVM_HIER); + if (hier == UVM_NO_HIER) + return m_n_bytes; + return m_system_n_bytes; +endfunction +function int unsigned uvm_reg_map::get_addr_unit_bytes(); + return (m_byte_addressing) ? 1 : m_n_bytes; +endfunction +function uvm_endianness_e uvm_reg_map::get_endian(uvm_hier_e hier=UVM_HIER); + if (hier == UVM_NO_HIER || m_parent_map == null) + return m_endian; + return m_parent_map.get_endian(hier); +endfunction +function uvm_sequencer_base uvm_reg_map::get_sequencer(uvm_hier_e hier=UVM_HIER); + if (hier == UVM_NO_HIER || m_parent_map == null) + return m_sequencer; + return m_parent_map.get_sequencer(hier); +endfunction +function uvm_reg_adapter uvm_reg_map::get_adapter(uvm_hier_e hier=UVM_HIER); + if (hier == UVM_NO_HIER || m_parent_map == null) + return m_adapter; + return m_parent_map.get_adapter(hier); +endfunction +function void uvm_reg_map::get_submaps(ref uvm_reg_map maps[$], input uvm_hier_e hier=UVM_HIER); + foreach (m_submaps[submap]) + maps.push_back(submap); + if (hier == UVM_HIER) + foreach (m_submaps[submap_]) begin + uvm_reg_map submap=submap_; + submap.get_submaps(maps); + end +endfunction +function void uvm_reg_map::get_registers(ref uvm_reg regs[$], input uvm_hier_e hier=UVM_HIER); + foreach (m_regs_info[rg]) + regs.push_back(rg); + if (hier == UVM_HIER) + foreach (m_submaps[submap_]) begin + uvm_reg_map submap=submap_; + submap.get_registers(regs); + end +endfunction +function void uvm_reg_map::get_fields(ref uvm_reg_field fields[$], input uvm_hier_e hier=UVM_HIER); + foreach (m_regs_info[rg_]) begin + uvm_reg rg = rg_; + rg.get_fields(fields); + end + if (hier == UVM_HIER) + foreach (this.m_submaps[submap_]) begin + uvm_reg_map submap=submap_; + submap.get_fields(fields); + end +endfunction +function void uvm_reg_map::get_memories(ref uvm_mem mems[$], input uvm_hier_e hier=UVM_HIER); + foreach (m_mems_info[mem]) + mems.push_back(mem); + if (hier == UVM_HIER) + foreach (m_submaps[submap_]) begin + uvm_reg_map submap=submap_; + submap.get_memories(mems); + end +endfunction +function void uvm_reg_map::get_virtual_registers(ref uvm_vreg regs[$], input uvm_hier_e hier=UVM_HIER); + uvm_mem mems[$]; + get_memories(mems,hier); + foreach (mems[i]) + mems[i].get_virtual_registers(regs); +endfunction +function void uvm_reg_map::get_virtual_fields(ref uvm_vreg_field fields[$], input uvm_hier_e hier=UVM_HIER); + uvm_vreg regs[$]; + get_virtual_registers(regs,hier); + foreach (regs[i]) + regs[i].get_fields(fields); +endfunction +function string uvm_reg_map::get_full_name(); + if (m_parent == null) + return get_name(); + else + return {m_parent.get_full_name(), ".", get_name()}; +endfunction +function uvm_reg_map_info uvm_reg_map::get_mem_map_info(uvm_mem mem, bit error=1); + if (!m_mems_info.exists(mem)) begin + if (error) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"REG_NO_MAP")) + uvm_report_error ("REG_NO_MAP", {"Memory '",mem.get_name(),"' not in map '",get_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1157, "", 1); + end + return null; + end + return m_mems_info[mem]; +endfunction +function uvm_reg_map_info uvm_reg_map::get_reg_map_info(uvm_reg rg, bit error=1); + uvm_reg_map_info result; + if (!m_regs_info.exists(rg)) begin + if (error) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"REG_NO_MAP")) + uvm_report_error ("REG_NO_MAP", {"Register '",rg.get_name(),"' not in map '",get_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1170, "", 1); + end + return null; + end + result = m_regs_info[rg]; + if(!result.is_initialized) + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"map '",get_name(),"' does not seem to be initialized correctly, check that the top register model is locked()"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1175, "", 1); + end + return result; +endfunction +function void uvm_reg_map::set_base_addr(uvm_reg_addr_t offset); + if (m_parent_map != null) begin + m_parent_map.set_submap_offset(this, offset); + end + else begin + m_base_addr = offset; + if (m_parent.is_locked()) begin + uvm_reg_map top_map = get_root_map(); + top_map.Xinit_address_mapX(); + end + end +endfunction +function int unsigned uvm_reg_map::get_size(); + int unsigned max_addr; + int unsigned addr; + foreach (m_regs_info[rg_]) begin + uvm_reg rg = rg_; + addr = m_regs_info[rg].offset + ((rg.get_n_bytes()-1)/m_n_bytes); + if (addr > max_addr) max_addr = addr; + end + foreach (m_mems_info[mem_]) begin + uvm_mem mem = mem_; + addr = m_mems_info[mem].offset + (mem.get_size() * (((mem.get_n_bytes()-1)/m_n_bytes)+1)) -1; + if (addr > max_addr) max_addr = addr; + end + foreach (m_submaps[submap_]) begin + uvm_reg_map submap=submap_; + addr = m_submaps[submap] + submap.get_size(); + if (addr > max_addr) max_addr = addr; + end + return max_addr + 1; +endfunction +function void uvm_reg_map::Xverify_map_configX(); + bit error; + uvm_reg_map root_map = get_root_map(); + if (root_map.get_adapter() == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Map '",root_map.get_full_name(), "' does not have an adapter registered"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1243, "", 1); + end + error++; + end + if (root_map.get_sequencer() == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Map '",root_map.get_full_name(), "' does not have a sequencer registered"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1248, "", 1); + end + error++; + end + if (error) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"RegModel")) + uvm_report_fatal ("RegModel", {"Must register an adapter and sequencer ", "for each top-level map in RegModel model"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1253, "", 1); + end + return; + end +endfunction +function int uvm_reg_map::get_physical_addresses_to_map( + uvm_reg_addr_t base_addr, + uvm_reg_addr_t mem_offset, + int unsigned n_bytes, + ref uvm_reg_addr_t addr[], + input uvm_reg_map parent_map, + ref int unsigned byte_offset, + input uvm_mem mem=null + ); + int bus_width = get_n_bytes(UVM_NO_HIER); + uvm_reg_map up_map; + uvm_reg_addr_t local_addr[]; + uvm_reg_addr_t lbase_addr; + up_map = get_parent_map(); + lbase_addr = up_map==null ? get_base_addr(UVM_NO_HIER): up_map.get_submap_offset(this); + if(up_map!=parent_map) begin + uvm_reg_addr_t lb; + uvm_reg_addr_t laddr; + begin + if(mem_offset) begin + base_addr+=mem_offset*mem.get_n_bytes()/get_addr_unit_bytes(); + end + laddr=lbase_addr + base_addr*get_addr_unit_bytes()/up_map.get_addr_unit_bytes(); + lb = (base_addr*get_addr_unit_bytes()) % up_map.get_addr_unit_bytes(); + byte_offset += lb; + end + return up_map.get_physical_addresses_to_map(laddr, 0, n_bytes+lb, addr,parent_map,byte_offset); + end else begin + uvm_reg_addr_t lbase_addr2; + local_addr= new[ceil(n_bytes,bus_width)]; + lbase_addr2 = base_addr; + if(mem_offset) + if(mem!=null && (mem.get_n_bytes() >= get_addr_unit_bytes())) begin + lbase_addr2 = base_addr + mem_offset*mem.get_n_bytes()/get_addr_unit_bytes(); + byte_offset += (mem_offset*mem.get_n_bytes() % get_addr_unit_bytes()); + end else begin + lbase_addr2 = base_addr + mem_offset; + end + case (get_endian(UVM_NO_HIER)) + UVM_LITTLE_ENDIAN: begin + foreach (local_addr[i]) begin + local_addr[i] = lbase_addr2 + i*bus_width/get_addr_unit_bytes(); + end + end + UVM_BIG_ENDIAN: begin + foreach (local_addr[i]) begin + local_addr[i] = lbase_addr2 + (local_addr.size()-1-i)*bus_width/get_addr_unit_bytes() ; + end + end + UVM_LITTLE_FIFO: begin + foreach (local_addr[i]) begin + local_addr[i] = lbase_addr2; + end + end + UVM_BIG_FIFO: begin + foreach (local_addr[i]) begin + local_addr[i] = lbase_addr2; + end + end + default: begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/REG/MAPNOENDIANESS")) + uvm_report_error ("UVM/REG/MAPNOENDIANESS", {"Map has no specified endianness. ", $sformatf("Cannot access %0d bytes register via its %0d byte \"%s\" interface", n_bytes, bus_width, get_full_name())}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1347, "", 1); + end + end + endcase + addr = new [local_addr.size()] (local_addr); + foreach(addr[idx]) + addr[idx] += lbase_addr; + end +endfunction +function int uvm_reg_map::get_physical_addresses(uvm_reg_addr_t base_addr, + uvm_reg_addr_t mem_offset, + int unsigned n_bytes, + ref uvm_reg_addr_t addr[]); + int unsigned skip; + return get_physical_addresses_to_map(base_addr, mem_offset, n_bytes, addr,null,skip); +endfunction +function void uvm_reg_map::set_submap_offset(uvm_reg_map submap, uvm_reg_addr_t offset); + if (submap == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"REG/NULL")) + uvm_report_error ("REG/NULL", "set_submap_offset: submap handle is null", UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1385, "", 1); + end + return; + end + m_submaps[submap] = offset; + if (m_parent.is_locked()) begin + uvm_reg_map root_map = get_root_map(); + root_map.Xinit_address_mapX(); + end +endfunction +function uvm_reg_addr_t uvm_reg_map::get_submap_offset(uvm_reg_map submap); + if (submap == null) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"REG/NULL")) + uvm_report_error ("REG/NULL", "set_submap_offset: submap handle is null", UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1400, "", 1); + end + return -1; + end + if (!m_submaps.exists(submap)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Map '",submap.get_full_name(), "' is not a submap of '",get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1405, "", 1); + end + return -1; + end + return m_submaps[submap]; +endfunction +function uvm_reg uvm_reg_map::get_reg_by_offset(uvm_reg_addr_t offset, + bit read = 1); + if (!m_parent.is_locked()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot get register by offset: Block %s is not locked.", m_parent.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1417, "", 1); + end + return null; + end + if (!read && m_regs_by_offset_wo.exists(offset)) + return m_regs_by_offset_wo[offset]; + if (m_regs_by_offset.exists(offset)) + return m_regs_by_offset[offset]; + return null; +endfunction +function uvm_mem uvm_reg_map::get_mem_by_offset(uvm_reg_addr_t offset); + if (!m_parent.is_locked()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Cannot memory register by offset: Block %s is not locked.", m_parent.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1435, "", 1); + end + return null; + end + foreach (m_mems_by_offset[range]) begin + if (range.min <= offset && offset <= range.max) begin + return m_mems_by_offset[range]; + end + end + return null; +endfunction +function void uvm_reg_map::Xinit_address_mapX(); + int unsigned bus_width; + uvm_reg_map top_map = get_root_map(); + if (this == top_map) begin + top_map.m_regs_by_offset.delete(); + top_map.m_regs_by_offset_wo.delete(); + top_map.m_mems_by_offset.delete(); + end + foreach (m_submaps[l]) begin + uvm_reg_map map=l; + map.Xinit_address_mapX(); + end + foreach (m_regs_info[rg_]) begin + uvm_reg rg = rg_; + m_regs_info[rg].is_initialized=1; + if (!m_regs_info[rg].unmapped) begin + string rg_acc = rg.Xget_fields_accessX(this); + uvm_reg_addr_t addrs[]; + bus_width = get_physical_addresses(m_regs_info[rg].offset,0,rg.get_n_bytes(),addrs); + foreach (addrs[i]) begin + uvm_reg_addr_t addr = addrs[i]; + if (top_map.m_regs_by_offset.exists(addr) && (top_map.m_regs_by_offset[addr] != rg)) begin + uvm_reg rg2 = top_map.m_regs_by_offset[addr]; + string rg2_acc = rg2.Xget_fields_accessX(this); + if (rg_acc == "RO" && rg2_acc == "WO") begin + top_map.m_regs_by_offset[addr] = rg; + uvm_reg_read_only_cbs::add(rg); + top_map.m_regs_by_offset_wo[addr] = rg2; + uvm_reg_write_only_cbs::add(rg2); + end + else if (rg_acc == "WO" && rg2_acc == "RO") begin + top_map.m_regs_by_offset_wo[addr] = rg; + uvm_reg_write_only_cbs::add(rg); + uvm_reg_read_only_cbs::add(rg2); + end + else begin + string a; + a = $sformatf("%0h",addr); + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"In map '",get_full_name(),"' register '", rg.get_full_name(), "' maps to same address as register '", top_map.m_regs_by_offset[addr].get_full_name(),"': 'h",a}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1503, "", 1); + end + end + end + else + top_map.m_regs_by_offset[addr] = rg; + foreach (top_map.m_mems_by_offset[range]) begin + if (addr >= range.min && addr <= range.max) begin + string a,b; + a = $sformatf("%0h",addr); + b = $sformatf("[%0h:%0h]",range.min,range.max); + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"In map '",get_full_name(),"' register '", rg.get_full_name(), "' with address ",a, "maps to same address as memory '", top_map.m_mems_by_offset[range].get_full_name(),"': ",b}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1517, "", 1); + end + end + end + end + m_regs_info[rg].addr = addrs; + end + end + foreach (m_mems_info[mem_]) begin + uvm_mem mem = mem_; + if (!m_mems_info[mem].unmapped) begin + uvm_reg_addr_t addrs[],addrs_max[]; + uvm_reg_addr_t min, max, min2, max2; + int unsigned stride; + int unsigned bo; + bus_width = get_physical_addresses_to_map(m_mems_info[mem].offset,0,mem.get_n_bytes(),addrs,null,bo,mem); + min = (addrs[0] < addrs[addrs.size()-1]) ? addrs[0] : addrs[addrs.size()-1]; + void'(get_physical_addresses_to_map(m_mems_info[mem].offset,(mem.get_size()-1),mem.get_n_bytes(),addrs_max,null,bo,mem)); + max = (addrs_max[0] > addrs_max[addrs_max.size()-1]) ? addrs_max[0] : addrs_max[addrs_max.size()-1]; + stride = mem.get_n_bytes()/get_addr_unit_bytes(); + if(mem.get_n_bytes() get_addr_unit_bytes()) + if(mem.get_n_bytes() % get_addr_unit_bytes()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/REG/ADDR")) + uvm_report_warning ("UVM/REG/ADDR", $sformatf("memory %s is not matching the word width of the enclosing map %s \ +(one memory word not fitting into k map addresses)", mem.get_full_name(),get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1571, "", 1); + end + end + if(mem.get_n_bytes() < get_addr_unit_bytes()) + if(get_addr_unit_bytes() % mem.get_n_bytes()) + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/REG/ADDR")) + uvm_report_warning ("UVM/REG/ADDR", $sformatf("the memory %s is not matching the word width of the enclosing map %s \ +(one map address doesnt cover k memory words)", mem.get_full_name(),get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1578, "", 1); + end + if(mem.get_n_bits() % 8) + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/REG/ADDR")) + uvm_report_warning ("UVM/REG/ADDR", $sformatf("this implementation of UVM requires memory words to be k*8 bits (mem %s \ +has %0d bit words)",mem.get_full_name(),mem.get_n_bits()), UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1582, "", 1); + end + foreach (top_map.m_regs_by_offset[reg_addr]) begin + if (reg_addr >= min && reg_addr <= max) begin + string a; + a = $sformatf("%0h",reg_addr); + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"In map '",get_full_name(),"' memory '", mem.get_full_name(), "' maps to same address as register '", top_map.m_regs_by_offset[reg_addr].get_full_name(),"': 'h",a}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1590, "", 1); + end + end + end + foreach (top_map.m_mems_by_offset[range]) begin + if (min <= range.max && max >= range.max || + min <= range.min && max >= range.min || + min >= range.min && max <= range.max) + if(top_map.m_mems_by_offset[range]!=mem) + begin + string a; + a = $sformatf("[%0h:%0h]",min,max); + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"In map '",get_full_name(),"' memory '", mem.get_full_name(), "' overlaps with address range of memory '", top_map.m_mems_by_offset[range].get_full_name(),"': 'h",a}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1604, "", 1); + end + end + end + begin + uvm_reg_map_addr_range range = '{ min, max, stride}; + top_map.m_mems_by_offset[ range ] = mem; + m_mems_info[mem].addr = addrs; + m_mems_info[mem].mem_range = range; + end + end + end + if (bus_width == 0) bus_width = m_n_bytes; + m_system_n_bytes = bus_width; +endfunction +function void uvm_reg_map::Xget_bus_infoX(uvm_reg_item rw, + output uvm_reg_map_info map_info, + output int size, + output int lsb, + output int addr_skip); + if (rw.element_kind == UVM_MEM) begin + uvm_mem mem; + if(rw.element == null || !$cast(mem,rw.element)) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"REG/CAST")) + uvm_report_fatal ("REG/CAST", {"uvm_reg_item 'element_kind' is UVM_MEM, ", "but 'element' does not point to a memory: ",rw.get_name()}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1639, "", 1); + end + map_info = get_mem_map_info(mem); + size = mem.get_n_bits(); + end + else if (rw.element_kind == UVM_REG) begin + uvm_reg rg; + if(rw.element == null || !$cast(rg,rw.element)) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"REG/CAST")) + uvm_report_fatal ("REG/CAST", {"uvm_reg_item 'element_kind' is UVM_REG, ", "but 'element' does not point to a register: ",rw.get_name()}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1647, "", 1); + end + map_info = get_reg_map_info(rg); + size = rg.get_n_bits(); + end + else if (rw.element_kind == UVM_FIELD) begin + uvm_reg_field field; + if(rw.element == null || !$cast(field,rw.element)) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"REG/CAST")) + uvm_report_fatal ("REG/CAST", {"uvm_reg_item 'element_kind' is UVM_FIELD, ", "but 'element' does not point to a field: ",rw.get_name()}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1655, "", 1); + end + map_info = get_reg_map_info(field.get_parent()); + size = field.get_n_bits(); + lsb = field.get_lsb_pos(); + addr_skip = lsb/(get_n_bytes()*8); + end +endfunction +task uvm_reg_map::do_write(uvm_reg_item rw); + uvm_sequence_base tmp_parent_seq; + uvm_reg_map system_map = get_root_map(); + uvm_reg_adapter adapter = system_map.get_adapter(); + uvm_sequencer_base sequencer = system_map.get_sequencer(); + uvm_reg_seq_base parent_proxy; + if (adapter != null && adapter.parent_sequence != null) begin + uvm_object o; + uvm_sequence_base seq; + o = adapter.parent_sequence.clone(); + if (o == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"REG/CLONE")) + uvm_report_fatal ("REG/CLONE", {"failed to clone adapter's parent sequence: '", adapter.parent_sequence.get_full_name(), "' (of type '", adapter.parent_sequence.get_type_name(), "')"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1686, "", 1); + end + if (!$cast(seq, o)) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"REG/CAST")) + uvm_report_fatal ("REG/CAST", {"failed to cast: '", o.get_full_name(), "' (of type '", o.get_type_name(), "') to uvm_sequence_base!"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1693, "", 1); + end + seq.set_parent_sequence(rw.parent); + rw.parent = seq; + tmp_parent_seq = seq; + end + if (rw.parent == null) begin + parent_proxy = new("default_parent_seq"); + rw.parent = parent_proxy; + tmp_parent_seq = rw.parent; + end + if (adapter == null) begin + uvm_event#(uvm_object) end_event ; + uvm_event_pool ep; + ep = rw.get_event_pool(); + end_event = ep.get("end") ; + rw.set_sequencer(sequencer); + rw.parent.start_item(rw,rw.prior); + rw.parent.finish_item(rw); + end_event.wait_on(); + end + else begin + do_bus_write(rw, sequencer, adapter); + end + if (tmp_parent_seq != null) + sequencer.m_sequence_exiting(tmp_parent_seq); +endtask +task uvm_reg_map::do_read(uvm_reg_item rw); + uvm_sequence_base tmp_parent_seq; + uvm_reg_map system_map = get_root_map(); + uvm_reg_adapter adapter = system_map.get_adapter(); + uvm_sequencer_base sequencer = system_map.get_sequencer(); + uvm_reg_seq_base parent_proxy; + if (adapter != null && adapter.parent_sequence != null) begin + uvm_object o; + uvm_sequence_base seq; + o = adapter.parent_sequence.clone(); + if (o == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"REG/CLONE")) + uvm_report_fatal ("REG/CLONE", {"failed to clone adapter's parent sequence: '", adapter.parent_sequence.get_full_name(), "' (of type '", adapter.parent_sequence.get_type_name(), "')"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1745, "", 1); + end + if (!$cast(seq, o)) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"REG/CAST")) + uvm_report_fatal ("REG/CAST", {"failed to cast: '", o.get_full_name(), "' (of type '", o.get_type_name(), "') to uvm_sequence_base!"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1752, "", 1); + end + seq.set_parent_sequence(rw.parent); + rw.parent = seq; + tmp_parent_seq = seq; + end + if (rw.parent == null) begin + parent_proxy = new("default_parent_seq"); + rw.parent = parent_proxy; + tmp_parent_seq = rw.parent; + end + if (adapter == null) begin + uvm_event#(uvm_object) end_event ; + uvm_event_pool ep; + ep = rw.get_event_pool(); + end_event = ep.get("end") ; + rw.set_sequencer(sequencer); + rw.parent.start_item(rw,rw.prior); + rw.parent.finish_item(rw); + end_event.wait_on(); + end + else begin + do_bus_read(rw, sequencer, adapter); + end + if (tmp_parent_seq != null) + sequencer.m_sequence_exiting(tmp_parent_seq); +endtask +task uvm_reg_map::do_bus_write (uvm_reg_item rw, + uvm_sequencer_base sequencer, + uvm_reg_adapter adapter); + do_bus_access(rw, sequencer, adapter); +endtask +task uvm_reg_map::perform_accesses(ref uvm_reg_bus_op accesses[$], + input uvm_reg_item rw, + input uvm_reg_adapter adapter, + input uvm_sequencer_base sequencer); + string op; + uvm_reg_data_logic_t data; + uvm_endianness_e endian; + op=(rw.kind inside {UVM_READ,UVM_BURST_READ}) ? "Read" : "Wrote"; + endian=get_endian(UVM_NO_HIER); + if(policy!=null) + policy.order(accesses); + foreach(accesses[i]) begin + uvm_reg_bus_op rw_access=accesses[i]; + uvm_sequence_item bus_req; + if ((rw_access.kind == UVM_WRITE) && (endian == UVM_BIG_ENDIAN)) begin + { >> { rw_access.data }} = { << byte { rw_access.data}}; + end + adapter.m_set_item(rw); + bus_req = adapter.reg2bus(rw_access); + adapter.m_set_item(null); + if (bus_req == null) + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"RegMem")) + uvm_report_fatal ("RegMem", {"adapter [",adapter.get_name(),"] didnt return a bus transaction"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_map.svh", 1823, "", 1); + end + bus_req.set_sequencer(sequencer); + rw.parent.start_item(bus_req,rw.prior); + if (rw.parent != null && i == 0) + rw.parent.mid_do(rw); + rw.parent.finish_item(bus_req); + begin + uvm_event#(uvm_object) end_event ; + uvm_event_pool ep; + ep = bus_req.get_event_pool(); + end_event = ep.get("end") ; + end_event.wait_on(); + end + if (adapter.provides_responses) begin + uvm_sequence_item bus_rsp; + uvm_access_e op; + rw.parent.get_base_response(bus_rsp,bus_req.get_transaction_id()); + adapter.bus2reg(bus_rsp,rw_access); + end + else begin + adapter.bus2reg(bus_req,rw_access); + end + if ((rw_access.kind == UVM_READ) && (endian == UVM_BIG_ENDIAN)) begin + { >> { rw_access.data }} = { << byte { rw_access.data}}; + end + rw.status = rw_access.status; + begin + data = rw_access.data & ((1<>bit_shift) & 'hff; + p[idx]=n; + end + if(extra_byte) + p.push_back(ac); + end + accesses.delete(); + foreach(adr[i]) begin + uvm_reg_bus_op rw_access; + uvm_reg_data_t data; + for(int i0=0;i0=0;i--) begin + if(rw_access.byte_en[i]==0) + rw_access.n_bits-=8; + else + break; + end + accesses.push_back(rw_access); + end + perform_accesses(accesses, rw, adapter, sequencer); + if(rw.kind inside {UVM_READ,UVM_BURST_READ}) begin + p.delete(); + foreach(accesses[i0]) + for(int i1=0;i1 max_size) + max_size = uvm_reg_field::get_max_size(); + if (uvm_mem::get_max_size() > max_size) + max_size = uvm_mem::get_max_size(); + if (max_size > 64) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_FATAL,"RegModel")) + uvm_report_fatal ("RegModel", $sformatf("Register model requires that UVM_REG_DATA_WIDTH be defined as %0d or greater. Currently defined as %0d", max_size, 64), UVM_NONE, "t/uvm/src/reg/uvm_reg_block.svh", 1153, "", 1); + end + end + Xinit_address_mapsX(); + if(m_root_names[get_name()]>1) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"UVM/REG/DUPLROOT")) + uvm_report_error ("UVM/REG/DUPLROOT", $sformatf("There are %0d root register models named \"%s\". The names of the root register models have to be unique", m_root_names[get_name()], get_name()), UVM_NONE, "t/uvm/src/reg/uvm_reg_block.svh", 1162, "", 1); + end + -> m_uvm_lock_model_complete; + end +endfunction +function string uvm_reg_block::get_full_name(); + if (parent == null) + return get_name(); + return {parent.get_full_name(), ".", get_name()}; +endfunction: get_full_name +function void uvm_reg_block::get_fields(ref uvm_reg_field fields[$], + input uvm_hier_e hier=UVM_HIER); + foreach (regs[rg_]) begin + uvm_reg rg = rg_; + rg.get_fields(fields); + end + if (hier == UVM_HIER) + foreach (blks[blk_]) + begin + uvm_reg_block blk = blk_; + blk.get_fields(fields); + end +endfunction: get_fields +function void uvm_reg_block::get_virtual_fields(ref uvm_vreg_field fields[$], + input uvm_hier_e hier=UVM_HIER); + foreach (vregs[vreg_]) begin + uvm_vreg vreg = vreg_; + vreg.get_fields(fields); + end + if (hier == UVM_HIER) + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + blk.get_virtual_fields(fields); + end +endfunction: get_virtual_fields +function void uvm_reg_block::get_registers(ref uvm_reg regs[$], + input uvm_hier_e hier=UVM_HIER); + foreach (this.regs[rg]) + regs.push_back(rg); + if (hier == UVM_HIER) + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + blk.get_registers(regs); + end +endfunction: get_registers +function void uvm_reg_block::get_virtual_registers(ref uvm_vreg regs[$], + input uvm_hier_e hier=UVM_HIER); + foreach (vregs[rg]) + regs.push_back(rg); + if (hier == UVM_HIER) + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + blk.get_virtual_registers(regs); + end +endfunction: get_virtual_registers +function void uvm_reg_block::get_memories(ref uvm_mem mems[$], + input uvm_hier_e hier=UVM_HIER); + foreach (this.mems[mem_]) begin + uvm_mem mem = mem_; + mems.push_back(mem); + end + if (hier == UVM_HIER) + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + blk.get_memories(mems); + end +endfunction: get_memories +function void uvm_reg_block::get_blocks(ref uvm_reg_block blks[$], + input uvm_hier_e hier=UVM_HIER); + foreach (this.blks[blk_]) begin + uvm_reg_block blk = blk_; + blks.push_back(blk); + if (hier == UVM_HIER) + blk.get_blocks(blks); + end +endfunction: get_blocks +function void uvm_reg_block::get_root_blocks(ref uvm_reg_block blks[$]); + foreach (m_roots[blk]) begin + blks.push_back(blk); + end +endfunction +function int uvm_reg_block::find_blocks(input string name, + ref uvm_reg_block blks[$], + input uvm_reg_block root = null, + input uvm_object accessor = null); + uvm_reg_block r[$]; + uvm_reg_block b[$]; + if (root != null) begin + name = {root.get_full_name(), ".", name}; + b='{root}; + end else begin + get_root_blocks(b); + end + foreach(b[idx]) begin + r.push_back(b[idx]); + b[idx].get_blocks(r); + end + blks.delete(); + foreach(r[idx]) begin + if ( uvm_is_match( name, r[idx].get_full_name() ) ) + blks.push_back(r[idx]); + end + return blks.size(); +endfunction +function uvm_reg_block uvm_reg_block::find_block(input string name, + input uvm_reg_block root = null, + input uvm_object accessor = null); + uvm_reg_block blks[$]; + if (!find_blocks(name, blks, root, accessor)) + return null; + if (blks.size() > 1) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"MRTH1BLK")) + uvm_report_warning ("MRTH1BLK", {"More than one block matched the name \"", name, "\"."}, UVM_NONE, "t/uvm/src/reg/uvm_reg_block.svh", 1341, "", 1); + end + end + return blks[0]; +endfunction +function void uvm_reg_block::get_maps(ref uvm_reg_map maps[$]); + foreach (this.maps[map]) + maps.push_back(map); +endfunction +function uvm_reg_block uvm_reg_block::get_parent(); + get_parent = this.parent; +endfunction: get_parent +function uvm_reg_block uvm_reg_block::get_block_by_name(string name); + if (get_name() == name) + return this; + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + if (blk.get_name() == name) + return blk; + end + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + uvm_reg_block subblks[$]; + blk_.get_blocks(subblks, UVM_HIER); + foreach (subblks[j]) + if (subblks[j].get_name() == name) + return subblks[j]; + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Unable to locate block '",name, "' in block '",get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_block.svh", 1395, "", 1); + end + return null; +endfunction: get_block_by_name +function uvm_reg uvm_reg_block::get_reg_by_name(string name); + foreach (regs[rg_]) begin + uvm_reg rg = rg_; + if (rg.get_name() == name) + return rg; + end + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + uvm_reg subregs[$]; + blk_.get_registers(subregs, UVM_HIER); + foreach (subregs[j]) + if (subregs[j].get_name() == name) + return subregs[j]; + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Unable to locate register '",name, "' in block '",get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_block.svh", 1422, "", 1); + end + return null; +endfunction: get_reg_by_name +function uvm_vreg uvm_reg_block::get_vreg_by_name(string name); + foreach (vregs[rg_]) begin + uvm_vreg rg = rg_; + if (rg.get_name() == name) + return rg; + end + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + uvm_vreg subvregs[$]; + blk_.get_virtual_registers(subvregs, UVM_HIER); + foreach (subvregs[j]) + if (subvregs[j].get_name() == name) + return subvregs[j]; + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Unable to locate virtual register '",name, "' in block '",get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_block.svh", 1449, "", 1); + end + return null; +endfunction: get_vreg_by_name +function uvm_mem uvm_reg_block::get_mem_by_name(string name); + foreach (mems[mem_]) begin + uvm_mem mem = mem_; + if (mem.get_name() == name) + return mem; + end + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + uvm_mem submems[$]; + blk_.get_memories(submems, UVM_HIER); + foreach (submems[j]) + if (submems[j].get_name() == name) + return submems[j]; + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Unable to locate memory '",name, "' in block '",get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_block.svh", 1476, "", 1); + end + return null; +endfunction: get_mem_by_name +function uvm_reg_field uvm_reg_block::get_field_by_name(string name); + foreach (regs[rg_]) begin + uvm_reg rg = rg_; + uvm_reg_field fields[$]; + rg.get_fields(fields); + foreach (fields[i]) + if (fields[i].get_name() == name) + return fields[i]; + end + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + uvm_reg subregs[$]; + blk_.get_registers(subregs, UVM_HIER); + foreach (subregs[j]) begin + uvm_reg_field fields[$]; + subregs[j].get_fields(fields); + foreach (fields[i]) + if (fields[i].get_name() == name) + return fields[i]; + end + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Unable to locate field '",name, "' in block '",get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_block.svh", 1511, "", 1); + end + return null; +endfunction: get_field_by_name +function uvm_vreg_field uvm_reg_block::get_vfield_by_name(string name); + foreach (vregs[rg_]) begin + uvm_vreg rg =rg_; + uvm_vreg_field fields[$]; + rg.get_fields(fields); + foreach (fields[i]) + if (fields[i].get_name() == name) + return fields[i]; + end + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + uvm_vreg subvregs[$]; + blk_.get_virtual_registers(subvregs, UVM_HIER); + foreach (subvregs[j]) begin + uvm_vreg_field fields[$]; + subvregs[j].get_fields(fields); + foreach (fields[i]) + if (fields[i].get_name() == name) + return fields[i]; + end + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Unable to locate virtual field '",name, "' in block '",get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_block.svh", 1547, "", 1); + end + return null; +endfunction: get_vfield_by_name +function uvm_reg_cvr_t uvm_reg_block::set_coverage(uvm_reg_cvr_t is_on); + this.cover_on = this.has_cover & is_on; + foreach (regs[rg_]) begin + uvm_reg rg = rg_; + void'(rg.set_coverage(is_on)); + end + foreach (mems[mem_]) begin + uvm_mem mem = mem_; + void'(mem.set_coverage(is_on)); + end + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + void'(blk.set_coverage(is_on)); + end + return this.cover_on; +endfunction: set_coverage +function void uvm_reg_block::sample_values(); + foreach (regs[rg_]) begin + uvm_reg rg = rg_; + rg.sample_values(); + end + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + blk.sample_values(); + end +endfunction +function void uvm_reg_block::XsampleX(uvm_reg_addr_t addr, + bit is_read, + uvm_reg_map map); + sample(addr, is_read, map); + if (parent != null) begin + end +endfunction +function uvm_reg_cvr_t uvm_reg_block::build_coverage(uvm_reg_cvr_t models); + build_coverage = UVM_NO_COVERAGE; + void'(uvm_reg_cvr_rsrc_db::read_by_name({"uvm_reg::", get_full_name()}, + "include_coverage", + build_coverage, this)); + return build_coverage & models; +endfunction: build_coverage +function void uvm_reg_block::add_coverage(uvm_reg_cvr_t models); + this.has_cover |= models; +endfunction: add_coverage +function bit uvm_reg_block::has_coverage(uvm_reg_cvr_t models); + return ((this.has_cover & models) == models); +endfunction: has_coverage +function bit uvm_reg_block::get_coverage(uvm_reg_cvr_t is_on = UVM_CVR_ALL); + if (this.has_coverage(is_on) == 0) return 0; + return ((this.cover_on & is_on) == is_on); +endfunction: get_coverage +function void uvm_reg_block::reset(string kind = "HARD"); + foreach (regs[rg_]) begin + uvm_reg rg = rg_; + rg.reset(kind); + end + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + blk.reset(kind); + end +endfunction +function bit uvm_reg_block::needs_update(); + needs_update = 0; + foreach (regs[rg_]) begin + uvm_reg rg = rg_; + if (rg.needs_update()) + return 1; + end + foreach (blks[blk_]) begin + uvm_reg_block blk =blk_; + if (blk.needs_update()) + return 1; + end +endfunction: needs_update +task uvm_reg_block::update(output uvm_status_e status, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + status = UVM_IS_OK; + if (!needs_update()) begin + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", $sformatf("%s:%0d - RegModel block %s does not need updating", fname, lineno, this.get_name()), UVM_HIGH, "t/uvm/src/reg/uvm_reg_block.svh", 1694, "", 1); + end + return; + end + begin + if (uvm_report_enabled(UVM_HIGH,UVM_INFO,"RegModel")) + uvm_report_info ("RegModel", $sformatf("%s:%0d - Updating model block %s with %s path", fname, lineno, this.get_name(), path.name ), UVM_HIGH, "t/uvm/src/reg/uvm_reg_block.svh", 1699, "", 1); + end + foreach (regs[rg_]) begin + uvm_reg rg = rg_; + if (rg.needs_update()) begin + rg.update(status, path, null, parent, prior, extension); + if (status != UVM_IS_OK && status != UVM_HAS_X) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", $sformatf("Register \"%s\" could not be updated", rg.get_full_name()), UVM_NONE, "t/uvm/src/reg/uvm_reg_block.svh", 1707, "", 1); + end + return; + end + end + end + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + blk.update(status,path,parent,prior,extension,fname,lineno); + end +endtask: update +task uvm_reg_block::mirror(output uvm_status_e status, + input uvm_check_e check = UVM_NO_CHECK, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_status_e final_status = UVM_IS_OK; + foreach (regs[rg_]) begin + uvm_reg rg = rg_; + rg.mirror(status, check, path, null, + parent, prior, extension, fname, lineno); + if (status != UVM_IS_OK && status != UVM_HAS_X) begin + final_status = status; + end + end + foreach (blks[blk_]) begin + uvm_reg_block blk = blk_; + blk.mirror(status, check, path, parent, prior, extension, fname, lineno); + if (status != UVM_IS_OK && status != UVM_HAS_X) begin + final_status = status; + end + end +endtask: mirror +task uvm_reg_block::write_reg_by_name(output uvm_status_e status, + input string name, + input uvm_reg_data_t data, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg rg; + this.fname = fname; + this.lineno = lineno; + status = UVM_NOT_OK; + rg = this.get_reg_by_name(name); + if (rg != null) + rg.write(status, data, path, map, parent, prior, extension); +endtask: write_reg_by_name +task uvm_reg_block::read_reg_by_name(output uvm_status_e status, + input string name, + output uvm_reg_data_t data, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_reg rg; + this.fname = fname; + this.lineno = lineno; + status = UVM_NOT_OK; + rg = this.get_reg_by_name(name); + if (rg != null) + rg.read(status, data, path, map, parent, prior, extension); +endtask: read_reg_by_name +task uvm_reg_block::write_mem_by_name(output uvm_status_e status, + input string name, + input uvm_reg_addr_t offset, + input uvm_reg_data_t data, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_mem mem; + this.fname = fname; + this.lineno = lineno; + status = UVM_NOT_OK; + mem = get_mem_by_name(name); + if (mem != null) + mem.write(status, offset, data, path, map, parent, prior, extension); +endtask: write_mem_by_name +task uvm_reg_block::read_mem_by_name(output uvm_status_e status, + input string name, + input uvm_reg_addr_t offset, + output uvm_reg_data_t data, + input uvm_door_e path = UVM_DEFAULT_DOOR, + input uvm_reg_map map = null, + input uvm_sequence_base parent = null, + input int prior = -1, + input uvm_object extension = null, + input string fname = "", + input int lineno = 0); + uvm_mem mem; + this.fname = fname; + this.lineno = lineno; + status = UVM_NOT_OK; + mem = get_mem_by_name(name); + if (mem != null) + mem.read(status, offset, data, path, map, parent, prior, extension); +endtask: read_mem_by_name +task uvm_reg_block::readmemh(string filename); +endtask: readmemh +task uvm_reg_block::writememh(string filename); +endtask: writememh +function uvm_reg_map uvm_reg_block::create_map(string name, + uvm_reg_addr_t base_addr, + int unsigned n_bytes, + uvm_endianness_e endian, + bit byte_addressing=1); + uvm_reg_map map; + map = uvm_reg_map::type_id_create(name,,this.get_full_name()); + map.configure(this,base_addr,n_bytes,endian,byte_addressing); + add_map(map); + return map; +endfunction +function void uvm_reg_block::add_map(uvm_reg_map map); + if (this.locked) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", "Cannot add map to locked model", UVM_NONE, "t/uvm/src/reg/uvm_reg_block.svh", 1894, "", 1); + end + return; + end + if (this.maps.exists(map)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Map '",map.get_name(), "' already exists in '",get_full_name(),"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_block.svh", 1900, "", 1); + end + return; + end + this.maps[map] = 1; + if (maps.num() == 1) + default_map = map; +endfunction: add_map +function uvm_reg_map uvm_reg_block::get_map_by_name(string name); + uvm_reg_map maps[$]; + this.get_maps(maps); + foreach (maps[i]) + if (maps[i].get_name() == name) + return maps[i]; + foreach (maps[i]) begin + uvm_reg_map submaps[$]; + maps[i].get_submaps(submaps, UVM_HIER); + foreach (submaps[j]) + if (submaps[j].get_name() == name) + return submaps[j]; + end + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Map with name '",name,"' does not exist in block"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_block.svh", 1932, "", 1); + end + return null; +endfunction +function void uvm_reg_block::set_default_map(uvm_reg_map map); + if (!maps.exists(map)) + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Map '",map.get_full_name(),"' does not exist in block"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_block.svh", 1941, "", 1); + end + default_map = map; +endfunction +function uvm_reg_map uvm_reg_block::get_default_map(); + return default_map; +endfunction +function uvm_door_e uvm_reg_block::get_default_door(); + if (this.default_path != UVM_DEFAULT_DOOR) + return this.default_path; + if (this.parent != null) + return this.parent.get_default_door(); + return UVM_FRONTDOOR; +endfunction +function void uvm_reg_block::set_default_door(uvm_door_e door); + this.default_path = door; +endfunction +function void uvm_reg_block::Xinit_address_mapsX(); + foreach (maps[map_]) begin + uvm_reg_map map = map_; + map.Xinit_address_mapX(); + end +endfunction +function void uvm_reg_block::set_backdoor(uvm_reg_backdoor bkdr, + string fname = "", + int lineno = 0); + bkdr.fname = fname; + bkdr.lineno = lineno; + if (this.backdoor != null && + this.backdoor.has_update_threads()) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", "Previous register backdoor still has update threads running. Backdoors with active mirroring should only be set before simulation starts.", UVM_NONE, "t/uvm/src/reg/uvm_reg_block.svh", 2004, "", 1); + end + end + this.backdoor = bkdr; +endfunction: set_backdoor +function uvm_reg_backdoor uvm_reg_block::get_backdoor(bit inherited = 1); + if (backdoor == null && inherited) begin + uvm_reg_block blk = get_parent(); + while (blk != null) begin + uvm_reg_backdoor bkdr = blk.get_backdoor(); + if (bkdr != null) + return bkdr; + blk = blk.get_parent(); + end + end + return this.backdoor; +endfunction: get_backdoor +function void uvm_reg_block::clear_hdl_path(string kind = "RTL"); + if (kind == "ALL") begin + hdl_paths_pool = new("hdl_paths"); + return; + end + if (kind == "") + kind = get_default_hdl_path(); + if (!hdl_paths_pool.exists(kind)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"RegModel")) + uvm_report_warning ("RegModel", {"Unknown HDL Abstraction '",kind,"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_block.svh", 2040, "", 1); + end + return; + end + hdl_paths_pool.delete(kind); +endfunction +function void uvm_reg_block::add_hdl_path(string path, string kind = "RTL"); + uvm_queue #(string) paths; + paths = hdl_paths_pool.get(kind); + paths.push_back(path); +endfunction +function bit uvm_reg_block::has_hdl_path(string kind = ""); + if (kind == "") begin + kind = get_default_hdl_path(); + end + return hdl_paths_pool.exists(kind); +endfunction +function void uvm_reg_block::get_hdl_path(ref string paths[$], input string kind = ""); + uvm_queue #(string) hdl_paths; + if (kind == "") + kind = get_default_hdl_path(); + if (!has_hdl_path(kind)) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"RegModel")) + uvm_report_error ("RegModel", {"Block does not have hdl path defined for abstraction '",kind,"'"}, UVM_NONE, "t/uvm/src/reg/uvm_reg_block.svh", 2081, "", 1); + end + return; + end + hdl_paths = hdl_paths_pool.get(kind); + for (int i=0; i 0) begin + mem.read(status, k-1, val, UVM_FRONTDOOR, maps[j], this); + if (status != UVM_IS_OK) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"uvm_mem_walk_seq")) + uvm_report_error ("uvm_mem_walk_seq", $sformatf("Status was %s when reading \"%s[%0d]\" through map \"%s\".", status.name(), mem.get_full_name(), k, maps[j].get_full_name()), UVM_NONE, "t/uvm/src/reg/sequences/uvm_mem_walk_seq.svh", 143, "", 1); + end + end + else begin + exp = ~(k-1) & ((1'b1< 32) + val = uvm_reg_data_t'(val << 32) | $random; + if (mode == "RO") begin + mem.peek(status, k, exp); + if (status != UVM_IS_OK) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"uvm_mem_access_seq")) + uvm_report_error ("uvm_mem_access_seq", $sformatf("Status was %s when reading \"%s[%0d]\" through backdoor.", status.name(), mem.get_full_name(), k), UVM_NONE, "t/uvm/src/reg/sequences/uvm_mem_access_seq.svh", 124, "", 1); + end + end + end + else exp = val; + mem.write(status, k, val, UVM_FRONTDOOR, maps[j], this); + if (status != UVM_IS_OK) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"uvm_mem_access_seq")) + uvm_report_error ("uvm_mem_access_seq", $sformatf("Status was %s when writing \"%s[%0d]\" through map \"%s\".", status.name(), mem.get_full_name(), k, maps[j].get_full_name()), UVM_NONE, "t/uvm/src/reg/sequences/uvm_mem_access_seq.svh", 132, "", 1); + end + end + #1; + val = 'x; + mem.peek(status, k, val); + if (status != UVM_IS_OK) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"uvm_mem_access_seq")) + uvm_report_error ("uvm_mem_access_seq", $sformatf("Status was %s when reading \"%s[%0d]\" through backdoor.", status.name(), mem.get_full_name(), k), UVM_NONE, "t/uvm/src/reg/sequences/uvm_mem_access_seq.svh", 140, "", 1); + end + end + else begin + if (val !== exp) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"uvm_mem_access_seq")) + uvm_report_error ("uvm_mem_access_seq", $sformatf("Backdoor \"%s[%0d]\" read back as 'h%h instead of 'h%h.", mem.get_full_name(), k, val, exp), UVM_NONE, "t/uvm/src/reg/sequences/uvm_mem_access_seq.svh", 145, "", 1); + end + end + end + exp = ~exp & ((1'b1< local_size__) + abstractions = abstractions[0:local_size__-1]; + else + while (abstractions.size() < local_size__) abstractions.push_back(abstractions[local_size__]); + foreach (abstractions[i]) + abstractions[i] = __local_packer__.unpack_string(); + end +UVM_RECORD: + if (!((UVM_DEFAULT)&UVM_NORECORD)) begin + begin + int sz__; + foreach (abstractions[i]) + sz__ = i; + if(sz__ == 0) begin + if (__local_recorder__ != null && __local_recorder__.is_open()) begin + if (__local_recorder__.use_record_attribute()) + __local_recorder__.record_generic("abstractions", $sformatf("%p", 0)); + else + if (32 > 64) + __local_recorder__.record_field("abstractions", 0, 32, UVM_DEC); + else + __local_recorder__.record_field_int("abstractions", 0, 32, UVM_DEC); + end + end + else if(sz__ < 10) begin + foreach(abstractions[i]) begin + string nm__ = $sformatf("%s[%0d]", "abstractions", i); + if (__local_recorder__ != null && __local_recorder__.is_open()) begin + if (__local_recorder__.use_record_attribute()) + __local_recorder__.record_generic(nm__, $sformatf("%p", abstractions[i])); + else + __local_recorder__.record_string(nm__,abstractions[i]); + end + end + end + else begin + for(int i=0; i<5; ++i) begin + string nm__ = $sformatf("%s[%0d]", "abstractions", i); + if (__local_recorder__ != null && __local_recorder__.is_open()) begin + if (__local_recorder__.use_record_attribute()) + __local_recorder__.record_generic(nm__, $sformatf("%p", abstractions[i])); + else + __local_recorder__.record_string(nm__,abstractions[i]); + end + end + for(int i=sz__-5; i __tmp_curr) + __tmp_curr = __tmp_max - __tmp_end_elements; + if (__tmp_curr < __tmp_begin_elements) + __tmp_curr = __tmp_begin_elements; + else + __local_printer__.print_array_range(__tmp_begin_elements, __tmp_curr-1); + while (__tmp_curr < __tmp_max) begin + __local_printer__.print_string($sformatf("[%0d]", __tmp_curr), abstractions[__tmp_curr]); + __tmp_curr++; + end + end + end + end + __local_printer__.print_array_footer(__tmp_max); +end + end +UVM_SET: + if (!((UVM_DEFAULT)&UVM_NOSET)) begin + if(local_rsrc_name__ == "abstractions") begin +begin +begin + uvm_resource#(uvm_integral_t) __tmp_rsrc__; + local_success__ = $cast(__tmp_rsrc__, local_rsrc__); + if (local_success__) begin + local_size__ = __tmp_rsrc__.read(this); + end +end + if (!local_success__) +begin + uvm_resource#(uvm_bitstream_t) __tmp_rsrc__; + local_success__ = $cast(__tmp_rsrc__, local_rsrc__); + if (local_success__) begin + local_size__ = __tmp_rsrc__.read(this); + end +end + if (!local_success__) +begin + uvm_resource#(int) __tmp_rsrc__; + local_success__ = $cast(__tmp_rsrc__, local_rsrc__); + if (local_success__) begin + local_size__ = __tmp_rsrc__.read(this); + end +end + if (!local_success__) +begin + uvm_resource#(int unsigned) __tmp_rsrc__; + local_success__ = $cast(__tmp_rsrc__, local_rsrc__); + if (local_success__) begin + local_size__ = __tmp_rsrc__.read(this); + end +end +end + if (local_success__) + if (abstractions.size() > local_size__) + abstractions = abstractions[0:local_size__-1]; + else + while (abstractions.size() < local_size__) abstractions.push_back(abstractions[local_size__]); + end + else begin + string local_name__ = {"abstractions", "["}; + if (local_rsrc_name__.len() && + local_rsrc_name__[local_rsrc_name__.len()-1] == "]" && + local_rsrc_name__.substr(0, local_name__.len()-1) == local_name__) begin + string local_index_str__ = local_rsrc_name__.substr(local_name__.len(), + local_rsrc_name__.len()-2); + int local_index__; + int local_code__ = $sscanf(local_index_str__, "%d", local_index__); + if (local_code__ > 0) begin + if (local_index__ < 0) begin + begin + if (uvm_report_enabled(UVM_NONE,UVM_WARNING,"UVM/FIELDS/QDA_IDX")) + uvm_report_warning ("UVM/FIELDS/QDA_IDX", $sformatf("Index '%0d' is not valid for field '%s.%s' of size '%0d'", local_index__, get_full_name(), "abstractions", abstractions.size() ), UVM_NONE, "t/uvm/src/reg/sequences/uvm_reg_mem_hdl_paths_seq.svh", 59, "", 1); + end + end + else begin + string tmp_string__; +begin + uvm_resource#(string) __tmp_rsrc__; + local_success__ = $cast(__tmp_rsrc__, local_rsrc__); + if (local_success__) begin + tmp_string__ = __tmp_rsrc__.read(this); + end +end + if (local_success__) begin + if (local_index__ >= abstractions.size()) + if (abstractions.size() > local_index__ + 1) + abstractions = abstractions[0:local_index__ + 1-1]; + else + while (abstractions.size() < local_index__ + 1) abstractions.push_back(abstractions[local_index__ + 1]); + abstractions[local_index__] = tmp_string__; + end + end + end + end + end + end + endcase + end +endfunction : __m_uvm_execute_field_op + function new(string name="uvm_reg_mem_hdl_paths_seq"); + super.new(name); + endfunction + virtual task body(); + if (model == null) begin + uvm_report_error("uvm_reg_mem_hdl_paths_seq", "Register model handle is null"); + return; + end + begin + if (uvm_report_enabled(UVM_LOW,UVM_INFO,"uvm_reg_mem_hdl_paths_seq")) + uvm_report_info ("uvm_reg_mem_hdl_paths_seq", {"checking HDL paths for all registers/memories in ", model.get_full_name()}, UVM_LOW, "t/uvm/src/reg/sequences/uvm_reg_mem_hdl_paths_seq.svh", 76, "", 1); + end + if (abstractions.size() == 0) + do_block(model, ""); + else begin + foreach (abstractions[i]) + do_block(model, abstractions[i]); + end + begin + if (uvm_report_enabled(UVM_LOW,UVM_INFO,"uvm_reg_mem_hdl_paths_seq")) + uvm_report_info ("uvm_reg_mem_hdl_paths_seq", "HDL path validation completed ", UVM_LOW, "t/uvm/src/reg/sequences/uvm_reg_mem_hdl_paths_seq.svh", 85, "", 1); + end + endtask: body + virtual task reset_blk(uvm_reg_block blk); + endtask + protected virtual function void do_block(uvm_reg_block blk, + string kind); + uvm_reg regs[$]; + uvm_mem mems[$]; + begin + if (uvm_report_enabled(UVM_MEDIUM,UVM_INFO,"uvm_reg_mem_hdl_paths_seq")) + uvm_report_info ("uvm_reg_mem_hdl_paths_seq", {"Validating HDL paths in ", blk.get_full_name(), " for ", (kind == "") ? "default" : kind, " design abstraction"}, UVM_MEDIUM, "t/uvm/src/reg/sequences/uvm_reg_mem_hdl_paths_seq.svh", 104, "", 1); + end + blk.get_registers(regs, UVM_NO_HIER); + foreach (regs[i]) + check_reg(regs[i], kind); + blk.get_memories(mems, UVM_NO_HIER); + foreach (mems[i]) + check_mem(mems[i], kind); + begin + uvm_reg_block blks[$]; + blk.get_blocks(blks); + foreach (blks[i]) begin + do_block(blks[i], kind); + end + end + endfunction: do_block + protected virtual function void check_reg(uvm_reg r, + string kind); + uvm_hdl_path_concat paths[$]; + if(!r.has_hdl_path(kind)) + return; + r.get_full_hdl_path(paths, kind); + if (paths.size() == 0) return; + foreach(paths[p]) begin + uvm_hdl_path_concat path=paths[p]; + foreach (path.slices[j]) begin + string p_ = path.slices[j].path; + uvm_reg_data_t d; +//TODO issue #4467 - Fix UVM function output width reassignment +//TODO %Error: t/t_uvm_pkg_todo.vh:19861:21: Function Argument expects a CLASSREFDTYPE 'uvm_sequencer__Tz97_TBz97', got CLASSREFDTYPE 'uvm_sequencer__Tz97' +//TODO if (!uvm_hdl_read(p_,d)) +//TODO begin +//TODO if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"uvm_reg_mem_hdl_paths_seq")) +//TODO uvm_report_error ("uvm_reg_mem_hdl_paths_seq", $sformatf("HDL path \"%s\" for register \"%s\" is not readable", p_, r.get_full_name()), UVM_NONE, "t/uvm/src/reg/sequences/uvm_reg_mem_hdl_paths_seq.svh", 145, "", 1); +//TODO end + if (!uvm_hdl_check_path(p_)) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"uvm_reg_mem_hdl_paths_seq")) + uvm_report_error ("uvm_reg_mem_hdl_paths_seq", $sformatf("HDL path \"%s\" for register \"%s\" is not accessible", p_, r.get_full_name()), UVM_NONE, "t/uvm/src/reg/sequences/uvm_reg_mem_hdl_paths_seq.svh", 149, "", 1); + end + end + end + endfunction + protected virtual function void check_mem(uvm_mem m, + string kind); + uvm_hdl_path_concat paths[$]; + if(!m.has_hdl_path(kind)) + return; + m.get_full_hdl_path(paths, kind); + if (paths.size() == 0) return; + foreach(paths[p]) begin + uvm_hdl_path_concat path=paths[p]; + foreach (path.slices[j]) + begin + string p_ = path.slices[j].path; + if(!uvm_hdl_check_path(p_)) + begin + if (uvm_report_enabled(UVM_NONE,UVM_ERROR,"uvm_reg_mem_hdl_paths_seq")) + uvm_report_error ("uvm_reg_mem_hdl_paths_seq", $sformatf("HDL path \"%s\" for memory \"%s\" is not accessible", p_, m.get_full_name()), UVM_NONE, "t/uvm/src/reg/sequences/uvm_reg_mem_hdl_paths_seq.svh", 174, "", 1); + end + end + end + endfunction +endclass: uvm_reg_mem_hdl_paths_seq +endpackage diff --git a/test_regress/t/t_uvm_todo.pl b/test_regress/t/t_uvm_todo.pl new file mode 100755 index 000000000..d45b6064f --- /dev/null +++ b/test_regress/t/t_uvm_todo.pl @@ -0,0 +1,30 @@ +#!/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 => ["--timing", + "-Wno-PKGNODECL -Wno-IMPLICITSTATIC -Wno-CONSTRAINTIGN -Wno-MISINDENT", + "-Wno-CASEINCOMPLETE -Wno-CASTCONST -Wno-SYMRSVDWORD -Wno-WIDTHEXPAND -Wno-WIDTHTRUNC", + "-Wno-REALCVT", # TODO note mostly related to $realtime - could suppress or fix upstream + "-Wno-INFINITELOOP" , # TODO issue #4323, false warning + "-Wno-RANDC", # TODO issue #4349, add support + "-Wno-ZERODLY", # TODO issue #4494, add support + ], + verilator_make_gmake => 0, + ); + +#execute( +# check_finished => 1, +# ); + +ok(1); +1; diff --git a/test_regress/t/t_uvm_todo.v b/test_regress/t/t_uvm_todo.v new file mode 100644 index 000000000..20bd2827d --- /dev/null +++ b/test_regress/t/t_uvm_todo.v @@ -0,0 +1,16 @@ +// 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 + +`include "t_uvm_pkg_todo.vh" + +module t(/*AUTOARG*/); + + initial begin + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule From aa608472aeb7df5ba3e0e453108c586936e39a81 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 15 Sep 2023 20:46:31 -0400 Subject: [PATCH 103/111] Support recursive function calls (#3267). --- Changes | 1 + src/V3Width.cpp | 8 +------- test_regress/t/t_func_recurse.out | 6 ------ test_regress/t/t_func_recurse.pl | 4 +--- test_regress/t/t_func_recurse2.out | 6 ------ test_regress/t/t_func_recurse2.pl | 4 +--- test_regress/t/t_func_recurse_param.out | 5 ----- test_regress/t/t_func_recurse_param_bad.out | 5 ----- test_regress/t/t_uvm_pkg_todo.vh | 6 ++---- 9 files changed, 6 insertions(+), 39 deletions(-) delete mode 100644 test_regress/t/t_func_recurse.out delete mode 100644 test_regress/t/t_func_recurse2.out diff --git a/Changes b/Changes index 5f835040b..dbdee17e6 100644 --- a/Changes +++ b/Changes @@ -14,6 +14,7 @@ Verilator 5.015 devel **Minor:** * Add --no-trace-top to not trace top signals (#4412) (#4422). [Frans Skarman] +* Support recursive function calls (#3267). * Support assignments of packed values to stream expressions on queues (#4401). [Ryszard Rozak, Antmicro Ltd] * Support no-parentheses calls to static methods (#4432). [Krzysztof Boroński] * Support 'let'. diff --git a/src/V3Width.cpp b/src/V3Width.cpp index a24f57345..b6a58fcea 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -5322,13 +5322,7 @@ private: // Grab width from the output variable (if it's a function) if (nodep->didWidth()) return; if (nodep->doingWidth()) { - if (nodep->classMethod()) { - UINFO(5, "Recursive method call: " << nodep); - } else { - UINFO(5, "Recursive function or task call: " << nodep); - nodep->v3warn(E_UNSUPPORTED, "Unsupported: Recursive function or task call: " - << nodep->prettyNameQ()); - } + UINFO(5, "Recursive function or task call: " << nodep); nodep->recursive(true); nodep->didWidth(true); return; diff --git a/test_regress/t/t_func_recurse.out b/test_regress/t/t_func_recurse.out deleted file mode 100644 index 81f9b9dde..000000000 --- a/test_regress/t/t_func_recurse.out +++ /dev/null @@ -1,6 +0,0 @@ -%Error-UNSUPPORTED: t/t_func_recurse.v:9:27: Unsupported: Recursive function or task call: 'recurse_self' - : ... In instance t - 9 | function automatic int recurse_self; - | ^~~~~~~~~~~~ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error: Exiting due to diff --git a/test_regress/t/t_func_recurse.pl b/test_regress/t/t_func_recurse.pl index be66c40e6..b46d46042 100755 --- a/test_regress/t/t_func_recurse.pl +++ b/test_regress/t/t_func_recurse.pl @@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - fails => $Self->{vlt_all}, - expect_filename => $Self->{golden_filename}, ); execute( check_finished => 1, - ) if !$Self->{vlt_all}; + ); ok(1); 1; diff --git a/test_regress/t/t_func_recurse2.out b/test_regress/t/t_func_recurse2.out deleted file mode 100644 index b93b57e47..000000000 --- a/test_regress/t/t_func_recurse2.out +++ /dev/null @@ -1,6 +0,0 @@ -%Error-UNSUPPORTED: t/t_func_recurse2.v:9:27: Unsupported: Recursive function or task call: 'recurse_1' - : ... In instance t - 9 | function automatic int recurse_1; - | ^~~~~~~~~ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error: Exiting due to diff --git a/test_regress/t/t_func_recurse2.pl b/test_regress/t/t_func_recurse2.pl index be66c40e6..b46d46042 100755 --- a/test_regress/t/t_func_recurse2.pl +++ b/test_regress/t/t_func_recurse2.pl @@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - fails => $Self->{vlt_all}, - expect_filename => $Self->{golden_filename}, ); execute( check_finished => 1, - ) if !$Self->{vlt_all}; + ); ok(1); 1; diff --git a/test_regress/t/t_func_recurse_param.out b/test_regress/t/t_func_recurse_param.out index 102d49d6f..ba95348dc 100644 --- a/test_regress/t/t_func_recurse_param.out +++ b/test_regress/t/t_func_recurse_param.out @@ -1,8 +1,3 @@ -%Error-UNSUPPORTED: t/t_func_recurse_param.v:9:27: Unsupported: Recursive function or task call: 'recurse_self' - : ... In instance t - 9 | function automatic int recurse_self; - | ^~~~~~~~~~~~ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest %Error: t/t_func_recurse_param.v:15:26: Expecting expression to be constant, but can't determine constant for FUNCREF 'recurse_self' : ... In instance t t/t_func_recurse_param.v:9:27: ... Location of non-constant FUNC 'recurse_self': Unsupported: Recursive constant functions diff --git a/test_regress/t/t_func_recurse_param_bad.out b/test_regress/t/t_func_recurse_param_bad.out index 121ee90f9..7ec686842 100644 --- a/test_regress/t/t_func_recurse_param_bad.out +++ b/test_regress/t/t_func_recurse_param_bad.out @@ -1,8 +1,3 @@ -%Error-UNSUPPORTED: t/t_func_recurse_param_bad.v:9:27: Unsupported: Recursive function or task call: 'recurse_self' - : ... In instance t - 9 | function automatic int recurse_self; - | ^~~~~~~~~~~~ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest %Error: t/t_func_recurse_param_bad.v:15:26: Expecting expression to be constant, but can't determine constant for FUNCREF 'recurse_self' : ... In instance t t/t_func_recurse_param_bad.v:9:27: ... Location of non-constant FUNC 'recurse_self': Unsupported: Recursive constant functions diff --git a/test_regress/t/t_uvm_pkg_todo.vh b/test_regress/t/t_uvm_pkg_todo.vh index be8852449..7f7c8b075 100644 --- a/test_regress/t/t_uvm_pkg_todo.vh +++ b/test_regress/t/t_uvm_pkg_todo.vh @@ -765,10 +765,8 @@ function void uvm_report_fatal(string id, uvm_coreservice_t cs; cs = uvm_coreservice_t::get(); top = cs.get_root(); -//TODO issue #3267 - Support recursive functions -//TODO %Error-UNSUPPORTED: t/t_uvm_pkg_todo.vh:753:15: Unsupported: Recursive function or task call: 'uvm_report_fatal' -//TODO top.uvm_report_fatal(id, message, verbosity, filename, line, context_name, -//TODO report_enabled_checked); + top.uvm_report_fatal(id, message, verbosity, filename, line, context_name, + report_enabled_checked); endfunction function void uvm_process_report_message(uvm_report_message report_message); uvm_root top; From 19f72795424664f936c2a2becd3f10a89f143b47 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 15 Sep 2023 22:05:55 -0400 Subject: [PATCH 104/111] Fix false INFINITELOOP on forever..mailbox.get() (#4323). --- Changes | 1 + src/V3Const.cpp | 11 ++++++++- test_regress/t/t_lint_infinite.pl | 23 ++++++++++++++++++ test_regress/t/t_lint_infinite.v | 36 ++++++++++++++++++++++++++++ test_regress/t/t_lint_infinite_bad.v | 1 + test_regress/t/t_uvm_todo.pl | 1 - 6 files changed, 71 insertions(+), 2 deletions(-) create mode 100755 test_regress/t/t_lint_infinite.pl create mode 100644 test_regress/t/t_lint_infinite.v diff --git a/Changes b/Changes index dbdee17e6..2c8535966 100644 --- a/Changes +++ b/Changes @@ -19,6 +19,7 @@ Verilator 5.015 devel * Support no-parentheses calls to static methods (#4432). [Krzysztof Boroński] * Support 'let'. * Fix Windows filename format, etc (#3873) (#4421). [Anthony Donlon]. +* Fix false INFINITELOOP on forever..mailbox.get() (#4323). [Srinivasan Venkataramanan] * Fix data type of condition operation on class objects (#4345) (#4352). [Ryszard Rozak, Antmicro Ltd] * Fix ++/-- under statements (#4399). [Aleksander Kiryk, Antmicro Ltd] * Fix detection of mixed blocking and nonblocking assignment in nested assignments (#4404). [Ryszard Rozak, Antmicro Ltd] diff --git a/src/V3Const.cpp b/src/V3Const.cpp index b76c8244b..696fceb5e 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -3204,8 +3204,17 @@ private: iterateChildren(nodep); } - void visit(AstFuncRef* nodep) override { + void visit(AstNodeCCall* nodep) override { iterateChildren(nodep); + m_hasJumpDelay = true; // As don't analyze inside tasks for timing controls + } + void visit(AstNodeFTaskRef* nodep) override { + // Note excludes AstFuncRef as other visitor below + iterateChildren(nodep); + m_hasJumpDelay = true; // As don't analyze inside tasks for timing controls + } + void visit(AstFuncRef* nodep) override { + visit(static_cast(nodep)); if (m_params) { // Only parameters force us to do constant function call propagation replaceWithSimulation(nodep); } diff --git a/test_regress/t/t_lint_infinite.pl b/test_regress/t/t_lint_infinite.pl new file mode 100755 index 000000000..3364f1ed7 --- /dev/null +++ b/test_regress/t/t_lint_infinite.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( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_lint_infinite.v b/test_regress/t/t_lint_infinite.v new file mode 100644 index 000000000..305cd1e2d --- /dev/null +++ b/test_regress/t/t_lint_infinite.v @@ -0,0 +1,36 @@ +// 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 + +module t; + + mailbox #(int) mbox; + + task main(); + // See issue #4323; not an INFINITELOOP due to delay inside get() + forever begin + int i; + mbox.get(i); + $display("[%0t] Got %0d", $time, i); + end + endtask + + initial begin + mbox = new (1); + + #10; + fork + main(); + join_none + + #10; + mbox.put(10); + mbox.put(11); + + #10; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_lint_infinite_bad.v b/test_regress/t/t_lint_infinite_bad.v index 4bf795db2..c3cc1cc1b 100644 --- a/test_regress/t/t_lint_infinite_bad.v +++ b/test_regress/t/t_lint_infinite_bad.v @@ -10,5 +10,6 @@ module t (); forever begin end // verilator lint_off UNSIGNED for (reg [31:0] i=0; i>=0; i=i+1) begin end + $display; // So loop not eaten end endmodule diff --git a/test_regress/t/t_uvm_todo.pl b/test_regress/t/t_uvm_todo.pl index d45b6064f..b71e06d09 100755 --- a/test_regress/t/t_uvm_todo.pl +++ b/test_regress/t/t_uvm_todo.pl @@ -15,7 +15,6 @@ compile( "-Wno-PKGNODECL -Wno-IMPLICITSTATIC -Wno-CONSTRAINTIGN -Wno-MISINDENT", "-Wno-CASEINCOMPLETE -Wno-CASTCONST -Wno-SYMRSVDWORD -Wno-WIDTHEXPAND -Wno-WIDTHTRUNC", "-Wno-REALCVT", # TODO note mostly related to $realtime - could suppress or fix upstream - "-Wno-INFINITELOOP" , # TODO issue #4323, false warning "-Wno-RANDC", # TODO issue #4349, add support "-Wno-ZERODLY", # TODO issue #4494, add support ], From 05d04a3959f31e645ee48ea079fd627c459e2d28 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 15 Sep 2023 23:02:34 -0400 Subject: [PATCH 105/111] Internals: Fix misnamed member. No functional change. --- src/V3Randomize.cpp | 4 ++-- src/V3Timing.cpp | 4 ++-- src/V3Width.cpp | 26 ++++++++++++++------------ 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index 95013b505..7d6aad6f9 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -139,7 +139,7 @@ private: const VNUser2InUse m_inuser2; // STATE - VMemberMap memberMap; // Member names cached for fast lookup + VMemberMap m_memberMap; // Member names cached for fast lookup AstNodeModule* m_modp = nullptr; // Current module const AstNodeFTask* m_ftaskp = nullptr; // Current function/task size_t m_enumValueTabCount = 0; // Number of tables with enum values created @@ -215,7 +215,7 @@ private: } } void addPrePostCall(AstClass* classp, AstFunc* funcp, const string& name) { - if (AstTask* userFuncp = VN_CAST(memberMap.findMember(classp, name), Task)) { + if (AstTask* userFuncp = VN_CAST(m_memberMap.findMember(classp, name), Task)) { AstTaskRef* const callp = new AstTaskRef{userFuncp->fileline(), userFuncp->name(), nullptr}; callp->taskp(userFuncp); diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp index a21892e00..ba5fb36e1 100644 --- a/src/V3Timing.cpp +++ b/src/V3Timing.cpp @@ -165,7 +165,7 @@ private: const VNUser5InUse m_user5InUse; // STATE - VMemberMap memberMap; // Member names cached for fast lookup + VMemberMap m_memberMap; // Member names cached for fast lookup AstClass* m_classp = nullptr; // Current class AstNode* m_procp = nullptr; // NodeProcedure/CFunc/Begin we're under uint8_t m_underFork = F_NONE; // F_NONE or flags of a fork we are under @@ -265,7 +265,7 @@ private: // the root of the inheritance hierarchy and check if the original method is // virtual or not. if (auto* const overriddenp - = VN_CAST(memberMap.findMember(cextp->classp(), nodep->name()), CFunc)) { + = VN_CAST(m_memberMap.findMember(cextp->classp(), nodep->name()), CFunc)) { // Suspendability and process affects typing, so they propagate both ways DepVtx* const overriddenSVxp = getSuspendDepVtx(overriddenp); DepVtx* const overriddenPVxp = getNeedsProcDepVtx(overriddenp); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index b6a58fcea..eb3e38dfe 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -223,7 +223,7 @@ private: using DTypeMap = std::map; // STATE - VMemberMap memberMap; // Member names cached for fast lookup + VMemberMap m_memberMap; // Member names cached for fast lookup 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 @@ -2640,7 +2640,8 @@ private: AstPackage* const packagep = getItemPackage(nodep); if (packagep && packagep->name() == "std") { // Change type of m_process to VlProcessRef - if (AstVar* const varp = VN_CAST(memberMap.findMember(nodep, "m_process"), Var)) { + if (AstVar* const varp + = VN_CAST(m_memberMap.findMember(nodep, "m_process"), Var)) { AstNodeDType* const dtypep = varp->getChildDTypep(); if (!varp->dtypep()) { VL_DO_DANGLING(pushDeletep(dtypep->unlinkFrBack()), dtypep); @@ -2652,7 +2653,7 @@ private: } // Mark that self requires process instance if (AstNodeFTask* const ftaskp - = VN_CAST(memberMap.findMember(nodep, "self"), NodeFTask)) { + = VN_CAST(m_memberMap.findMember(nodep, "self"), NodeFTask)) { ftaskp->setNeedProcess(); } } @@ -2761,7 +2762,7 @@ private: AstClass* const first_classp = adtypep->classp(); UASSERT_OBJ(first_classp, nodep, "Unlinked"); for (AstClass* classp = first_classp; classp;) { - if (AstNode* const foundp = memberMap.findMember(classp, nodep->name())) { + if (AstNode* const foundp = m_memberMap.findMember(classp, nodep->name())) { if (AstVar* const varp = VN_CAST(foundp, Var)) { if (!varp->didWidth()) userIterate(varp, nullptr); if (varp->lifetime().isStatic()) { @@ -2837,7 +2838,7 @@ private: bool memberSelStruct(AstMemberSel* nodep, AstNodeUOrStructDType* adtypep) { // Returns true if ok if (AstMemberDType* const memberp - = VN_CAST(memberMap.findMember(adtypep, nodep->name()), MemberDType)) { + = VN_CAST(m_memberMap.findMember(adtypep, nodep->name()), MemberDType)) { if (m_attrp) { // Looking for the base of the attribute nodep->dtypep(memberp); UINFO(9, " MEMBERSEL(attr) -> " << nodep << endl); @@ -3500,10 +3501,10 @@ private: AstClass* const first_classp = adtypep->classp(); if (nodep->name() == "randomize") { V3Randomize::newRandomizeFunc(first_classp); - memberMap.clear(); + m_memberMap.clear(); } else if (nodep->name() == "srandom") { V3Randomize::newSRandomFunc(first_classp); - memberMap.clear(); + m_memberMap.clear(); } UASSERT_OBJ(first_classp, nodep, "Unlinked"); for (AstClass* classp = first_classp; classp;) { @@ -3526,7 +3527,7 @@ private: } } if (AstNodeFTask* const ftaskp - = VN_CAST(memberMap.findMember(classp, nodep->name()), NodeFTask)) { + = VN_CAST(m_memberMap.findMember(classp, nodep->name()), NodeFTask)) { userIterate(ftaskp, nullptr); if (ftaskp->lifetime().isStatic()) { AstNodeExpr* argsp = nullptr; @@ -3795,7 +3796,8 @@ private: classp = refp->classp(); UASSERT_OBJ(classp, nodep, "Unlinked"); - if (AstNodeFTask* const ftaskp = VN_CAST(memberMap.findMember(classp, "new"), Func)) { + if (AstNodeFTask* const ftaskp + = VN_CAST(m_memberMap.findMember(classp, "new"), Func)) { nodep->taskp(ftaskp); nodep->classOrPackagep(classp); } else { @@ -3963,7 +3965,7 @@ private: // '{member:value} or '{data_type: default_value} if (const AstText* textp = VN_CAST(patp->keyp(), Text)) { // member: value - memp = VN_CAST(memberMap.findMember(vdtypep, textp->text()), + memp = VN_CAST(m_memberMap.findMember(vdtypep, textp->text()), MemberDType); if (!memp) { patp->keyp()->v3error("Assignment pattern key '" @@ -5609,10 +5611,10 @@ private: UASSERT_OBJ(classp, nodep, "Should have failed in V3LinkDot"); if (nodep->name() == "randomize") { nodep->taskp(V3Randomize::newRandomizeFunc(classp)); - memberMap.clear(); + m_memberMap.clear(); } else if (nodep->name() == "srandom") { nodep->taskp(V3Randomize::newSRandomFunc(classp)); - memberMap.clear(); + m_memberMap.clear(); } else if (nodep->name() == "get_randstate") { methodOkArguments(nodep, 0, 0); classp->baseMostClassp()->needRNG(true); From 10fbe74cef33dbe0ded48037da020460a71e2578 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 15 Sep 2023 23:25:28 -0400 Subject: [PATCH 106/111] Commentary: Changes update --- Changes | 15 +++++++++++++++ docs/spelling.txt | 4 ++++ 2 files changed, 19 insertions(+) diff --git a/Changes b/Changes index 2c8535966..3677caa4e 100644 --- a/Changes +++ b/Changes @@ -13,17 +13,28 @@ Verilator 5.015 devel **Minor:** +* Add prepareClone and atClone APIs for Verilated models (#3503) (#4444). [Yinan Xu] +* Add check for conflicting options e.g. binary and lint-only (#4409). [Ethan Sifferman] * Add --no-trace-top to not trace top signals (#4412) (#4422). [Frans Skarman] * Support recursive function calls (#3267). * Support assignments of packed values to stream expressions on queues (#4401). [Ryszard Rozak, Antmicro Ltd] * 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 '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] +* Optimize preparations towards multithreading Verilation (#4463) (#4476) (#4477) (#4479). [Kamil Rakoczy, Antmicro Ltd] * Fix Windows filename format, etc (#3873) (#4421). [Anthony Donlon]. +* Fix using type in parameterized classes without #() (#4281) (#4440). [Anthony Donlon] * Fix false INFINITELOOP on forever..mailbox.get() (#4323). [Srinivasan Venkataramanan] * Fix data type of condition operation on class objects (#4345) (#4352). [Ryszard Rozak, Antmicro Ltd] +* Fix variables mutated under fork..join_none/join_any blocks into anonymous objects (#4356). [Krzysztof Boroński] +* Fix V3CUse, do not consider implementations (.cpp) at all (#4386). [Krzysztof Boroński] * Fix ++/-- under statements (#4399). [Aleksander Kiryk, Antmicro Ltd] * Fix detection of mixed blocking and nonblocking assignment in nested assignments (#4404). [Ryszard Rozak, Antmicro Ltd] * Fix jumping over object initialization (#4411). [Krzysztof Boroński] +* Fix multiple issues towards short circuit support (#4413) (#4460). [Ryszard Rozak, Antmicro Ltd] * Fix variable lifetimes in extern methods (#4414). [Krzysztof Boroński] * Fix multiple function definitions in V3Sched (#4416). [Hennadii Chernyshchyk] * Fix false UNUSEDPARAM on generate localparam (#4427). [Bill Pringlemeir] @@ -33,8 +44,12 @@ Verilator 5.015 devel * Fix false MULTITOP on bound interfaces (#4438). [Alex Solomatnikov] * Fix internal error on real conversion (#4447). [vdhotre-ventana] * Fix lifetime unknown error on enum.name (#4448). [jwoutersymatra] +* Fix unstable output of VHashSha256 (#4453). [Anthony Donlon] +* Fix static cast from a stream type (#4469) (#4485). [Ryszard Rozak, Antmicro Ltd] * Fix error on enum with VARHIDDEN of cell (#4482). [Michail Rontionov] +* Fix lint of case statements with enum and wildcard bits (#4464) (#4487). [Anthony Donlon] * Fix reference to extended class in parameterized class (#4466). +* Fix the error message when the type of ref argument is wrong (#4490). [Ryszard Rozak, Antmicro Ltd] * Fix display %x formatting of real. * Fix mis-warning on #() in classes' own functions. * Fix IGNOREDRETURN to not warn on void-cast static function calls. diff --git a/docs/spelling.txt b/docs/spelling.txt index e05450bce..cddf6a1b2 100644 --- a/docs/spelling.txt +++ b/docs/spelling.txt @@ -214,6 +214,7 @@ Maupin Mdir Mednick Menküc +Michail Michiels Microsystems Milanovic @@ -278,6 +279,7 @@ Renga Requin Rodionov Rolfe +Rontionov Roodselaar Runtime Ruud @@ -416,6 +418,7 @@ arrarys assertOn astgen async +atClone ato atoi autoconf @@ -774,6 +777,7 @@ pragmas pre precisions predefines +prepareClone prepend prepended preprocess From 891cc0f9b6c5d18f54958a9d704c54adca0efe96 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 16 Sep 2023 09:22:12 -0400 Subject: [PATCH 107/111] Fix t_dist_cppstyle Perl performance issue (#4085). --- Changes | 3 ++- test_regress/t/t_dist_cppstyle.pl | 27 ++++++++++++++------------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/Changes b/Changes index 3677caa4e..04727c088 100644 --- a/Changes +++ b/Changes @@ -24,8 +24,9 @@ Verilator 5.015 devel * 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] -* Optimize preparations towards multithreading Verilation (#4463) (#4476) (#4477) (#4479). [Kamil Rakoczy, Antmicro Ltd] +* Optimize preparations towards multithreaded Verilation (#4291) (#4463) (#4476) (#4477) (#4479). [Kamil Rakoczy, Antmicro Ltd] * Fix Windows filename format, etc (#3873) (#4421). [Anthony Donlon]. +* Fix t_dist_cppstyle Perl performance issue (#4085). [Srinivasan Venkataramanan] * Fix using type in parameterized classes without #() (#4281) (#4440). [Anthony Donlon] * Fix false INFINITELOOP on forever..mailbox.get() (#4323). [Srinivasan Venkataramanan] * Fix data type of condition operation on class objects (#4345) (#4352). [Ryszard Rozak, Antmicro Ltd] diff --git a/test_regress/t/t_dist_cppstyle.pl b/test_regress/t/t_dist_cppstyle.pl index 7a8f23e5d..222addde0 100755 --- a/test_regress/t/t_dist_cppstyle.pl +++ b/test_regress/t/t_dist_cppstyle.pl @@ -63,18 +63,19 @@ sub checkPattern { my $pattern = shift; my $message = shift; - my $offset = 0; - my $buffer = $contents; - while ($buffer =~ s/.*?^($pattern)//sm) { - my $lineno = offset_to_lineno($contents, $offset + $-[-1]); - $offset += $+[1]; - error("$filename:$lineno: $message"); + my $lineno = 0; + my $buffer; + foreach my $line (split(/\n/, $contents . "\n\n")) { + ++$lineno; + if ($line ne "") { + # Don't do whole file at once - see issue #4085 + # Build a buffer until a newline so we check a block at a time. + $buffer .= $line . "\n"; + next; + } + if ($buffer =~ s/.*?^($pattern)//sm) { + error("$filename:$lineno: $message"); + } + $buffer = ""; } } - -sub offset_to_lineno { - my $contents = shift; - my $offset = shift; - my $count = (substr $contents, 0, $offset) =~ tr/\n//; - return $count + 1; -} From e6fb7e970dfadf8e1e9664ad54e40c52bfc4cb84 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 16 Sep 2023 10:10:21 -0400 Subject: [PATCH 108/111] Fix recursive display causing segfault (#4480). --- Changes | 1 + src/V3EmitCFunc.cpp | 1 + test_regress/t/t_display_recurse.out | 9 +++++ test_regress/t/t_display_recurse.pl | 22 ++++++++++++ test_regress/t/t_display_recurse.v | 52 ++++++++++++++++++++++++++++ 5 files changed, 85 insertions(+) create mode 100644 test_regress/t/t_display_recurse.out create mode 100755 test_regress/t/t_display_recurse.pl create mode 100644 test_regress/t/t_display_recurse.v diff --git a/Changes b/Changes index 04727c088..5b2c2f8ea 100644 --- a/Changes +++ b/Changes @@ -50,6 +50,7 @@ Verilator 5.015 devel * Fix error on enum with VARHIDDEN of cell (#4482). [Michail Rontionov] * Fix lint of case statements with enum and wildcard bits (#4464) (#4487). [Anthony Donlon] * Fix reference to extended class in parameterized class (#4466). +* Fix recursive display causing segfault (#4480). [Kuoping Hsu] * Fix the error message when the type of ref argument is wrong (#4490). [Ryszard Rozak, Antmicro Ltd] * Fix display %x formatting of real. * Fix mis-warning on #() in classes' own functions. diff --git a/src/V3EmitCFunc.cpp b/src/V3EmitCFunc.cpp index 8fd63dcf8..644aa9b78 100644 --- a/src/V3EmitCFunc.cpp +++ b/src/V3EmitCFunc.cpp @@ -314,6 +314,7 @@ void EmitCFunc::displayNode(AstNode* nodep, AstScopeName* scopenamep, const stri // Convert Verilog display to C printf formats // "%0t" becomes "%d" + VL_RESTORER(m_emitDispState); m_emitDispState.clear(); string vfmt; string::const_iterator pos = vformat.begin(); diff --git a/test_regress/t/t_display_recurse.out b/test_regress/t/t_display_recurse.out new file mode 100644 index 000000000..a06cc8e4c --- /dev/null +++ b/test_regress/t/t_display_recurse.out @@ -0,0 +1,9 @@ + 0: 0000dead + 4: 0001dead + 8: 0002dead + 12: 0003dead + 16: 0004dead + 20: 0005dead + 24: 0006dead + 28: 0007dead +*-* All Finished *-* diff --git a/test_regress/t/t_display_recurse.pl b/test_regress/t/t_display_recurse.pl new file mode 100755 index 000000000..6e4e9e231 --- /dev/null +++ b/test_regress/t/t_display_recurse.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 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(simulator => 1); + +compile( + ); + +execute( + expect_filename => $Self->{golden_filename}, + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_display_recurse.v b/test_regress/t/t_display_recurse.v new file mode 100644 index 000000000..877792b0f --- /dev/null +++ b/test_regress/t/t_display_recurse.v @@ -0,0 +1,52 @@ +// 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 + +module t(/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + integer i; + integer count = 'd0; + + always @(posedge clk) begin + count <= count + 1; + if (count == 10) begin + for(i=0; i<30; i=i+4) begin + // See issue #4480, verilator may inline getb() which has another display inside it + $display("%d: %02x%02x%02x%02x", i, getb(i+3), getb(i+2), getb(i+1), getb(i)); + end + end + if (count == 11) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + + localparam SIZE = 64*1024; + localparam ADDRW = $clog2(SIZE/4); + reg [31: 0] ram [(SIZE/4)-1: 0]; + + function [7:0] getb; + input [31:0] address; + if (address[31:ADDRW+2] != 0) begin + $display("Address out of range"); + end + case(address[1:0]) + 0: getb = ram[address[ADDRW+1: 2]][8*0+7:8*0]; + 1: getb = ram[address[ADDRW+1: 2]][8*1+7:8*1]; + 2: getb = ram[address[ADDRW+1: 2]][8*2+7:8*2]; + 3: getb = ram[address[ADDRW+1: 2]][8*3+7:8*3]; + endcase + endfunction + + initial begin + for (i=0; i Date: Sat, 16 Sep 2023 17:37:25 -0400 Subject: [PATCH 109/111] 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 = "", From 783b7ecdab320f32c4a900cf666bc52c668b54fa Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 16 Sep 2023 17:52:02 -0400 Subject: [PATCH 110/111] Fix clang override warning (last commit) --- src/V3AstNodeOther.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index 0d9da1d1e..ffb7ef422 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -2111,7 +2111,7 @@ public: } ASTGEN_MEMBERS_AstFunc; bool hasDType() const override { return true; } - AstNodeFTask* cloneType(const string& name) { + AstNodeFTask* cloneType(const string& name) override { return new AstFunc{fileline(), name, nullptr, nullptr}; } }; @@ -2128,7 +2128,7 @@ public: BROKEN_RTN(!VN_IS(stmtsp(), StmtExpr)); return nullptr; } - AstNodeFTask* cloneType(const string& name) { return new AstLet{fileline(), name}; } + AstNodeFTask* cloneType(const string& name) override { return new AstLet{fileline(), name}; } }; class AstProperty final : public AstNodeFTask { // A property inside a module @@ -2137,7 +2137,7 @@ public: : ASTGEN_SUPER_Property(fl, name, stmtp) {} ASTGEN_MEMBERS_AstProperty; bool hasDType() const override { return true; } - AstNodeFTask* cloneType(const string& name) { + AstNodeFTask* cloneType(const string& name) override { return new AstProperty{fileline(), name, nullptr}; } }; @@ -2147,7 +2147,9 @@ 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}; } + AstNodeFTask* cloneType(const string& name) override { + return new AstTask{fileline(), name, nullptr}; + } }; // === AstNodeFile === From cef3960a4ed704e9aa3b8297a6356b1b64a8fbd7 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 16 Sep 2023 18:36:39 -0400 Subject: [PATCH 111/111] Version bump --- Changes | 2 +- configure.ac | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Changes b/Changes index 6d82938f2..2a6f93e02 100644 --- a/Changes +++ b/Changes @@ -8,7 +8,7 @@ The changes in each Verilator version are described below. The contributors that suggested a given feature are shown in []. Thanks! -Verilator 5.015 devel +Verilator 5.016 2023-09-16 ========================== **Minor:** diff --git a/configure.ac b/configure.ac index e0886a557..c10eadcd1 100644 --- a/configure.ac +++ b/configure.ac @@ -10,7 +10,7 @@ # Then 'make maintainer-dist' #AC_INIT([Verilator],[#.### YYYY-MM-DD]) #AC_INIT([Verilator],[#.### devel]) -AC_INIT([Verilator],[5.015 devel], +AC_INIT([Verilator],[5.016 2023-09-16], [https://verilator.org], [verilator],[https://verilator.org])