Merge d53295a3fb into 5ead758f28
This commit is contained in:
commit
4f9dc73040
|
|
@ -3136,6 +3136,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||||
bool m_inPackedArray = false; // Currently traversing a packed array tree
|
bool m_inPackedArray = false; // Currently traversing a packed array tree
|
||||||
bool m_replaceWithAlias
|
bool m_replaceWithAlias
|
||||||
= true; // Replace VarScope with an alias. Used in the handling of AstAlias
|
= true; // Replace VarScope with an alias. Used in the handling of AstAlias
|
||||||
|
bool m_isParam = false; // Specifies whether currently visiting param variable
|
||||||
|
|
||||||
struct DotStates final {
|
struct DotStates final {
|
||||||
DotPosition m_dotPos; // Scope part of dotted resolution
|
DotPosition m_dotPos; // Scope part of dotted resolution
|
||||||
|
|
@ -5092,6 +5093,8 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||||
void visit(AstVar* nodep) override {
|
void visit(AstVar* nodep) override {
|
||||||
LINKDOT_VISIT_START();
|
LINKDOT_VISIT_START();
|
||||||
checkNoDot(nodep);
|
checkNoDot(nodep);
|
||||||
|
VL_RESTORER(m_isParam);
|
||||||
|
m_isParam = nodep->varType().isParam();
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
if (m_statep->forPrimary() && nodep->isIO() && !m_ftaskp && !nodep->user4()) {
|
if (m_statep->forPrimary() && nodep->isIO() && !m_ftaskp && !nodep->user4()) {
|
||||||
nodep->v3error(
|
nodep->v3error(
|
||||||
|
|
@ -5273,27 +5276,32 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||||
// which may find std::randomize and overwrite classOrPackagep
|
// which may find std::randomize and overwrite classOrPackagep
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (m_insideClassExtParam) {
|
VSymEnt* const foundp
|
||||||
// The reference may point to a method declared in a super class, which is proved
|
= m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot, first);
|
||||||
// by a parameter. In such a case, it can't be linked at the first stage.
|
AstNodeFTask* const taskp = foundp ? VN_CAST(foundp->nodep(), NodeFTask) : nullptr;
|
||||||
// Must not do any linking, because e.g. might find an extends of an upper class
|
AstNodeModule* const taskModulep = foundp ? foundp->classOrPackagep() : nullptr;
|
||||||
// because the current class (under parent) isn't yet importing it's extended class
|
// Ignore deferring linking of functions inside params of classes extending
|
||||||
// symbols
|
// parametric classes if referenced function can be linked in the first pass.
|
||||||
return;
|
if (!m_isParam || !taskp
|
||||||
}
|
|| (taskp->classMethod() && taskModulep && taskModulep->hasParameterList())) {
|
||||||
if (AstClass* const targetClassp = VN_CAST(dotSymp->nodep(), Class)) {
|
if (m_insideClassExtParam) {
|
||||||
if (m_extendsParam.count(targetClassp)) {
|
// The reference may point to a method declared in a super class, which is
|
||||||
// Target class has parameterized extends not yet resolved.
|
// proved by a parameter. In such a case, it can't be linked at the first
|
||||||
// Its inherited symbols (e.g. static functions from the base class)
|
// stage. Must not do any linking, because e.g. might find an extends of an
|
||||||
// aren't imported yet - defer to linkDotParamed.
|
// upper class because the current class (under parent) isn't yet importing
|
||||||
|
// it's extended class symbols.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (AstClass* const targetClassp = VN_CAST(dotSymp->nodep(), Class)) {
|
||||||
|
if (m_extendsParam.count(targetClassp)) {
|
||||||
|
// Target class has parameterized extends not yet resolved.
|
||||||
|
// Its inherited symbols (e.g. static functions from the base class)
|
||||||
|
// aren't imported yet - defer to linkDotParamed.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VSymEnt* const foundp
|
|
||||||
= m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot, first);
|
|
||||||
AstNodeFTask* const taskp
|
|
||||||
= foundp ? VN_CAST(foundp->nodep(), NodeFTask) : nullptr; // Maybe nullptr
|
|
||||||
if (taskp) {
|
if (taskp) {
|
||||||
if (staticAccess && !taskp->isStatic()) {
|
if (staticAccess && !taskp->isStatic()) {
|
||||||
// TODO bug4077
|
// TODO bug4077
|
||||||
|
|
|
||||||
|
|
@ -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('vlt')
|
||||||
|
|
||||||
|
test.compile()
|
||||||
|
|
||||||
|
test.execute()
|
||||||
|
|
||||||
|
test.passes()
|
||||||
|
|
@ -0,0 +1,86 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain
|
||||||
|
// SPDX-FileCopyrightText: 2026 Antmicro
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
`define stop $stop
|
||||||
|
`define checkh(gotv, expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0x exp=%0x (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
|
||||||
|
|
||||||
|
function automatic int align(input int a, input int b);
|
||||||
|
return a - (a % b);
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
class Foo;
|
||||||
|
|
||||||
|
static function int mul(input int a, input int b);
|
||||||
|
return a * b;
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
endclass : Foo
|
||||||
|
|
||||||
|
class FooParam #(parameter int param = 5);
|
||||||
|
|
||||||
|
static function int mul(input int a);
|
||||||
|
return a * param;
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
endclass : FooParam
|
||||||
|
|
||||||
|
class Base #(parameter int param = 5);
|
||||||
|
|
||||||
|
function int get_base_param();
|
||||||
|
return param;
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
static function int alignUp(input int a);
|
||||||
|
return ((a + param - 1) / param) * param;
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
endclass : Base
|
||||||
|
|
||||||
|
class Derived #(
|
||||||
|
parameter int a = 17,
|
||||||
|
parameter int b = 8,
|
||||||
|
parameter int c = align(a, b),
|
||||||
|
parameter int d = Base#(b)::alignUp(a),
|
||||||
|
parameter int e = Foo::mul(a, b),
|
||||||
|
parameter int f = FooParam#()::mul(a)
|
||||||
|
) extends Base #(
|
||||||
|
.param (a)
|
||||||
|
);
|
||||||
|
|
||||||
|
function int get_third_param();
|
||||||
|
return c;
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function int get_fourth_param();
|
||||||
|
return d;
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function int get_fifth_param();
|
||||||
|
return e;
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function int get_sixth_param();
|
||||||
|
return f;
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
endclass : Derived
|
||||||
|
|
||||||
|
module t (clk);
|
||||||
|
input clk;
|
||||||
|
|
||||||
|
Derived inst = new;
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
`checkh(inst.get_base_param(), 17)
|
||||||
|
`checkh(inst.get_third_param(), 16)
|
||||||
|
`checkh(inst.get_fourth_param(), 24)
|
||||||
|
`checkh(inst.get_fifth_param(), 136)
|
||||||
|
`checkh(inst.get_sixth_param(), 85)
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
Loading…
Reference in New Issue