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