1 // -*- mode: C++; c-file-style: "cc-mode" -*-
2 //*************************************************************************
3 // DESCRIPTION: Verilator: Break always into sensitivity block domains
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 // V3Scope's Transformations:
17 //
18 //      For every CELL that references this module, create a
19 //              SCOPE
20 //                      {all blocked statements}
21 //
22 //*************************************************************************
23 
24 #include "config_build.h"
25 #include "verilatedos.h"
26 
27 #include "V3Global.h"
28 #include "V3Scope.h"
29 #include "V3Ast.h"
30 
31 #include <algorithm>
32 #include <map>
33 #include <unordered_map>
34 #include <unordered_set>
35 
36 //######################################################################
37 // Scope class functions
38 
39 class ScopeVisitor final : public AstNVisitor {
40 private:
41     // NODE STATE
42     // AstVar::user1p           -> AstVarScope replacement for this variable
43     // AstTask::user2p          -> AstTask*.  Replacement task
44     const AstUser1InUse m_inuser1;
45     const AstUser2InUse m_inuser2;
46 
47     // TYPES
48     // These cannot be unordered unless make a specialized hashing pair (gcc-8)
49     using VarScopeMap = std::map<std::pair<AstVar*, AstScope*>, AstVarScope*>;
50 
51     // STATE, inside processing a single module
52     AstNodeModule* m_modp = nullptr;  // Current module
53     AstScope* m_scopep = nullptr;  // Current scope we are building
54     // STATE, for passing down one level of hierarchy (may need save/restore)
55     AstCell* m_aboveCellp = nullptr;  // Cell that instantiates this module
56     AstScope* m_aboveScopep = nullptr;  // Scope that instantiates this scope
57 
58     std::unordered_map<AstNodeModule*, AstScope*> m_packageScopes;  // Scopes for each package
59     VarScopeMap m_varScopes;  // Varscopes created for each scope and var
60     std::set<std::pair<AstVarRef*, AstScope*>>
61         m_varRefScopes;  // Varrefs-in-scopes needing fixup when done
62 
63     // METHODS
64     VL_DEBUG_FUNC;  // Declare debug()
65 
cleanupVarRefs()66     void cleanupVarRefs() {
67         for (const auto& itr : m_varRefScopes) {
68             AstVarRef* const nodep = itr.first;
69             AstScope* scopep = itr.second;
70             if (nodep->classOrPackagep()) {
71                 const auto it2 = m_packageScopes.find(nodep->classOrPackagep());
72                 UASSERT_OBJ(it2 != m_packageScopes.end(), nodep, "Can't locate package scope");
73                 scopep = it2->second;
74             }
75             const auto it3 = m_varScopes.find(std::make_pair(nodep->varp(), scopep));
76             UASSERT_OBJ(it3 != m_varScopes.end(), nodep, "Can't locate varref scope");
77             AstVarScope* const varscp = it3->second;
78             nodep->varScopep(varscp);
79         }
80     }
81 
82     // VISITORS
visit(AstNetlist * nodep)83     virtual void visit(AstNetlist* nodep) override {
84         AstNodeModule* const modp = nodep->topModulep();
85         if (!modp) {
86             nodep->v3error("No top level module found");
87             return;
88         }
89         // Operate starting at the top of the hierarchy
90         m_aboveCellp = nullptr;
91         m_aboveScopep = nullptr;
92         iterate(modp);
93         cleanupVarRefs();
94     }
visit(AstNodeModule * nodep)95     virtual void visit(AstNodeModule* nodep) override {
96         // Create required blocks and add to module
97         string scopename;
98         if (!m_aboveScopep) {
99             scopename = "TOP";
100         } else {
101             scopename = m_aboveScopep->name() + "." + m_aboveCellp->name();
102         }
103 
104         UINFO(4, " MOD AT " << scopename << "  " << nodep << endl);
105         AstNode::user1ClearTree();
106 
107         m_scopep = new AstScope(
108             (m_aboveCellp ? static_cast<AstNode*>(m_aboveCellp) : static_cast<AstNode*>(nodep))
109                 ->fileline(),
110             nodep, scopename, m_aboveScopep, m_aboveCellp);
111         if (VN_IS(nodep, Package)) m_packageScopes.emplace(nodep, m_scopep);
112 
113         // Now for each child cell, iterate the module this cell points to
114         for (AstNode* cellnextp = nodep->stmtsp(); cellnextp; cellnextp = cellnextp->nextp()) {
115             if (AstCell* const cellp = VN_CAST(cellnextp, Cell)) {
116                 VL_RESTORER(m_scopep);  // Protects m_scopep set in called module
117                 // which is "above" in this code, but later in code execution order
118                 VL_RESTORER(m_aboveCellp);
119                 VL_RESTORER(m_aboveScopep);
120                 {
121                     m_aboveCellp = cellp;
122                     m_aboveScopep = m_scopep;
123                     AstNodeModule* const modp = cellp->modp();
124                     UASSERT_OBJ(modp, cellp, "Unlinked mod");
125                     iterate(modp);  // Recursive call to visit(AstNodeModule)
126                 }
127             }
128         }
129 
130         // Create scope for the current usage of this module
131         UINFO(4, " back AT " << scopename << "  " << nodep << endl);
132         AstNode::user1ClearTree();
133         m_modp = nodep;
134         if (m_modp->isTop()) {
135             v3Global.rootp()->createTopScope(m_scopep);
136         } else {
137             m_modp->addStmtp(m_scopep);
138         }
139 
140         // Copy blocks into this scope
141         // If this is the first usage of the block ever, we can simply move the reference
142         iterateChildren(nodep);
143 
144         // ***Note m_scopep is passed back to the caller of the routine (above)
145     }
visit(AstClass * nodep)146     virtual void visit(AstClass* nodep) override {
147         // Create required blocks and add to module
148         VL_RESTORER(m_scopep);
149         VL_RESTORER(m_aboveCellp);
150         VL_RESTORER(m_aboveScopep);
151         VL_RESTORER(m_modp);
152         {
153             m_aboveScopep = m_scopep;
154             m_modp = nodep;
155 
156             string scopename;
157             if (!m_aboveScopep) {
158                 scopename = "TOP";
159             } else {
160                 scopename = m_aboveScopep->name() + "." + nodep->name();
161             }
162 
163             UINFO(4, " CLASS AT " << scopename << "  " << nodep << endl);
164             AstNode::user1ClearTree();
165 
166             const AstNode* const abovep = (m_aboveCellp ? static_cast<AstNode*>(m_aboveCellp)
167                                                         : static_cast<AstNode*>(nodep));
168             m_scopep
169                 = new AstScope(abovep->fileline(), m_modp, scopename, m_aboveScopep, m_aboveCellp);
170             m_packageScopes.emplace(nodep, m_scopep);
171 
172             // Create scope for the current usage of this cell
173             AstNode::user1ClearTree();
174             nodep->addMembersp(m_scopep);
175 
176             iterateChildren(nodep);
177         }
178     }
visit(AstCellInline * nodep)179     virtual void visit(AstCellInline* nodep) override {  //
180         nodep->scopep(m_scopep);
181     }
visit(AstActive * nodep)182     virtual void visit(AstActive* nodep) override {  // LCOV_EXCL_LINE
183         nodep->v3fatalSrc("Actives now made after scoping");
184     }
visit(AstNodeProcedure * nodep)185     virtual void visit(AstNodeProcedure* nodep) override {
186         // Add to list of blocks under this scope
187         UINFO(4, "    Move " << nodep << endl);
188         AstNode* const clonep = nodep->cloneTree(false);
189         nodep->user2p(clonep);
190         m_scopep->addActivep(clonep);
191         iterateChildren(clonep);  // We iterate under the *clone*
192     }
visit(AstAssignAlias * nodep)193     virtual void visit(AstAssignAlias* nodep) override {
194         // Add to list of blocks under this scope
195         UINFO(4, "    Move " << nodep << endl);
196         AstNode* const clonep = nodep->cloneTree(false);
197         nodep->user2p(clonep);
198         m_scopep->addActivep(clonep);
199         iterateChildren(clonep);  // We iterate under the *clone*
200     }
visit(AstAssignVarScope * nodep)201     virtual void visit(AstAssignVarScope* nodep) override {
202         // Copy under the scope but don't recurse
203         UINFO(4, "    Move " << nodep << endl);
204         AstNode* const clonep = nodep->cloneTree(false);
205         nodep->user2p(clonep);
206         m_scopep->addActivep(clonep);
207         iterateChildren(clonep);  // We iterate under the *clone*
208     }
visit(AstAssignW * nodep)209     virtual void visit(AstAssignW* nodep) override {
210         // Add to list of blocks under this scope
211         UINFO(4, "    Move " << nodep << endl);
212         AstNode* const clonep = nodep->cloneTree(false);
213         nodep->user2p(clonep);
214         m_scopep->addActivep(clonep);
215         iterateChildren(clonep);  // We iterate under the *clone*
216     }
visit(AstAlwaysPublic * nodep)217     virtual void visit(AstAlwaysPublic* nodep) override {
218         // Add to list of blocks under this scope
219         UINFO(4, "    Move " << nodep << endl);
220         AstNode* const clonep = nodep->cloneTree(false);
221         nodep->user2p(clonep);
222         m_scopep->addActivep(clonep);
223         iterateChildren(clonep);  // We iterate under the *clone*
224     }
visit(AstCoverToggle * nodep)225     virtual void visit(AstCoverToggle* nodep) override {
226         // Add to list of blocks under this scope
227         UINFO(4, "    Move " << nodep << endl);
228         AstNode* const clonep = nodep->cloneTree(false);
229         nodep->user2p(clonep);
230         m_scopep->addActivep(clonep);
231         iterateChildren(clonep);  // We iterate under the *clone*
232     }
visit(AstCFunc * nodep)233     virtual void visit(AstCFunc* nodep) override {
234         // Add to list of blocks under this scope
235         UINFO(4, "    CFUNC " << nodep << endl);
236         AstCFunc* const clonep = nodep->cloneTree(false);
237         nodep->user2p(clonep);
238         m_scopep->addActivep(clonep);
239         clonep->scopep(m_scopep);
240         // We iterate under the *clone*
241         iterateChildren(clonep);
242     }
visit(AstNodeFTask * nodep)243     virtual void visit(AstNodeFTask* nodep) override {
244         // Add to list of blocks under this scope
245         UINFO(4, "    FTASK " << nodep << endl);
246         AstNodeFTask* clonep;
247         if (nodep->classMethod()) {
248             // Only one scope will be created, so avoid pointless cloning
249             nodep->unlinkFrBack();
250             clonep = nodep;
251         } else {
252             clonep = nodep->cloneTree(false);
253         }
254         nodep->user2p(clonep);
255         m_scopep->addActivep(clonep);
256         // We iterate under the *clone*
257         iterateChildren(clonep);
258     }
visit(AstVar * nodep)259     virtual void visit(AstVar* nodep) override {
260         // Make new scope variable
261         if (!nodep->user1p()) {
262             AstVarScope* const varscp = new AstVarScope(nodep->fileline(), m_scopep, nodep);
263             UINFO(6, "   New scope " << varscp << endl);
264             if (m_aboveCellp && !m_aboveCellp->isTrace()) varscp->trace(false);
265             nodep->user1p(varscp);
266             if (v3Global.opt.isClocker(varscp->prettyName())) {
267                 nodep->attrClocker(VVarAttrClocker::CLOCKER_YES);
268             }
269             if (v3Global.opt.isNoClocker(varscp->prettyName())) {
270                 nodep->attrClocker(VVarAttrClocker::CLOCKER_NO);
271             }
272             UASSERT_OBJ(m_scopep, nodep, "No scope for var");
273             m_varScopes.emplace(std::make_pair(nodep, m_scopep), varscp);
274             m_scopep->addVarp(varscp);
275         }
276     }
visit(AstVarRef * nodep)277     virtual void visit(AstVarRef* nodep) override {
278         // VarRef needs to point to VarScope
279         // Make sure variable has made user1p.
280         UASSERT_OBJ(nodep->varp(), nodep, "Unlinked");
281         if (nodep->varp()->isIfaceRef()) {
282             nodep->varScopep(nullptr);
283         } else {
284             // We may have not made the variable yet, and we can't make it now as
285             // the var's referenced package etc might not be created yet.
286             // So push to a list and post-correct.
287             // No check here for nodep->classOrPackagep(), will check when walk list.
288             m_varRefScopes.emplace(nodep, m_scopep);
289         }
290     }
visit(AstScopeName * nodep)291     virtual void visit(AstScopeName* nodep) override {
292         // If there's a %m in the display text, we add a special node that will contain the name()
293         const string prefix = string("__DOT__") + m_scopep->name();
294         // TOP and above will be the user's name().
295         // Note 'TOP.' is stripped by scopePrettyName
296         // To keep correct visual order, must add before other Text's
297         AstNode* afterp = nodep->scopeAttrp();
298         if (afterp) afterp->unlinkFrBackWithNext();
299         nodep->scopeAttrp(new AstText(nodep->fileline(), prefix));
300         if (afterp) nodep->scopeAttrp(afterp);
301         afterp = nodep->scopeEntrp();
302         if (afterp) afterp->unlinkFrBackWithNext();
303         nodep->scopeEntrp(new AstText(nodep->fileline(), prefix));
304         if (afterp) nodep->scopeEntrp(afterp);
305         iterateChildren(nodep);
306     }
visit(AstScope * nodep)307     virtual void visit(AstScope* nodep) override {
308         // Scope that was made by this module for different cell;
309         // Want to ignore blocks under it, so just do nothing
310     }
311     //--------------------
visit(AstNode * nodep)312     virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
313 
314 public:
315     // CONSTRUCTORS
ScopeVisitor(AstNetlist * nodep)316     explicit ScopeVisitor(AstNetlist* nodep) { iterate(nodep); }
317     virtual ~ScopeVisitor() override = default;
318 };
319 
320 //######################################################################
321 // Scope cleanup -- remove unused activates
322 
323 class ScopeCleanupVisitor final : public AstNVisitor {
324 private:
325     // STATE
326     AstScope* m_scopep = nullptr;  // Current scope we are building
327 
328     // METHODS
329     VL_DEBUG_FUNC;  // Declare debug()
330 
331     // VISITORS
visit(AstScope * nodep)332     virtual void visit(AstScope* nodep) override {
333         // Want to ignore blocks under it
334         VL_RESTORER(m_scopep);
335         {
336             m_scopep = nodep;
337             iterateChildren(nodep);
338         }
339     }
340 
movedDeleteOrIterate(AstNode * nodep)341     virtual void movedDeleteOrIterate(AstNode* nodep) {
342         if (m_scopep) {
343             // The new block; repair varrefs
344             iterateChildren(nodep);
345         } else {
346             // A block that was just moved under a scope, Kill it.
347             // Certain nodes can be referenced later in this pass, notably
348             // an FTaskRef needs to access the FTask to find the cloned task
349             VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
350         }
351     }
352 
visit(AstNodeProcedure * nodep)353     virtual void visit(AstNodeProcedure* nodep) override { movedDeleteOrIterate(nodep); }
visit(AstAssignAlias * nodep)354     virtual void visit(AstAssignAlias* nodep) override { movedDeleteOrIterate(nodep); }
visit(AstAssignVarScope * nodep)355     virtual void visit(AstAssignVarScope* nodep) override { movedDeleteOrIterate(nodep); }
visit(AstAssignW * nodep)356     virtual void visit(AstAssignW* nodep) override { movedDeleteOrIterate(nodep); }
visit(AstAlwaysPublic * nodep)357     virtual void visit(AstAlwaysPublic* nodep) override { movedDeleteOrIterate(nodep); }
visit(AstCoverToggle * nodep)358     virtual void visit(AstCoverToggle* nodep) override { movedDeleteOrIterate(nodep); }
visit(AstNodeFTask * nodep)359     virtual void visit(AstNodeFTask* nodep) override { movedDeleteOrIterate(nodep); }
visit(AstCFunc * nodep)360     virtual void visit(AstCFunc* nodep) override { movedDeleteOrIterate(nodep); }
361 
visit(AstVarXRef * nodep)362     virtual void visit(AstVarXRef* nodep) override {
363         // The crossrefs are dealt with in V3LinkDot
364         nodep->varp(nullptr);
365     }
visit(AstNodeFTaskRef * nodep)366     virtual void visit(AstNodeFTaskRef* nodep) override {
367         // The crossrefs are dealt with in V3LinkDot
368         UINFO(9, "   Old pkg-taskref " << nodep << endl);
369         if (nodep->classOrPackagep()) {
370             // Point to the clone
371             UASSERT_OBJ(nodep->taskp(), nodep, "Unlinked");
372             AstNodeFTask* const newp = VN_AS(nodep->taskp()->user2p(), NodeFTask);
373             UASSERT_OBJ(newp, nodep, "No clone for package function");
374             nodep->taskp(newp);
375             UINFO(9, "   New pkg-taskref " << nodep << endl);
376         } else if (!VN_IS(nodep, MethodCall)) {
377             nodep->taskp(nullptr);
378             UINFO(9, "   New pkg-taskref " << nodep << endl);
379         }
380         iterateChildren(nodep);
381     }
visit(AstModportFTaskRef * nodep)382     virtual void visit(AstModportFTaskRef* nodep) override {
383         // The modport persists only for xml dump
384         // The crossrefs are dealt with in V3LinkDot
385         nodep->ftaskp(nullptr);
386         iterateChildren(nodep);
387     }
388 
389     //--------------------
visit(AstNode * nodep)390     virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
391 
392 public:
393     // CONSTRUCTORS
ScopeCleanupVisitor(AstNetlist * nodep)394     explicit ScopeCleanupVisitor(AstNetlist* nodep) { iterate(nodep); }
395     virtual ~ScopeCleanupVisitor() override = default;
396 };
397 
398 //######################################################################
399 // Scope class functions
400 
scopeAll(AstNetlist * nodep)401 void V3Scope::scopeAll(AstNetlist* nodep) {
402     UINFO(2, __FUNCTION__ << ": " << endl);
403     {
404         const ScopeVisitor visitor{nodep};
405         ScopeCleanupVisitor{nodep};
406     }  // Destruct before checking
407     V3Global::dumpCheckGlobalTree("scope", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
408 }
409