From 1299b70945ef04708b5c0a87250eb49914c15143 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 27 Nov 2020 22:48:42 -0500 Subject: [PATCH] Internals: Pass class parameters through link. --- src/V3AstNodes.h | 5 +++- src/V3LinkCells.cpp | 7 ++++++ src/V3LinkDot.cpp | 36 +++++++++++++++++++++------- test_regress/t/t_class_param_bad.out | 17 +++++++++++++ test_regress/t/t_class_param_bad.pl | 19 +++++++++++++++ test_regress/t/t_class_param_bad.v | 15 ++++++++++++ test_regress/t/t_class_vparam.out | 3 +++ 7 files changed, 93 insertions(+), 9 deletions(-) create mode 100644 test_regress/t/t_class_param_bad.out create mode 100755 test_regress/t/t_class_param_bad.pl create mode 100644 test_regress/t/t_class_param_bad.v diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 3dfca497b..09d1cdc91 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -988,14 +988,16 @@ public: class AstClassRefDType final : public AstNodeDType { // Reference to a class + // Children: PINs (for parameter settings) private: AstClass* m_classp; // data type pointed to, BELOW the AstTypedef AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy public: - AstClassRefDType(FileLine* fl, AstClass* classp) + AstClassRefDType(FileLine* fl, AstClass* classp, AstNode* paramsp) : ASTGEN_SUPER(fl) , m_classp{classp} { dtypep(this); + addNOp4p(paramsp); } ASTNODE_NODE_FUNCS(ClassRefDType) // METHODS @@ -1032,6 +1034,7 @@ public: void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; } AstClass* classp() const { return m_classp; } void classp(AstClass* nodep) { m_classp = nodep; } + AstPin* paramsp() const { return VN_CAST(op4p(), Pin); } }; class AstIfaceRefDType final : public AstNodeDType { diff --git a/src/V3LinkCells.cpp b/src/V3LinkCells.cpp index b4dec71fa..df9d24582 100644 --- a/src/V3LinkCells.cpp +++ b/src/V3LinkCells.cpp @@ -457,6 +457,13 @@ private: UINFO(4, " Link Cell done: " << nodep << endl); } + virtual void visit(AstRefDType* nodep) override { + for (AstPin* pinp = nodep->paramsp(); pinp; pinp = VN_CAST(pinp->nextp(), Pin)) { + pinp->param(true); + if (pinp->name() == "") pinp->name("__paramNumber" + cvtToStr(pinp->pinNum())); + } + } + // Accelerate the recursion // Must do statements to support Generates, math though... virtual void visit(AstNodeMath*) override {} diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index c2058735f..23f600284 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -1941,11 +1941,13 @@ private: virtual void visit(AstCell* nodep) override { // Cell: Recurse inside or cleanup not founds checkNoDot(nodep); - m_cellp = nodep; AstNode::user5ClearTree(); UASSERT_OBJ(nodep->modp(), nodep, "Cell has unlinked module"); // V3LinkCell should have errored out + VL_RESTORER(m_cellp); + VL_RESTORER(m_pinSymp); { + m_cellp = nodep; if (VN_IS(nodep->modp(), NotFoundModule)) { // Prevent warnings about missing pin connects if (nodep->pinsp()) nodep->pinsp()->unlinkFrBackWithNext()->deleteTree(); @@ -1960,13 +1962,26 @@ private: // if (debug()) nodep->dumpTree(cout, "linkcell:"); // if (debug()) nodep->modp()->dumpTree(cout, "linkcemd:"); iterateChildren(nodep); - m_pinSymp = nullptr; } } - m_cellp = nullptr; // Parent module inherits child's publicity // This is done bottom up in the LinkBotupVisitor stage } + virtual void visit(AstClassRefDType* nodep) override { + // Cell: Recurse inside or cleanup not founds + checkNoDot(nodep); + AstNode::user5ClearTree(); + UASSERT_OBJ(nodep->classp(), nodep, "ClassRef has unlinked class"); + VL_RESTORER(m_pinSymp); + { + // ClassRef's have pins, so track + m_pinSymp = m_statep->getNodeSym(nodep->classp()); + UINFO(4, "(Backto) Link ClassRefDType: " << nodep << endl); + // if (debug()) nodep->dumpTree(cout, "linkcell:"); + // if (debug()) nodep->modp()->dumpTree(cout, "linkcemd:"); + iterateChildren(nodep); + } + } virtual void visit(AstPin* nodep) override { // Pin: Link to submodule's port checkNoDot(nodep); @@ -1976,7 +1991,8 @@ private: VSymEnt* foundp = m_pinSymp->findIdFlat(nodep->name()); const char* whatp = nodep->param() ? "parameter pin" : "pin"; if (!foundp) { - if (nodep->name() == "__paramNumber1" && VN_IS(m_cellp->modp(), Primitive)) { + if (nodep->name() == "__paramNumber1" && m_cellp + && VN_IS(m_cellp->modp(), Primitive)) { // Primitive parameter is really a delay we can just ignore VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); return; @@ -2540,7 +2556,7 @@ private: "Unsupported: " << AstNode::prettyNameQ(cpackagerefp->name())); } if (cpackagerefp->paramsp()) { - nodep->v3warn(E_UNSUPPORTED, "Unsupported: parameterized packages"); + nodep->v3warn(E_UNSUPPORTED, "Unsupported: parameterized packages for task calls"); } UASSERT_OBJ(cpackagerefp->classOrPackagep(), m_ds.m_dotp->lhsp(), "Bad package link"); nodep->classOrPackagep(cpackagerefp->classOrPackagep()); @@ -2817,8 +2833,10 @@ private: cextp->v3error("Attempting to extend class " << nodep->prettyNameQ() << " from itself"); } else { - AstClassRefDType* newp - = new AstClassRefDType{nodep->fileline(), classp}; + AstNode* paramsp = cpackagerefp->paramsp(); + if (paramsp) paramsp = paramsp->cloneTree(true); + const auto newp + = new AstClassRefDType{nodep->fileline(), classp, paramsp}; cextp->childDTypep(newp); classp->isExtended(true); nodep->isExtended(true); @@ -2909,7 +2927,9 @@ private: nodep->refDTypep(defp); nodep->classOrPackagep(foundp->classOrPackagep()); } else if (AstClass* defp = foundp ? VN_CAST(foundp->nodep(), Class) : nullptr) { - AstClassRefDType* newp = new AstClassRefDType(nodep->fileline(), defp); + AstNode* paramsp = nodep->paramsp(); + if (paramsp) paramsp->unlinkFrBackWithNext(); + AstClassRefDType* newp = new AstClassRefDType{nodep->fileline(), defp, paramsp}; newp->classOrPackagep(foundp->classOrPackagep()); nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); diff --git a/test_regress/t/t_class_param_bad.out b/test_regress/t/t_class_param_bad.out new file mode 100644 index 000000000..d7a071bf0 --- /dev/null +++ b/test_regress/t/t_class_param_bad.out @@ -0,0 +1,17 @@ +%Error-UNSUPPORTED: t/t_class_param_bad.v:12:4: Unsupported: parameterized packages + 12 | Cls #(.PARAMBAD(1)) c; + | ^~~ +%Error: t/t_class_param_bad.v:12:11: Parameter pin not found: 'PARAMBAD' + : ... Suggested alternative: 'PARAMB' + 12 | Cls #(.PARAMBAD(1)) c; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_class_param_bad.v:13:4: Unsupported: parameterized packages + 13 | Cls #(13, 1) cd; + | ^~~ +%Error: t/t_class_param_bad.v:13:14: Parameter pin not found: '__paramNumber2' + 13 | Cls #(13, 1) cd; + | ^ +%Error-UNSUPPORTED: t/t_class_param_bad.v:7:23: Unsupported: class parameter + 7 | class Cls #(parameter PARAMB = 12); + | ^~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_class_param_bad.pl b/test_regress/t/t_class_param_bad.pl new file mode 100755 index 000000000..7be596e0f --- /dev/null +++ b/test_regress/t/t_class_param_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 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_class_param_bad.v b/test_regress/t/t_class_param_bad.v new file mode 100644 index 000000000..ba12815f1 --- /dev/null +++ b/test_regress/t/t_class_param_bad.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, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +class Cls #(parameter PARAMB = 12); +endclass + +module t (/*AUTOARG*/); + + Cls #(.PARAMBAD(1)) c; // Bad param name + Cls #(13, 1) cd; // Bad param number + +endmodule diff --git a/test_regress/t/t_class_vparam.out b/test_regress/t/t_class_vparam.out index c5a35f922..1816089b8 100644 --- a/test_regress/t/t_class_vparam.out +++ b/test_regress/t/t_class_vparam.out @@ -1,4 +1,7 @@ %Error-UNSUPPORTED: t/t_class_vparam.v:13:40: Unsupported: parameterized packages 13 | pure virtual function void funcname(paramed_class_t #(CTYPE_t) v); | ^~~~~~~~~~~~~~~ +%Error: t/t_class_vparam.v:13:58: Parameter pin not found: '__paramNumber1' + 13 | pure virtual function void funcname(paramed_class_t #(CTYPE_t) v); + | ^~~~~~~ %Error: Exiting due to