Fix missing scope when calling package function (#7128 repair) (#7188) (#7190)

This commit is contained in:
em2machine 2026-03-04 15:37:55 -05:00 committed by GitHub
parent 9a5c1d27c8
commit c34cd6ddf1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 334 additions and 11 deletions

View File

@ -2293,20 +2293,21 @@ class ParamVisitor final : public VNVisitor {
nodep->v3error("Parameter without default value is never given value"
<< " (IEEE 1800-2023 6.20.1): " << nodep->prettyNameQ());
} else if (nodep->valuep()) {
// In visit(AstVar*) for localparams, check if expression contains VARXREF
// to another localparam (not parameter). Parameters are already const,
// but localparams may not be evaluated yet.
bool hasVarXRefToLparam = false;
// If the value expression contains a VarXRef to an interface
// localparam whose value is not yet constant, defer constification
// to avoid premature widthing with unresolved values (see
// t_lparam_dep_iface tests). When the referenced localparam is
// already const, proceed normally so FUNCREFs with resolved iface
// param args get folded.
bool hasUnresolvedLparamXRef = false;
nodep->valuep()->foreach([&](const AstVarXRef* xrefp) {
if (xrefp->varp() && xrefp->varp()->varType() == VVarType::LPARAM) {
hasVarXRefToLparam = true;
if (const AstVar* const varp = xrefp->varp()) {
if (varp->varType() == VVarType::LPARAM && !VN_IS(varp->valuep(), Const)) {
hasUnresolvedLparamXRef = true;
}
}
});
if (hasVarXRefToLparam) {
// Don't constify - let it be evaluated later
return;
}
if (hasUnresolvedLparamXRef) return;
V3Const::constifyParamsEdit(nodep);
}
}
@ -2328,6 +2329,13 @@ class ParamVisitor final : public VNVisitor {
if (nodep->name() == candp->name()) {
if (AstVar* const varp = VN_CAST(candp, Var)) {
UINFO(9, "Found interface parameter: " << varp);
// The interface may not have been visited yet (it is at a
// deeper level in the work queue), so its localparams may
// not be constified. Eagerly constify here so that the
// caller's hasUnresolvedLparamXRef check sees a Const.
if (varp->isParam() && varp->valuep() && !VN_IS(varp->valuep(), Const)) {
V3Const::constifyParamsEdit(varp);
}
nodep->varp(varp);
return true;
} else if (const AstPin* const pinp = VN_CAST(candp, Pin)) {

View File

@ -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()

View File

@ -0,0 +1,37 @@
// DESCRIPTION: Verilator: Localparam with package function call using interface param
//
// 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
// verilog_format: off
`define stop $stop
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
// verilog_format: on
package pkg;
function automatic bit fn(int value);
return (value > 0) ? 1'b1 : 1'b0;
endfunction
endpackage
interface ifc();
localparam int PARAM = 1;
endinterface
module mod(ifc i);
localparam bit lpbit = pkg::fn(i.PARAM);
endmodule
module t;
ifc i();
mod m(.i);
initial begin
`checkd(m.lpbit, 1'b1);
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -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()

View File

@ -0,0 +1,42 @@
// DESCRIPTION: Verilator: Localparam with package function call using computed interface param
//
// 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
// verilog_format: off
`define stop $stop
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
// verilog_format: on
package pkg;
function automatic bit fn(int value);
return (value > 0) ? 1'b1 : 1'b0;
endfunction
endpackage
interface ifc #(parameter int WIDTH = 8);
localparam int DEPTH = $clog2(WIDTH);
localparam int COMPUTED = DEPTH * 2;
endinterface
module mod(ifc i);
// LPARAM references i.COMPUTED which depends on i.DEPTH which depends on WIDTH
localparam bit lpbit = pkg::fn(i.COMPUTED);
localparam int lpval = i.COMPUTED + 1;
endmodule
module t;
ifc #(.WIDTH(64)) i();
mod m(.i);
initial begin
// DEPTH = $clog2(64) = 6, COMPUTED = 6*2 = 12
`checkd(m.lpbit, 1'b1); // fn(12) returns 1 since 12 > 0
`checkd(m.lpval, 13); // lpval = 12 + 1 = 13
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -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()

View File

@ -0,0 +1,45 @@
// DESCRIPTION: Verilator: Localparam with function call using type-parameterized interface param
//
// 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
// verilog_format: off
`define stop $stop
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
// verilog_format: on
package pkg;
function automatic bit fn(int value);
return (value > 0) ? 1'b1 : 1'b0;
endfunction
endpackage
interface ifc #(parameter type some_type) ();
localparam int PARAM = 1;
localparam int TYPE_WIDTH = $bits(some_type);
endinterface
function automatic bit assert_func(bit value);
if (!value) $fatal(2, "DEAD");
return value;
endfunction
module mod(ifc i);
localparam bit lpbit = pkg::fn(i.PARAM);
localparam bit test = assert_func(i.TYPE_WIDTH == 32);
endmodule
module t;
ifc #(.some_type(int)) i();
mod m(.i);
initial begin
`checkd(m.lpbit, 1'b1); // fn(1) returns 1 since 1 > 0
`checkd(m.test, 1'b1); // $bits(int) == 32, so assert_func(1) returns 1
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -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()

View File

@ -0,0 +1,49 @@
// DESCRIPTION: Verilator: Interface array with multiple consumer modules using FUNCREF LPARAMs
//
// 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
// verilog_format: off
`define stop $stop
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
// verilog_format: on
package pkg;
function automatic int decode_width(int value);
return (value > 0) ? value * 2 : 0;
endfunction
endpackage
interface ifc #(parameter int WIDTH = 8);
localparam int DEPTH = $clog2(WIDTH);
localparam int DECODED = pkg::decode_width(DEPTH);
endinterface
module producer(ifc i);
localparam int BUF_SIZE = pkg::decode_width(i.DEPTH);
localparam int OUT_W = i.DECODED + 1;
endmodule
module consumer(ifc i);
localparam int HALF = i.DECODED / 2;
localparam int TAG_W = pkg::decode_width(i.DEPTH) + i.DECODED;
endmodule
module t;
ifc #(.WIDTH(64)) bus[2]();
producer p(.i(bus[0]));
consumer c(.i(bus[1]));
initial begin
// WIDTH=64, DEPTH=$clog2(64)=6, DECODED=decode_width(6)=12
`checkd(p.BUF_SIZE, 12); // decode_width(6) = 12
`checkd(p.OUT_W, 13); // 12 + 1 = 13
`checkd(c.HALF, 6); // 12 / 2 = 6
`checkd(c.TAG_W, 24); // decode_width(6) + 12 = 12 + 12 = 24
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -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()

View File

@ -0,0 +1,52 @@
// DESCRIPTION: Verilator: Hierarchical interface pass-through with FUNCREF LPARAMs
//
// 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
// verilog_format: off
`define stop $stop
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
// verilog_format: on
package pkg;
function automatic int decode_width(int value);
return (value > 0) ? value * 2 : 0;
endfunction
endpackage
interface ifc #(parameter int WIDTH = 8);
localparam int DEPTH = $clog2(WIDTH);
localparam int DECODED = pkg::decode_width(DEPTH);
endinterface
// Leaf module: uses interface LPARAM in a FUNCREF-based localparam
module leaf(ifc i);
localparam int BUF_SIZE = pkg::decode_width(i.DEPTH);
localparam int OUT_W = i.DECODED + 1;
endmodule
// Intermediate wrapper: passes interface through to leaf
module wrapper(ifc i);
leaf u_leaf(.i);
endmodule
// Second level wrapper: adds another layer of hierarchy
module subsystem(ifc bus);
wrapper u_wrap(.i(bus));
endmodule
module t;
ifc #(.WIDTH(64)) bus();
subsystem u_sub(.bus);
initial begin
// WIDTH=64, DEPTH=$clog2(64)=6, DECODED=decode_width(6)=12
`checkd(u_sub.u_wrap.u_leaf.BUF_SIZE, 12); // decode_width(6) = 12
`checkd(u_sub.u_wrap.u_leaf.OUT_W, 13); // 12 + 1 = 13
$write("*-* All Finished *-*\n");
$finish;
end
endmodule