Fix static vars under member select (#6313)
This commit is contained in:
parent
95c8b7bb00
commit
11667160f2
|
|
@ -44,6 +44,7 @@ class WidthCommitVisitor final : public VNVisitor {
|
||||||
AstNodeModule* m_modp = nullptr;
|
AstNodeModule* m_modp = nullptr;
|
||||||
std::string m_contNba; // In continuous- or non-blocking assignment
|
std::string m_contNba; // In continuous- or non-blocking assignment
|
||||||
VMemberMap m_memberMap; // Member names cached for fast lookup
|
VMemberMap m_memberMap; // Member names cached for fast lookup
|
||||||
|
bool m_underSel = false; // Whether is currently under AstMemberSel or AstSel
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// METHODS
|
// METHODS
|
||||||
|
|
@ -126,7 +127,9 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void varLifetimeCheck(AstNode* nodep, AstVar* varp) {
|
void varLifetimeCheck(AstNode* nodep, AstVar* varp) {
|
||||||
if (!m_contNba.empty()) {
|
// Skip if we are under a member select (lhs of a dot)
|
||||||
|
// We don't care about lifetime of anything else than rhs of a dot
|
||||||
|
if (!m_underSel && !m_contNba.empty()) {
|
||||||
std::string varType;
|
std::string varType;
|
||||||
const AstNodeDType* const varDtp = varp->dtypep()->skipRefp();
|
const AstNodeDType* const varDtp = varp->dtypep()->skipRefp();
|
||||||
if (varp->lifetime().isAutomatic() && !VN_IS(varDtp, IfaceRefDType)
|
if (varp->lifetime().isAutomatic() && !VN_IS(varDtp, IfaceRefDType)
|
||||||
|
|
@ -368,7 +371,11 @@ private:
|
||||||
classEncapCheck(nodep, nodep->taskp(), VN_CAST(nodep->classOrPackagep(), Class));
|
classEncapCheck(nodep, nodep->taskp(), VN_CAST(nodep->classOrPackagep(), Class));
|
||||||
}
|
}
|
||||||
void visit(AstMemberSel* nodep) override {
|
void visit(AstMemberSel* nodep) override {
|
||||||
iterateChildren(nodep);
|
{
|
||||||
|
VL_RESTORER(m_underSel);
|
||||||
|
m_underSel = true;
|
||||||
|
iterateChildren(nodep);
|
||||||
|
}
|
||||||
editDType(nodep);
|
editDType(nodep);
|
||||||
if (auto* const classrefp = VN_CAST(nodep->fromp()->dtypep(), ClassRefDType)) {
|
if (auto* const classrefp = VN_CAST(nodep->fromp()->dtypep(), ClassRefDType)) {
|
||||||
classEncapCheck(nodep, nodep->varp(), classrefp->classp());
|
classEncapCheck(nodep, nodep->varp(), classrefp->classp());
|
||||||
|
|
@ -388,6 +395,14 @@ private:
|
||||||
// This check could go anywhere after V3Param
|
// This check could go anywhere after V3Param
|
||||||
nodep->v3fatalSrc("Presels should have been removed before this point");
|
nodep->v3fatalSrc("Presels should have been removed before this point");
|
||||||
}
|
}
|
||||||
|
void visit(AstSel* nodep) override {
|
||||||
|
{
|
||||||
|
VL_RESTORER(m_underSel);
|
||||||
|
m_underSel = true;
|
||||||
|
iterateChildren(nodep);
|
||||||
|
}
|
||||||
|
editDType(nodep);
|
||||||
|
}
|
||||||
void visit(AstNode* nodep) override {
|
void visit(AstNode* nodep) override {
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
editDType(nodep);
|
editDType(nodep);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2025 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(timing_loop=True, verilator_flags2=['--timing'])
|
||||||
|
|
||||||
|
test.execute()
|
||||||
|
|
||||||
|
test.passes()
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
interface Iface;
|
||||||
|
bit clk;
|
||||||
|
int x;
|
||||||
|
|
||||||
|
clocking cb @(posedge clk);
|
||||||
|
default input #0 output #0;
|
||||||
|
inout x;
|
||||||
|
endclocking
|
||||||
|
endinterface
|
||||||
|
|
||||||
|
class Foo;
|
||||||
|
virtual Iface iface;
|
||||||
|
function new(virtual Iface tmp);
|
||||||
|
iface = tmp;
|
||||||
|
endfunction
|
||||||
|
task update(virtual Iface tmp);
|
||||||
|
iface = tmp;
|
||||||
|
endtask
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class Bar;
|
||||||
|
Foo foo;
|
||||||
|
function new(Foo tmp);
|
||||||
|
foo = tmp;
|
||||||
|
endfunction
|
||||||
|
task update(Foo tmp);
|
||||||
|
foo = tmp;
|
||||||
|
endtask
|
||||||
|
task assignment();
|
||||||
|
foo.iface.cb.x <= 8;
|
||||||
|
endtask
|
||||||
|
endclass
|
||||||
|
|
||||||
|
module t;
|
||||||
|
Iface iface();
|
||||||
|
Iface iface2();
|
||||||
|
|
||||||
|
task clockSome();
|
||||||
|
#2;
|
||||||
|
iface.clk = ~iface.clk;
|
||||||
|
iface2.clk = ~iface2.clk;
|
||||||
|
#2;
|
||||||
|
iface.clk = ~iface.clk;
|
||||||
|
iface2.clk = ~iface2.clk;
|
||||||
|
endtask
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
Foo foo = new(iface);
|
||||||
|
Foo foo2 = new(iface2);
|
||||||
|
Bar bar = new(foo);
|
||||||
|
clockSome();
|
||||||
|
if (iface.x != 0) $stop;
|
||||||
|
if (iface2.x != 0) $stop;
|
||||||
|
bar.assignment();
|
||||||
|
clockSome();
|
||||||
|
if (iface.x != 8) $stop;
|
||||||
|
if (iface2.x != 0) $stop;
|
||||||
|
foo.update(iface2);
|
||||||
|
clockSome();
|
||||||
|
if (iface.x != 8) $stop;
|
||||||
|
if (iface2.x != 0) $stop;
|
||||||
|
bar.update(foo2);
|
||||||
|
clockSome();
|
||||||
|
if (iface.x != 8) $stop;
|
||||||
|
if (iface2.x != 0) $stop;
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2025 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(timing_loop=True, verilator_flags2=['--timing'])
|
||||||
|
|
||||||
|
test.execute()
|
||||||
|
|
||||||
|
test.passes()
|
||||||
|
|
@ -0,0 +1,93 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
interface Iface;
|
||||||
|
bit clk;
|
||||||
|
int x[2:0];
|
||||||
|
|
||||||
|
clocking cb @(posedge clk);
|
||||||
|
default input #0 output #0;
|
||||||
|
inout x;
|
||||||
|
endclocking
|
||||||
|
endinterface
|
||||||
|
|
||||||
|
class Foo;
|
||||||
|
virtual Iface iface;
|
||||||
|
int index = 0;
|
||||||
|
function new(virtual Iface tmp);
|
||||||
|
iface = tmp;
|
||||||
|
endfunction
|
||||||
|
task update(virtual Iface tmp);
|
||||||
|
iface = tmp;
|
||||||
|
endtask
|
||||||
|
task update_index(int i);
|
||||||
|
index = i;
|
||||||
|
endtask
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class Bar;
|
||||||
|
Foo foo;
|
||||||
|
function new(Foo tmp);
|
||||||
|
foo = tmp;
|
||||||
|
endfunction
|
||||||
|
task update(Foo tmp);
|
||||||
|
foo = tmp;
|
||||||
|
endtask
|
||||||
|
task assignment();
|
||||||
|
foo.iface.cb.x[foo.index] <= 8;
|
||||||
|
endtask
|
||||||
|
endclass
|
||||||
|
|
||||||
|
module t;
|
||||||
|
Iface iface();
|
||||||
|
Iface iface2();
|
||||||
|
|
||||||
|
task clockSome();
|
||||||
|
#2;
|
||||||
|
iface.clk = ~iface.clk;
|
||||||
|
iface2.clk = ~iface2.clk;
|
||||||
|
#2;
|
||||||
|
iface.clk = ~iface.clk;
|
||||||
|
iface2.clk = ~iface2.clk;
|
||||||
|
endtask
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
Foo foo = new(iface);
|
||||||
|
Foo foo2 = new(iface2);
|
||||||
|
Bar bar = new(foo);
|
||||||
|
clockSome();
|
||||||
|
if (iface.x[0] != 0) $stop;
|
||||||
|
if (iface.x[1] != 0) $stop;
|
||||||
|
if (iface2.x[0] != 0) $stop;
|
||||||
|
if (iface2.x[1] != 0) $stop;
|
||||||
|
bar.assignment();
|
||||||
|
clockSome();
|
||||||
|
if (iface.x[0] != 8) $stop;
|
||||||
|
if (iface.x[1] != 0) $stop;
|
||||||
|
if (iface2.x[0] != 0) $stop;
|
||||||
|
if (iface2.x[1] != 0) $stop;
|
||||||
|
foo.update_index(1);
|
||||||
|
clockSome();
|
||||||
|
if (iface.x[0] != 8) $stop;
|
||||||
|
if (iface.x[1] != 0) $stop;
|
||||||
|
if (iface2.x[0] != 0) $stop;
|
||||||
|
if (iface2.x[1] != 0) $stop;
|
||||||
|
foo.update(iface2);
|
||||||
|
clockSome();
|
||||||
|
if (iface.x[0] != 8) $stop;
|
||||||
|
if (iface.x[1] != 0) $stop;
|
||||||
|
if (iface2.x[0] != 0) $stop;
|
||||||
|
if (iface2.x[1] != 0) $stop;
|
||||||
|
bar.update(foo2);
|
||||||
|
clockSome();
|
||||||
|
if (iface.x[0] != 8) $stop;
|
||||||
|
if (iface.x[1] != 0) $stop;
|
||||||
|
if (iface2.x[0] != 0) $stop;
|
||||||
|
if (iface2.x[1] != 0) $stop;
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
Loading…
Reference in New Issue