This commit is contained in:
Zhou Shen 2025-12-23 19:29:15 -05:00 committed by GitHub
commit 746c882eda
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 106 additions and 1 deletions

View File

@ -1940,6 +1940,7 @@ public:
, m_processor{netlistp} {
// Relies on modules already being in top-down-order
iterate(netlistp);
V3Width::clearTypeMap();
}
~ParamVisitor() override = default;
VL_UNCOPYABLE(ParamVisitor);

View File

@ -207,13 +207,16 @@ class WidthVisitor final : public VNVisitor {
using TableMap = std::map<std::pair<const AstNodeDType*, VAttrType>, AstVar*>;
using PatVecMap = std::map<int, AstPatMember*>;
using DTypeMap = std::map<const std::string, AstPatMember*>;
using ModVarExpMap = std::map<AstVar*, AstNodeExpr*>;
// STATE
V3UniqueNames m_insideTempNames; // For generating unique temporary variable names for
// `inside` expressions
VMemberMap m_memberMap; // Member names cached for fast lookup
ModVarExpMap m_modVarExpMap;
V3TaskConnectState m_taskConnectState; // State to cache V3Task::taskConnects
WidthVP* m_vup = nullptr; // Current node state
static std::map<AstNodeDType*, AstNodeDType*> m_typeMap;
bool m_underFork = false; // Visiting under a fork
bool m_underSExpr = false; // Visiting under a sequence expression
AstNode* m_seqUnsupp = nullptr; // Property has unsupported node
@ -232,6 +235,7 @@ class WidthVisitor final : public VNVisitor {
const bool m_doGenerate; // Do errors later inside generate statement
bool m_streamConcat = false; // True if visiting arguments of stream concatenation
int m_dtTables = 0; // Number of created data type tables
bool m_hasParamRef; // Whether there is parameter ref.
TableMap m_tableMap; // Created tables so can remove duplicates
std::map<const AstNodeDType*, AstQueueDType*>
m_queueDTypeIndexed; // Queues with given index type
@ -2095,6 +2099,11 @@ class WidthVisitor final : public VNVisitor {
new AstConst(elementsNewFl, 1)},
true}};
}
AstUnpackArrayDType* arrDtypep = VN_CAST(newp, UnpackArrayDType);
if (m_hasParamRef && arrDtypep) {
if (m_typeMap.find(arrDtypep) == m_typeMap.end())
m_typeMap[arrDtypep] = arrDtypep->cloneTree(false);
}
nodep->replaceWith(newp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
// Normally parent's iteration would cover this, but we might have entered by a specific
@ -2708,6 +2717,7 @@ class WidthVisitor final : public VNVisitor {
nodep->doingWidth(false);
}
void visit(AstNodeVarRef* nodep) override {
if (m_modVarExpMap.find(nodep->varp()) != m_modVarExpMap.end()) { m_hasParamRef = true; }
if (nodep->didWidth()) return;
if (!nodep->varp()) {
if (m_paramsOnly && VN_IS(nodep, VarXRef)) {
@ -6193,12 +6203,26 @@ class WidthVisitor final : public VNVisitor {
bool didWidth = false;
if (AstPattern* const patternp = VN_CAST(nodep->exprp(), Pattern)) {
const AstVar* const modVarp = nodep->modVarp();
m_hasParamRef = false;
// Convert BracketArrayDType
userIterate(modVarp->childDTypep(),
WidthVP{SELF, BOTH}.p()); // May relink pointed to node
AstNodeDType* const setDtp = modVarp->childDTypep();
if (!patternp->childDTypep()) patternp->childDTypep(setDtp->cloneTree(false));
if (!patternp->childDTypep()) {
if (m_typeMap.find(setDtp) != m_typeMap.end()) {
AstNodeDType* const currentDtypep = m_typeMap[setDtp]->cloneTree(false);
currentDtypep->foreach([&](AstNodeVarRef* nodep) {
if (m_modVarExpMap.find(nodep->varp()) != m_modVarExpMap.end())
nodep->replaceWith(
m_modVarExpMap[nodep->varp()]->cloneTree(false));
});
patternp->childDTypep(currentDtypep);
VL_DO_DANGLING(userIterate(currentDtypep, nullptr), currentDtypep);
} else
patternp->childDTypep(setDtp->cloneTree(false));
}
userIterateChildren(nodep, WidthVP{setDtp, BOTH}.p());
m_hasParamRef = false;
didWidth = true;
}
if (!didWidth) userIterateChildren(nodep, WidthVP{SELF, BOTH}.p());
@ -6333,7 +6357,21 @@ class WidthVisitor final : public VNVisitor {
if (nodep->rangep()) userIterateAndNext(nodep->rangep(), WidthVP{SELF, BOTH}.p());
userIterateAndNext(nodep->pinsp(), nullptr);
}
if (nodep->paramsp()) {
nodep->paramsp()->foreach([&](const AstPin* pinNodep) {
if (!VN_CAST(pinNodep->exprp(), Pattern)) {
if (AstNodeExpr* const nodeExprp = VN_CAST(pinNodep->exprp(), NodeExpr)) {
m_modVarExpMap[pinNodep->modVarp()] = nodeExprp->cloneTree(false);
}
}
});
}
userIterateAndNext(nodep->paramsp(), nullptr);
for (auto itr = m_modVarExpMap.begin(); itr != m_modVarExpMap.end(); itr++) {
AstNodeExpr* exprp = itr->second;
VL_DO_DANGLING(exprp->deleteTree(), exprp);
}
m_modVarExpMap.clear();
}
void visit(AstGatePin* nodep) override {
assertAtExpr(nodep);
@ -9165,6 +9203,13 @@ class WidthVisitor final : public VNVisitor {
}
public:
static void clearTypeMap() {
for (auto itr = m_typeMap.begin(); itr != m_typeMap.end(); itr++) {
AstNodeDType* nodeDTypep = itr->second;
VL_DO_DANGLING(nodeDTypep->deleteTree(), nodeDTypep);
}
m_typeMap.clear();
}
// CONSTRUCTORS
WidthVisitor(bool paramsOnly, // [in] TRUE if we are considering parameters only.
bool doGenerate) // [in] TRUE if we are inside a generate statement and
@ -9177,6 +9222,7 @@ public:
}
~WidthVisitor() override = default;
};
std::map<AstNodeDType*, AstNodeDType*> WidthVisitor::m_typeMap;
//######################################################################
// Width class functions
@ -9222,3 +9268,4 @@ AstNode* V3Width::widthGenerateParamsEdit(
// No WidthRemoveVisitor, as don't want to drop $signed etc inside gen blocks
return nodep;
}
void V3Width::clearTypeMap() { WidthVisitor::clearTypeMap(); }

View File

@ -31,6 +31,7 @@ public:
static void width(AstNetlist* nodep) VL_MT_DISABLED;
static AstNode* widthParamsEdit(AstNode* nodep) VL_MT_DISABLED;
static AstNode* widthGenerateParamsEdit(AstNode* nodep) VL_MT_DISABLED;
static void clearTypeMap();
// For use only in WidthVisitor
// Replace AstSelBit, etc with AstSel/AstArraySel

View File

@ -0,0 +1,17 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2024 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')
# Compile only test.
test.compile()
test.passes()

View File

@ -0,0 +1,39 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2017 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
module t();
parameter LEN1 = 8;
test #(
.LEN(LEN1),
.LST('{LEN1{0}})
)
inst1();
parameter LEN2 = 3;
test #(
.LEN(LEN2*2),
.LST('{LEN2*2{0}})
)
inst2();
test #(
.LEN(LEN1 + LEN2),
.LST('{(LEN1+LEN2){0}})
)
inst3();
test #(
.LEN(LEN1 + LEN2),
.LST('{LEN1{0}, LEN2{1}})
)
inst4();
endmodule
module test #(
parameter LEN = 4,
parameter LST[LEN] = '{LEN{0}}
)();
endmodule