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