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