From a10b51705f8ed2634608097f8be1be96c4a1532b Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Mon, 17 Apr 2023 14:08:57 +0200 Subject: [PATCH] Fix class param extends A=B (#4128) Visit global class params even if a class extends a param --- src/V3LinkDot.cpp | 34 ++++++++++++++++---- test_regress/t/t_class_param_type.v | 48 ++++++++++++++++++++++++++++- 2 files changed, 75 insertions(+), 7 deletions(-) diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index d16fcf454..79de07076 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2011,9 +2011,6 @@ private: // *::user4() -> See LinkDotState // Cleared on Cell // AstVar::user5() // bool. True if pin used in this cell - // AstClass::user5() // bool. True if class has a parameter - // as a (possibly indirect) base class. - // Used only in LDS_PRIMARY pass const VNUser3InUse m_inuser3; const VNUser5InUse m_inuser5; @@ -2037,6 +2034,7 @@ private: int m_modportNum = 0; // Uniqueify modport numbers bool m_inSens = false; // True if in senitem std::set m_ifClassImpNames; // Names imported from interface class + std::set m_extendsParam; // Classes that has a parameter as its super class struct DotStates { DotPosition m_dotPos; // Scope part of dotted resolution @@ -2240,6 +2238,26 @@ private: if (classp->isInterfaceClass()) importImplementsClass(nodep, srcp, classp); if (!cextp->isImplements()) m_curSymp->importFromClass(m_statep->symsp(), srcp); } + void visitGlobalClassParams(AstClass* const nodep) { + // Parameters from port parameter list are at the beginning of the members list, so if a + // node, that isn't a parameter, is encountered, all nodes after aren't global parameters + // too. + for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) { + // Global parameters are at the beginning of the members list, so if a node, that isn't + // a global parameter, is encountered, all nodes after it aren't global parameters too. + bool globalParam = false; + if (const AstParamTypeDType* const parp = VN_CAST(stmtp, ParamTypeDType)) { + if (parp->isGParam()) globalParam = true; + } else if (const AstVar* const varp = VN_CAST(stmtp, Var)) { + if (varp->isGParam()) globalParam = true; + } + if (globalParam) { + iterate(stmtp); + } else { + break; + } + } + } // VISITs void visit(AstNetlist* nodep) override { @@ -3330,9 +3348,13 @@ private: // function iterate(classp); } - if (classp->user5()) { + if (m_statep->forPrimary() + && m_extendsParam.find(classp) != m_extendsParam.end()) { // Has a parameter as its base class - nodep->user5(true); + m_extendsParam.insert(nodep); + // Link global parameters. They are declared before the extends + // statement, so should be unrelated to the base class + visitGlobalClassParams(nodep); return; } AstPin* paramsp = cpackagerefp->paramsp(); @@ -3345,7 +3367,7 @@ private: // Extending has to be handled after V3Param.cpp, but the type // reference has to be visited iterate(paramp); - nodep->user5(true); + m_extendsParam.insert(nodep); return; } else { AstNodeDType* const paramTypep = paramp->getChildDTypep(); diff --git a/test_regress/t/t_class_param_type.v b/test_regress/t/t_class_param_type.v index 31402e10a..f636b4336 100644 --- a/test_regress/t/t_class_param_type.v +++ b/test_regress/t/t_class_param_type.v @@ -1,7 +1,7 @@ // DESCRIPTION: Verilator: Verilog Test module // // This file ONLY is placed under the Creative Commons Public Domain, for -// any use, without warranty, 2022 by Arkadiusz Kozdra. +// any use, without warranty, 2023 by Antmicro Ltd. // SPDX-License-Identifier: CC0-1.0 // See also t_class_param.v @@ -44,6 +44,36 @@ class SingletonUnusedDefault #(type T=int); endfunction endclass +class Empty; +endclass + +class Foo #(type IF=Empty) extends IF; + typedef Foo foo_t; + int a = 1; +endclass + +class Bar #(type A=int, type B=A) extends Foo; + function int get_size_A; + return $bits(A); + endfunction + function int get_size_B; + return $bits(B); + endfunction +endclass + +class Empty2; +endclass + +class Baz #(type T=Empty2) extends Foo; +endclass + +class Getter1 extends Baz; + function int get_1; + foo_t f = new; + return f.a; + endfunction +endclass + module t (/*AUTOARG*/); initial begin @@ -61,6 +91,20 @@ module t (/*AUTOARG*/); automatic SingletonUnusedDefault #(bit) sud1 = SingletonUnusedDefault#(bit)::self(); automatic SingletonUnusedDefault #(bit) sud2 = SingletonUnusedDefault#(bit)::self(); + automatic Getter1 getter1 = new; + + typedef bit my_bit_t; + Bar#(.A(my_bit_t)) bar_a_bit = new; + Bar#(.B(my_bit_t)) bar_b_bit = new; + Bar#() bar_default = new; + + if (bar_a_bit.get_size_A != 1) $stop; + if (bar_a_bit.get_size_B != 1) $stop; + if (bar_b_bit.get_size_A != 32) $stop; + if (bar_b_bit.get_size_B != 1) $stop; + if (bar_default.get_size_A != 32) $stop; + if (bar_default.get_size_B != 32) $stop; + if (pdt1 != pdt2) $stop; if (pdt2 != pdt3) $stop; if (p1 != p2) $stop; @@ -77,6 +121,8 @@ module t (/*AUTOARG*/); if (pdt1.get_p() != 20) $stop; if (Parcls#(cls2_t)::get_p() != 20) $stop; + if (getter1.get_1() != 1) $stop; + $write("*-* All Finished *-*\n"); $finish; end