1 // -*- mode: C++; c-file-style: "cc-mode" -*-
2 //*************************************************************************
3 // DESCRIPTION: Verilator: Replicate modules for parameterization
4 //
5 // Code available from: https://verilator.org
6 //
7 //*************************************************************************
8 //
9 // Copyright 2003-2021 by Wilson Snyder. This program is free software; you
10 // can redistribute it and/or modify it under the terms of either the GNU
11 // Lesser General Public License Version 3 or the Perl Artistic License
12 // Version 2.0.
13 // SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
14 //
15 //*************************************************************************
16 // PARAM TRANSFORMATIONS:
17 // Top down traversal:
18 // For each cell:
19 // If parameterized,
20 // Determine all parameter widths, constant values.
21 // (Interfaces also matter, as if an interface is parameterized
22 // this effectively changes the width behavior of all that
23 // reference the iface.)
24 // Clone module cell calls, renaming with __{par1}_{par2}_...
25 // Substitute constants for cell's module's parameters.
26 // Relink pins and cell and ifacerefdtype to point to new module.
27 //
28 // For interface Parent's we have the AstIfaceRefDType::cellp()
29 // pointing to this module. If that parent cell's interface
30 // module gets parameterized, AstIfaceRefDType::cloneRelink
31 // will update AstIfaceRefDType::cellp(), and V3LinkDot will
32 // see the new interface.
33 //
34 // However if a submodule's AstIfaceRefDType::ifacep() points
35 // to the old (unparameterized) interface and needs correction.
36 // To detect this we must walk all pins looking for interfaces
37 // that the parent has changed and propagate down.
38 //
39 // Then process all modules called by that cell.
40 // (Cells never referenced after parameters expanded must be ignored.)
41 //
42 // After we complete parameters, the varp's will be wrong (point to old module)
43 // and must be relinked.
44 //
45 //*************************************************************************
46
47 #include "config_build.h"
48 #include "verilatedos.h"
49
50 #include "V3Global.h"
51 #include "V3Param.h"
52 #include "V3Ast.h"
53 #include "V3Case.h"
54 #include "V3Const.h"
55 #include "V3Os.h"
56 #include "V3Parse.h"
57 #include "V3Width.h"
58 #include "V3Unroll.h"
59 #include "V3Hasher.h"
60
61 #include <deque>
62 #include <map>
63 #include <memory>
64 #include <vector>
65
66 //######################################################################
67 // Hierarchical block and parameter db (modules without parameter is also handled)
68
69 class ParameterizedHierBlocks final {
70 using HierBlockOptsByOrigName = std::multimap<std::string, const V3HierarchicalBlockOption*>;
71 using HierMapIt = HierBlockOptsByOrigName::const_iterator;
72 using HierBlockModMap = std::map<const std::string, AstNodeModule*>;
73 using ParamConstMap = std::map<const std::string, std::unique_ptr<AstConst>>;
74 using GParamsMap = std::map<const std::string, AstVar*>; // key:parameter name value:parameter
75
76 // MEMBERS
77 // key:Original module name, value:HiearchyBlockOption*
78 // If a module is parameterized, the module is uniquiefied to overridden parameters.
79 // This is why HierBlockOptsByOrigName is multimap.
80 HierBlockOptsByOrigName m_hierBlockOptsByOrigName;
81 // key:mangled module name, value:AstNodeModule*
82 HierBlockModMap m_hierBlockMod;
83 // Overridden parameters of the hierarchical block
84 std::map<const V3HierarchicalBlockOption*, ParamConstMap> m_hierParams;
85 std::map<const std::string, GParamsMap>
86 m_modParams; // Parameter variables of hierarchical blocks
87
88 // METHODS
89 VL_DEBUG_FUNC; // Declare debug()
90
91 public:
ParameterizedHierBlocks(const V3HierBlockOptSet & hierOpts,AstNetlist * nodep)92 ParameterizedHierBlocks(const V3HierBlockOptSet& hierOpts, AstNetlist* nodep) {
93 for (const auto& hierOpt : hierOpts) {
94 m_hierBlockOptsByOrigName.insert(
95 std::make_pair(hierOpt.second.origName(), &hierOpt.second));
96 const V3HierarchicalBlockOption::ParamStrMap& params = hierOpt.second.params();
97 ParamConstMap& consts = m_hierParams[&hierOpt.second];
98 for (V3HierarchicalBlockOption::ParamStrMap::const_iterator pIt = params.begin();
99 pIt != params.end(); ++pIt) {
100 std::unique_ptr<AstConst> constp{AstConst::parseParamLiteral(
101 new FileLine(FileLine::EmptySecret()), pIt->second)};
102 UASSERT(constp, pIt->second << " is not a valid parameter literal");
103 const bool inserted = consts.emplace(pIt->first, std::move(constp)).second;
104 UASSERT(inserted, pIt->first << " is already added");
105 }
106 // origName may be already registered, but it's fine.
107 m_modParams.insert({hierOpt.second.origName(), {}});
108 }
109 for (AstNodeModule* modp = nodep->modulesp(); modp;
110 modp = VN_AS(modp->nextp(), NodeModule)) {
111 if (hierOpts.find(modp->prettyName()) != hierOpts.end()) {
112 m_hierBlockMod.emplace(modp->name(), modp);
113 }
114 const auto defParamIt = m_modParams.find(modp->name());
115 if (defParamIt != m_modParams.end()) {
116 // modp is the original of parameterized hierarchical block
117 for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
118 if (AstVar* const varp = VN_CAST(stmtp, Var)) {
119 if (varp->isGParam()) defParamIt->second.emplace(varp->name(), varp);
120 }
121 }
122 }
123 }
124 }
findByParams(const string & origName,AstPin * firstPinp,const AstNodeModule * modp)125 AstNodeModule* findByParams(const string& origName, AstPin* firstPinp,
126 const AstNodeModule* modp) {
127 if (m_hierBlockOptsByOrigName.find(origName) == m_hierBlockOptsByOrigName.end()) {
128 return nullptr;
129 }
130 // This module is a hierarchical block. Need to replace it by the --lib-create wrapper.
131 const std::pair<HierMapIt, HierMapIt> candidates
132 = m_hierBlockOptsByOrigName.equal_range(origName);
133 const auto paramsIt = m_modParams.find(origName);
134 UASSERT_OBJ(paramsIt != m_modParams.end(), modp, origName << " must be registered");
135 HierMapIt hierIt;
136 for (hierIt = candidates.first; hierIt != candidates.second; ++hierIt) {
137 bool found = true;
138 size_t paramIdx = 0;
139 const ParamConstMap& params = m_hierParams[hierIt->second];
140 UASSERT(params.size() == hierIt->second->params().size(), "not match");
141 for (AstPin* pinp = firstPinp; pinp; pinp = VN_AS(pinp->nextp(), Pin)) {
142 if (!pinp->exprp()) continue;
143 UASSERT_OBJ(!pinp->modPTypep(), pinp,
144 "module with type parameter must not be a hierarchical block");
145 if (const AstVar* const modvarp = pinp->modVarp()) {
146 AstConst* const constp = VN_AS(pinp->exprp(), Const);
147 UASSERT_OBJ(constp, pinp,
148 "parameter for a hierarchical block must have been constified");
149 const auto paramIt = paramsIt->second.find(modvarp->name());
150 UASSERT_OBJ(paramIt != paramsIt->second.end(), modvarp, "must be registered");
151 AstConst* const defValuep = VN_CAST(paramIt->second->valuep(), Const);
152 if (defValuep && areSame(constp, defValuep)) {
153 UINFO(5, "Setting default value of " << constp << " to " << modvarp
154 << std::endl);
155 continue; // Skip this parameter because setting the same value
156 }
157 const auto pIt = vlstd::as_const(params).find(modvarp->name());
158 UINFO(5, "Comparing " << modvarp->name() << " " << constp << std::endl);
159 if (pIt == params.end() || paramIdx >= params.size()
160 || !areSame(constp, pIt->second.get())) {
161 found = false;
162 break;
163 }
164 UINFO(5, "Matched " << modvarp->name() << " " << constp << " and "
165 << pIt->second.get() << std::endl);
166 ++paramIdx;
167 }
168 }
169 if (found && paramIdx == hierIt->second->params().size()) break;
170 }
171 UASSERT_OBJ(hierIt != candidates.second, firstPinp, "No --lib-create wrapper found");
172 // parameter settings will be removed in the bottom of caller visitCell().
173 const HierBlockModMap::const_iterator modIt
174 = m_hierBlockMod.find(hierIt->second->mangledName());
175 UASSERT_OBJ(modIt != m_hierBlockMod.end(), firstPinp,
176 hierIt->second->mangledName() << " is not found");
177
178 const auto it = vlstd::as_const(m_hierBlockMod).find(hierIt->second->mangledName());
179 if (it == m_hierBlockMod.end()) return nullptr;
180 return it->second;
181 }
areSame(AstConst * pinValuep,AstConst * hierOptParamp)182 static bool areSame(AstConst* pinValuep, AstConst* hierOptParamp) {
183 if (pinValuep->isString()) {
184 return pinValuep->num().toString() == hierOptParamp->num().toString();
185 }
186
187 // Bitwidth of hierOptParamp is accurate because V3Width already caluclated in the previous
188 // run. Bitwidth of pinValuep is before width analysis, so pinValuep is casted to
189 // hierOptParamp width.
190 V3Number varNum(pinValuep, hierOptParamp->num().width());
191 if (hierOptParamp->isDouble()) {
192 varNum.isDouble(true);
193 if (pinValuep->isDouble()) {
194 varNum.opAssign(pinValuep->num());
195 } else { // Cast from integer to real
196 varNum.opIToRD(pinValuep->num());
197 }
198 return v3EpsilonEqual(varNum.toDouble(), hierOptParamp->num().toDouble());
199 } else { // Now integer type is assumed
200 if (pinValuep->isDouble()) { // Need to cast to int
201 // Parameter is actually an integral type, but passed value is floating point.
202 // Conversion from real to integer uses rounding in V3Width.cpp
203 varNum.opRToIRoundS(pinValuep->num());
204 } else if (pinValuep->isSigned()) {
205 varNum.opExtendS(pinValuep->num(), pinValuep->num().width());
206 } else {
207 varNum.opAssign(pinValuep->num());
208 }
209 V3Number isEq(pinValuep, 1);
210 isEq.opEq(varNum, hierOptParamp->num());
211 return isEq.isNeqZero();
212 }
213 }
214 };
215
216 //######################################################################
217 // Remove parameters from cells and build new modules
218
219 class ParamProcessor final {
220 // NODE STATE - Local
221 // AstVar::user4() // int Global parameter number (for naming new module)
222 // // (0=not processed, 1=iterated, but no number,
223 // // 65+ parameter numbered)
224 // NODE STATE - Shared with ParamVisitor
225 // AstNodeModule::user5() // bool True if processed
226 // AstGenFor::user5() // bool True if processed
227 // AstVar::user5() // bool True if constant propagated
228 // AstCell::user5p() // string* Generate portion of hierarchical name
229 const AstUser4InUse m_inuser4;
230 const AstUser5InUse m_inuser5;
231 // User1/2/3 used by constant function simulations
232
233 // TYPES
234 // Note may have duplicate entries
235 using IfaceRefRefs = std::deque<std::pair<AstIfaceRefDType*, AstIfaceRefDType*>>;
236
237 // STATE
238 using CloneMap = std::unordered_map<const AstNode*, AstNode*>;
239 struct ModInfo {
240 AstNodeModule* const m_modp; // Module with specified name
241 CloneMap m_cloneMap; // Map of old-varp -> new cloned varp
ModInfoParamProcessor::ModInfo242 explicit ModInfo(AstNodeModule* modp)
243 : m_modp{modp} {}
244 };
245 std::map<const std::string, ModInfo> m_modNameMap; // Hash of created module flavors by name
246
247 std::map<const std::string, std::string>
248 m_longMap; // Hash of very long names to unique identity number
249 int m_longId = 0;
250
251 // All module names that are loaded from source code
252 // Generated modules by this visitor is not included
253 V3StringSet m_allModuleNames;
254
255 using ValueMapValue = std::pair<int, std::string>;
256 std::map<const V3Hash, ValueMapValue> m_valueMap; // Hash of node hash to (param value, name)
257 int m_nextValue = 1; // Next value to use in m_valueMap
258
259 const AstNodeModule* m_modp = nullptr; // Current module being processed
260
261 // Database to get lib-create wrapper that matches parameters in hierarchical Verilation
262 ParameterizedHierBlocks m_hierBlocks;
263 // Default parameter values key:parameter name, value:default value (can be nullptr)
264 using DefaultValueMap = std::map<std::string, AstConst*>;
265 // Default parameter values of hierarchical blocks
266 std::map<AstNodeModule*, DefaultValueMap> m_defaultParameterValues;
267
268 // METHODS
269 VL_DEBUG_FUNC; // Declare debug()
270
makeSmallNames(AstNodeModule * modp)271 static void makeSmallNames(AstNodeModule* modp) {
272 std::vector<int> usedLetter;
273 usedLetter.resize(256);
274 // Pass 1, assign first letter to each gparam's name
275 for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
276 if (AstVar* const varp = VN_CAST(stmtp, Var)) {
277 if (varp->isGParam() || varp->isIfaceRef()) {
278 char ch = varp->name()[0];
279 ch = std::toupper(ch);
280 if (ch < 'A' || ch > 'Z') ch = 'Z';
281 varp->user4(usedLetter[static_cast<int>(ch)] * 256 + ch);
282 usedLetter[static_cast<int>(ch)]++;
283 }
284 } else if (AstParamTypeDType* const typep = VN_CAST(stmtp, ParamTypeDType)) {
285 const char ch = 'T';
286 typep->user4(usedLetter[static_cast<int>(ch)] * 256 + ch);
287 usedLetter[static_cast<int>(ch)]++;
288 }
289 }
290 }
paramSmallName(AstNodeModule * modp,AstNode * varp)291 string paramSmallName(AstNodeModule* modp, AstNode* varp) {
292 if (varp->user4() <= 1) makeSmallNames(modp);
293 int index = varp->user4() / 256;
294 const char ch = varp->user4() & 255;
295 string st = cvtToStr(ch);
296 while (index) {
297 st += cvtToStr(char((index % 25) + 'A'));
298 index /= 26;
299 }
300 return st;
301 }
302
paramValueKey(const AstNode * nodep)303 static string paramValueKey(const AstNode* nodep) {
304 if (const AstRefDType* const refp = VN_CAST(nodep, RefDType)) { nodep = refp->skipRefp(); }
305 string key = nodep->name();
306 if (const AstIfaceRefDType* const ifrtp = VN_CAST(nodep, IfaceRefDType)) {
307 if (ifrtp->cellp() && ifrtp->cellp()->modp()) {
308 key = ifrtp->cellp()->modp()->name();
309 } else if (ifrtp->ifacep()) {
310 key = ifrtp->ifacep()->name();
311 } else {
312 nodep->v3fatalSrc("Can't parameterize interface without module name");
313 }
314 } else if (const AstNodeUOrStructDType* const dtypep
315 = VN_CAST(nodep, NodeUOrStructDType)) {
316 key += " ";
317 key += dtypep->verilogKwd();
318 key += " {";
319 for (const AstNode* memberp = dtypep->membersp(); memberp;
320 memberp = memberp->nextp()) {
321 key += paramValueKey(memberp);
322 key += ";";
323 }
324 key += "}";
325 } else if (const AstMemberDType* const dtypep = VN_CAST(nodep, MemberDType)) {
326 key += " ";
327 key += paramValueKey(dtypep->subDTypep());
328 } else if (const AstBasicDType* const dtypep = VN_CAST(nodep, BasicDType)) {
329 if (dtypep->isRanged()) {
330 key += "[" + cvtToStr(dtypep->left()) + ":" + cvtToStr(dtypep->right()) + "]";
331 }
332 }
333 return key;
334 }
335
paramValueNumber(AstNode * nodep)336 string paramValueNumber(AstNode* nodep) {
337 // TODO: This parameter value number lookup via a constructed key string is not
338 // particularly robust for type parameters. We should really have a type
339 // equivalence predicate function.
340 const string key = paramValueKey(nodep);
341 V3Hash hash = V3Hasher::uncachedHash(nodep);
342 // Force hash collisions -- for testing only
343 if (VL_UNLIKELY(v3Global.opt.debugCollision())) hash = V3Hash();
344 int num;
345 const auto it = m_valueMap.find(hash);
346 if (it != m_valueMap.end() && it->second.second == key) {
347 num = it->second.first;
348 } else {
349 num = m_nextValue++;
350 m_valueMap[hash] = std::make_pair(num, key);
351 }
352 return string("z") + cvtToStr(num);
353 }
moduleCalcName(AstNodeModule * srcModp,const string & longname)354 string moduleCalcName(AstNodeModule* srcModp, const string& longname) {
355 string newname = longname;
356 if (longname.length() > 30) {
357 const auto iter = m_longMap.find(longname);
358 if (iter != m_longMap.end()) {
359 newname = iter->second;
360 } else {
361 newname = srcModp->name();
362 // We use all upper case above, so lower here can't conflict
363 newname += "__pi" + cvtToStr(++m_longId);
364 m_longMap.emplace(longname, newname);
365 }
366 }
367 UINFO(4, "Name: " << srcModp->name() << "->" << longname << "->" << newname << endl);
368 return newname;
369 }
arraySubDTypep(AstNodeDType * nodep)370 AstNodeDType* arraySubDTypep(AstNodeDType* nodep) {
371 // If an unpacked array, return the subDTypep under it
372 if (const AstUnpackArrayDType* const adtypep = VN_CAST(nodep, UnpackArrayDType)) {
373 return adtypep->subDTypep();
374 }
375 // We have not resolved parameter of the child yet, so still
376 // have BracketArrayDType's. We'll presume it'll end up as assignment
377 // compatible (or V3Width will complain).
378 if (const AstBracketArrayDType* const adtypep = VN_CAST(nodep, BracketArrayDType)) {
379 return adtypep->subDTypep();
380 }
381 return nullptr;
382 }
collectPins(CloneMap * clonemapp,AstNodeModule * modp)383 void collectPins(CloneMap* clonemapp, AstNodeModule* modp) {
384 // Grab all I/O so we can remap our pins later
385 for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
386 if (AstVar* const varp = VN_CAST(stmtp, Var)) {
387 if (varp->isIO() || varp->isGParam() || varp->isIfaceRef()) {
388 // Cloning saved a pointer to the new node for us, so just follow that link.
389 const AstVar* const oldvarp = varp->clonep();
390 // UINFO(8,"Clone list 0x"<<hex<<(uint32_t)oldvarp
391 // <<" -> 0x"<<(uint32_t)varp<<endl);
392 clonemapp->emplace(oldvarp, varp);
393 }
394 } else if (AstParamTypeDType* const ptp = VN_CAST(stmtp, ParamTypeDType)) {
395 if (ptp->isGParam()) {
396 const AstParamTypeDType* const oldptp = ptp->clonep();
397 clonemapp->emplace(oldptp, ptp);
398 }
399 }
400 }
401 }
relinkPins(const CloneMap * clonemapp,AstPin * startpinp)402 void relinkPins(const CloneMap* clonemapp, AstPin* startpinp) {
403 for (AstPin* pinp = startpinp; pinp; pinp = VN_AS(pinp->nextp(), Pin)) {
404 if (pinp->modVarp()) {
405 // Find it in the clone structure
406 // UINFO(8,"Clone find 0x"<<hex<<(uint32_t)pinp->modVarp()<<endl);
407 const auto cloneiter = clonemapp->find(pinp->modVarp());
408 UASSERT_OBJ(cloneiter != clonemapp->end(), pinp,
409 "Couldn't find pin in clone list");
410 pinp->modVarp(VN_AS(cloneiter->second, Var));
411 } else if (pinp->modPTypep()) {
412 const auto cloneiter = clonemapp->find(pinp->modPTypep());
413 UASSERT_OBJ(cloneiter != clonemapp->end(), pinp,
414 "Couldn't find pin in clone list");
415 pinp->modPTypep(VN_AS(cloneiter->second, ParamTypeDType));
416 } else {
417 pinp->v3fatalSrc("Not linked?");
418 }
419 }
420 }
relinkPinsByName(AstPin * startpinp,AstNodeModule * modp)421 void relinkPinsByName(AstPin* startpinp, AstNodeModule* modp) {
422 std::map<const string, AstVar*> nameToPin;
423 for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
424 if (AstVar* const varp = VN_CAST(stmtp, Var)) {
425 if (varp->isIO() || varp->isGParam() || varp->isIfaceRef()) {
426 nameToPin.emplace(varp->name(), varp);
427 }
428 }
429 }
430 for (AstPin* pinp = startpinp; pinp; pinp = VN_AS(pinp->nextp(), Pin)) {
431 if (const AstVar* const varp = pinp->modVarp()) {
432 const auto varIt = vlstd::as_const(nameToPin).find(varp->name());
433 UASSERT_OBJ(varIt != nameToPin.end(), varp,
434 "Not found in " << modp->prettyNameQ());
435 pinp->modVarp(varIt->second);
436 }
437 }
438 }
439 // Check if parameter setting during instantiation is simple enough for hierarchical verilation
checkSupportedParam(AstNodeModule * modp,AstPin * pinp) const440 void checkSupportedParam(AstNodeModule* modp, AstPin* pinp) const {
441 // InitArray and AstParamTypeDType are not supported because that can not be set via -G
442 // option.
443 if (pinp->modVarp()) {
444 bool supported = false;
445 if (const AstConst* const constp = VN_CAST(pinp->exprp(), Const)) {
446 supported = !constp->isOpaque();
447 }
448 if (!supported) {
449 pinp->v3error(AstNode::prettyNameQ(modp->origName())
450 << " has hier_block metacomment, hierarchical verilation"
451 << " supports only integer/floating point/string parameters");
452 }
453 } else {
454 pinp->v3error(AstNode::prettyNameQ(modp->origName())
455 << " has hier_block metacomment, but 'parameter type' is not supported");
456 }
457 }
moduleExists(const string & modName) const458 bool moduleExists(const string& modName) const {
459 if (m_allModuleNames.find(modName) != m_allModuleNames.end()) return true;
460 if (m_modNameMap.find(modName) != m_modNameMap.end()) return true;
461 return false;
462 }
463
parameterizedHierBlockName(AstNodeModule * modp,AstPin * paramPinsp)464 string parameterizedHierBlockName(AstNodeModule* modp, AstPin* paramPinsp) {
465 // Create a unique name in the following steps
466 // - Make a long name that includes all parameters, that appear
467 // in the alphabetical order.
468 // - Hash the long name to get valid Verilog symbol
469 UASSERT_OBJ(modp->hierBlock(), modp, "should be used for hierarchical block");
470
471 std::map<string, AstConst*> pins;
472 for (AstPin* pinp = paramPinsp; pinp; pinp = VN_AS(pinp->nextp(), Pin)) {
473 checkSupportedParam(modp, pinp);
474 if (const AstVar* const varp = pinp->modVarp()) {
475 if (!pinp->exprp()) continue;
476 if (varp->isGParam()) {
477 AstConst* const constp = VN_CAST(pinp->exprp(), Const);
478 pins.emplace(varp->name(), constp);
479 }
480 }
481 }
482
483 auto paramsIt = m_defaultParameterValues.find(modp);
484 if (paramsIt == m_defaultParameterValues.end()) { // Not cached yet, so check parameters
485 // Using map with key=string so that we can scan it in deterministic order
486 DefaultValueMap params;
487 for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
488 if (const AstVar* const varp = VN_CAST(stmtp, Var)) {
489 if (varp->isGParam()) {
490 AstConst* const constp = VN_CAST(varp->valuep(), Const);
491 // constp can be nullptr if the parameter is not used to instantiate sub
492 // module. varp->valuep() is not contified yet in the case.
493 // nullptr means that the parameter is using some default value.
494 params.emplace(varp->name(), constp);
495 }
496 }
497 }
498 paramsIt = m_defaultParameterValues.emplace(modp, std::move(params)).first;
499 }
500 if (paramsIt->second.empty()) return modp->name(); // modp has no parameter
501
502 string longname = modp->name();
503 for (auto&& defaultValue : paramsIt->second) {
504 const auto pinIt = pins.find(defaultValue.first);
505 const AstConst* const constp
506 = pinIt == pins.end() ? defaultValue.second : pinIt->second;
507 // This longname is not valid as verilog symbol, but ok, because it will be hashed
508 longname += "_" + defaultValue.first + "=";
509 // constp can be nullptr
510 if (constp) longname += constp->num().ascii(false);
511 }
512
513 const auto iter = m_longMap.find(longname);
514 if (iter != m_longMap.end()) return iter->second; // Already calculated
515
516 VHashSha256 hash;
517 // Calculate hash using longname
518 // The hash is used as the module suffix to find a module name that is unique in the design
519 hash.insert(longname);
520 while (true) {
521 // Copy VHashSha256 just in case of hash collision
522 VHashSha256 hashStrGen = hash;
523 // Hex string must be a safe suffix for any symbol
524 const string hashStr = hashStrGen.digestHex();
525 for (string::size_type i = 1; i < hashStr.size(); ++i) {
526 string newName = modp->name();
527 // Don't use '__' not to be encoded when this module is loaded later by Verilator
528 if (newName.at(newName.size() - 1) != '_') newName += '_';
529 newName += hashStr.substr(0, i);
530 if (!moduleExists(newName)) {
531 m_longMap.emplace(longname, newName);
532 return newName;
533 }
534 }
535 // Hash collision. maybe just v3error is practically enough
536 hash.insert(V3Os::trueRandom(64));
537 }
538 }
deepCloneModule(AstNodeModule * srcModp,AstNode * cellp,AstPin * paramsp,const string & newname,const IfaceRefRefs & ifaceRefRefs)539 void deepCloneModule(AstNodeModule* srcModp, AstNode* cellp, AstPin* paramsp,
540 const string& newname, const IfaceRefRefs& ifaceRefRefs) {
541 // Deep clone of new module
542 // Note all module internal variables will be re-linked to the new modules by clone
543 // However links outside the module (like on the upper cells) will not.
544 AstNodeModule* const newmodp = srcModp->cloneTree(false);
545 newmodp->name(newname);
546 newmodp->user5(false); // We need to re-recurse this module once changed
547 newmodp->recursive(false);
548 newmodp->recursiveClone(false);
549 // Only the first generation of clone holds this property
550 newmodp->hierBlock(srcModp->hierBlock() && !srcModp->recursiveClone());
551 // Recursion may need level cleanups
552 if (newmodp->level() <= m_modp->level()) newmodp->level(m_modp->level() + 1);
553 if ((newmodp->level() - srcModp->level()) >= (v3Global.opt.moduleRecursionDepth() - 2)) {
554 cellp->v3error("Exceeded maximum --module-recursion-depth of "
555 << v3Global.opt.moduleRecursionDepth());
556 }
557 // Keep tree sorted by level
558 AstNodeModule* insertp = srcModp;
559 while (VN_IS(insertp->nextp(), NodeModule)
560 && VN_AS(insertp->nextp(), NodeModule)->level() < newmodp->level()) {
561 insertp = VN_AS(insertp->nextp(), NodeModule);
562 }
563 insertp->addNextHere(newmodp);
564
565 m_modNameMap.emplace(newmodp->name(), ModInfo(newmodp));
566 const auto iter = m_modNameMap.find(newname);
567 CloneMap* const clonemapp = &(iter->second.m_cloneMap);
568 UINFO(4, " De-parameterize to new: " << newmodp << endl);
569
570 // Grab all I/O so we can remap our pins later
571 // Note we allow multiple users of a parameterized model,
572 // thus we need to stash this info.
573 collectPins(clonemapp, newmodp);
574 // Relink parameter vars to the new module
575 relinkPins(clonemapp, paramsp);
576 // Fix any interface references
577 for (auto it = ifaceRefRefs.cbegin(); it != ifaceRefRefs.cend(); ++it) {
578 const AstIfaceRefDType* const portIrefp = it->first;
579 const AstIfaceRefDType* const pinIrefp = it->second;
580 AstIfaceRefDType* const cloneIrefp = portIrefp->clonep();
581 UINFO(8, " IfaceOld " << portIrefp << endl);
582 UINFO(8, " IfaceTo " << pinIrefp << endl);
583 UASSERT_OBJ(cloneIrefp, portIrefp, "parameter clone didn't hit AstIfaceRefDType");
584 UINFO(8, " IfaceClo " << cloneIrefp << endl);
585 cloneIrefp->ifacep(pinIrefp->ifaceViaCellp());
586 UINFO(8, " IfaceNew " << cloneIrefp << endl);
587 }
588 // Assign parameters to the constants specified
589 // DOES clone() so must be finished with module clonep() before here
590 for (AstPin* pinp = paramsp; pinp; pinp = VN_AS(pinp->nextp(), Pin)) {
591 if (pinp->exprp()) {
592 if (AstVar* const modvarp = pinp->modVarp()) {
593 AstNode* const newp = pinp->exprp(); // Const or InitArray
594 AstConst* const exprp = VN_CAST(newp, Const);
595 AstConst* const origp = VN_CAST(modvarp->valuep(), Const);
596 const bool overridden
597 = !(origp && ParameterizedHierBlocks::areSame(exprp, origp));
598 // Remove any existing parameter
599 if (modvarp->valuep()) modvarp->valuep()->unlinkFrBack()->deleteTree();
600 // Set this parameter to value requested by cell
601 UINFO(9, " set param " << modvarp << " = " << newp << endl);
602 modvarp->valuep(newp->cloneTree(false));
603 modvarp->overriddenParam(overridden);
604 } else if (AstParamTypeDType* const modptp = pinp->modPTypep()) {
605 AstNodeDType* const dtypep = VN_AS(pinp->exprp(), NodeDType);
606 UASSERT_OBJ(dtypep, pinp, "unlinked param dtype");
607 if (modptp->childDTypep()) modptp->childDTypep()->unlinkFrBack()->deleteTree();
608 // Set this parameter to value requested by cell
609 modptp->childDTypep(dtypep->cloneTree(false));
610 // Later V3LinkDot will convert the ParamDType to a Typedef
611 // Not done here as may be localparams, etc, that also need conversion
612 }
613 }
614 }
615 }
moduleFindOrClone(AstNodeModule * srcModp,AstNode * cellp,AstPin * paramsp,const string & newname,const IfaceRefRefs & ifaceRefRefs)616 const ModInfo* moduleFindOrClone(AstNodeModule* srcModp, AstNode* cellp, AstPin* paramsp,
617 const string& newname, const IfaceRefRefs& ifaceRefRefs) {
618 // Already made this flavor?
619 auto it = m_modNameMap.find(newname);
620 if (it != m_modNameMap.end()) {
621 UINFO(4, " De-parameterize to old: " << it->second.m_modp << endl);
622 } else {
623 deepCloneModule(srcModp, cellp, paramsp, newname, ifaceRefRefs);
624 it = m_modNameMap.find(newname);
625 UASSERT(it != m_modNameMap.end(), "should find just-made module");
626 }
627 const ModInfo* const modInfop = &(it->second);
628 return modInfop;
629 }
630
cellPinCleanup(AstNode * nodep,AstPin * pinp,AstNodeModule * srcModp,string & longnamer,bool & any_overridesr)631 void cellPinCleanup(AstNode* nodep, AstPin* pinp, AstNodeModule* srcModp, string& longnamer,
632 bool& any_overridesr) {
633 if (!pinp->exprp()) return; // No-connect
634 if (AstVar* const modvarp = pinp->modVarp()) {
635 if (!modvarp->isGParam()) {
636 pinp->v3error("Attempted parameter setting of non-parameter: Param "
637 << pinp->prettyNameQ() << " of " << nodep->prettyNameQ());
638 } else if (VN_IS(pinp->exprp(), InitArray) && arraySubDTypep(modvarp->subDTypep())) {
639 // Array assigned to array
640 AstNode* const exprp = pinp->exprp();
641 longnamer += "_" + paramSmallName(srcModp, modvarp) + paramValueNumber(exprp);
642 any_overridesr = true;
643 } else {
644 AstConst* const exprp = VN_CAST(pinp->exprp(), Const);
645 const AstConst* const origp = VN_CAST(modvarp->valuep(), Const);
646 if (!exprp) {
647 // if (debug()) pinp->dumpTree(cout, "error:");
648 pinp->v3error("Can't convert defparam value to constant: Param "
649 << pinp->prettyNameQ() << " of " << nodep->prettyNameQ());
650 pinp->exprp()->replaceWith(new AstConst(
651 pinp->fileline(), AstConst::WidthedValue(), modvarp->width(), 0));
652 } else if (origp && exprp->sameTree(origp)) {
653 // Setting parameter to its default value. Just ignore it.
654 // This prevents making additional modules, and makes coverage more
655 // obvious as it won't show up under a unique module page name.
656 } else if (exprp->num().isDouble() || exprp->num().isString()
657 || exprp->num().isFourState() || exprp->num().width() != 32) {
658 longnamer
659 += ("_" + paramSmallName(srcModp, modvarp) + paramValueNumber(exprp));
660 any_overridesr = true;
661 } else {
662 longnamer
663 += ("_" + paramSmallName(srcModp, modvarp) + exprp->num().ascii(false));
664 any_overridesr = true;
665 }
666 }
667 } else if (AstParamTypeDType* const modvarp = pinp->modPTypep()) {
668 AstNodeDType* const exprp = VN_CAST(pinp->exprp(), NodeDType);
669 const AstNodeDType* const origp = modvarp->subDTypep();
670 if (!exprp) {
671 pinp->v3error("Parameter type pin value isn't a type: Param "
672 << pinp->prettyNameQ() << " of " << nodep->prettyNameQ());
673 } else if (!origp) {
674 pinp->v3error("Parameter type variable isn't a type: Param "
675 << modvarp->prettyNameQ());
676 } else {
677 UINFO(9, "Parameter type assignment expr=" << exprp << " to " << origp << endl);
678 if (exprp->sameTree(origp)) {
679 // Setting parameter to its default value. Just ignore it.
680 // This prevents making additional modules, and makes coverage more
681 // obvious as it won't show up under a unique module page name.
682 } else {
683 V3Const::constifyParamsEdit(exprp);
684 longnamer += "_" + paramSmallName(srcModp, modvarp) + paramValueNumber(exprp);
685 any_overridesr = true;
686 }
687 }
688 } else {
689 pinp->v3error("Parameter not found in sub-module: Param "
690 << pinp->prettyNameQ() << " of " << nodep->prettyNameQ());
691 }
692 }
693
cellInterfaceCleanup(AstCell * nodep,AstNodeModule * srcModp,string & longnamer,bool & any_overridesr,IfaceRefRefs & ifaceRefRefs)694 void cellInterfaceCleanup(AstCell* nodep, AstNodeModule* srcModp, string& longnamer,
695 bool& any_overridesr, IfaceRefRefs& ifaceRefRefs) {
696 for (AstPin* pinp = nodep->pinsp(); pinp; pinp = VN_AS(pinp->nextp(), Pin)) {
697 const AstVar* const modvarp = pinp->modVarp();
698 if (modvarp->isIfaceRef()) {
699 AstIfaceRefDType* portIrefp = VN_CAST(modvarp->subDTypep(), IfaceRefDType);
700 if (!portIrefp && arraySubDTypep(modvarp->subDTypep())) {
701 portIrefp = VN_CAST(arraySubDTypep(modvarp->subDTypep()), IfaceRefDType);
702 }
703 AstIfaceRefDType* pinIrefp = nullptr;
704 const AstNode* const exprp = pinp->exprp();
705 const AstVar* const varp
706 = (exprp && VN_IS(exprp, VarRef)) ? VN_AS(exprp, VarRef)->varp() : nullptr;
707 if (varp && varp->subDTypep() && VN_IS(varp->subDTypep(), IfaceRefDType)) {
708 pinIrefp = VN_AS(varp->subDTypep(), IfaceRefDType);
709 } else if (varp && varp->subDTypep() && arraySubDTypep(varp->subDTypep())
710 && VN_CAST(arraySubDTypep(varp->subDTypep()), IfaceRefDType)) {
711 pinIrefp = VN_CAST(arraySubDTypep(varp->subDTypep()), IfaceRefDType);
712 } else if (exprp && exprp->op1p() && VN_IS(exprp->op1p(), VarRef)
713 && VN_CAST(exprp->op1p(), VarRef)->varp()
714 && VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep()
715 && arraySubDTypep(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep())
716 && VN_CAST(
717 arraySubDTypep(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep()),
718 IfaceRefDType)) {
719 pinIrefp
720 = VN_AS(arraySubDTypep(VN_AS(exprp->op1p(), VarRef)->varp()->subDTypep()),
721 IfaceRefDType);
722 }
723
724 UINFO(9, " portIfaceRef " << portIrefp << endl);
725
726 if (!portIrefp) {
727 pinp->v3error("Interface port " << modvarp->prettyNameQ()
728 << " is not an interface " << modvarp);
729 } else if (!pinIrefp) {
730 pinp->v3error("Interface port "
731 << modvarp->prettyNameQ()
732 << " is not connected to interface/modport pin expression");
733 } else {
734 UINFO(9, " pinIfaceRef " << pinIrefp << endl);
735 if (portIrefp->ifaceViaCellp() != pinIrefp->ifaceViaCellp()) {
736 UINFO(9, " IfaceRefDType needs reconnect " << pinIrefp << endl);
737 longnamer += ("_" + paramSmallName(srcModp, pinp->modVarp())
738 + paramValueNumber(pinIrefp));
739 any_overridesr = true;
740 ifaceRefRefs.push_back(std::make_pair(portIrefp, pinIrefp));
741 if (portIrefp->ifacep() != pinIrefp->ifacep()
742 // Might be different only due to param cloning, so check names too
743 && portIrefp->ifaceName() != pinIrefp->ifaceName()) {
744 pinp->v3error("Port " << pinp->prettyNameQ() << " expects "
745 << AstNode::prettyNameQ(portIrefp->ifaceName())
746 << " interface but pin connects "
747 << AstNode::prettyNameQ(pinIrefp->ifaceName())
748 << " interface");
749 }
750 }
751 }
752 }
753 }
754 }
755
756 public:
cellDeparam(AstCell * nodep,AstNodeModule * modp,const string & hierName)757 void cellDeparam(AstCell* nodep, AstNodeModule* modp, const string& hierName) {
758 m_modp = modp;
759 // Cell: Check for parameters in the instantiation.
760 // We always run this, even if no parameters, as need to look for interfaces,
761 // and remove any recursive references
762 UINFO(4, "De-parameterize: " << nodep << endl);
763 // Create new module name with _'s between the constants
764 if (debug() >= 10) nodep->dumpTree(cout, "-cell: ");
765 // Evaluate all module constants
766 V3Const::constifyParamsEdit(nodep);
767 AstNodeModule* const srcModp = nodep->modp();
768 srcModp->hierName(hierName + "." + nodep->name());
769
770 // Make sure constification worked
771 // Must be a separate loop, as constant conversion may have changed some pointers.
772 // if (debug()) nodep->dumpTree(cout, "-cel2: ");
773 string longname = srcModp->name() + "_";
774 bool any_overrides = false;
775 // Must always clone __Vrcm (recursive modules)
776 if (nodep->recursive()) any_overrides = true;
777 if (debug() > 8) nodep->paramsp()->dumpTreeAndNext(cout, "-cellparams: ");
778
779 if (srcModp->hierBlock()) {
780 longname = parameterizedHierBlockName(srcModp, nodep->paramsp());
781 any_overrides = longname != srcModp->name();
782 } else {
783 for (AstPin* pinp = nodep->paramsp(); pinp; pinp = VN_AS(pinp->nextp(), Pin)) {
784 cellPinCleanup(nodep, pinp, srcModp, longname /*ref*/, any_overrides /*ref*/);
785 }
786 }
787 IfaceRefRefs ifaceRefRefs;
788 cellInterfaceCleanup(nodep, srcModp, longname /*ref*/, any_overrides /*ref*/,
789 ifaceRefRefs /*ref*/);
790
791 if (!any_overrides) {
792 UINFO(8, "Cell parameters all match original values, skipping expansion.\n");
793 } else if (AstNodeModule* const paramedModp
794 = m_hierBlocks.findByParams(srcModp->name(), nodep->paramsp(), m_modp)) {
795 nodep->modp(paramedModp);
796 nodep->modName(paramedModp->name());
797 paramedModp->dead(false);
798 // We need to relink the pins to the new module
799 relinkPinsByName(nodep->pinsp(), paramedModp);
800 } else {
801 const string newname
802 = srcModp->hierBlock() ? longname : moduleCalcName(srcModp, longname);
803 const ModInfo* const modInfop
804 = moduleFindOrClone(srcModp, nodep, nodep->paramsp(), newname, ifaceRefRefs);
805 // Have child use this module instead.
806 nodep->modp(modInfop->m_modp);
807 nodep->modName(newname);
808 // We need to relink the pins to the new module
809 relinkPinsByName(nodep->pinsp(), modInfop->m_modp);
810 UINFO(8, " Done with " << modInfop->m_modp << endl);
811 }
812
813 nodep->recursive(false);
814
815 // Delete the parameters from the cell; they're not relevant any longer.
816 if (nodep->paramsp()) nodep->paramsp()->unlinkFrBackWithNext()->deleteTree();
817 UINFO(8, " Done with " << nodep << endl);
818 // if (debug() >= 10)
819 // v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("param-out.tree"));
820 }
821
822 // CONSTRUCTORS
ParamProcessor(AstNetlist * nodep)823 explicit ParamProcessor(AstNetlist* nodep)
824 : m_hierBlocks{v3Global.opt.hierBlocks(), nodep} {
825 for (AstNodeModule* modp = nodep->modulesp(); modp;
826 modp = VN_AS(modp->nextp(), NodeModule)) {
827 m_allModuleNames.insert(modp->name());
828 }
829 }
830 ~ParamProcessor() = default;
831 VL_UNCOPYABLE(ParamProcessor);
832 };
833
834 //######################################################################
835 // Process parameter visitor
836
837 class ParamVisitor final : public AstNVisitor {
838 // STATE
839 ParamProcessor m_processor; // De-parameterize a cell, build modules
840 UnrollStateful m_unroller; // Loop unroller
841
842 AstNodeModule* m_modp = nullptr; // Current module being processed
843 string m_generateHierName; // Generate portion of hierarchy name
844 string m_unlinkedTxt; // Text for AstUnlinkedRef
845 std::deque<AstCell*> m_cellps; // Cells left to process (in this module)
846
847 std::multimap<int, AstNodeModule*> m_todoModps; // Modules left to process
848
849 // METHODS
850 VL_DEBUG_FUNC; // Declare debug()
851
visitCellDeparam(AstCell * nodep,const string & hierName)852 void visitCellDeparam(AstCell* nodep, const string& hierName) {
853 // Cell: Check for parameters in the instantiation.
854 iterateChildren(nodep);
855 UASSERT_OBJ(nodep->modp(), nodep, "Not linked?");
856 m_processor.cellDeparam(nodep, m_modp, hierName);
857 // Remember to process the child module at the end of the module
858 m_todoModps.emplace(nodep->modp()->level(), nodep->modp());
859 }
visitModules()860 void visitModules() {
861 // Loop on all modules left to process
862 // Hitting a cell adds to the appropriate level of this level-sorted list,
863 // so since cells originally exist top->bottom we process in top->bottom order too.
864 while (!m_todoModps.empty()) {
865 const auto itm = m_todoModps.cbegin();
866 AstNodeModule* const nodep = itm->second;
867 m_todoModps.erase(itm);
868 if (!nodep->user5SetOnce()) { // Process once; note clone() must clear so we do it
869 // again
870 m_modp = nodep;
871 UINFO(4, " MOD " << nodep << endl);
872 if (m_modp->hierName().empty()) m_modp->hierName(m_modp->origName());
873 iterateChildren(nodep);
874 // Note above iterate may add to m_todoModps
875 //
876 // Process interface cells, then non-interface which may ref an interface cell
877 for (int nonIf = 0; nonIf < 2; ++nonIf) {
878 for (AstCell* const cellp : m_cellps) {
879 if ((nonIf == 0 && VN_IS(cellp->modp(), Iface))
880 || (nonIf == 1 && !VN_IS(cellp->modp(), Iface))) {
881 string fullName(m_modp->hierName());
882 if (const string* const genHierNamep = (string*)cellp->user5p()) {
883 fullName += *genHierNamep;
884 cellp->user5p(nullptr);
885 VL_DO_DANGLING(delete genHierNamep, genHierNamep);
886 }
887 VL_DO_DANGLING(visitCellDeparam(cellp, fullName), cellp);
888 }
889 }
890 }
891 m_cellps.clear();
892 m_modp = nullptr;
893 UINFO(4, " MOD-done\n");
894 }
895 }
896 }
897
898 // VISITORS
visit(AstNodeModule * nodep)899 virtual void visit(AstNodeModule* nodep) override {
900 if (nodep->dead()) {
901 UINFO(4, " MOD-dead. " << nodep << endl); // Marked by LinkDot
902 return;
903 } else if (nodep->recursiveClone()) {
904 // Fake, made for recursive elimination
905 UINFO(4, " MOD-recursive-dead. " << nodep << endl);
906 nodep->dead(true); // So Dead checks won't count references to it
907 return;
908 }
909 //
910 if (!nodep->dead() && VN_IS(nodep, Class)) {
911 for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
912 if (const AstVar* const varp = VN_CAST(stmtp, Var)) {
913 if (varp->isParam()) {
914 varp->v3warn(E_UNSUPPORTED, "Unsupported: class parameters");
915 }
916 }
917 }
918 }
919 //
920 if (m_modp) {
921 UINFO(4, " MOD-under-MOD. " << nodep << endl);
922 iterateChildren(nodep);
923 } else if (nodep->level() <= 2 // Haven't added top yet, so level 2 is the top
924 || VN_IS(nodep, Class) // Nor moved classes
925 || VN_IS(nodep, Package)) { // Likewise haven't done wrapTopPackages yet
926 // Add request to END of modules left to process
927 m_todoModps.emplace(nodep->level(), nodep);
928 m_generateHierName = "";
929 visitModules();
930 } else if (nodep->user5()) {
931 UINFO(4, " MOD-done " << nodep << endl); // Already did it
932 } else {
933 // Should have been done by now, if not dead
934 UINFO(4, " MOD-dead? " << nodep << endl);
935 }
936 }
visit(AstCell * nodep)937 virtual void visit(AstCell* nodep) override {
938 // Must do ifaces first, so push to list and do in proper order
939 string* const genHierNamep = new string(m_generateHierName);
940 nodep->user5p(genHierNamep);
941 m_cellps.push_back(nodep);
942 }
943
visit(AstClassRefDType * nodep)944 virtual void visit(AstClassRefDType* nodep) override {
945 if (nodep->paramsp()) {
946 nodep->paramsp()->v3warn(E_UNSUPPORTED, "Unsupported: parameterized classes");
947 pushDeletep(nodep->paramsp()->unlinkFrBackWithNext());
948 }
949 iterateChildren(nodep);
950 }
951
952 // Make sure all parameters are constantified
visit(AstVar * nodep)953 virtual void visit(AstVar* nodep) override {
954 if (nodep->user5SetOnce()) return; // Process once
955 iterateChildren(nodep);
956 if (nodep->isParam()) {
957 if (!nodep->valuep()) {
958 nodep->v3error("Parameter without initial value is never given value"
959 << " (IEEE 1800-2017 6.20.1): " << nodep->prettyNameQ());
960 } else {
961 V3Const::constifyParamsEdit(nodep); // The variable, not just the var->init()
962 }
963 }
964 }
965 // Make sure varrefs cause vars to constify before things above
visit(AstVarRef * nodep)966 virtual void visit(AstVarRef* nodep) override {
967 // Might jump across functions, so beware if ever add a m_funcp
968 if (nodep->varp()) iterate(nodep->varp());
969 }
ifaceParamReplace(AstVarXRef * nodep,AstNode * candp)970 bool ifaceParamReplace(AstVarXRef* nodep, AstNode* candp) {
971 for (; candp; candp = candp->nextp()) {
972 if (nodep->name() == candp->name()) {
973 if (AstVar* const varp = VN_CAST(candp, Var)) {
974 UINFO(9, "Found interface parameter: " << varp << endl);
975 nodep->varp(varp);
976 return true;
977 } else if (const AstPin* const pinp = VN_CAST(candp, Pin)) {
978 UINFO(9, "Found interface parameter: " << pinp << endl);
979 UASSERT_OBJ(pinp->exprp(), pinp, "Interface parameter pin missing expression");
980 VL_DO_DANGLING(nodep->replaceWith(pinp->exprp()->cloneTree(false)), nodep);
981 return true;
982 }
983 }
984 }
985 return false;
986 }
visit(AstVarXRef * nodep)987 virtual void visit(AstVarXRef* nodep) override {
988 // Check to see if the scope is just an interface because interfaces are special
989 const string dotted = nodep->dotted();
990 if (!dotted.empty() && nodep->varp() && nodep->varp()->isParam()) {
991 const AstNode* backp = nodep;
992 while ((backp = backp->backp())) {
993 if (VN_IS(backp, NodeModule)) {
994 UINFO(9, "Hit module boundary, done looking for interface" << endl);
995 break;
996 }
997 if (VN_IS(backp, Var) && VN_AS(backp, Var)->isIfaceRef()
998 && VN_AS(backp, Var)->childDTypep()
999 && (VN_CAST(VN_CAST(backp, Var)->childDTypep(), IfaceRefDType)
1000 || (VN_CAST(VN_CAST(backp, Var)->childDTypep(), UnpackArrayDType)
1001 && VN_CAST(VN_CAST(backp, Var)->childDTypep()->getChildDTypep(),
1002 IfaceRefDType)))) {
1003 const AstIfaceRefDType* ifacerefp
1004 = VN_CAST(VN_CAST(backp, Var)->childDTypep(), IfaceRefDType);
1005 if (!ifacerefp) {
1006 ifacerefp = VN_CAST(VN_CAST(backp, Var)->childDTypep()->getChildDTypep(),
1007 IfaceRefDType);
1008 }
1009 // Interfaces passed in on the port map have ifaces
1010 if (const AstIface* const ifacep = ifacerefp->ifacep()) {
1011 if (dotted == backp->name()) {
1012 UINFO(9, "Iface matching scope: " << ifacep << endl);
1013 if (ifaceParamReplace(nodep, ifacep->stmtsp())) { //
1014 return;
1015 }
1016 }
1017 }
1018 // Interfaces declared in this module have cells
1019 else if (const AstCell* const cellp = ifacerefp->cellp()) {
1020 if (dotted == cellp->name()) {
1021 UINFO(9, "Iface matching scope: " << cellp << endl);
1022 if (ifaceParamReplace(nodep, cellp->paramsp())) { //
1023 return;
1024 }
1025 }
1026 }
1027 }
1028 }
1029 }
1030 nodep->varp(nullptr); // Needs relink, as may remove pointed-to var
1031 }
1032
visit(AstUnlinkedRef * nodep)1033 virtual void visit(AstUnlinkedRef* nodep) override {
1034 AstVarXRef* const varxrefp = VN_CAST(nodep->op1p(), VarXRef);
1035 AstNodeFTaskRef* const taskrefp = VN_CAST(nodep->op1p(), NodeFTaskRef);
1036 if (varxrefp) {
1037 m_unlinkedTxt = varxrefp->dotted();
1038 } else if (taskrefp) {
1039 m_unlinkedTxt = taskrefp->dotted();
1040 } else {
1041 nodep->v3fatalSrc("Unexpected AstUnlinkedRef node");
1042 return;
1043 }
1044 iterate(nodep->cellrefp());
1045
1046 if (varxrefp) {
1047 varxrefp->dotted(m_unlinkedTxt);
1048 } else {
1049 taskrefp->dotted(m_unlinkedTxt);
1050 }
1051 nodep->replaceWith(nodep->op1p()->unlinkFrBack());
1052 VL_DO_DANGLING(pushDeletep(nodep), nodep);
1053 }
visit(AstCellArrayRef * nodep)1054 virtual void visit(AstCellArrayRef* nodep) override {
1055 V3Const::constifyParamsEdit(nodep->selp());
1056 if (const AstConst* const constp = VN_CAST(nodep->selp(), Const)) {
1057 const string index = AstNode::encodeNumber(constp->toSInt());
1058 const string replacestr = nodep->name() + "__BRA__??__KET__";
1059 const size_t pos = m_unlinkedTxt.find(replacestr);
1060 UASSERT_OBJ(pos != string::npos, nodep,
1061 "Could not find array index in unlinked text: '"
1062 << m_unlinkedTxt << "' for node: " << nodep);
1063 m_unlinkedTxt.replace(pos, replacestr.length(),
1064 nodep->name() + "__BRA__" + index + "__KET__");
1065 } else {
1066 nodep->v3error("Could not expand constant selection inside dotted reference: "
1067 << nodep->selp()->prettyNameQ());
1068 return;
1069 }
1070 }
1071
1072 // Generate Statements
visit(AstGenIf * nodep)1073 virtual void visit(AstGenIf* nodep) override {
1074 UINFO(9, " GENIF " << nodep << endl);
1075 iterateAndNextNull(nodep->condp());
1076 // We suppress errors when widthing params since short-circuiting in
1077 // the conditional evaluation may mean these error can never occur. We
1078 // then make sure that short-circuiting is used by constifyParamsEdit.
1079 V3Width::widthGenerateParamsEdit(nodep); // Param typed widthing will
1080 // NOT recurse the body.
1081 V3Const::constifyGenerateParamsEdit(nodep->condp()); // condp may change
1082 if (const AstConst* const constp = VN_CAST(nodep->condp(), Const)) {
1083 if (AstNode* const keepp = (constp->isZero() ? nodep->elsesp() : nodep->ifsp())) {
1084 keepp->unlinkFrBackWithNext();
1085 nodep->replaceWith(keepp);
1086 } else {
1087 nodep->unlinkFrBack();
1088 }
1089 VL_DO_DANGLING(nodep->deleteTree(), nodep);
1090 // Normal edit rules will now recurse the replacement
1091 } else {
1092 nodep->condp()->v3error("Generate If condition must evaluate to constant");
1093 }
1094 }
1095
1096 //! Parameter substitution for generated for loops.
1097 //! @todo Unlike generated IF, we don't have to worry about short-circuiting the conditional
1098 //! expression, since this is currently restricted to simple comparisons. If we ever do
1099 //! move to more generic constant expressions, such code will be needed here.
visit(AstBegin * nodep)1100 virtual void visit(AstBegin* nodep) override {
1101 if (nodep->genforp()) {
1102 AstGenFor* const forp = VN_AS(nodep->genforp(), GenFor);
1103 UASSERT_OBJ(forp, nodep, "Non-GENFOR under generate-for BEGIN");
1104 // We should have a GENFOR under here. We will be replacing the begin,
1105 // so process here rather than at the generate to avoid iteration problems
1106 UINFO(9, " BEGIN " << nodep << endl);
1107 UINFO(9, " GENFOR " << forp << endl);
1108 V3Width::widthParamsEdit(forp); // Param typed widthing will NOT recurse the body
1109 // Outer wrapper around generate used to hold genvar, and to ensure genvar
1110 // doesn't conflict in V3LinkDot resolution with other genvars
1111 // Now though we need to change BEGIN("zzz", GENFOR(...)) to
1112 // a BEGIN("zzz__BRA__{loop#}__KET__")
1113 const string beginName = nodep->name();
1114 // Leave the original Begin, as need a container for the (possible) GENVAR
1115 // Note V3Unroll will replace some AstVarRef's to the loop variable with constants
1116 // Don't remove any deleted nodes in m_unroller until whole process finishes,
1117 // (are held in m_unroller), as some AstXRefs may still point to old nodes.
1118 VL_DO_DANGLING(m_unroller.unrollGen(forp, beginName), forp);
1119 // Blocks were constructed under the special begin, move them up
1120 // Note forp is null, so grab statements again
1121 if (AstNode* const stmtsp = nodep->genforp()) {
1122 stmtsp->unlinkFrBackWithNext();
1123 nodep->addNextHere(stmtsp);
1124 // Note this clears nodep->genforp(), so begin is no longer special
1125 }
1126 } else {
1127 VL_RESTORER(m_generateHierName);
1128 m_generateHierName += "." + nodep->prettyName();
1129 iterateChildren(nodep);
1130 }
1131 }
visit(AstGenFor * nodep)1132 virtual void visit(AstGenFor* nodep) override { // LCOV_EXCL_LINE
1133 nodep->v3fatalSrc("GENFOR should have been wrapped in BEGIN");
1134 }
visit(AstGenCase * nodep)1135 virtual void visit(AstGenCase* nodep) override {
1136 UINFO(9, " GENCASE " << nodep << endl);
1137 AstNode* keepp = nullptr;
1138 iterateAndNextNull(nodep->exprp());
1139 V3Case::caseLint(nodep);
1140 V3Width::widthParamsEdit(nodep); // Param typed widthing will NOT recurse the body,
1141 // don't trigger errors yet.
1142 V3Const::constifyParamsEdit(nodep->exprp()); // exprp may change
1143 const AstConst* const exprp = VN_AS(nodep->exprp(), Const);
1144 // Constify
1145 for (AstCaseItem* itemp = nodep->itemsp(); itemp;
1146 itemp = VN_AS(itemp->nextp(), CaseItem)) {
1147 for (AstNode* ep = itemp->condsp(); ep;) {
1148 AstNode* const nextp = ep->nextp(); // May edit list
1149 iterateAndNextNull(ep);
1150 VL_DO_DANGLING(V3Const::constifyParamsEdit(ep), ep); // ep may change
1151 ep = nextp;
1152 }
1153 }
1154 // Item match
1155 for (AstCaseItem* itemp = nodep->itemsp(); itemp;
1156 itemp = VN_AS(itemp->nextp(), CaseItem)) {
1157 if (!itemp->isDefault()) {
1158 for (AstNode* ep = itemp->condsp(); ep; ep = ep->nextp()) {
1159 if (const AstConst* const ccondp = VN_CAST(ep, Const)) {
1160 V3Number match(nodep, 1);
1161 match.opEq(ccondp->num(), exprp->num());
1162 if (!keepp && match.isNeqZero()) keepp = itemp->bodysp();
1163 } else {
1164 itemp->v3error("Generate Case item does not evaluate to constant");
1165 }
1166 }
1167 }
1168 }
1169 // Else default match
1170 for (AstCaseItem* itemp = nodep->itemsp(); itemp;
1171 itemp = VN_AS(itemp->nextp(), CaseItem)) {
1172 if (itemp->isDefault()) {
1173 if (!keepp) keepp = itemp->bodysp();
1174 }
1175 }
1176 // Replace
1177 if (keepp) {
1178 keepp->unlinkFrBackWithNext();
1179 nodep->replaceWith(keepp);
1180 } else {
1181 nodep->unlinkFrBack();
1182 }
1183 VL_DO_DANGLING(nodep->deleteTree(), nodep);
1184 }
1185
visit(AstNode * nodep)1186 virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
1187
1188 public:
1189 // CONSTRUCTORS
ParamVisitor(AstNetlist * nodep)1190 explicit ParamVisitor(AstNetlist* nodep)
1191 : m_processor{nodep} {
1192 // Relies on modules already being in top-down-order
1193 iterate(nodep);
1194 }
1195 virtual ~ParamVisitor() override = default;
1196 VL_UNCOPYABLE(ParamVisitor);
1197 };
1198
1199 //######################################################################
1200 // Param class functions
1201
param(AstNetlist * rootp)1202 void V3Param::param(AstNetlist* rootp) {
1203 UINFO(2, __FUNCTION__ << ": " << endl);
1204 { ParamVisitor{rootp}; } // Destruct before checking
1205 V3Global::dumpCheckGlobalTree("param", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6);
1206 }
1207