Fix type parameters order (#7615)
This commit is contained in:
parent
efdc8d1cbf
commit
b06ea01afb
|
|
@ -296,8 +296,8 @@ class ParamProcessor final {
|
|||
// Default parameter values of hierarchical blocks
|
||||
std::map<AstNodeModule*, DefaultValueMap> m_defaultParameterValues;
|
||||
VNDeleter m_deleter; // Used to delay deletion of nodes
|
||||
// Class default paramater dependencies
|
||||
std::vector<std::pair<AstParamTypeDType*, int>> m_classParams;
|
||||
// Class default type paramater dependencies
|
||||
std::vector<std::pair<AstParamTypeDType*, int>> m_classTypeParams;
|
||||
std::unordered_map<AstParamTypeDType*, int> m_paramIndex;
|
||||
|
||||
// Guard against infinite recursion in classTypeMatchesDefaultClone slow path
|
||||
|
|
@ -1835,24 +1835,24 @@ class ParamProcessor final {
|
|||
UASSERT_OBJ(classp, nodep, "Class or interface ref has no classp/ifacep");
|
||||
|
||||
// Get the parameter list for this class
|
||||
m_classParams.clear();
|
||||
m_classTypeParams.clear();
|
||||
m_paramIndex.clear();
|
||||
for (AstNode* stmtp = classp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
if (AstParamTypeDType* paramTypep = VN_CAST(stmtp, ParamTypeDType)) {
|
||||
// Only consider formal class type parameters (generic parameters),
|
||||
// not localparam type declarations inside the class body.
|
||||
if (!paramTypep->isGParam()) continue;
|
||||
m_paramIndex.emplace(paramTypep, static_cast<int>(m_classParams.size()));
|
||||
m_classParams.emplace_back(paramTypep, -1);
|
||||
m_paramIndex.emplace(paramTypep, static_cast<int>(m_classTypeParams.size()));
|
||||
m_classTypeParams.emplace_back(paramTypep, -1);
|
||||
}
|
||||
}
|
||||
|
||||
// For each parameter, detect either a dependent default (copy from previous param)
|
||||
// or a direct type default (for ex. int). Store dependency index in
|
||||
// m_classParams[i].second, default type in defaultTypeNodes[i].
|
||||
std::vector<AstNodeDType*> defaultTypeNodes(m_classParams.size(), nullptr);
|
||||
for (size_t i = 0; i < m_classParams.size(); ++i) {
|
||||
AstParamTypeDType* const paramTypep = m_classParams[i].first;
|
||||
std::vector<AstNodeDType*> defaultTypeNodes(m_classTypeParams.size(), nullptr);
|
||||
for (size_t i = 0; i < m_classTypeParams.size(); ++i) {
|
||||
AstParamTypeDType* const paramTypep = m_classTypeParams[i].first;
|
||||
// Parser places defaults/constraints under childDTypep as AstRequireDType
|
||||
AstRequireDType* const reqDtp = VN_CAST(paramTypep->getChildDTypep(), RequireDType);
|
||||
if (!reqDtp) continue;
|
||||
|
|
@ -1862,7 +1862,7 @@ class ParamProcessor final {
|
|||
if (AstParamTypeDType* const sourceParamp
|
||||
= VN_CAST(refDtp->refDTypep(), ParamTypeDType)) {
|
||||
auto it = m_paramIndex.find(sourceParamp);
|
||||
if (it != m_paramIndex.end()) { m_classParams[i].second = it->second; }
|
||||
if (it != m_paramIndex.end()) { m_classTypeParams[i].second = it->second; }
|
||||
continue; // dependency handled
|
||||
}
|
||||
}
|
||||
|
|
@ -1875,14 +1875,23 @@ class ParamProcessor final {
|
|||
}
|
||||
|
||||
// Count existing pins and capture them by index for easy lookup
|
||||
// Type parameters when named can be given in any order, but later we depend
|
||||
// on the order when handling defaults. So here we reorder them
|
||||
// for proper handling. The remaining ones are just pushed back
|
||||
std::vector<AstPin*> pinsByIndex;
|
||||
pinsByIndex.resize(m_classTypeParams.size(), nullptr);
|
||||
for (AstPin* pinp = paramsp; pinp; pinp = VN_AS(pinp->nextp(), Pin)) {
|
||||
pinsByIndex.push_back(pinp);
|
||||
if (AstParamTypeDType* typep = pinp->modPTypep()) {
|
||||
pinsByIndex[m_paramIndex[typep]] = pinp;
|
||||
} else {
|
||||
pinsByIndex.push_back(pinp);
|
||||
}
|
||||
}
|
||||
|
||||
// For each missing parameter, get its pin from dependency or direct default
|
||||
for (size_t paramIdx = pinsByIndex.size(); paramIdx < m_classParams.size(); paramIdx++) {
|
||||
const int sourceParamIdx = m_classParams[paramIdx].second;
|
||||
for (size_t paramIdx = 0; paramIdx < m_classTypeParams.size(); paramIdx++) {
|
||||
if (pinsByIndex[paramIdx]) continue;
|
||||
const int sourceParamIdx = m_classTypeParams[paramIdx].second;
|
||||
|
||||
AstPin* newPinp = nullptr;
|
||||
|
||||
|
|
@ -1900,7 +1909,7 @@ class ParamProcessor final {
|
|||
if (newPinp) {
|
||||
newPinp->name("__paramNumber" + cvtToStr(paramIdx + 1));
|
||||
newPinp->param(true);
|
||||
newPinp->modPTypep(m_classParams[paramIdx].first);
|
||||
newPinp->modPTypep(m_classTypeParams[paramIdx].first);
|
||||
if (classOrPackageRef) {
|
||||
classOrPackageRef->addParamsp(newPinp);
|
||||
} else if (classRefDType) {
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
// 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
|
||||
|
||||
// verilog_format: off
|
||||
`define stop $stop;
|
||||
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
||||
// verilog_format: on
|
||||
|
||||
class obj;
|
||||
endclass
|
||||
class TypeParams #(
|
||||
type T1 = obj,
|
||||
type T2 = obj,
|
||||
type T3 = obj
|
||||
);
|
||||
T1 t1;
|
||||
T2 t2;
|
||||
T3 t3;
|
||||
endclass
|
||||
|
||||
class ValueParams #(
|
||||
int P1 = 1,
|
||||
int P2 = 1,
|
||||
int P3 = 1
|
||||
);
|
||||
logic[P1:0] x1;
|
||||
logic[P2:0] x2;
|
||||
logic[P3:0] x3;
|
||||
endclass
|
||||
|
||||
class Mixed #(
|
||||
type T1 = obj,
|
||||
int P1 = 1,
|
||||
type T2 = obj,
|
||||
int P2 = 1,
|
||||
type T3 = obj,
|
||||
int P3 = 1
|
||||
);
|
||||
T1 t1;
|
||||
T2 t2;
|
||||
T3 t3;
|
||||
logic[P1:0] x1;
|
||||
logic[P2:0] x2;
|
||||
logic[P3:0] x3;
|
||||
endclass
|
||||
|
||||
module t;
|
||||
TypeParams #(
|
||||
.T2 (int),
|
||||
.T3 (logic)
|
||||
) t;
|
||||
obj o;
|
||||
|
||||
ValueParams #(
|
||||
.P3 (5),
|
||||
.P2 (2)
|
||||
) v;
|
||||
|
||||
Mixed #(
|
||||
.P3 (3),
|
||||
.T1 (logic),
|
||||
.T3 (int),
|
||||
.P2 (7)
|
||||
) m;
|
||||
initial begin
|
||||
o = new;
|
||||
t = new;
|
||||
t.t1 = o;
|
||||
t.t2 = 32;
|
||||
t.t3 = 1;
|
||||
if (t.t1 != o) $stop;
|
||||
`checkd(t.t2, 32);
|
||||
`checkd(t.t3, 1);
|
||||
|
||||
v = new;
|
||||
v.x1 = 2;
|
||||
v.x2 = 5;
|
||||
v.x3 = 40;
|
||||
`checkd(v.x1, 2);
|
||||
`checkd(v.x2, 5);
|
||||
`checkd(v.x3, 40);
|
||||
|
||||
m = new;
|
||||
m.t1 = 1;
|
||||
m.t2 = o;
|
||||
m.t3 = 12345;
|
||||
m.x1 = 0;
|
||||
m.x2 = 250;
|
||||
m.x3 = 15;
|
||||
`checkd(m.t1, 1);
|
||||
if (m.t2 != o) $stop;
|
||||
`checkd(m.t3, 12345);
|
||||
`checkd(m.x1, 0);
|
||||
`checkd(m.x2, 250);
|
||||
`checkd(m.x3, 15);
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
Loading…
Reference in New Issue