Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com> Signed-off-by: Artur Bieniek <abieniek@internships.antmicro.com> Co-authored-by: Krzysztof Bieganski <kbieganski@antmicro.com>
This commit is contained in:
parent
c6b0918db5
commit
1923d23cff
|
|
@ -1689,7 +1689,7 @@ class LinkDotFindVisitor final : public VNVisitor {
|
|||
"'import::*' in $unit scope may pollute global namespace");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} else if (!nodep->resolvedClassp()) {
|
||||
VSymEnt* const impp = srcp->findIdFlat(nodep->name());
|
||||
if (!impp) {
|
||||
nodep->v3error("Import object not found: " << nodep->prettyPkgNameQ());
|
||||
|
|
|
|||
111
src/V3Param.cpp
111
src/V3Param.cpp
|
|
@ -280,6 +280,9 @@ 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;
|
||||
std::unordered_map<AstParamTypeDType*, int> m_paramIndex;
|
||||
|
||||
// METHODS
|
||||
|
||||
|
|
@ -929,6 +932,102 @@ class ParamProcessor final {
|
|||
UASSERT(paramspMap.empty(), "Not every generic interface implicit param is used");
|
||||
}
|
||||
|
||||
void resolveDefaultParams(AstNode* nodep) {
|
||||
AstClassOrPackageRef* classOrPackageRef = VN_CAST(nodep, ClassOrPackageRef);
|
||||
AstClassRefDType* classRefDType = VN_CAST(nodep, ClassRefDType);
|
||||
AstClass* classp = nullptr;
|
||||
AstPin* paramsp = nullptr;
|
||||
|
||||
if (classOrPackageRef) {
|
||||
classp = VN_CAST(classOrPackageRef->classOrPackageSkipp(), Class);
|
||||
if (!classp) return; // No parameters in packages
|
||||
paramsp = classOrPackageRef->paramsp();
|
||||
} else if (classRefDType) {
|
||||
classp = classRefDType->classp();
|
||||
paramsp = classRefDType->paramsp();
|
||||
} else {
|
||||
nodep->v3fatalSrc("resolveDefaultParams called on node which is not a Class ref");
|
||||
}
|
||||
|
||||
UASSERT_OBJ(classp, nodep, "Class or interface ref has no classp/ifacep");
|
||||
|
||||
// Get the parameter list for this class
|
||||
m_classParams.clear();
|
||||
m_paramIndex.clear();
|
||||
for (AstNode* stmtp = classp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
if (AstParamTypeDType* paramTypep = VN_CAST(stmtp, ParamTypeDType)) {
|
||||
m_paramIndex.emplace(paramTypep, m_classParams.size());
|
||||
m_classParams.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;
|
||||
// Parser places defaults/constraints under childDTypep as AstRequireDType
|
||||
AstRequireDType* const reqDtp = VN_CAST(paramTypep->getChildDTypep(), RequireDType);
|
||||
if (!reqDtp) continue;
|
||||
|
||||
// If default is a reference to another param type, record dependency
|
||||
if (AstRefDType* const refDtp = VN_CAST(reqDtp->subDTypep(), RefDType)) {
|
||||
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; }
|
||||
continue; // dependency handled
|
||||
}
|
||||
}
|
||||
|
||||
// If default is a direct type (for ex. int)
|
||||
// also record dependency
|
||||
if (AstNodeDType* const dtp = VN_CAST(reqDtp->lhsp(), NodeDType)) {
|
||||
defaultTypeNodes[i] = dtp;
|
||||
}
|
||||
}
|
||||
|
||||
// Count existing pins and capture them by index for easy lookup
|
||||
std::vector<AstPin*> pinsByIndex;
|
||||
for (AstPin* pinp = paramsp; pinp; pinp = VN_AS(pinp->nextp(), Pin)) {
|
||||
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;
|
||||
|
||||
AstPin* newPin = nullptr;
|
||||
|
||||
// Case 1: Dependent default -> clone the source pin's type
|
||||
if (sourceParamIdx >= 0) { newPin = pinsByIndex[sourceParamIdx]->cloneTree(false); }
|
||||
|
||||
// Case 2: Direct default type (e.g., int), create a new pin with that dtype
|
||||
if (!newPin && defaultTypeNodes[paramIdx]) {
|
||||
AstNodeDType* const dtypep = defaultTypeNodes[paramIdx];
|
||||
newPin = new AstPin{dtypep->fileline(), static_cast<int>(paramIdx) + 1,
|
||||
"__paramNumber" + cvtToStr(paramIdx + 1),
|
||||
dtypep->cloneTree(false)};
|
||||
}
|
||||
|
||||
if (newPin) {
|
||||
newPin->name("__paramNumber" + cvtToStr(paramIdx + 1));
|
||||
newPin->param(true);
|
||||
newPin->modPTypep(m_classParams[paramIdx].first);
|
||||
if (classOrPackageRef) {
|
||||
classOrPackageRef->addParamsp(newPin);
|
||||
} else if (classRefDType) {
|
||||
classRefDType->addParamsp(newPin);
|
||||
}
|
||||
// Update local tracking so future dependent defaults can find it
|
||||
pinsByIndex.resize(paramIdx + 1, nullptr);
|
||||
pinsByIndex[paramIdx] = newPin;
|
||||
if (!paramsp) paramsp = newPin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool nodeDeparamCommon(AstNode* nodep, AstNodeModule*& srcModpr, AstPin* paramsp,
|
||||
AstPin* pinsp, bool any_overrides) {
|
||||
// Make sure constification worked
|
||||
|
|
@ -949,6 +1048,16 @@ class ParamProcessor final {
|
|||
cellInterfaceCleanup(pinsp, srcModpr, longname /*ref*/, any_overrides /*ref*/,
|
||||
ifaceRefRefs /*ref*/);
|
||||
|
||||
// Default params are resolved as overrides
|
||||
if (!any_overrides) {
|
||||
for (AstPin* pinp = paramsp; pinp; pinp = VN_AS(pinp->nextp(), Pin)) {
|
||||
if (pinp->modPTypep()) {
|
||||
any_overrides = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_hierBlocks.hierSubRun() && m_hierBlocks.isHierBlock(srcModpr->origName())) {
|
||||
AstNodeModule* const paramedModp
|
||||
= m_hierBlocks.findByParams(srcModpr->origName(), paramsp, m_modp);
|
||||
|
|
@ -1021,11 +1130,13 @@ class ParamProcessor final {
|
|||
}
|
||||
|
||||
void classRefDeparam(AstClassOrPackageRef* nodep, AstNodeModule*& srcModpr) {
|
||||
resolveDefaultParams(nodep);
|
||||
if (nodeDeparamCommon(nodep, srcModpr, nodep->paramsp(), nullptr, false))
|
||||
nodep->classOrPackagep(srcModpr);
|
||||
}
|
||||
|
||||
void classRefDeparam(AstClassRefDType* nodep, AstNodeModule*& srcModpr) {
|
||||
resolveDefaultParams(nodep);
|
||||
if (nodeDeparamCommon(nodep, srcModpr, nodep->paramsp(), nullptr, false)) {
|
||||
AstClass* const classp = VN_AS(srcModpr, Class);
|
||||
nodep->classp(classp);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 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('vlt')
|
||||
|
||||
test.compile()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Antmicro.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
class c0 #(type T= real);
|
||||
static function T f();
|
||||
endfunction
|
||||
endclass
|
||||
class c2 #(type REQ=int, type RSP= int, type IMP=int);
|
||||
function new (IMP imp);
|
||||
endfunction
|
||||
endclass
|
||||
class c3 #(type REQ, type RSP, type IMP=RSP);
|
||||
function new (IMP imp);
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
class c1 #(type REQ= int, RSP=REQ);
|
||||
typedef c1 #( REQ , RSP) this_type;
|
||||
typedef c0 #(this_type) type_id;
|
||||
c2 #(REQ, RSP, this_type) c2inst;
|
||||
function new (string name, int parent);
|
||||
c2inst = new (this);
|
||||
endfunction
|
||||
|
||||
c3 #(REQ, this_type) c3inst;
|
||||
endclass
|
||||
|
||||
`define test \
|
||||
c1 #(real) c1inst1;\
|
||||
c1 #(real, real) c1inst2;\
|
||||
c1 #(real, int) c1inst3;\
|
||||
c1 #() c1inst4;\
|
||||
c1 c1inst5;
|
||||
|
||||
`test
|
||||
interface interf;
|
||||
// `test
|
||||
endinterface
|
||||
module t;
|
||||
// `test
|
||||
interf interf_inst();
|
||||
endmodule
|
||||
class topc;
|
||||
// `test
|
||||
endclass
|
||||
|
||||
class paramcl;
|
||||
endclass: paramcl
|
||||
class c5;
|
||||
c1 #(paramcl) seq;
|
||||
function void f();
|
||||
seq = c1 #(paramcl)::type_id::f();
|
||||
endfunction: f
|
||||
endclass
|
||||
c5 c5inst;
|
||||
|
|
@ -19744,9 +19744,7 @@ endclass
|
|||
typedef uvm_sequencer #(uvm_sequence_item) uvm_virtual_sequencer;
|
||||
function uvm_sequencer::new (string name, uvm_component parent=null);
|
||||
super.new(name, parent);
|
||||
//TODO issue #4497 - Fix uvm_sequencer wrong reference type
|
||||
//TODO %Error: t/t_uvm_pkg_todo.vh:19869:21: Function Argument expects a CLASSREFDTYPE 'uvm_sequencer__Tz97_TBz97', got CLASSREFDTYPE 'uvm_sequencer__Tz97'
|
||||
//TODO seq_item_export = new ("seq_item_export", this);
|
||||
seq_item_export = new ("seq_item_export", this);
|
||||
endfunction
|
||||
function void uvm_sequencer::stop_sequences();
|
||||
REQ t;
|
||||
|
|
|
|||
Loading…
Reference in New Issue