1 // Copyright 2017-2019 VMware, Inc.
2 // SPDX-License-Identifier: BSD-2-Clause
3 //
4 // The BSD-2 license (the License) set forth below applies to all parts of the
5 // Cascade project.  You may not use this file except in compliance with the
6 // License.
7 //
8 // BSD-2 License
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are met:
12 //
13 // 1. Redistributions of source code must retain the above copyright notice, this
14 // list of conditions and the following disclaimer.
15 //
16 // 2. Redistributions in binary form must reproduce the above copyright notice,
17 // this list of conditions and the following disclaimer in the documentation
18 // and/or other materials provided with the distribution.
19 //
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND
21 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 #include "runtime/isolate.h"
32 
33 #include <cassert>
34 #include <map>
35 #include <sstream>
36 #include <string>
37 #include "common/bits.h"
38 #include "runtime/data_plane.h"
39 #include "verilog/analyze/evaluate.h"
40 #include "verilog/analyze/module_info.h"
41 #include "verilog/analyze/navigate.h"
42 #include "verilog/analyze/resolve.h"
43 #include "verilog/program/elaborate.h"
44 
45 using namespace std;
46 
47 namespace cascade {
48 
isolate(const ModuleDeclaration * src,int ignore)49 ModuleDeclaration* Isolate::isolate(const ModuleDeclaration* src, int ignore) {
50   src_ = src;
51   ignore_ = ignore;
52   return src_->accept(this);
53 }
54 
isolate(const Identifier * id)55 VId Isolate::isolate(const Identifier* id) {
56   const auto* r = Resolve().get_resolution(id);
57   assert(r != nullptr);
58 
59   auto itr = symbol_table_.find(r);
60   if (itr == symbol_table_.end()) {
61     itr = symbol_table_.insert(make_pair(r, symbol_table_.size()+1)).first;
62   }
63   return itr->second;
64 }
65 
isolate(const ModuleInstantiation * mi)66 MId Isolate::isolate(const ModuleInstantiation* mi) {
67   auto itr = module_table_.find(mi->get_iid());
68   if (itr == module_table_.end()) {
69     itr = module_table_.insert(make_pair(mi->get_iid(), module_table_.size())).first;
70   }
71   return itr->second;
72 }
73 
build(const Attributes * as)74 Attributes* Isolate::build(const Attributes* as) {
75   // Ignore attributes
76   (void) as;
77   return new Attributes();
78 }
79 
build(const Identifier * id)80 Expression* Isolate::build(const Identifier* id) {
81   if (Resolve().get_resolution(id) == nullptr) {
82     return id->clone();
83   } else if (ModuleInfo(src_).is_read(id) || ModuleInfo(src_).is_write(id)) {
84     return to_global_id(id);
85   } else {
86     return to_local_id(id);
87   }
88 }
89 
build(const ModuleDeclaration * md)90 ModuleDeclaration* Isolate::build(const ModuleDeclaration* md) {
91   // Create a new module with a mangled id and global io ports
92   auto* res = get_shell();
93   // Generate local declarations.
94   auto ld = get_local_decls();
95   res->push_back_items(ld.begin(), ld.end());
96   // Transform the remainder of the code
97   auto mis = get_items(md->begin_items(), md->end_items(), true);
98   res->push_back_items(mis.begin(), mis.end());
99 
100   return res;
101 }
102 
build(const InitialConstruct * ic)103 ModuleItem* Isolate::build(const InitialConstruct* ic) {
104   return (ignore_ >= 0) ?
105     nullptr :
106     new InitialConstruct(ic->accept_attrs(this), ic->accept_stmt(this));
107 }
108 
build(const GenvarDeclaration * gd)109 ModuleItem* Isolate::build(const GenvarDeclaration* gd) {
110   // Does nothing. We delete these.
111   (void) gd;
112   return nullptr;
113 }
114 
build(const LocalparamDeclaration * ld)115 ModuleItem* Isolate::build(const LocalparamDeclaration* ld) {
116   // Careful: We don't want what's on the rhs of the assignment, we want the
117   // value of the identifier, which may have different sign/size.
118   auto* res = new LocalparamDeclaration(
119     ld->get_attrs()->accept(this),
120     ld->accept_id(this),
121     ld->get_type(),
122     ld->accept_dim(this),
123     new Number(Evaluate().get_value(ld->get_id()), Number::Format::HEX)
124   );
125   res->get_attrs()->push_back_as(new AttrSpec(
126     new Identifier("__id"),
127     Resolve().get_full_id(ld->get_id())
128   ));
129   return res;
130 }
131 
build(const ParameterDeclaration * pd)132 ModuleItem* Isolate::build(const ParameterDeclaration* pd) {
133   // Parameter declarations are downgraded to local params
134   // Careful: We don't want what's on the rhs of the assignment, we want the
135   // value of the identifier, which may have different sign/size.
136   auto* res = new LocalparamDeclaration(
137     pd->get_attrs()->accept(this),
138     pd->accept_id(this),
139     pd->get_type(),
140     pd->accept_dim(this),
141     new Number(Evaluate().get_value(pd->get_id()), Number::Format::HEX)
142   );
143   res->get_attrs()->push_back_as(new AttrSpec(
144     new Identifier("__id"),
145     Resolve().get_full_id(pd->get_id())
146   ));
147   return res;
148 }
149 
build(const PortDeclaration * pd)150 ModuleItem* Isolate::build(const PortDeclaration* pd) {
151   // Does nothing. We emit declarations at the top level.
152   (void) pd;
153   return nullptr;
154 }
155 
build(const ParBlock * pb)156 Statement* Isolate::build(const ParBlock* pb) {
157   // Until the day when we add support for delay statements, sequential
158   // execution is guaranteed to be a valid scheduling of a par block.
159   auto* res =  new SeqBlock();
160   pb->accept_stmts(this, res->back_inserter_stmts());
161   return res;
162 }
163 
build(const SeqBlock * sb)164 Statement* Isolate::build(const SeqBlock* sb) {
165   auto* res = new SeqBlock();
166   sb->accept_stmts(this, res->back_inserter_stmts());
167   return res;
168 }
169 
build(const DebugStatement * ds)170 Statement* Isolate::build(const DebugStatement* ds) {
171   // Get the fully qualified name of this scope
172   const auto* id = Navigate(ds).name();
173   assert(id != nullptr);
174   auto* s = Resolve().get_full_id(id);
175   assert(s != nullptr);
176 
177   // Create a new debug statement
178   auto* res = ds->clone();
179   const auto action = Evaluate().get_value(ds->get_action()).to_uint();
180 
181   // For all variants, if no arg was provided, attach the scope name
182   if (ds->is_null_arg()) {
183     res->replace_arg(s);
184   }
185   // If this is a call to list or showvars with an arg, prepend the scope to it.
186   else if ((action == 0) || (action == 3)) {
187     for (auto i = res->get_arg()->begin_ids(), ie = res->get_arg()->end_ids(); i != ie; ++i) {
188       s->push_back_ids((*i)->clone());
189     }
190     res->replace_arg(s);
191   }
192 
193   return res;
194 }
195 
to_mangled_id(const ModuleInstantiation * mi)196 Identifier* Isolate::to_mangled_id(const ModuleInstantiation* mi) {
197   stringstream ss;
198   ss << "__M" << isolate(mi);
199   return new Identifier(ss.str());
200 }
201 
to_local_id(const Identifier * id)202 Identifier* Isolate::to_local_id(const Identifier* id) {
203   stringstream ss;
204   ss << "__l" << isolate(id);
205   auto* res = new Identifier(new Id(ss.str()));
206   id->accept_dim(this, res->back_inserter_dim());
207   return res;
208 }
209 
to_global_id(const Identifier * id)210 Identifier* Isolate::to_global_id(const Identifier* id) {
211   stringstream ss;
212   ss << "__x" << isolate(id);
213   auto* res =  new Identifier(new Id(ss.str()));
214   id->accept_dim(this, res->back_inserter_dim());
215   return res;
216 }
217 
get_shell()218 ModuleDeclaration* Isolate::get_shell() {
219   ModuleInfo info(src_);
220 
221   assert(src_->get_parent()->is(Node::Tag::module_instantiation));
222   auto* res = new ModuleDeclaration(
223     src_->get_attrs()->clone(),
224     to_mangled_id(static_cast<const ModuleInstantiation*>(src_->get_parent()))
225   );
226 
227   // Sort ports lexicographically by name so that we assign VIds
228   // deterministically
229   unordered_set<const Identifier*> ios;
230   ios.insert(info.reads().begin(), info.reads().end());
231   ios.insert(info.writes().begin(), info.writes().end());
232   map<string, const Identifier*> ports;
233   for (auto* i : ios) {
234     ports.insert(make_pair(Resolve().get_readable_full_id(i), i));
235   }
236 
237   // Generate port and localparam declarations
238   for (auto& p : ports) {
239     const auto read = info.is_read(p.second);
240     const auto write = info.is_write(p.second);
241     const auto width = Evaluate().get_width(p.second);
242 
243     // If this is an external variable which corresponds to a parameter, and is
244     // read by this module, we can replace it with a localparam. If it's
245     // written, we can ignore it entirely.
246     const auto* r = Resolve().get_resolution(p.second);
247     assert(r != nullptr);
248     assert(r->get_parent() != nullptr);
249     assert(r->get_parent()->is_subclass_of(Node::Tag::declaration));
250     const auto* decl = static_cast<const Declaration*>(r->get_parent());
251     if (decl->is(Node::Tag::localparam_declaration) || decl->is(Node::Tag::parameter_declaration)) {
252       if (write) {
253         res->push_back_items(new LocalparamDeclaration(
254           new Attributes(),
255           to_global_id(p.second),
256           decl->get_type(),
257           decl->clone_dim(),
258           decl->is(Node::Tag::localparam_declaration) ?
259             static_cast<const LocalparamDeclaration*>(decl)->clone_val() :
260             static_cast<const ParameterDeclaration*>(decl)->clone_val()
261         ));
262       }
263       continue;
264     }
265 
266     // Otherwise, turn this signal into a port
267     res->push_back_ports(new ArgAssign(
268       nullptr,
269       to_global_id(p.second)
270     ));
271 
272     // TODO(eschkufz) Is this logic correct? When should a global read/write be
273     // promoted to a register and when should it remain a net? There could be a
274     // funny interaction here if a dereference of an external register is
275     // promoted to an input.
276 
277     const auto is_signed = p.second->get_parent()->is(Node::Tag::reg_declaration) ?
278       static_cast<const RegDeclaration*>(p.second->get_parent())->get_type() :
279       static_cast<const NetDeclaration*>(p.second->get_parent())->get_type();
280 
281     auto* pd = new PortDeclaration(
282       new Attributes(),
283       (read && write) ? PortDeclaration::Type::INOUT : write ? PortDeclaration::Type::INPUT : PortDeclaration::Type::OUTPUT,
284       (info.is_local(p.second) && p.second->get_parent()->is(Node::Tag::reg_declaration)) ?
285         static_cast<Declaration*>(new RegDeclaration(
286           new Attributes(),
287           to_global_id(p.second),
288           is_signed,
289           (width == 1) ? nullptr : new RangeExpression(width),
290           static_cast<const RegDeclaration*>(p.second->get_parent())->clone_val()
291         )) :
292         static_cast<Declaration*>(new NetDeclaration(
293           new Attributes(),
294           to_global_id(p.second),
295           is_signed,
296           (width == 1) ? nullptr : new RangeExpression(width)
297         ))
298     );
299     pd->get_attrs()->push_back_as(new AttrSpec(
300       new Identifier("__id"),
301       Resolve().get_full_id(p.second)
302     ));
303     res->push_back_items(pd);
304   }
305 
306   return res;
307 }
308 
get_local_decls()309 vector<ModuleItem*> Isolate::get_local_decls() {
310   // Sort variables lexicographically by name so that we assign VIds
311   // deterministically
312   map<string, const Identifier*> locals;
313   for (auto* l : ModuleInfo(src_).locals()) {
314     if (ModuleInfo(src_).is_read(l) || ModuleInfo(src_).is_write(l)) {
315       continue;
316     }
317     locals.insert(make_pair(Resolve().get_readable_full_id(l), l));
318   }
319 
320   vector<ModuleItem*> res;
321   for (auto& l : locals) {
322     assert(l.second->get_parent()->is_subclass_of(Node::Tag::declaration));
323     auto* d = static_cast<const Declaration*>(l.second->get_parent())->accept(this);
324     if (d != nullptr) {
325       res.push_back(d);
326     }
327   }
328   return res;
329 }
330 
replace(vector<ModuleItem * > & res,const ModuleInstantiation * mi)331 void Isolate::replace(vector<ModuleItem*>& res, const ModuleInstantiation* mi) {
332   const auto& conns = ModuleInfo(src_).connections();
333   const auto itr = conns.find(mi->get_iid());
334   assert(itr != conns.end());
335 
336   // Sort connections lexicographically by name so that we generate statements
337   // deterministically.
338   map<string, pair<const Identifier*, const Expression*>> sorted_conns;
339   for (auto& c : itr->second) {
340     sorted_conns.insert(make_pair(Resolve().get_readable_full_id(c.first), c));
341   }
342 
343   for (const auto& sc : sorted_conns) {
344     const auto& c = sc.second;
345     auto* lhs = ModuleInfo(Resolve().get_origin(c.first)).is_input(c.first) ?
346         c.first->accept(this) :
347         static_cast<Identifier*>(c.second->accept(this));
348     auto* rhs = ModuleInfo(Resolve().get_origin(c.first)).is_input(c.first) ?
349         static_cast<Expression*>(c.second->accept(this)) :
350         c.first->accept(this);
351     auto* ca = new ContinuousAssign(lhs, rhs);
352     res.push_back(ca);
353   }
354 }
355 
flatten(vector<ModuleItem * > & res,const CaseGenerateConstruct * cgc)356 void Isolate::flatten(vector<ModuleItem*>& res, const CaseGenerateConstruct* cgc) {
357   if (Elaborate().is_elaborated(cgc)) {
358     auto* elab = Elaborate().get_elaboration(cgc);
359     flatten(res, elab);
360   }
361 }
362 
flatten(vector<ModuleItem * > & res,const IfGenerateConstruct * igc)363 void Isolate::flatten(vector<ModuleItem*>& res, const IfGenerateConstruct* igc) {
364   if (Elaborate().is_elaborated(igc)) {
365     auto* elab = Elaborate().get_elaboration(igc);
366     flatten(res, elab);
367   }
368 }
369 
flatten(vector<ModuleItem * > & res,const LoopGenerateConstruct * lgc)370 void Isolate::flatten(vector<ModuleItem*>& res, const LoopGenerateConstruct* lgc) {
371   if (Elaborate().is_elaborated(lgc)) {
372     auto elab = Elaborate().get_elaboration(lgc);
373     for (auto* gb : elab) {
374       flatten(res, gb);
375     }
376   }
377 }
378 
flatten(vector<ModuleItem * > & res,const GenerateBlock * gb)379 void Isolate::flatten(vector<ModuleItem*>& res, const GenerateBlock* gb) {
380   auto temp = get_items(gb->begin_items(), gb->end_items(), false);
381   res.insert(res.end(), temp.begin(), temp.end());
382 }
383 
flatten(vector<ModuleItem * > & res,const GenerateRegion * gr)384 void Isolate::flatten(vector<ModuleItem*>& res, const GenerateRegion* gr) {
385   auto temp = get_items(gr->begin_items(), gr->end_items(), false);
386   res.insert(res.end(), temp.begin(), temp.end());
387 }
388 
389 } // namespace cascade
390