Fixes #7236
This commit is contained in:
parent
56ed47ee7c
commit
e7a644a3fc
|
|
@ -233,6 +233,7 @@ private:
|
||||||
string m_dotted; // Dotted part of scope the name()ed task/func is under or ""
|
string m_dotted; // Dotted part of scope the name()ed task/func is under or ""
|
||||||
string m_inlinedDots; // Dotted hierarchy flattened out
|
string m_inlinedDots; // Dotted hierarchy flattened out
|
||||||
bool m_pli = false; // Pli system call ($name)
|
bool m_pli = false; // Pli system call ($name)
|
||||||
|
bool m_containsGenBlock = false; // Contains gen block reference
|
||||||
VIsCached m_purity; // Pure state
|
VIsCached m_purity; // Pure state
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
@ -259,6 +260,8 @@ public:
|
||||||
void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; }
|
void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; }
|
||||||
bool pli() const { return m_pli; }
|
bool pli() const { return m_pli; }
|
||||||
void pli(bool flag) { m_pli = flag; }
|
void pli(bool flag) { m_pli = flag; }
|
||||||
|
bool containsGenBlock() const { return m_containsGenBlock; }
|
||||||
|
void containsGenBlock(const bool flag) { m_containsGenBlock = flag; }
|
||||||
bool isPure() override;
|
bool isPure() override;
|
||||||
|
|
||||||
string emitVerilog() final override { V3ERROR_NA_RETURN(""); }
|
string emitVerilog() final override { V3ERROR_NA_RETURN(""); }
|
||||||
|
|
|
||||||
|
|
@ -3111,6 +3111,7 @@ void AstActive::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
||||||
void AstNodeFTaskRef::dump(std::ostream& str) const {
|
void AstNodeFTaskRef::dump(std::ostream& str) const {
|
||||||
this->AstNodeExpr::dump(str);
|
this->AstNodeExpr::dump(str);
|
||||||
if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep());
|
if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep());
|
||||||
|
if (containsGenBlock()) str << " [GENBLK]";
|
||||||
str << " -> ";
|
str << " -> ";
|
||||||
if (dotted() != "") str << ".=" << dotted() << " ";
|
if (dotted() != "") str << ".=" << dotted() << " ";
|
||||||
if (taskp()) {
|
if (taskp()) {
|
||||||
|
|
@ -3121,6 +3122,7 @@ void AstNodeFTaskRef::dump(std::ostream& str) const {
|
||||||
}
|
}
|
||||||
void AstNodeFTaskRef::dumpJson(std::ostream& str) const {
|
void AstNodeFTaskRef::dumpJson(std::ostream& str) const {
|
||||||
dumpJsonStrFunc(str, dotted);
|
dumpJsonStrFunc(str, dotted);
|
||||||
|
dumpJsonBoolFuncIf(str, containsGenBlock);
|
||||||
dumpJsonGen(str);
|
dumpJsonGen(str);
|
||||||
}
|
}
|
||||||
void AstNodeFTask::dump(std::ostream& str) const {
|
void AstNodeFTask::dump(std::ostream& str) const {
|
||||||
|
|
|
||||||
|
|
@ -5067,6 +5067,17 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||||
m_ds.m_dotPos = DP_MEMBER;
|
m_ds.m_dotPos = DP_MEMBER;
|
||||||
} else if (m_ds.m_dotp && m_ds.m_dotPos == DP_FINAL) {
|
} else if (m_ds.m_dotp && m_ds.m_dotPos == DP_FINAL) {
|
||||||
nodep->dotted(m_ds.m_dotText); // Maybe ""
|
nodep->dotted(m_ds.m_dotText); // Maybe ""
|
||||||
|
// Only flag FTaskRefs under generate-if/case blocks that may be
|
||||||
|
// pruned. GenFor and plain begin-blocks won't be pruned by V3Param.
|
||||||
|
// VarXRef uses the broader m_genBlk flag (set for all GenBlocks)
|
||||||
|
// because genfor unrolling also removes variables.
|
||||||
|
if (m_ds.m_genBlk && m_ds.m_dotSymp) {
|
||||||
|
const AstNode* const blkp = m_ds.m_dotSymp->nodep();
|
||||||
|
if (VN_IS(blkp, GenBlock)
|
||||||
|
&& (VN_IS(blkp->backp(), GenIf) || VN_IS(blkp->backp(), GenCase))) {
|
||||||
|
nodep->containsGenBlock(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (m_ds.m_dotp && m_ds.m_dotPos == DP_MEMBER) {
|
} else if (m_ds.m_dotp && m_ds.m_dotPos == DP_MEMBER) {
|
||||||
// Found a Var, everything following is method call.
|
// Found a Var, everything following is method call.
|
||||||
// {scope}.{var}.HERE {method} ( ARGS )
|
// {scope}.{var}.HERE {method} ( ARGS )
|
||||||
|
|
|
||||||
|
|
@ -2529,6 +2529,14 @@ class ParamVisitor final : public VNVisitor {
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
void visit(AstNodeFTaskRef* nodep) override {
|
||||||
|
if (nodep->containsGenBlock()) {
|
||||||
|
// Needs relink, as may remove pointed-to task/func
|
||||||
|
nodep->taskp(nullptr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
iterateChildren(nodep);
|
||||||
|
}
|
||||||
void visit(AstVarXRef* nodep) override {
|
void visit(AstVarXRef* nodep) override {
|
||||||
if (nodep->containsGenBlock()) {
|
if (nodep->containsGenBlock()) {
|
||||||
// Needs relink, as may remove pointed-to var
|
// Needs relink, as may remove pointed-to var
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# 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-FileCopyrightText: 2026 Wilson Snyder
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
import vltest_bootstrap
|
||||||
|
|
||||||
|
test.scenarios('simulator')
|
||||||
|
|
||||||
|
test.compile(verilator_flags2=["--binary"])
|
||||||
|
|
||||||
|
test.execute()
|
||||||
|
|
||||||
|
test.passes()
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
// DESCRIPTION: Verilator: Verify function calls through generate-if block references
|
||||||
|
//
|
||||||
|
// When a function is defined inside a generate-if block and called via a
|
||||||
|
// dotted reference (e.g. defs.foo()), the FUNCREF must survive generate
|
||||||
|
// pruning. Previously the FUNCREF could point to the deleted else-branch
|
||||||
|
// function, causing a broken-link internal error.
|
||||||
|
//
|
||||||
|
// 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-FileCopyrightText: 2026 Wilson Snyder
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
module t(/*AUTOARG*/);
|
||||||
|
generate
|
||||||
|
if (1) begin : defs
|
||||||
|
function automatic logic foo;
|
||||||
|
foo = 1'b1;
|
||||||
|
endfunction
|
||||||
|
end else begin : defs
|
||||||
|
function automatic logic foo;
|
||||||
|
foo = 1'b0;
|
||||||
|
endfunction
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
if (defs.foo() !== 1'b1) begin
|
||||||
|
$display("%%Error: defs.foo() returned wrong value");
|
||||||
|
$stop;
|
||||||
|
end
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
Loading…
Reference in New Issue