Signed-off-by: Kamil Rakoczy <krakoczy@antmicro.com>
This commit is contained in:
parent
fbe8439eb8
commit
c840ffb0ae
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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"); }
|
||||
|
|
|
@ -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
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
|
@ -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()
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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()
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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()
|
|
@ -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"
|
Loading…
Reference in New Issue