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