parent
77f0883b06
commit
3d126b77cd
|
|
@ -1285,7 +1285,7 @@ class AstNetlist final : public AstNode {
|
|||
bool m_timescaleSpecified = false; // Input HDL specified timescale
|
||||
uint32_t m_nTraceCodes = 0; // Number of trace codes used by design
|
||||
// V3Param-deferred params awaiting V3LinkDot::linkDotParamed scope-resolution.
|
||||
std::vector<AstVar*> m_deferredParamVarps;
|
||||
std::set<AstVar*> m_deferredParamVarps;
|
||||
// Sparse metadata for constants produced from named parameters/localparams. Keep this off
|
||||
// AstConst itself, as AstConst is a very common node and only a small fraction carry this
|
||||
// name.
|
||||
|
|
@ -1295,8 +1295,8 @@ public:
|
|||
AstNetlist();
|
||||
ASTGEN_MEMBERS_AstNetlist;
|
||||
const char* broken() const override;
|
||||
void pushDeferredParamVarp(AstVar* varp) { m_deferredParamVarps.push_back(varp); }
|
||||
const std::vector<AstVar*>& deferredParamVarps() const { return m_deferredParamVarps; }
|
||||
void pushDeferredParamVarp(AstVar* varp) { m_deferredParamVarps.insert(varp); }
|
||||
const std::set<AstVar*>& deferredParamVarps() const { return m_deferredParamVarps; }
|
||||
void clearDeferredParamVarps() { m_deferredParamVarps.clear(); }
|
||||
void deleteContents();
|
||||
void cloneRelink() override { V3ERROR_NA; } // Not cloneable
|
||||
|
|
|
|||
|
|
@ -2924,10 +2924,22 @@ class ParamVisitor final : public VNVisitor {
|
|||
}
|
||||
});
|
||||
if (hasUnresolvedLparamXRef) return;
|
||||
// Defer if value contains a class::member Dot. By V3Param time the only
|
||||
// surviving such Dots are paramed-class refs awaiting linkDotParamed.
|
||||
if (nodep->valuep()->exists(
|
||||
[](AstDot* dotp) { return VN_IS(dotp->lhsp(), ClassOrPackageRef); })) {
|
||||
// Defer if value has a class::member Dot, or references a deferred lparam
|
||||
const bool hasDot = nodep->valuep()->exists(
|
||||
[](AstDot* dotp) { return VN_IS(dotp->lhsp(), ClassOrPackageRef); });
|
||||
bool refsDeferred = false;
|
||||
if (!hasDot) {
|
||||
const auto& deferredVarps = v3Global.rootp()->deferredParamVarps();
|
||||
nodep->valuep()->foreach([&](const AstVarRef* refp) {
|
||||
if (refsDeferred) return;
|
||||
AstVar* const refVarp = refp->varp();
|
||||
if (refVarp && refVarp->varType() == VVarType::LPARAM
|
||||
&& deferredVarps.count(refVarp)) {
|
||||
refsDeferred = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (hasDot || refsDeferred) {
|
||||
v3Global.rootp()->pushDeferredParamVarp(nodep);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,53 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// localparams that chain through a class-scope-resolved localparam
|
||||
// (typedef alias of a parameterized class, e.g. inst::b). V3LinkDot defers
|
||||
// the inst::b Dot until post-V3Param; V3Param must also defer any
|
||||
// localparam whose value transitively depends on a deferred one, including
|
||||
// same-module VarRef chains (b -> c -> d) and not just cross-module
|
||||
// VarXRefs.
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// verilog_format: off
|
||||
`define stop $stop
|
||||
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0)
|
||||
// verilog_format: on
|
||||
|
||||
module t;
|
||||
virtual class C #(parameter int a);
|
||||
localparam int b = a;
|
||||
endclass
|
||||
|
||||
typedef C#(0) inst0;
|
||||
typedef C#(42) inst42;
|
||||
|
||||
// Direct: inst::b Dot in the value
|
||||
localparam int b0 = inst0::b;
|
||||
localparam int b42 = inst42::b;
|
||||
|
||||
// One-step chain: refers to a deferred lparam
|
||||
localparam int c0 = b0;
|
||||
localparam int c42 = b42;
|
||||
|
||||
// Multi-step chain: d -> c -> b -> inst::b
|
||||
localparam int d0 = c0;
|
||||
localparam int d42 = c42;
|
||||
|
||||
// Expression referencing two deferred lparams
|
||||
localparam int sum = b0 + b42;
|
||||
|
||||
initial begin
|
||||
`checkh(b0, 32'd0);
|
||||
`checkh(b42, 32'd42);
|
||||
`checkh(c0, 32'd0);
|
||||
`checkh(c42, 32'd42);
|
||||
`checkh(d0, 32'd0);
|
||||
`checkh(d42, 32'd42);
|
||||
`checkh(sum, 32'd42);
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
Loading…
Reference in New Issue