Support class extends with arguments.
This commit is contained in:
parent
86f6ac2960
commit
7c2b1971a4
1
Changes
1
Changes
|
@ -24,6 +24,7 @@ Verilator 5.035 devel
|
|||
* Support command-line overriding `define (#5900) (#5908). [Brian Li]
|
||||
* Support `$setuphold` (#5884). [Krzysztof Sychla]
|
||||
* Support `systemc_interface and related inside `class`.
|
||||
* Support class extends with arguments.
|
||||
* Change `--trace` to `--trace-vcd`.
|
||||
* Add multi-thread hierarchical simulation (#2583) (#5871). [Bartłomiej Chmiel, Antmicro Ltd.]
|
||||
* Add check for `let` misused in statement context (#5733).
|
||||
|
|
|
@ -4407,12 +4407,15 @@ public:
|
|||
class AstNew final : public AstNodeFTaskRef {
|
||||
// New as constructor
|
||||
// Don't need the class we are extracting from, as the "fromp()"'s datatype can get us to it
|
||||
bool m_isImplicit = false; // Implicitly generated from extends args
|
||||
public:
|
||||
AstNew(FileLine* fl, AstNodeExpr* pinsp)
|
||||
: ASTGEN_SUPER_New(fl, "new", pinsp) {}
|
||||
ASTGEN_MEMBERS_AstNew;
|
||||
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
||||
int instrCount() const override { return widthInstrs(); }
|
||||
bool isImplicit() const { return m_isImplicit; }
|
||||
void isImplicit(bool flag) { m_isImplicit = flag; }
|
||||
};
|
||||
class AstTaskRef final : public AstNodeFTaskRef {
|
||||
// A reference to a task
|
||||
|
|
|
@ -915,6 +915,7 @@ class AstClassExtends final : public AstNode {
|
|||
// during early parse, then moves to dtype
|
||||
// @astgen op1 := childDTypep : Optional[AstNodeDType]
|
||||
// @astgen op2 := classOrPkgsp : Optional[AstNode]
|
||||
// @astgen op3 := argsp : List[AstNodeExpr]
|
||||
const bool m_isImplements = false; // class implements
|
||||
bool m_parameterized = false; // has parameters in its statement
|
||||
|
||||
|
|
|
@ -2254,7 +2254,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||
// (except the default instances)
|
||||
// They are added to the set only in linkDotPrimary.
|
||||
bool m_insideClassExtParam = false; // Inside a class from m_extendsParam
|
||||
bool m_explicitSuperNew = false; // Hit a "super.new" call inside a "new" function
|
||||
AstNew* m_explicitSuperNewp = nullptr; // Hit a "super.new" call inside a "new" function
|
||||
std::map<AstNode*, AstPin*> m_usedPins; // Pin used in this cell, map to duplicate
|
||||
std::map<std::string, AstNodeModule*> m_modulesToRevisit; // Modules to revisit a second time
|
||||
AstNode* m_lastDeferredp = nullptr; // Last node which requested a revisit of its module
|
||||
|
@ -2354,12 +2354,16 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||
return nullptr;
|
||||
}
|
||||
}
|
||||
AstNodeStmt* addImplicitSuperNewCall(AstFunc* nodep) {
|
||||
AstNodeStmt* addImplicitSuperNewCall(AstFunc* const nodep,
|
||||
const AstClassExtends* const classExtendsp) {
|
||||
// Returns the added node
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstNodeExpr* pinsp = nullptr;
|
||||
if (classExtendsp->argsp()) pinsp = classExtendsp->argsp()->cloneTree(true);
|
||||
AstNew* const newExprp = new AstNew{fl, pinsp};
|
||||
newExprp->isImplicit(true);
|
||||
AstDot* const superNewp
|
||||
= new AstDot{fl, false, new AstParseRef{fl, VParseRefExp::PX_ROOT, "super"},
|
||||
new AstNew{fl, nullptr}};
|
||||
= new AstDot{fl, false, new AstParseRef{fl, VParseRefExp::PX_ROOT, "super"}, newExprp};
|
||||
AstNodeStmt* const superNewStmtp = superNewp->makeStmt();
|
||||
for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
// super.new shall be the first statement (IEEE 1800-2023 8.15)
|
||||
|
@ -3982,17 +3986,33 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||
}
|
||||
VL_RESTORER(m_curSymp);
|
||||
VL_RESTORER(m_ftaskp);
|
||||
VL_RESTORER(m_explicitSuperNewp);
|
||||
{
|
||||
m_ftaskp = nodep;
|
||||
m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep);
|
||||
const bool isNew = nodep->name() == "new";
|
||||
if (isNew) m_explicitSuperNew = false;
|
||||
if (isNew) m_explicitSuperNewp = nullptr;
|
||||
iterateChildren(nodep);
|
||||
if (isNew && !m_explicitSuperNew && m_statep->forParamed()) {
|
||||
if (isNew) {
|
||||
const AstClassExtends* const classExtendsp = VN_AS(m_modp, Class)->extendsp();
|
||||
if (m_explicitSuperNewp && !m_explicitSuperNewp->isImplicit()
|
||||
&& classExtendsp->argsp()) {
|
||||
m_explicitSuperNewp->v3error(
|
||||
"Explicit super.new not allowed with class "
|
||||
"extends arguments (IEEE 1800-2023 8.17)\n"
|
||||
<< m_explicitSuperNewp->warnMore() << "... Suggest remove super.new\n"
|
||||
<< m_explicitSuperNewp->warnContextPrimary() << '\n'
|
||||
<< classExtendsp->argsp()->warnOther()
|
||||
<< "... Location of extends argument(s)\n"
|
||||
<< classExtendsp->argsp()->warnContextSecondary());
|
||||
}
|
||||
if (classExtendsp && classExtendsp->classOrNullp()) {
|
||||
AstNodeStmt* const superNewp = addImplicitSuperNewCall(VN_AS(nodep, Func));
|
||||
iterate(superNewp);
|
||||
if (!m_explicitSuperNewp && m_statep->forParamed()) {
|
||||
AstNodeStmt* const superNewp
|
||||
= addImplicitSuperNewCall(VN_AS(nodep, Func), classExtendsp);
|
||||
UINFO(9, "created super new " << superNewp << endl);
|
||||
iterate(superNewp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4356,12 +4376,14 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||
LINKDOT_VISIT_START();
|
||||
checkNoDot(nodep);
|
||||
// Check if nodep represents a super.new call;
|
||||
if (VN_IS(nodep->exprp(), New)) {
|
||||
if (AstNew* const newExprp = VN_CAST(nodep->exprp(), New)) {
|
||||
// in this case it was already linked, so it doesn't have a super reference
|
||||
m_explicitSuperNew = true;
|
||||
m_explicitSuperNewp = newExprp;
|
||||
} else if (const AstDot* const dotp = VN_CAST(nodep->exprp(), Dot)) {
|
||||
if (dotp->lhsp()->name() == "super" && VN_IS(dotp->rhsp(), New)) {
|
||||
m_explicitSuperNew = true;
|
||||
if (dotp->lhsp()->name() == "super") {
|
||||
if (AstNew* const newExprp = VN_CAST(dotp->rhsp(), New)) {
|
||||
m_explicitSuperNewp = newExprp;
|
||||
}
|
||||
}
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
|
|
|
@ -147,6 +147,12 @@ private:
|
|||
}
|
||||
}
|
||||
}
|
||||
void visit(AstClassExtends* nodep) override {
|
||||
if (nodep->user1SetOnce()) return; // Process once
|
||||
// Extend arguments were converted to super.new arguments in V3LinkDot
|
||||
if (nodep->argsp()) pushDeletep(nodep->argsp()->unlinkFrBackWithNext());
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstConst* nodep) override {
|
||||
if (nodep->user1SetOnce()) return; // Process once
|
||||
UASSERT_OBJ(nodep->dtypep(), nodep, "No dtype");
|
||||
|
|
|
@ -7340,7 +7340,7 @@ classExtendsOne<classExtendsp>: // IEEE: part of class_declaration
|
|||
$<scp>$ = $<scp>1; }
|
||||
| class_typeExtImpList '(' list_of_argumentsE ')'
|
||||
{ $$ = new AstClassExtends{$1->fileline(), $1, GRAMMARP->m_inImplements};
|
||||
BBUNSUP($<fl>2, "Unsupported: 'extends' with class list_of_arguments");
|
||||
$$->addArgsp($3);
|
||||
$<scp>$ = $<scp>1; }
|
||||
// // IEEE-2023: Added: yEXTENDS class_type '(' yDEFAULT ')'
|
||||
| class_typeExtImpList '(' yDEFAULT ')'
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
%Error-UNSUPPORTED: t/t_class_extends_arg.v:14:25: Unsupported: 'extends' with 'default'
|
||||
14 | class Cls1 extends Base1(default);
|
||||
| ^
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Error-UNSUPPORTED: t/t_class_extends_arg.v:18:25: Unsupported: 'extends' with class list_of_arguments
|
||||
18 | class Cls5 extends Base1(5);
|
||||
| ^
|
||||
%Error: Exiting due to
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2024 by Wilson Snyder. This program is free software; you
|
||||
# Copyright 2025 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.
|
||||
|
@ -9,8 +9,10 @@
|
|||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('linter')
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.lint(fails=test.vlt_all, expect_filename=test.golden_filename)
|
||||
test.compile()
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
|
@ -1,36 +1,44 @@
|
|||
// 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.
|
||||
// any use, without warranty, 2025 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
class Base1;
|
||||
int s = 2;
|
||||
`define stop $stop
|
||||
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0x exp=%0x (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
|
||||
|
||||
class Base;
|
||||
int m_s = 2;
|
||||
function new(int def = 3);
|
||||
s = def;
|
||||
m_s = def;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
class Cls1 extends Base1(default);
|
||||
// Gets new(int def)
|
||||
class Cls5Exp extends Base(5);
|
||||
int m_a = 11;
|
||||
function new(int def = 42); // Explicit new
|
||||
m_a = def;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
class Cls5 extends Base1(5);
|
||||
// Gets new()
|
||||
class Cls5Imp extends Base(5);
|
||||
int m_a = 12;
|
||||
// Implicit new
|
||||
endclass
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
module t ();
|
||||
|
||||
Cls5Exp ce;
|
||||
Cls5Imp ci;
|
||||
|
||||
initial begin
|
||||
Cls1 c1;
|
||||
Cls1 c5;
|
||||
c1 = new(57);
|
||||
if (c1.s !== 57) $stop;
|
||||
|
||||
c5 = new;
|
||||
if (c5.s !== 5) $stop;
|
||||
|
||||
ce = new(37);
|
||||
`checkh(ce.m_s, 5);
|
||||
`checkh(ce.m_a, 37);
|
||||
ci = new;
|
||||
`checkh(ci.m_s, 5);
|
||||
`checkh(ci.m_a, 12);
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
%Error: t/t_class_extends_arg_super_bad.v:17:13: Explicit super.new not allowed with class extends arguments (IEEE 1800-2023 8.17)
|
||||
: ... Suggest remove super.new
|
||||
17 | super.new(33);
|
||||
| ^~~
|
||||
t/t_class_extends_arg_super_bad.v:14:25: ... Location of extends argument(s)
|
||||
14 | class Cls5 extends Base(5);
|
||||
| ^
|
||||
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
||||
%Error: Exiting due to
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 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('linter')
|
||||
|
||||
test.lint(fails=True, expect_filename=test.golden_filename)
|
||||
|
||||
test.passes()
|
|
@ -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, 2025 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
class Base;
|
||||
int m_s = 2;
|
||||
function new(int def = 3);
|
||||
m_s = def;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
class Cls5 extends Base(5);
|
||||
int m_a;
|
||||
function new(int def = 42);
|
||||
super.new(33); // Bad, can't super.new with extends args
|
||||
m_a = def;
|
||||
endfunction
|
||||
endclass
|
|
@ -0,0 +1,5 @@
|
|||
%Error-UNSUPPORTED: t/t_class_extends_default.v:14:25: Unsupported: 'extends' with 'default'
|
||||
14 | class Cls1 extends Base1(default);
|
||||
| ^
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Error: Exiting due to
|
|
@ -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('linter')
|
||||
|
||||
test.lint(fails=test.vlt_all, expect_filename=test.golden_filename)
|
||||
|
||||
test.passes()
|
|
@ -0,0 +1,32 @@
|
|||
// 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 Base1;
|
||||
int s = 2;
|
||||
function new(int def = 3);
|
||||
s = def;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
class Cls1 extends Base1(default);
|
||||
// Gets new(int def)
|
||||
endclass
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
initial begin
|
||||
Cls1 c1;
|
||||
Cls1 c5;
|
||||
c1 = new(57);
|
||||
if (c1.s !== 57) $stop;
|
||||
|
||||
c5 = new;
|
||||
if (c5.s !== 5) $stop;
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
Loading…
Reference in New Issue