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 "target/core/sw/sw_logic.h"
32 
33 #include <algorithm>
34 #include <cassert>
35 #include <iostream>
36 #include "target/core/common/interfacestream.h"
37 #include "target/core/common/printf.h"
38 #include "target/core/common/scanf.h"
39 #include "target/core/sw/monitor.h"
40 #include "target/input.h"
41 #include "target/state.h"
42 #include "verilog/analyze/module_info.h"
43 #include "verilog/analyze/resolve.h"
44 #include "verilog/ast/ast.h"
45 #include "verilog/print/print.h"
46 
47 using namespace std;
48 
49 namespace cascade::sw {
50 
SwLogic(Interface * interface,ModuleDeclaration * md)51 SwLogic::SwLogic(Interface* interface, ModuleDeclaration* md) : Logic(interface), Visitor() {
52   // Record pointer to source code and provision update pool
53   src_ = md;
54   update_pool_.resize(1);
55 
56   // Initialize monitors and system tasks
57   for (auto i = src_->begin_items(), ie = src_->end_items(); i != ie; ++i) {
58     Monitor().init(*i);
59   }
60   eval_.set_feof_handler([this](Evaluate* eval, const FeofExpression* fe) {
61     const auto fd = eval_.get_value(fe->get_fd()).to_uint();
62     return get_stream(fd)->eof();
63   });
64   EofIndex ei(this);
65   src_->accept(&ei);
66 
67   // Set silent mode, schedule always constructs and continuous assigns, and then
68   // place the silent flag in its default, disabled state
69   silent_ = true;
70   for (auto i = src_->begin_items(), ie = src_->end_items(); i != ie; ++i) {
71     if ((*i)->is(Node::Tag::continuous_assign)) {
72       schedule_now(*i);
73     }
74   }
75   silent_ = false;
76 }
77 
~SwLogic()78 SwLogic::~SwLogic() {
79   delete src_;
80   for (auto& s : streams_) {
81     delete s.second;
82   }
83 }
84 
set_input(const Identifier * id,VId vid)85 SwLogic& SwLogic::set_input(const Identifier* id, VId vid) {
86   if (vid >= inputs_.size()) {
87     inputs_.resize(vid+1, nullptr);
88   }
89   inputs_[vid] = id;
90   return *this;
91 }
92 
set_state(const Identifier * id,VId vid)93 SwLogic& SwLogic::set_state(const Identifier* id, VId vid) {
94   state_.insert(make_pair(vid, id));
95   return *this;
96 }
97 
set_output(const Identifier * id,VId vid)98 SwLogic& SwLogic::set_output(const Identifier* id, VId vid) {
99   outputs_.push_back(make_pair(id, vid));
100   return *this;
101 }
102 
get_state()103 State* SwLogic::get_state() {
104   auto* s = new State();
105   for (const auto& sv : state_) {
106     s->insert(sv.first, eval_.get_array_value(sv.second));
107   }
108   return s;
109 }
110 
set_state(const State * s)111 void SwLogic::set_state(const State* s) {
112   for (const auto& sv : state_) {
113     const auto itr = s->find(sv.first);
114     if (itr != s->end()) {
115       eval_.assign_array_value(sv.second, itr->second);
116       notify(sv.second);
117     }
118   }
119   silent_evaluate();
120 }
121 
get_input()122 Input* SwLogic::get_input() {
123   auto* i = new Input();
124   for (size_t v = 0, ve = inputs_.size(); v < ve; ++v) {
125     const auto* id = inputs_[v];
126     if (id == nullptr) {
127       continue;
128     }
129     i->insert(v, eval_.get_value(id));
130   }
131   return i;
132 }
133 
set_input(const Input * i)134 void SwLogic::set_input(const Input* i) {
135   for (size_t v = 0, ve = inputs_.size(); v < ve; ++v) {
136     const auto* id = inputs_[v];
137     if (id == nullptr) {
138       continue;
139     }
140     const auto itr = i->find(v);
141     if (itr != i->end()) {
142       if (eval_.assign_value(id, itr->second)) {
143         notify(id);
144       }
145     }
146   }
147   silent_evaluate();
148 }
149 
finalize()150 void SwLogic::finalize() {
151   // Handle calls to fopen.
152   for (auto i = src_->begin_items(), ie = src_->end_items(); i != ie; ++i) {
153     if ((*i)->is(Node::Tag::reg_declaration)) {
154       const auto* rd = static_cast<const RegDeclaration*>(*i);
155       if (rd->is_non_null_val() && rd->get_val()->is(Node::Tag::fopen_expression)) {
156         const auto* fe = static_cast<const FopenExpression*>(rd->get_val());
157         if (eval_.get_value(rd->get_id()).to_uint() == 0) {
158           const auto path = eval_.get_value(fe->get_path()).to_string();
159           const auto type = eval_.get_value(fe->get_type()).to_string();
160           uint8_t mode = 0;
161           if (type == "r" || type == "rb") {
162             mode = 0;
163           } else if (type == "w" || type == "wb") {
164             mode = 1;
165           } else if (type == "a" || type == "ab") {
166             mode = 2;
167           } else if (type == "r+" || type == "r+b" || type == "rb+") {
168             mode = 3;
169           } else if (type == "w+" || type == "w+b" || type == "wb+") {
170             mode = 4;
171           } else if (type == "a+" || type == "a+b" || type == "ab+") {
172             mode = 5;
173           }
174           const auto fd = interface()->fopen(path, mode);
175           if (eval_.assign_value(rd->get_id(), Bits(32, fd))) {
176             notify(rd->get_id());
177           }
178         }
179       }
180     }
181   }
182   // Schedule initial constructs
183   for (auto i = src_->begin_items(), ie = src_->end_items(); i != ie; ++i) {
184     if ((*i)->is(Node::Tag::initial_construct)) {
185       schedule_now(*i);
186     }
187   }
188 }
189 
read(VId vid,const Bits * b)190 void SwLogic::read(VId vid, const Bits* b) {
191   const auto* id = inputs_[vid];
192   if (eval_.assign_value(id, *b)) {
193     notify(id);
194   }
195 }
196 
evaluate()197 void SwLogic::evaluate() {
198   // This is a while loop. Active events can generate new active events.
199   there_were_tasks_ = false;
200   while (!active_.empty()) {
201     auto* e = active_.back();
202     active_.pop_back();
203     const_cast<Node*>(e)->set_flag<1>(false);
204     schedule_now(e);
205   }
206   for (auto& o : outputs_) {
207     interface()->write(o.second, &eval_.get_value(o.first));
208   }
209 }
210 
there_are_updates() const211 bool SwLogic::there_are_updates() const {
212   return !updates_.empty();
213 }
214 
update()215 void SwLogic::update() {
216   // This is a for loop. Updates happen simultaneously
217   for (size_t i = 0, ie = updates_.size(); i < ie; ++i) {
218     const auto& val = update_pool_[i];
219     if (eval_.assign_value(get<0>(updates_[i]), get<1>(updates_[i]), get<2>(updates_[i]), get<3>(updates_[i]), val)) {
220       notify(get<0>(updates_[i]));
221     }
222   }
223   updates_.clear();
224 
225   // This is while loop. Active events can generate new active events.
226   there_were_tasks_ = false;
227   while (!active_.empty()) {
228     auto* e = active_.back();
229     active_.pop_back();
230     const_cast<Node*>(e)->set_flag<1>(false);
231     schedule_now(e);
232   }
233 
234   for (auto& o : outputs_) {
235     interface()->write(o.second, &eval_.get_value(o.first));
236   }
237 }
238 
there_were_tasks() const239 bool SwLogic::there_were_tasks() const {
240   return there_were_tasks_;
241 }
242 
EofIndex(SwLogic * sw)243 SwLogic::EofIndex::EofIndex(SwLogic* sw) : Visitor() {
244   sw_ = sw;
245 }
246 
visit(const FeofExpression * fe)247 void SwLogic::EofIndex::visit(const FeofExpression* fe) {
248   sw_->eofs_.push_back(fe);
249 }
250 
schedule_now(const Node * n)251 void SwLogic::schedule_now(const Node* n) {
252   n->accept(this);
253 }
254 
schedule_active(const Node * n)255 void SwLogic::schedule_active(const Node* n) {
256   if (!n->get_flag<1>()) {
257     active_.push_back(n);
258     const_cast<Node*>(n)->set_flag<1>(true);
259   }
260 }
261 
notify(const Node * n)262 void SwLogic::notify(const Node* n) {
263   switch (n->get_tag()) {
264     case Node::Tag::identifier:
265       for (auto* m : static_cast<const Identifier*>(n)->monitor_) {
266         schedule_active(m);
267       }
268       break;
269     case Node::Tag::feof_expression:
270       for (auto* m : static_cast<const FeofExpression*>(n)->monitor_) {
271         schedule_active(m);
272       }
273       break;
274     case Node::Tag::event:
275       assert(n->get_parent()->is(Node::Tag::event_control));
276       assert(n->get_parent()->get_parent()->is(Node::Tag::timing_control_statement));
277       schedule_active(static_cast<const TimingControlStatement*>(n->get_parent()->get_parent())->get_stmt());
278       return;
279     default:
280       break;
281   }
282 }
283 
silent_evaluate()284 void SwLogic::silent_evaluate() {
285   // Turn on silent mode and drain the active queue
286   silent_ = true;
287   while (!active_.empty()) {
288     auto* e = active_.back();
289     active_.pop_back();
290     const_cast<Node*>(e)->set_flag<1>(false);
291     schedule_now(e);
292   }
293   silent_ = false;
294 }
295 
get_stream(FId fd)296 interfacestream* SwLogic::get_stream(FId fd) {
297   const auto itr = streams_.find(fd);
298   if (itr != streams_.end()) {
299     return itr->second;
300   }
301   auto* is = new interfacestream(interface(), fd);
302   streams_[fd] = is;
303   return is;
304 }
305 
update_eofs()306 void SwLogic::update_eofs() {
307   for (auto* fe : eofs_) {
308     eval_.flag_changed(fe);
309     notify(fe);
310   }
311 }
312 
visit(const Event * e)313 void SwLogic::visit(const Event* e) {
314   // TODO(eschkufz) Support for complex expressions
315   assert(e->get_expr()->is(Node::Tag::identifier));
316   const auto* id = static_cast<const Identifier*>(e->get_expr());
317   const auto* r = Resolve().get_resolution(id);
318 
319   if (e->get_type() != Event::Type::NEGEDGE && eval_.get_value(r).to_bool()) {
320     notify(e);
321   } else if (e->get_type() != Event::Type::POSEDGE && !eval_.get_value(r).to_bool()) {
322     notify(e);
323   }
324 }
325 
visit(const ContinuousAssign * ca)326 void SwLogic::visit(const ContinuousAssign* ca) {
327   const auto& val = eval_.get_value(ca->get_rhs());
328   if (eval_.assign_value(ca->get_lhs(), val)) {
329     notify(Resolve().get_resolution(ca->get_lhs()));
330   }
331 }
332 
visit(const BlockingAssign * ba)333 void SwLogic::visit(const BlockingAssign* ba) {
334   // TODO(eschkufz) Support for timing control
335   assert(ba->is_null_ctrl());
336 
337   const auto& res = eval_.get_value(ba->get_rhs());
338   if (eval_.assign_value(ba->get_lhs(), res)) {
339     notify(Resolve().get_resolution(ba->get_lhs()));
340   }
341 }
342 
visit(const NonblockingAssign * na)343 void SwLogic::visit(const NonblockingAssign* na) {
344   // TODO(eschkufz) Support for timing control
345   assert(na->is_null_ctrl());
346 
347   if (!silent_) {
348     const auto* r = Resolve().get_resolution(na->get_lhs());
349     assert(r != nullptr);
350     const auto target = eval_.dereference(r, na->get_lhs());
351     const auto& res = eval_.get_value(na->get_rhs());
352 
353     const auto idx = updates_.size();
354     if (idx >= update_pool_.size()) {
355       update_pool_.resize(2*update_pool_.size());
356     }
357 
358     updates_.push_back(make_tuple(r, get<0>(target), get<1>(target), get<2>(target)));
359     update_pool_[idx].copy(res);
360   }
361 }
362 
visit(const SeqBlock * sb)363 void SwLogic::visit(const SeqBlock* sb) {
364   for (auto i = sb->begin_stmts(), ie = sb->end_stmts(); i != ie; ++i) {
365     schedule_now(*i);
366   }
367 }
368 
visit(const CaseStatement * cs)369 void SwLogic::visit(const CaseStatement* cs) {
370   const auto s = eval_.get_value(cs->get_cond()).to_uint();
371   for (auto i = cs->begin_items(), ie = cs->end_items(); i != ie; ++i) {
372     for (auto j = (*i)->begin_exprs(), je = (*i)->end_exprs(); j != je; ++j) {
373       const auto c = eval_.get_value(*j).to_uint();
374       if (s == c) {
375         schedule_now((*i)->get_stmt());
376         return;
377       }
378     }
379     if ((*i)->empty_exprs()) {
380       schedule_now((*i)->get_stmt());
381       return;
382     }
383   }
384 }
385 
visit(const ConditionalStatement * cs)386 void SwLogic::visit(const ConditionalStatement* cs) {
387   if (eval_.get_value(cs->get_if()).to_bool()) {
388     schedule_now(cs->get_then());
389   } else {
390     schedule_now(cs->get_else());
391   }
392 }
393 
visit(const FflushStatement * fs)394 void SwLogic::visit(const FflushStatement* fs) {
395   if (!silent_) {
396     const auto fd = eval_.get_value(fs->get_fd()).to_uint();
397     auto* is = get_stream(fd);
398     is->clear();
399     is->flush();
400     update_eofs();
401   }
402 }
403 
visit(const FinishStatement * fs)404 void SwLogic::visit(const FinishStatement* fs) {
405   if (!silent_) {
406     interface()->finish(eval_.get_value(fs->get_arg()).to_uint());
407     there_were_tasks_ = true;
408   }
409 }
410 
visit(const FseekStatement * fs)411 void SwLogic::visit(const FseekStatement* fs) {
412   if (!silent_) {
413     const auto fd = eval_.get_value(fs->get_fd()).to_uint();
414     auto* is = get_stream(fd);
415 
416     const auto offset = eval_.get_value(fs->get_offset()).to_uint();
417     const auto op = eval_.get_value(fs->get_op()).to_uint();
418     const auto way = (op == 0) ? ios_base::beg : (op == 1) ? ios_base::cur : ios_base::end;
419 
420     is->clear();
421     is->seekg(offset, way);
422     is->seekp(offset, way);
423     update_eofs();
424   }
425 }
426 
visit(const DebugStatement * ds)427 void SwLogic::visit(const DebugStatement* ds) {
428   if (!silent_) {
429     stringstream ss;
430     ss << ds->get_arg();
431     interface()->debug(Evaluate().get_value(ds->get_action()).to_uint(), ss.str());
432     there_were_tasks_ = true;
433   }
434 }
435 
visit(const GetStatement * gs)436 void SwLogic::visit(const GetStatement* gs) {
437   if (!silent_) {
438     const auto fd = eval_.get_value(gs->get_fd()).to_uint();
439     auto* is = get_stream(fd);
440     Scanf().read(*is, &eval_, gs);
441 
442     if (gs->is_non_null_var()) {
443       const auto* r = Resolve().get_resolution(gs->get_var());
444       assert(r != nullptr);
445       notify(r);
446     }
447     update_eofs();
448   }
449 }
450 
visit(const PutStatement * ps)451 void SwLogic::visit(const PutStatement* ps) {
452   if (!silent_) {
453     const auto fd = eval_.get_value(ps->get_fd()).to_uint();
454     auto* is = get_stream(fd);
455     Printf().write(*is, &eval_, ps);
456     update_eofs();
457   }
458 }
459 
visit(const RestartStatement * rs)460 void SwLogic::visit(const RestartStatement* rs) {
461   if (!silent_) {
462     interface()->restart(rs->get_arg()->get_readable_val());
463     there_were_tasks_ = true;
464   }
465 }
466 
visit(const RetargetStatement * rs)467 void SwLogic::visit(const RetargetStatement* rs) {
468   if (!silent_) {
469     interface()->retarget(rs->get_arg()->get_readable_val());
470     there_were_tasks_ = true;
471   }
472 }
473 
visit(const SaveStatement * ss)474 void SwLogic::visit(const SaveStatement* ss) {
475   if (!silent_) {
476     interface()->save(ss->get_arg()->get_readable_val());
477     there_were_tasks_ = true;
478   }
479 }
480 
log(const string & op,const Node * n)481 void SwLogic::log(const string& op, const Node* n) {
482   cout << "[" << src_->get_id() << "] " << op << " " << n << endl;
483 }
484 
485 } // namespace cascade::sw
486