From 3fae11595a7653573b60dff324e43c66d9ef1e94 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 9 Nov 2024 12:05:26 -0500 Subject: [PATCH] Support `pure constraint`. --- Changes | 1 + src/V3AstNodeOther.h | 7 ++++- src/V3AstNodes.cpp | 11 +++++++- src/V3LinkDot.cpp | 23 ++++++++++++++-- src/V3WidthCommit.cpp | 12 +++++++++ src/verilog.y | 3 +-- test_regress/t/t_constraint_pure.py | 21 +++++++++++++++ test_regress/t/t_constraint_pure.v | 26 +++++++++++++++++++ .../t/t_constraint_pure_missing_bad.out | 7 +++++ .../t/t_constraint_pure_missing_bad.py | 16 ++++++++++++ .../t/t_constraint_pure_missing_bad.v | 16 ++++++++++++ .../t/t_constraint_pure_nonabs_bad.out | 5 ++++ .../t/t_constraint_pure_nonabs_bad.py | 16 ++++++++++++ test_regress/t/t_constraint_pure_nonabs_bad.v | 12 +++++++++ test_regress/t/t_randomize_extern.out | 5 +--- 15 files changed, 171 insertions(+), 10 deletions(-) create mode 100755 test_regress/t/t_constraint_pure.py create mode 100644 test_regress/t/t_constraint_pure.v create mode 100644 test_regress/t/t_constraint_pure_missing_bad.out create mode 100755 test_regress/t/t_constraint_pure_missing_bad.py create mode 100644 test_regress/t/t_constraint_pure_missing_bad.v create mode 100644 test_regress/t/t_constraint_pure_nonabs_bad.out create mode 100755 test_regress/t/t_constraint_pure_nonabs_bad.py create mode 100644 test_regress/t/t_constraint_pure_nonabs_bad.v diff --git a/Changes b/Changes index de90148a5..17b5201c5 100644 --- a/Changes +++ b/Changes @@ -15,6 +15,7 @@ Verilator 5.031 devel * Support queue's assignment `push_back/push_front('{})` (#5585) (#5586). [Yilou Wang] * Support basic constrained random for multi-dimensional dynamic array and queue (#5591). [Yilou Wang] +* Support `pure constraint`. * Add error on illegal enum base type (#3010). [Iztok Jeras] * Add error on `wait` with missing `.triggered` (#4457). * Add error when improperly storing to parameter (#5147). [Gökçe Aydos] diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index e4b3cee54..49442e9e7 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -1026,7 +1026,8 @@ class AstConstraint final : public AstNode { // Constraint // @astgen op1 := itemsp : List[AstNode] string m_name; // Name of constraint - bool m_isStatic = false; // static constraint + bool m_isKwdPure = false; // Pure constraint + bool m_isStatic = false; // Static constraint public: AstConstraint(FileLine* fl, const string& name, AstNode* itemsp) : ASTGEN_SUPER_Constraint(fl) @@ -1034,11 +1035,15 @@ public: this->addItemsp(itemsp); } ASTGEN_MEMBERS_AstConstraint; + void dump(std::ostream& str) const override; + void dumpJson(std::ostream& str) const override; string name() const override VL_MT_STABLE { return m_name; } // * = Scope name bool isGateOptimizable() const override { return false; } bool isPredictOptimizable() const override { return false; } bool maybePointedTo() const override VL_MT_SAFE { return true; } bool same(const AstNode* /*samep*/) const override { return true; } + void isKwdPure(bool flag) { m_isKwdPure = flag; } + bool isKwdPure() const { return m_isKwdPure; } void isStatic(bool flag) { m_isStatic = flag; } bool isStatic() const { return m_isStatic; } }; diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 326a3d77d..00ca3aff5 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -366,7 +366,16 @@ void AstConsQueue::dumpJson(std::ostream& str) const { dumpJsonBoolFunc(str, rhsIsValue); dumpJsonGen(str); } - +void AstConstraint::dump(std::ostream& str) const { + this->AstNode::dump(str); + if (isKwdPure()) str << " [KWDPURE]"; + if (isStatic()) str << " [STATIC]"; +} +void AstConstraint::dumpJson(std::ostream& str) const { + dumpJsonBoolFunc(str, isKwdPure); + dumpJsonBoolFunc(str, isStatic); + dumpJsonGen(str); +} AstConst* AstConst::parseParamLiteral(FileLine* fl, const string& literal) { bool success = false; if (literal[0] == '"') { diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 41a449d33..af5c5c9b8 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2334,13 +2334,13 @@ class LinkDotResolveVisitor final : public VNVisitor { ++it) { if (AstNode* interfaceSubp = it->second->nodep()) { UINFO(8, indent() << " SymFunc " << interfaceSubp << endl); + const string impOrExtends + = baseClassp->isInterfaceClass() ? " implements " : " extends "; if (VN_IS(interfaceSubp, NodeFTask)) { const VSymEnt* const foundp = m_curSymp->findIdFlat(interfaceSubp->name()); const AstNodeFTask* const interfaceFuncp = VN_CAST(interfaceSubp, NodeFTask); if (!interfaceFuncp || !interfaceFuncp->pureVirtual()) continue; bool existsInChild = foundp && !foundp->imported(); - const string impOrExtends - = baseClassp->isInterfaceClass() ? " implements " : " extends "; if (!existsInChild && !implementsClassp->isInterfaceClass()) { implementsClassp->v3error( "Class " << implementsClassp->prettyNameQ() << impOrExtends @@ -2368,6 +2368,25 @@ class LinkDotResolveVisitor final : public VNVisitor { } m_ifClassImpNames.emplace(interfaceSubp->name(), interfaceSubp); } + if (VN_IS(interfaceSubp, Constraint)) { + const VSymEnt* const foundp = m_curSymp->findIdFlat(interfaceSubp->name()); + const AstConstraint* const interfaceFuncp = VN_CAST(interfaceSubp, Constraint); + if (!interfaceFuncp || !interfaceFuncp->isKwdPure()) continue; + bool existsInChild = foundp && !foundp->imported(); + if (!existsInChild && !implementsClassp->isInterfaceClass() + && !implementsClassp->isVirtual()) { + implementsClassp->v3error( + "Class " << implementsClassp->prettyNameQ() << impOrExtends + << baseClassp->prettyNameQ() + << " but is missing constraint implementation for " + << interfaceSubp->prettyNameQ() + << " (IEEE 1800-2023 18.5.2)\n" + << implementsClassp->warnContextPrimary() << '\n' + << interfaceSubp->warnOther() + << "... Location of interface class's pure constraint\n" + << interfaceSubp->warnContextSecondary()); + } + } } } } diff --git a/src/V3WidthCommit.cpp b/src/V3WidthCommit.cpp index 1c9e1640f..e4a6e3f6c 100644 --- a/src/V3WidthCommit.cpp +++ b/src/V3WidthCommit.cpp @@ -162,6 +162,18 @@ private: nodep->replaceWith(nodep->lhsp()->unlinkFrBack()); VL_DO_DANGLING(pushDeletep(nodep), nodep); } + void visit(AstConstraint* nodep) override { + iterateChildren(nodep); + editDType(nodep); + { + const AstClass* const classp = VN_CAST(m_modp, Class); + if (nodep->isKwdPure() + && (!classp || (!classp->isInterfaceClass() && !classp->isVirtual()))) { + nodep->v3error("Illegal to have 'pure constraint' in non-abstract class" + " (IEEE 1800-2023 18.5.2)"); + } + } + } void visit(AstNodeDType* nodep) override { // Note some specific dtypes have unique visitors visitIterateNodeDType(nodep); diff --git a/src/verilog.y b/src/verilog.y index d7058a9bc..73bb8967a 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -7391,8 +7391,7 @@ class_constraint: // ==IEEE: class_constraint { $$ = $4; $$->isStatic($1); SYMP->popScope($4); BBUNSUP($1, "Unsupported: extern constraint"); } | yPURE constraintStaticE yCONSTRAINT constraintIdNew ';' - { $$ = $4; $$->isStatic($1); SYMP->popScope($4); - BBUNSUP($1, "Unsupported: pure constraint"); } + { $$ = $4; $$->isKwdPure($1); $$->isStatic($1); SYMP->popScope($4); } ; constraintIdNew: // IEEE: id part of class_constraint diff --git a/test_regress/t/t_constraint_pure.py b/test_regress/t/t_constraint_pure.py new file mode 100755 index 000000000..a2b131082 --- /dev/null +++ b/test_regress/t/t_constraint_pure.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 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 + +import vltest_bootstrap + +test.scenarios('simulator') + +if not test.have_solver: + test.skip("No constraint solver installed") + +test.compile() + +test.execute() + +test.passes() diff --git a/test_regress/t/t_constraint_pure.v b/test_regress/t/t_constraint_pure.v new file mode 100644 index 000000000..c3fc3f64a --- /dev/null +++ b/test_regress/t/t_constraint_pure.v @@ -0,0 +1,26 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2024 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +virtual class Base; + pure constraint raint; +endclass + +class Cls extends Base; + rand int b2; + constraint raint { b2 == 5; } +endclass + +virtual class Virt extends Base; + // No constraint needed +endclass + +module t; + initial begin + Cls c = new; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_constraint_pure_missing_bad.out b/test_regress/t/t_constraint_pure_missing_bad.out new file mode 100644 index 000000000..e9b226c01 --- /dev/null +++ b/test_regress/t/t_constraint_pure_missing_bad.out @@ -0,0 +1,7 @@ +%Error: t/t_constraint_pure_missing_bad.v:11:1: Class 'Cls' extends 'Base' but is missing constraint implementation for 'raint' (IEEE 1800-2023 18.5.2) + 11 | class Cls extends Base; + | ^~~~~ + t/t_constraint_pure_missing_bad.v:8:21: ... Location of interface class's pure constraint + 8 | pure constraint raint; + | ^~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_constraint_pure_missing_bad.py b/test_regress/t/t_constraint_pure_missing_bad.py new file mode 100755 index 000000000..e33e10acf --- /dev/null +++ b/test_regress/t/t_constraint_pure_missing_bad.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 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 + +import vltest_bootstrap + +test.scenarios('vlt') + +test.lint(fails=True, expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_constraint_pure_missing_bad.v b/test_regress/t/t_constraint_pure_missing_bad.v new file mode 100644 index 000000000..9d81382d5 --- /dev/null +++ b/test_regress/t/t_constraint_pure_missing_bad.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, 2024 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +virtual class Base; + pure constraint raint; +endclass + +class Cls extends Base; + // Bad: Missing 'constraint raint' +endclass + +module t; +endmodule diff --git a/test_regress/t/t_constraint_pure_nonabs_bad.out b/test_regress/t/t_constraint_pure_nonabs_bad.out new file mode 100644 index 000000000..039a415a0 --- /dev/null +++ b/test_regress/t/t_constraint_pure_nonabs_bad.out @@ -0,0 +1,5 @@ +%Error: t/t_constraint_pure_nonabs_bad.v:8:21: Illegal to have 'pure constraint' in non-abstract class (IEEE 1800-2023 18.5.2) + : ... note: In instance 't' + 8 | pure constraint raintBad; + | ^~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_constraint_pure_nonabs_bad.py b/test_regress/t/t_constraint_pure_nonabs_bad.py new file mode 100755 index 000000000..e33e10acf --- /dev/null +++ b/test_regress/t/t_constraint_pure_nonabs_bad.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 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 + +import vltest_bootstrap + +test.scenarios('vlt') + +test.lint(fails=True, expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_constraint_pure_nonabs_bad.v b/test_regress/t/t_constraint_pure_nonabs_bad.v new file mode 100644 index 000000000..0ea5366d2 --- /dev/null +++ b/test_regress/t/t_constraint_pure_nonabs_bad.v @@ -0,0 +1,12 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2024 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +class NonAsbstract; + pure constraint raintBad; // Bad: Not in abstract class +endclass + +module t; +endmodule diff --git a/test_regress/t/t_randomize_extern.out b/test_regress/t/t_randomize_extern.out index a56aaa409..91ae91a9d 100644 --- a/test_regress/t/t_randomize_extern.out +++ b/test_regress/t/t_randomize_extern.out @@ -1,10 +1,7 @@ -%Error-UNSUPPORTED: t/t_randomize_extern.v:8:4: Unsupported: pure constraint - 8 | pure constraint pur; - | ^~~~ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest %Error-UNSUPPORTED: t/t_randomize_extern.v:17:4: Unsupported: extern constraint 17 | extern constraint ex; | ^~~~~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest %Error-UNSUPPORTED: t/t_randomize_extern.v:21:1: Unsupported: extern constraint 21 | constraint Packet::ex { header == 2; } | ^~~~~~~~~~