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. # pthreads is harmless otherwise.
CFG_LIBS="$LIBS $CFG_LIBS" CFG_LIBS="$LIBS $CFG_LIBS"
_MY_LDLIBS_CHECK_OPT(CFG_LIBS, -lpthread) _MY_LDLIBS_CHECK_OPT(CFG_LIBS, -lpthread)
_MY_LDLIBS_CHECK_OPT(CFG_LIBS, -latomic)
# Check libraries for MingW # Check libraries for MingW
_MY_LDLIBS_CHECK_OPT(CFG_LIBS, -lbcrypt) _MY_LDLIBS_CHECK_OPT(CFG_LIBS, -lbcrypt)

View File

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

View File

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