Support interface class diamond relationship.

This commit is contained in:
Wilson Snyder 2024-01-23 22:07:35 -05:00
parent 21e85f87bc
commit 74ec50f933
6 changed files with 112 additions and 11 deletions

View File

@ -474,6 +474,7 @@ AC_SUBST(CFG_LDFLAGS_VERILATED)
# pthreads is harmless otherwise.
CFG_LIBS="$LIBS $CFG_LIBS"
_MY_LDLIBS_CHECK_OPT(CFG_LIBS, -lpthread)
_MY_LDLIBS_CHECK_OPT(CFG_LIBS, -latomic)
# Check libraries for MingW
_MY_LDLIBS_CHECK_OPT(CFG_LIBS, -lbcrypt)

View File

@ -248,16 +248,18 @@ public:
return nullptr;
}
void putConstructorSubinit(const AstClass* classp, AstCFunc* cfuncp, bool top, bool& firstr) {
void putConstructorSubinit(const AstClass* classp, AstCFunc* cfuncp, bool top, std::set<AstClass*> &doneClassesr) {
for (const AstClassExtends* extp = classp->extendsp(); extp;
extp = VN_AS(extp->nextp(), ClassExtends)) {
if (extp->classp()->useVirtualPublic()) {
// It's a c++ virtual class (diamond relation)
// Must get the subclasses initialized first
putConstructorSubinit(extp->classp(), cfuncp, false, firstr);
putConstructorSubinit(extp->classp(), cfuncp, false, doneClassesr);
}
puts(firstr ? "" : "\n, ");
firstr = false;
// Diamond pattern with same base class twice?
if (doneClassesr.find(extp->classp()) != doneClassesr.end()) continue;
puts(doneClassesr.empty() ? "" : "\n , ");
doneClassesr.emplace(extp->classp());
puts(prefixNameProtect(extp->classp()));
if (constructorNeedsProcess(extp->classp())) {
puts("(vlProcess, vlSymsp");
@ -295,8 +297,8 @@ public:
const AstClass* const classp = VN_CAST(nodep->scopep()->modp(), Class);
if (nodep->isConstructor() && classp && classp->extendsp()) {
puts("\n : ");
bool first = true;
putConstructorSubinit(classp, nodep, true, first /*ref*/);
std::set<AstClass*> doneClasses;
putConstructorSubinit(classp, nodep, true, doneClasses /*ref*/);
}
}
puts(" {\n");

View File

@ -2030,7 +2030,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
AstNodeFTask* m_ftaskp = nullptr; // Current function/task
int m_modportNum = 0; // Uniqueify modport numbers
bool m_inSens = false; // True if in senitem
std::set<std::string> m_ifClassImpNames; // Names imported from interface class
std::map<std::string, AstNode*> m_ifClassImpNames; // Names imported from interface class
std::set<AstClass*> m_extendsParam; // Classes that have a parameterized super class
// (except the default instances)
// They are added to the set only in linkDotPrimary.
@ -2235,9 +2235,9 @@ class LinkDotResolveVisitor final : public VNVisitor {
<< "... Location of interface class's function\n"
<< interfaceSubp->warnContextSecondary());
}
if (!existsInChild
&& m_ifClassImpNames.find(interfaceSubp->name())
!= m_ifClassImpNames.end()) {
const auto it = m_ifClassImpNames.find(interfaceSubp->name());
if (!existsInChild && it != m_ifClassImpNames.end()
&& it->second != interfaceSubp) { // Not exact same function from diamond
implementsClassp->v3error(
"Class " << implementsClassp->prettyNameQ() << " implements "
<< interfaceClassp->prettyNameQ()
@ -2249,7 +2249,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
<< "... Location of interface class's function\n"
<< interfaceSubp->warnContextSecondary());
}
m_ifClassImpNames.emplace(interfaceSubp->name());
m_ifClassImpNames.emplace(interfaceSubp->name(), interfaceSubp);
}
}
}

View File

@ -0,0 +1,21 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# 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
scenarios(simulator => 1);
compile(
);
execute(
check_finished => 1,
);
ok(1);
1;

View File

@ -0,0 +1,59 @@
// 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
module class_tb ();
interface class Ibase;
pure virtual function int fn();
endclass
interface class Ic1 extends Ibase;
pure virtual function int fn1();
endclass
interface class Ic2 extends Ibase;
pure virtual function int fn2();
endclass
interface class Ic3 extends Ic1, Ic2;
endclass
class Cls implements Ic3;
virtual function int fn();
return 10;
endfunction
virtual function int fn1();
return 1;
endfunction
virtual function int fn2();
return 2;
endfunction
endclass
initial begin
Cls cls;
Ibase ibase;
Ic1 ic1;
Ic2 ic2;
Ic3 ic3;
cls = new;
if (cls.fn() != 10) $stop;
if (cls.fn1() != 1) $stop;
if (cls.fn2() != 2) $stop;
ibase = cls;
ic1 = cls;
ic2 = cls;
ic3 = cls;
if (ibase.fn() != 10) $stop;
if (ic1.fn() != 10) $stop;
if (ic2.fn() != 10) $stop;
if (ic3.fn() != 10) $stop;
if (ic1.fn1() != 1) $stop;
if (ic2.fn2() != 2) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -19,6 +19,24 @@ endclass
class Cls implements IclsBoth;
endclass
// This is not a collision - diamond
interface class Ibase;
pure virtual function int fn();
endclass
interface class Ic1 extends Ibase;
pure virtual function int fn1();
endclass
interface class Ic2 extends Ibase;
pure virtual function int fn2();
endclass
interface class Ic3 extends Ic1, Ic2;
endclass
module t (/*AUTOARG*/);
Cls c;
endmodule