Support nested classes (#4178) (#5778)

Signed-off-by: Kamil Rakoczy <krakoczy@antmicro.com>
This commit is contained in:
Kamil Rakoczy 2025-02-17 13:47:41 +01:00 committed by GitHub
parent fbe8439eb8
commit c840ffb0ae
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
31 changed files with 664 additions and 23 deletions

View File

@ -1013,6 +1013,7 @@ class LinkDotFindVisitor final : public VNVisitor {
VL_RESTORER(m_modBlockNum);
VL_RESTORER(m_modWithNum);
VL_RESTORER(m_modArgNum);
VL_RESTORER(m_explicitNew);
{
UINFO(4, " Link Class: " << nodep << endl);
VSymEnt* const upperSymp = m_curSymp;
@ -1176,12 +1177,39 @@ class LinkDotFindVisitor final : public VNVisitor {
}
// Change to appropriate package if extern declaration (vs definition)
if (nodep->classOrPackagep()) {
// class-in-class
AstDot* const dotp = VN_CAST(nodep->classOrPackagep(), Dot);
AstClassOrPackageRef* const cpackagerefp
= VN_CAST(nodep->classOrPackagep(), ClassOrPackageRef);
if (!cpackagerefp) {
nodep->v3warn(E_UNSUPPORTED,
"Unsupported: extern function definition with class-in-class");
} else {
if (dotp) {
AstClassOrPackageRef* const lhsp = VN_AS(dotp->lhsp(), ClassOrPackageRef);
m_statep->resolveClassOrPackage(m_curSymp, lhsp, false,
"External definition :: reference");
AstClass* const lhsclassp = VN_CAST(lhsp->classOrPackageSkipp(), Class);
if (!lhsclassp) {
nodep->v3error("Extern declaration's scope is not a defined class");
} else {
m_curSymp = m_statep->getNodeSym(lhsclassp);
upSymp = m_curSymp;
AstClassOrPackageRef* const rhsp = VN_AS(dotp->rhsp(), ClassOrPackageRef);
m_statep->resolveClassOrPackage(m_curSymp, rhsp, false,
"External definition :: reference");
AstClass* const rhsclassp = VN_CAST(rhsp->classOrPackageSkipp(), Class);
if (!rhsclassp) {
nodep->v3error("Extern declaration's scope is not a defined class");
} else {
m_curSymp = m_statep->getNodeSym(rhsclassp);
upSymp = m_curSymp;
if (!nodep->isExternDef()) {
// Move it to proper spot under the target class
nodep->unlinkFrBack();
rhsclassp->addStmtsp(nodep);
nodep->isExternDef(true); // So we check there's a matching extern
nodep->classOrPackagep()->unlinkFrBack()->deleteTree();
}
}
}
} else if (cpackagerefp) {
if (!cpackagerefp->classOrPackageSkipp()) {
m_statep->resolveClassOrPackage(m_curSymp, cpackagerefp, false,
"External definition :: reference");
@ -1200,6 +1228,8 @@ class LinkDotFindVisitor final : public VNVisitor {
nodep->classOrPackagep()->unlinkFrBack()->deleteTree();
}
}
} else {
v3fatalSrc("Unhandled extern function definition package");
}
}
// Set the class as package for iteration
@ -4007,6 +4037,11 @@ class LinkDotResolveVisitor final : public VNVisitor {
LINKDOT_VISIT_START();
UINFO(5, indent() << "visit " << nodep << endl);
checkNoDot(nodep);
AstClass* const topclassp = VN_CAST(m_modp, Class);
if (nodep->isInterfaceClass() && topclassp && topclassp->isInterfaceClass()) {
nodep->v3error("Interface class shall not be nested within another interface class."
" (IEEE 1800-2023 8.26)");
}
VL_RESTORER(m_curSymp);
VL_RESTORER(m_modSymp);
VL_RESTORER(m_modp);

View File

@ -100,9 +100,15 @@ private:
if (local || prot) {
const auto refClassp = VN_CAST(m_modp, Class);
const char* how = nullptr;
if (local && defClassp && refClassp != defClassp) {
// Inner nested classes can access `local` or `protected` members of their outer class
const auto nestedAccess = [refClassp](const AstClass*, const AstNode* memberp) {
return memberp == refClassp;
};
if (local && defClassp
&& ((refClassp != defClassp) && !(defClassp->existsMember(nestedAccess)))) {
how = "'local'";
} else if (prot && defClassp && !AstClass::isClassExtendedFrom(refClassp, defClassp)) {
} else if (prot && defClassp && !AstClass::isClassExtendedFrom(refClassp, defClassp)
&& !(defClassp->existsMember(nestedAccess))) {
how = "'protected'";
}
if (how) {

View File

@ -7354,8 +7354,7 @@ class_item<nodep>: // ==IEEE: class_item
| class_method { $$ = $1; }
| class_constraint { $$ = $1; }
//
| class_declaration
{ $$ = nullptr; BBUNSUP($1, "Unsupported: class within class"); }
| class_declaration { $$ = $1; }
| timeunits_declaration { $$ = $1; }
| covergroup_declaration
{ $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: covergroup within class"); }

View File

@ -1,5 +0,0 @@
%Error-UNSUPPORTED: t/t_class_class.v:12:4: Unsupported: class within class
12 | class SubCls;
| ^~~~~
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error: Exiting due to

View File

@ -11,6 +11,8 @@ import vltest_bootstrap
test.scenarios('simulator')
test.compile(fails=test.vlt_all, expect_filename=test.golden_filename)
test.compile()
test.execute()
test.passes()

View File

@ -31,5 +31,8 @@ module t (/*AUTOARG*/);
if (c.imemberb != 20) $stop;
if (c.sc.smembera != 30) $stop;
if (c.sc.smemberb != 40) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -11,6 +11,9 @@
`define check_ne(lhs, rhs) `check_comp(lhs, rhs, ==, 1'b0) `check_comp(lhs, rhs, !=, 1'b1)
class Cls;
class InnerCls;
int j;
endclass
int i;
endclass
@ -22,14 +25,25 @@ module t;
Cls a = new;
Cls b = new;
ExtendCls ext = new;
Cls::InnerCls ia = new;
Cls::InnerCls ib = new;
ExtendCls::InnerCls iext = new;
`check_ne(a, b)
`check_ne(a, ext)
`check_ne(ext, a)
`check_ne(ia, ib)
`check_ne(ia, iext)
`check_ne(iext, ia)
a = b;
ia = ib;
`check_eq(a, b)
`check_eq(ia, ib)
a = ext;
ia = iext;
`check_eq(a, ext)
`check_eq(ext, a)
`check_eq(ia, iext)
`check_eq(iext, ia)
$write("*-* All Finished *-*\n");
$finish;
end

View File

@ -5,21 +5,55 @@
// SPDX-License-Identifier: CC0-1.0
class Base0;
class BaseInnerOnly;
int inneronly;
function new();
inneronly = 10;
if (inneronly != 10) $stop;
endfunction
endclass
class BaseInnerOver;
int innerover;
function new();
innerover = 10;
if (innerover != 10) $stop;
endfunction
endclass
int baseonly;
int baseover;
BaseInnerOnly inneronly = new;
BaseInnerOver innerover = new;
function void b_set_bo(int v); baseover = v; endfunction
function int b_get_bo(); return baseover; endfunction
function int get_bo(); return baseover; endfunction
function void b_set_io(int v); innerover.innerover = v; endfunction
function int b_get_io(); return innerover.innerover; endfunction
function int get_io(); return innerover.innerover; endfunction
endclass
class Ext extends Base0;
class BaseInnerOver;
int innerover;
function new();
innerover = 20;
if (innerover != 20) $stop;
endfunction
endclass
int baseover;
int extonly;
BaseInnerOnly inneronly = new;
BaseInnerOver innerover = new;
function void e_set_bo(int v); baseover = v; endfunction
function int e_get_bo(); return baseover; endfunction
function int get_bo(); return baseover; endfunction
function void e_set_io(int v); innerover.innerover = v; endfunction
function int e_get_io(); return innerover.innerover; endfunction
function int get_io(); return innerover.innerover; endfunction
endclass
module t (/*AUTOARG*/);
@ -29,15 +63,24 @@ module t (/*AUTOARG*/);
c.baseonly = 10;
c.baseover = 20;
c.extonly = 30;
c.inneronly.inneronly = 40;
c.innerover.innerover = 50;
if (c.baseonly != 10) $stop;
if (c.baseover != 20) $stop;
if (c.extonly != 30) $stop;
if (c.inneronly.inneronly != 40) $stop;
if (c.innerover.innerover != 50) $stop;
c.b_set_bo(100);
c.e_set_bo(200);
c.b_set_io(300);
c.e_set_io(400);
if (c.b_get_bo() != 100) $stop;
if (c.e_get_bo() != 200) $stop;
if (c.get_bo() != 200) $stop;
if (c.b_get_io() != 300) $stop;
if (c.e_get_io() != 400) $stop;
if (c.get_io() != 400) $stop;
$write("*-* All Finished *-*\n");
$finish;

View File

@ -6,22 +6,59 @@
package Pkg;
class Base0;
class BaseInnerOnly;
int inneronly;
function new();
inneronly = 10;
if (inneronly != 10) $stop;
endfunction
endclass
class BaseInnerOver;
int innerover;
function new();
innerover = 10;
if (innerover != 10) $stop;
endfunction
endclass
int baseonly;
int baseover;
BaseInnerOnly inneronly = new;
BaseInnerOver innerover = new;
function void b_set_bo(int v); baseover = v; endfunction
function int b_get_bo(); return baseover; endfunction
function int get_bo(); return baseover; endfunction
function void b_set_io(int v); innerover.innerover = v; endfunction
function int b_get_io(); return innerover.innerover; endfunction
function int get_io(); return innerover.innerover; endfunction
endclass
endpackage
// We need to import Base0, as verilator currently doesn't support
// multiple `::` references, but we would need to do that to reference
// `BaseInnerOnly` class inside `Ext` class.
import Pkg::Base0;
class Ext extends Pkg::Base0;
class BaseInnerOver;
int innerover;
function new();
innerover = 20;
if (innerover != 20) $stop;
endfunction
endclass
int baseover;
int extonly;
BaseInnerOnly inneronly = new;
BaseInnerOver innerover = new;
function void e_set_bo(int v); baseover = v; endfunction
function int e_get_bo(); return baseover; endfunction
function int get_bo(); return baseover; endfunction
function void e_set_io(int v); innerover.innerover = v; endfunction
function int e_get_io(); return innerover.innerover; endfunction
function int get_io(); return innerover.innerover; endfunction
endclass
module t (/*AUTOARG*/);
@ -31,15 +68,24 @@ module t (/*AUTOARG*/);
c.baseonly = 10;
c.baseover = 20;
c.extonly = 30;
c.inneronly.inneronly = 40;
c.innerover.innerover = 50;
if (c.baseonly != 10) $stop;
if (c.baseover != 20) $stop;
if (c.extonly != 30) $stop;
if (c.inneronly.inneronly != 40) $stop;
if (c.innerover.innerover != 50) $stop;
c.b_set_bo(100);
c.e_set_bo(200);
c.b_set_io(300);
c.e_set_io(400);
if (c.b_get_bo() != 100) $stop;
if (c.e_get_bo() != 200) $stop;
if (c.get_bo() != 200) $stop;
if (c.b_get_io() != 300) $stop;
if (c.e_get_io() != 400) $stop;
if (c.get_io() != 400) $stop;
$write("*-* All Finished *-*\n");
$finish;

View File

@ -8,26 +8,53 @@ module t (/*AUTOARG*/
);
class Foo;
class InnerFoo;
int y = 10;
function int get_y;
return y;
endfunction
function int get_30;
return 30;
endfunction
endclass
int x = 1;
InnerFoo foo = new;
function int get_x;
return x;
endfunction
function int get_3;
return 3;
endfunction
function InnerFoo get_foo;
return foo;
endfunction
endclass
class Bar #(type T=Foo) extends T;
endclass
class Baz;
class InnerFoo;
int y = 20;
function int get_y;
return y;
endfunction
function int get_40;
return 40;
endfunction
endclass
int x = 2;
InnerFoo foo = new;
function int get_x;
return x;
endfunction
function int get_4;
return 4;
endfunction
function InnerFoo get_foo;
return foo;
endfunction
endclass
class ExtendBar extends Bar#();
@ -71,6 +98,9 @@ module t (/*AUTOARG*/
function int get_x_of_item(int i);
return q[i].x;
endfunction
function int get_y_of_item(int i);
return q[i].get_foo().get_y();
endfunction
endclass
Bar #() bar_foo_i;
@ -93,8 +123,12 @@ module t (/*AUTOARG*/
if (bar_foo_i.get_x() != 1) $stop;
if (bar_foo_i.get_3() != 3) $stop;
if (bar_foo_i.get_foo().get_y() != 10) $stop;
if (bar_foo_i.get_foo().get_30() != 30) $stop;
if (bar_baz_i.get_x() != 2) $stop;
if (bar_baz_i.get_4() != 4) $stop;
if (bar_baz_i.get_foo().get_y() != 20) $stop;
if (bar_baz_i.get_foo().get_40() != 40) $stop;
if (extend_bar_i.get_x() != 1) $stop;
if (extend_bar_i.get_6() != 6) $stop;
if (extend_bar_i.get_x() != 1) $stop;
@ -106,6 +140,7 @@ module t (/*AUTOARG*/
if (extend_extend_bar_i.get_x() != 1) $stop;
if (extend_extend_bar_i.get_12() != 12) $stop;
if (extend_foo_dict_i.get_x_of_item(1) != 1) $stop;
if (extend_foo_dict_i.get_y_of_item(1) != 10) $stop;
$write("*-* All Finished *-*\n");
$finish;

View File

@ -7,7 +7,20 @@
typedef class Cls;
class Base;
class BaseInner;
int value = 10;
function void test;
if (value != 10) $stop;
if (this.value != 10) $stop;
value = 20;
if (value != 20) $stop;
this.value = 30;
if (value != 30) $stop;
endfunction
endclass
int value = 1;
BaseInner inner = new;
function void test;
if (value != 1) $stop;
if (this.value != 1) $stop;
@ -19,7 +32,25 @@ class Base;
endclass
class Cls extends Base;
class BaseInner extends Base::BaseInner;
int value = 100;
function void test;
if (value != 100) $stop;
if (this.value != 100) $stop;
if (super.value != 10) $stop;
super.test();
if (value != 100) $stop;
if (this.value != 100) $stop;
if (super.value != 30) $stop;
value = 200;
if (value != 200) $stop;
this.value = 300;
if (value != 300) $stop;
endfunction
endclass
int value = 20;
BaseInner inner = new;
function void test;
if (value != 20) $stop;
if (this.value != 20) $stop;
@ -31,7 +62,9 @@ class Cls extends Base;
super.value = 9;
this.value = 29;
if (super.value != 9) $stop;
if (value != 29) $stop;;
if (value != 29) $stop;
inner.test();
endfunction
endclass

View File

@ -7,15 +7,24 @@
typedef class Cls;
class Base;
class Inner;
int value = 10;
function void testBaseInner;
if (value != 10) $stop;
endfunction
endclass
int value = 1;
Inner inner = new;
function void testBase;
if (value != 1) $stop;
if (inner.value != 10) $stop;
endfunction
endclass
class Cls extends Base;
function void testDerived;
if (value != 1) $stop;
if (inner.value != 10) $stop;
endfunction
endclass
@ -25,6 +34,7 @@ module t (/*AUTOARG*/);
c = new;
c.testBase();
c.testDerived();
c.inner.testBaseInner();
$write("*-* All Finished *-*\n");
$finish;
end

View File

@ -13,6 +13,16 @@ class Cls;
extern task ext_t_np;
extern task ext_t_p();
extern task ext_t_i(int in);
class SubCls;
int value;
extern function int ext_f_np;
extern function int ext_f_p();
extern function int ext_f_i(int in);
extern static function int get_10();
extern task ext_t_np;
extern task ext_t_p();
extern task ext_t_i(int in);
endclass
endclass
function int Cls::ext_f_np;
@ -42,15 +52,51 @@ task Cls::ext_t_i(int in);
value = in;
endtask
function int Cls::SubCls::ext_f_np;
return 10;
endfunction
function int Cls::SubCls::ext_f_p();
return value;
endfunction
function int Cls::SubCls::ext_f_i(int in);
return in+10;
endfunction
function int Cls::SubCls::get_10();
return 10;
endfunction
task Cls::SubCls::ext_t_np();
$write("Cls::SubCls::ext_t_np\n");
endtask
task Cls::SubCls::ext_t_p();
$write("Cls::SubCls::ext_t_p\n");
endtask
task Cls::SubCls::ext_t_i(int in);
if (in != 20) $stop;
value = in;
endtask
module t (/*AUTOARG*/);
initial begin
Cls c = new;
Cls::SubCls subc = new;
c.ext_t_i(2);
c.ext_t_np();
c.ext_t_p();
if (c.ext_f_np() != 1) $stop;
if (c.ext_f_p() != 2) $stop;
if (c.ext_f_i(10) != 11) $stop;
if (Cls::get_1() != 1) $stop;
subc.ext_t_i(20);
if (subc.ext_f_np() != 10) $stop;
if (subc.ext_f_p() != 20) $stop;
if (subc.ext_f_i(11) != 21) $stop;
if (Cls::SubCls::get_10() != 10) $stop;
subc.ext_t_np();
subc.ext_t_p();
c.ext_t_np();
c.ext_t_p();
end
endmodule

View File

@ -31,6 +31,34 @@ class Cls;
Cls::s_loc(); // Ok
Cls::s_prot(); // Ok
endtask
class InnerCls;
typedef enum {A = 10, B = 20, C = 30} en_t;
int m_pub = 1;
local int m_loc = 2;
protected int m_prot = B;
task f_pub; endtask
local task f_loc; endtask
protected task f_prot; endtask
static task s_pub; endtask
static local task s_loc; endtask
static protected task s_prot; endtask
task check;
Cls o;
if (m_pub != 1) $stop;
if (m_loc != 2) $stop;
if (m_prot != 20) $stop;
f_pub(); // Ok
f_loc(); // Ok
f_prot(); // Ok
s_pub(); // Ok
s_loc(); // Ok
s_prot(); // Ok
Cls::s_pub(); // Ok
Cls::s_loc(); // Ok
Cls::s_prot(); // Ok
endtask
endclass
endclass
class Ext extends Cls;
@ -44,27 +72,52 @@ class Ext extends Cls;
Cls::s_pub(); // Ok
Cls::s_prot(); // Ok
endtask
class ExtInner extends Cls::InnerCls;
task check;
if (m_pub != 1) $stop;
if (m_prot != 20) $stop;
f_pub(); // Ok
f_prot(); // Ok
s_pub(); // Ok
s_prot(); // Ok
Cls::InnerCls::s_pub(); // Ok
Cls::InnerCls::s_prot(); // Ok
endtask
endclass
endclass
module t (/*AUTOARG*/);
const Cls mod_c = new;
const Cls::InnerCls imod_c = new;
initial begin
Cls c;
Cls::InnerCls i;
Ext e;
Ext::ExtInner ei;
if (c.A != 10) $stop;
if (i.A != 10) $stop;
c = new;
i = new;
e = new;
ei = new;
if (c.m_pub != 1) $stop;
if (i.m_pub != 1) $stop;
//
if (mod_c.A != 10) $stop;
if (imod_c.A != 10) $stop;
//
c.check();
i.check();
e.check();
ei.check();
//
Cls::s_pub(); // Ok
Cls::InnerCls::s_pub(); // Ok
c.s_pub(); // Ok
i.s_pub(); // Ok
e.s_pub(); // Ok
ei.s_pub(); // Ok
//
$write("*-* All Finished *-*\n");
$finish;

View File

@ -0,0 +1,9 @@
%Error-ENCAPSULATED: t/t_class_local_nested_bad.v:14:22: 'name' is hidden as 'local' within this context (IEEE 1800-2023 8.18)
: ... note: In instance 't'
14 | name = Node::name;
| ^~~~
t/t_class_local_nested_bad.v:14:22: ... Location of definition
9 | static local string name;
| ^~~~
... For error description see https://verilator.org/warn/ENCAPSULATED?v=latest
%Error: Exiting due to

View File

@ -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('simulator')
test.compile(fails=test.vlt_all, expect_filename=test.golden_filename)
test.passes()

View File

@ -0,0 +1,25 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2025 by Antmicro.
// SPDX-License-Identifier: CC0-1.0
class NodeList;
class Node;
static local string name;
endclass
string name;
function new();
name = Node::name;
endfunction
endclass
module t(/*AUTOARG*/);
initial begin
NodeList n = new;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -7,8 +7,13 @@
module t (/*AUTOARG*/);
class Cls;
class Inner;
int imemberinnera;
int imemberinnerb;
endclass
int imembera;
int imemberb;
Inner innermemberc;
endclass : Cls
class Dead;
@ -18,10 +23,16 @@ endclass
Cls c;
if (c != null) $stop;
c = new;
if (c.innermemberc != null) $stop;
c.innermemberc = new;
c.imembera = 10;
c.imemberb = 20;
c.innermemberc.imemberinnera = 30;
c.innermemberc.imemberinnerb = 40;
if (c.imembera != 10) $stop;
if (c.imemberb != 20) $stop;
if (c.innermemberc.imemberinnera != 30) $stop;
if (c.innermemberc.imemberinnerb != 40) $stop;
$write("*-* All Finished *-*\n");
$finish;
end

View File

@ -0,0 +1,18 @@
#!/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')
test.compile(verilator_flags2=["--exe --main"])
test.execute()
test.passes()

View File

@ -0,0 +1,90 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2025 by Antmicro.
// SPDX-License-Identifier: CC0-1.0
class NodeList;
class Node;
string name;
Node link;
function new();
name = "node";
endfunction
endclass
Node head;
endclass
class NodeTree;
class Node;
int id;
Node link;
endclass
Node root;
endclass
// Based on IEEE 1800-2017 section 8.23 Nested classes
class Outer;
int outerProp;
local int outerLocalProp;
static int outerStaticProp;
static local int outerLocalStaticProp;
class Inner;
function void innerMethod(Outer h);
outerStaticProp = 1;
outerLocalStaticProp = 1;
h.outerProp = 1;
h.outerLocalProp = 1;
endfunction
endclass
endclass
module t(/*AUTOARG*/);
initial begin
NodeList n = new;
NodeList::Node n1 = new;
NodeList::Node n2 = new;
NodeTree tr = new;
NodeTree::Node t1 = new;
NodeTree::Node t2 = new;
Outer o = new;
Outer::Inner i = new;
i.innerMethod(o);
if(o.outerProp != 1) $stop;
if(Outer::outerStaticProp != 1) $stop;
if (n1.name != "node") $stop;
n1.name = "n1";
if (n1.name != "n1") $stop;
n2.name = "n2";
if (n2.name != "n2") $stop;
n.head = n1;
n1.link = n2;
if (n.head.name != "n1") $stop;
if (n.head.link.name != "n2") $stop;
t1.id = 1;
if (t1.id != 1) $stop;
t2.id = 2;
if (t2.id != 2) $stop;
tr.root = t1;
t1.link = t2;
if (tr.root.id != 1) $stop;
if (tr.root.link.id != 2) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -11,6 +11,17 @@ class ClsNoArg;
imembera = 5;
if (other != 6) $stop;
endfunction : new
class InnerNoArg;
const int imembera;
function new();
int other = other_func();
imembera = 5;
if (other != 6) $stop;
endfunction
function int other_func();
return 6;
endfunction
endclass
function int other_func();
return 6;
endfunction
@ -52,6 +63,7 @@ module t (/*AUTOARG*/);
ClsArg c2;
Cls2Arg c3;
Cls2Arg c4;
ClsNoArg::InnerNoArg c5 = new;
c1 = new;
if (c1.imembera != 5) $stop;
@ -72,6 +84,9 @@ module t (/*AUTOARG*/);
if (c4.imembera != 6) $stop;
if (c4.imemberb != 9) $stop;
c5 = new;
if (c5.imembera != 5) $stop;
$write("*-* All Finished *-*\n");
$finish;
end

View File

@ -42,6 +42,9 @@ class Cls #(parameter PBASE = 12);
return PBASE;
endfunction
typedef enum { E_PBASE = PBASE } enum_t;
class ClsInner;
bit [PBASE-1:0] member;
endclass
endclass
typedef Cls#(8) Cls8_t;
@ -136,6 +139,8 @@ module t (/*AUTOARG*/);
Cls c12;
Cls #(.PBASE(4)) c4;
Cls8_t c8;
Cls#()::ClsInner ci;
Cls#(8)::ClsInner ci8;
Wrap #(.P(16)) w16;
Wrap2 #(.P(32)) w32;
SelfRefClassTypeParam src_logic;
@ -155,6 +160,8 @@ module t (/*AUTOARG*/);
c12 = new;
c4 = new;
c8 = new;
ci = new;
ci8 = new;
w16 = new;
w32 = new;
src_int = new;
@ -195,6 +202,10 @@ module t (/*AUTOARG*/);
c4.member = 32'haaaaaaaa;
c8.member = 32'haaaaaaaa;
// verilator lint_on WIDTH
ci.member = 12'haaa;
ci8.member = 8'hff;
if (ci.member != 12'haaa) $stop;
if (ci8.member != 8'hff) $stop;
if (c12.member != 12'haaa) $stop;
if (c4.member != 4'ha) $stop;
if (c12.get_member() != 12'haaa) $stop;

View File

@ -14,10 +14,18 @@ module test;
if (enum_item.first().name() != "BAR_0")
$stop;
endfunction
class Inner1;
static function void print();
E enum_item;
if (enum_item.first().name() != "BAR_0")
$stop;
endfunction
endclass
endclass
initial begin
baz#(bar_e)::print();
baz#(bar_e)::Inner1::print();
$write("*-* All Finished *-*\n");
$finish;

View File

@ -8,6 +8,12 @@
`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);
class Cls;
class InnerCls;
static function int f_inner_cs_st();
++c_st; return c_st;
endfunction
endclass
int c_no = 2;
//automatic int c_au = 2; // automatic not a legal keyword here
static int c_st = 22;
@ -22,7 +28,6 @@ class Cls;
static function int f_cs_st ();
++c_st; return c_st;
endfunction
endclass
module t (/*AUTOARG*/);
@ -43,6 +48,7 @@ module t (/*AUTOARG*/);
v = b.f_c_st(); `checkh(v, 26);
//
v = Cls::f_cs_st(); `checkh(v, 27);
v = Cls::InnerCls::f_inner_cs_st(); `checkh(v, 28);
$write("*-* All Finished *-*\n");
$finish;

View File

@ -8,18 +8,33 @@ virtual class VBase;
virtual function int hello;
return 1;
endfunction
virtual class VNested;
virtual function int hello;
return 10;
endfunction
endclass
endclass
class VA extends VBase;
virtual function int hello;
return 2;
endfunction
class VNested extends VBase::VNested;
virtual function int hello;
return 20;
endfunction
endclass
endclass
class VB extends VBase;
virtual function int hello;
return 3;
endfunction
class VNested extends VBase::VNested;
virtual function int hello;
return 30;
endfunction
endclass
endclass
virtual class uvm_phase;
@ -59,18 +74,27 @@ module t;
initial begin
VA va = new;
VB vb = new;
VA::VNested vna = new;
VB::VNested vnb = new;
VBase b;
VBase::VNested bn;
uvm_build_phase ph;
ExtendsCls ec;
if (va.hello() != 2) $stop;
if (vb.hello() != 3) $stop;
if (vna.hello() != 20) $stop;
if (vnb.hello() != 30) $stop;
b = va;
bn = vna;
if (b.hello() != 2) $stop;
if (bn.hello() != 20) $stop;
b = vb;
bn = vnb;
if (b.hello() != 3) $stop;
if (bn.hello() != 30) $stop;
ph = new;
if (ph.get1() != 1) $stop;

View File

@ -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()
test.passes()

View File

@ -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, 2025 Antmicro.
// SPDX-License-Identifier: CC0-1.0
class Cls;
// IEEE 2023 only disallows nested interface inside another interface, not
// class
interface class good_can_nest;
endclass
endclass
module t (/*AUTOARG*/);
Cls c;
endmodule

View File

@ -1,5 +1,4 @@
%Error-UNSUPPORTED: t/t_implements_nested_bad.v:8:14: Unsupported: class within class
8 | interface class bad_cannot_nest;
| ^~~~~
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error: t/t_implements_nested_bad.v:9:17: Interface class shall not be nested within another interface class. (IEEE 1800-2023 8.26)
9 | interface class bad_cannot_nest;
| ^~~~~
%Error: Exiting due to

View File

@ -5,7 +5,9 @@
// SPDX-License-Identifier: CC0-1.0
class Cls;
interface class bad_cannot_nest;
interface class inte;
interface class bad_cannot_nest;
endclass
endclass
endclass

View File

@ -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('simulator')
test.compile(verilator_flags2=["--binary --timing"])
test.passes()

View File

@ -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, 2025 by Antmicro.
// SPDX-License-Identifier: CC0-1.0
class semaphore_cls;
class InnerKeyClass;
int innerKeys;
function new(int keyCount = 0);
innerKeys = keyCount;
endfunction
endclass
// Test an implementation similar to what Verilator will do internally
InnerKeyClass m_keys;
function new(int keyCount = 0);
m_keys = new(keyCount);
endfunction
function void put(int keyCount = 1);
m_keys.innerKeys += keyCount;
endfunction
task get(int keyCount = 1);
wait (m_keys.innerKeys >= keyCount);
m_keys.innerKeys -= keyCount;
endtask
function int try_get(int keyCount = 1);
if (m_keys.innerKeys >= keyCount) begin
m_keys.innerKeys -= keyCount;
return 1;
end
else begin
return 0;
end
endfunction
endclass
`define SEMAPHORE_T semaphore_cls
`include "t_semaphore.v"