use strftime instead of put_time for gcc 4.8 compatibility
[yosys.git] / passes / sat / sim.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 */
19
20 #include "kernel/yosys.h"
21 #include "kernel/sigtools.h"
22 #include "kernel/celltypes.h"
23
24 #include <ctime>
25
26 USING_YOSYS_NAMESPACE
27 PRIVATE_NAMESPACE_BEGIN
28
29 struct SimShared
30 {
31 bool debug = false;
32 bool hide_internal = true;
33 bool writeback = false;
34 bool zinit = false;
35 int rstlen = 1;
36 };
37
38 void zinit(State &v)
39 {
40 if (v != State::S1)
41 v = State::S0;
42 }
43
44 void zinit(Const &v)
45 {
46 for (auto &bit : v.bits)
47 zinit(bit);
48 }
49
50 struct SimInstance
51 {
52 SimShared *shared;
53
54 Module *module;
55 Cell *instance;
56
57 SimInstance *parent;
58 dict<Cell*, SimInstance*> children;
59
60 SigMap sigmap;
61 dict<SigBit, State> state_nets;
62 dict<SigBit, pool<Cell*>> upd_cells;
63 dict<SigBit, pool<Wire*>> upd_outports;
64
65 pool<SigBit> dirty_bits;
66 pool<Cell*> dirty_cells;
67 pool<SimInstance*, hash_ptr_ops> dirty_children;
68
69 struct ff_state_t
70 {
71 State past_clock;
72 Const past_d;
73 };
74
75 struct mem_state_t
76 {
77 Const past_wr_clk;
78 Const past_wr_en;
79 Const past_wr_addr;
80 Const past_wr_data;
81 Const data;
82 };
83
84 dict<Cell*, ff_state_t> ff_database;
85 dict<Cell*, mem_state_t> mem_database;
86 pool<Cell*> formal_database;
87
88 dict<Wire*, pair<int, Const>> vcd_database;
89
90 SimInstance(SimShared *shared, Module *module, Cell *instance = nullptr, SimInstance *parent = nullptr) :
91 shared(shared), module(module), instance(instance), parent(parent), sigmap(module)
92 {
93 log_assert(module);
94
95 if (parent) {
96 log_assert(parent->children.count(instance) == 0);
97 parent->children[instance] = this;
98 }
99
100 for (auto wire : module->wires())
101 {
102 SigSpec sig = sigmap(wire);
103
104 for (int i = 0; i < GetSize(sig); i++) {
105 if (state_nets.count(sig[i]) == 0)
106 state_nets[sig[i]] = State::Sx;
107 if (wire->port_output) {
108 upd_outports[sig[i]].insert(wire);
109 dirty_bits.insert(sig[i]);
110 }
111 }
112
113 if (wire->attributes.count(ID::init)) {
114 Const initval = wire->attributes.at(ID::init);
115 for (int i = 0; i < GetSize(sig) && i < GetSize(initval); i++)
116 if (initval[i] == State::S0 || initval[i] == State::S1) {
117 state_nets[sig[i]] = initval[i];
118 dirty_bits.insert(sig[i]);
119 }
120 }
121 }
122
123 for (auto cell : module->cells())
124 {
125 Module *mod = module->design->module(cell->type);
126
127 if (mod != nullptr) {
128 dirty_children.insert(new SimInstance(shared, mod, cell, this));
129 }
130
131 for (auto &port : cell->connections()) {
132 if (cell->input(port.first))
133 for (auto bit : sigmap(port.second)) {
134 upd_cells[bit].insert(cell);
135 // Make sure cell inputs connected to constants are updated in the first cycle
136 if (bit.wire == nullptr)
137 dirty_bits.insert(bit);
138 }
139 }
140
141 if (cell->type.in(ID($dff))) {
142 ff_state_t ff;
143 ff.past_clock = State::Sx;
144 ff.past_d = Const(State::Sx, cell->getParam(ID::WIDTH).as_int());
145 ff_database[cell] = ff;
146 }
147
148 if (cell->type == ID($mem))
149 {
150 mem_state_t mem;
151
152 mem.past_wr_clk = Const(State::Sx, GetSize(cell->getPort(ID::WR_CLK)));
153 mem.past_wr_en = Const(State::Sx, GetSize(cell->getPort(ID::WR_EN)));
154 mem.past_wr_addr = Const(State::Sx, GetSize(cell->getPort(ID::WR_ADDR)));
155 mem.past_wr_data = Const(State::Sx, GetSize(cell->getPort(ID::WR_DATA)));
156
157 mem.data = cell->getParam(ID::INIT);
158 int sz = cell->getParam(ID::SIZE).as_int() * cell->getParam(ID::WIDTH).as_int();
159
160 if (GetSize(mem.data) > sz)
161 mem.data.bits.resize(sz);
162
163 while (GetSize(mem.data) < sz)
164 mem.data.bits.push_back(State::Sx);
165
166 mem_database[cell] = mem;
167 }
168 if (cell->type.in(ID($memwr),ID($memrd)))
169 {
170 log_error("$memrd and $memwr cells have to be merged to stand-alone $mem cells (execute memory_collect pass)\n");
171 }
172 if (cell->type.in(ID($assert), ID($cover), ID($assume))) {
173 formal_database.insert(cell);
174 }
175 }
176
177 if (shared->zinit)
178 {
179 for (auto &it : ff_database)
180 {
181 Cell *cell = it.first;
182 ff_state_t &ff = it.second;
183 zinit(ff.past_d);
184
185 SigSpec qsig = cell->getPort(ID::Q);
186 Const qdata = get_state(qsig);
187 zinit(qdata);
188 set_state(qsig, qdata);
189 }
190
191 for (auto &it : mem_database) {
192 mem_state_t &mem = it.second;
193 zinit(mem.past_wr_en);
194 zinit(mem.data);
195 }
196 }
197 }
198
199 ~SimInstance()
200 {
201 for (auto child : children)
202 delete child.second;
203 }
204
205 IdString name() const
206 {
207 if (instance != nullptr)
208 return instance->name;
209 return module->name;
210 }
211
212 std::string hiername() const
213 {
214 if (instance != nullptr)
215 return parent->hiername() + "." + log_id(instance->name);
216
217 return log_id(module->name);
218 }
219
220 Const get_state(SigSpec sig)
221 {
222 Const value;
223
224 for (auto bit : sigmap(sig))
225 if (bit.wire == nullptr)
226 value.bits.push_back(bit.data);
227 else if (state_nets.count(bit))
228 value.bits.push_back(state_nets.at(bit));
229 else
230 value.bits.push_back(State::Sz);
231
232 if (shared->debug)
233 log("[%s] get %s: %s\n", hiername().c_str(), log_signal(sig), log_signal(value));
234 return value;
235 }
236
237 bool set_state(SigSpec sig, Const value)
238 {
239 bool did_something = false;
240
241 sig = sigmap(sig);
242 log_assert(GetSize(sig) <= GetSize(value));
243
244 for (int i = 0; i < GetSize(sig); i++)
245 if (state_nets.at(sig[i]) != value[i]) {
246 state_nets.at(sig[i]) = value[i];
247 dirty_bits.insert(sig[i]);
248 did_something = true;
249 }
250
251 if (shared->debug)
252 log("[%s] set %s: %s\n", hiername().c_str(), log_signal(sig), log_signal(value));
253 return did_something;
254 }
255
256 void update_cell(Cell *cell)
257 {
258 if (ff_database.count(cell))
259 return;
260
261 if (formal_database.count(cell))
262 return;
263
264 if (mem_database.count(cell))
265 {
266 mem_state_t &mem = mem_database.at(cell);
267
268 int num_rd_ports = cell->getParam(ID::RD_PORTS).as_int();
269
270 int size = cell->getParam(ID::SIZE).as_int();
271 int offset = cell->getParam(ID::OFFSET).as_int();
272 int abits = cell->getParam(ID::ABITS).as_int();
273 int width = cell->getParam(ID::WIDTH).as_int();
274
275 if (cell->getParam(ID::RD_CLK_ENABLE).as_bool())
276 log_error("Memory %s.%s has clocked read ports. Run 'memory' with -nordff.\n", log_id(module), log_id(cell));
277
278 SigSpec rd_addr_sig = cell->getPort(ID::RD_ADDR);
279 SigSpec rd_data_sig = cell->getPort(ID::RD_DATA);
280
281 for (int port_idx = 0; port_idx < num_rd_ports; port_idx++)
282 {
283 Const addr = get_state(rd_addr_sig.extract(port_idx*abits, abits));
284 Const data = Const(State::Sx, width);
285
286 if (addr.is_fully_def()) {
287 int index = addr.as_int() - offset;
288 if (index >= 0 && index < size)
289 data = mem.data.extract(index*width, width);
290 }
291
292 set_state(rd_data_sig.extract(port_idx*width, width), data);
293 }
294
295 return;
296 }
297
298 if (children.count(cell))
299 {
300 auto child = children.at(cell);
301 for (auto &conn: cell->connections())
302 if (cell->input(conn.first)) {
303 Const value = get_state(conn.second);
304 child->set_state(child->module->wire(conn.first), value);
305 }
306 dirty_children.insert(child);
307 return;
308 }
309
310 if (yosys_celltypes.cell_evaluable(cell->type))
311 {
312 RTLIL::SigSpec sig_a, sig_b, sig_c, sig_d, sig_s, sig_y;
313 bool has_a, has_b, has_c, has_d, has_s, has_y;
314
315 has_a = cell->hasPort(ID::A);
316 has_b = cell->hasPort(ID::B);
317 has_c = cell->hasPort(ID::C);
318 has_d = cell->hasPort(ID::D);
319 has_s = cell->hasPort(ID::S);
320 has_y = cell->hasPort(ID::Y);
321
322 if (has_a) sig_a = cell->getPort(ID::A);
323 if (has_b) sig_b = cell->getPort(ID::B);
324 if (has_c) sig_c = cell->getPort(ID::C);
325 if (has_d) sig_d = cell->getPort(ID::D);
326 if (has_s) sig_s = cell->getPort(ID::S);
327 if (has_y) sig_y = cell->getPort(ID::Y);
328
329 if (shared->debug)
330 log("[%s] eval %s (%s)\n", hiername().c_str(), log_id(cell), log_id(cell->type));
331
332 // Simple (A -> Y) and (A,B -> Y) cells
333 if (has_a && !has_c && !has_d && !has_s && has_y) {
334 set_state(sig_y, CellTypes::eval(cell, get_state(sig_a), get_state(sig_b)));
335 return;
336 }
337
338 // (A,B,C -> Y) cells
339 if (has_a && has_b && has_c && !has_d && !has_s && has_y) {
340 set_state(sig_y, CellTypes::eval(cell, get_state(sig_a), get_state(sig_b), get_state(sig_c)));
341 return;
342 }
343
344 // (A,B,S -> Y) cells
345 if (has_a && has_b && !has_c && !has_d && has_s && has_y) {
346 set_state(sig_y, CellTypes::eval(cell, get_state(sig_a), get_state(sig_b), get_state(sig_s)));
347 return;
348 }
349
350 log_warning("Unsupported evaluable cell type: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell));
351 return;
352 }
353
354 log_error("Unsupported cell type: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell));
355 }
356
357 void update_ph1()
358 {
359 pool<Cell*> queue_cells;
360 pool<Wire*> queue_outports;
361
362 queue_cells.swap(dirty_cells);
363
364 while (1)
365 {
366 for (auto bit : dirty_bits)
367 {
368 if (upd_cells.count(bit))
369 for (auto cell : upd_cells.at(bit))
370 queue_cells.insert(cell);
371
372 if (upd_outports.count(bit) && parent != nullptr)
373 for (auto wire : upd_outports.at(bit))
374 queue_outports.insert(wire);
375 }
376
377 dirty_bits.clear();
378
379 if (!queue_cells.empty())
380 {
381 for (auto cell : queue_cells)
382 update_cell(cell);
383
384 queue_cells.clear();
385 continue;
386 }
387
388 for (auto wire : queue_outports)
389 if (instance->hasPort(wire->name)) {
390 Const value = get_state(wire);
391 parent->set_state(instance->getPort(wire->name), value);
392 }
393
394 queue_outports.clear();
395
396 for (auto child : dirty_children)
397 child->update_ph1();
398
399 dirty_children.clear();
400
401 if (dirty_bits.empty())
402 break;
403 }
404 }
405
406 bool update_ph2()
407 {
408 bool did_something = false;
409
410 for (auto &it : ff_database)
411 {
412 Cell *cell = it.first;
413 ff_state_t &ff = it.second;
414
415 if (cell->type.in(ID($dff)))
416 {
417 bool clkpol = cell->getParam(ID::CLK_POLARITY).as_bool();
418 State current_clock = get_state(cell->getPort(ID::CLK))[0];
419
420 if (clkpol ? (ff.past_clock == State::S1 || current_clock != State::S1) :
421 (ff.past_clock == State::S0 || current_clock != State::S0))
422 continue;
423
424 if (set_state(cell->getPort(ID::Q), ff.past_d))
425 did_something = true;
426 }
427 }
428
429 for (auto &it : mem_database)
430 {
431 Cell *cell = it.first;
432 mem_state_t &mem = it.second;
433
434 int num_wr_ports = cell->getParam(ID::WR_PORTS).as_int();
435
436 int size = cell->getParam(ID::SIZE).as_int();
437 int offset = cell->getParam(ID::OFFSET).as_int();
438 int abits = cell->getParam(ID::ABITS).as_int();
439 int width = cell->getParam(ID::WIDTH).as_int();
440
441 Const wr_clk_enable = cell->getParam(ID::WR_CLK_ENABLE);
442 Const wr_clk_polarity = cell->getParam(ID::WR_CLK_POLARITY);
443 Const current_wr_clk = get_state(cell->getPort(ID::WR_CLK));
444
445 for (int port_idx = 0; port_idx < num_wr_ports; port_idx++)
446 {
447 Const addr, data, enable;
448
449 if (wr_clk_enable[port_idx] == State::S0)
450 {
451 addr = get_state(cell->getPort(ID::WR_ADDR).extract(port_idx*abits, abits));
452 data = get_state(cell->getPort(ID::WR_DATA).extract(port_idx*width, width));
453 enable = get_state(cell->getPort(ID::WR_EN).extract(port_idx*width, width));
454 }
455 else
456 {
457 if (wr_clk_polarity[port_idx] == State::S1 ?
458 (mem.past_wr_clk[port_idx] == State::S1 || current_wr_clk[port_idx] != State::S1) :
459 (mem.past_wr_clk[port_idx] == State::S0 || current_wr_clk[port_idx] != State::S0))
460 continue;
461
462 addr = mem.past_wr_addr.extract(port_idx*abits, abits);
463 data = mem.past_wr_data.extract(port_idx*width, width);
464 enable = mem.past_wr_en.extract(port_idx*width, width);
465 }
466
467 if (addr.is_fully_def())
468 {
469 int index = addr.as_int() - offset;
470 if (index >= 0 && index < size)
471 for (int i = 0; i < width; i++)
472 if (enable[i] == State::S1 && mem.data.bits.at(index*width+i) != data[i]) {
473 mem.data.bits.at(index*width+i) = data[i];
474 dirty_cells.insert(cell);
475 did_something = true;
476 }
477 }
478 }
479 }
480
481 for (auto it : children)
482 if (it.second->update_ph2()) {
483 dirty_children.insert(it.second);
484 did_something = true;
485 }
486
487 return did_something;
488 }
489
490 void update_ph3()
491 {
492 for (auto &it : ff_database)
493 {
494 Cell *cell = it.first;
495 ff_state_t &ff = it.second;
496
497 if (cell->type.in(ID($dff))) {
498 ff.past_clock = get_state(cell->getPort(ID::CLK))[0];
499 ff.past_d = get_state(cell->getPort(ID::D));
500 }
501 }
502
503 for (auto &it : mem_database)
504 {
505 Cell *cell = it.first;
506 mem_state_t &mem = it.second;
507
508 mem.past_wr_clk = get_state(cell->getPort(ID::WR_CLK));
509 mem.past_wr_en = get_state(cell->getPort(ID::WR_EN));
510 mem.past_wr_addr = get_state(cell->getPort(ID::WR_ADDR));
511 mem.past_wr_data = get_state(cell->getPort(ID::WR_DATA));
512 }
513
514 for (auto cell : formal_database)
515 {
516 string label = log_id(cell);
517 if (cell->attributes.count(ID::src))
518 label = cell->attributes.at(ID::src).decode_string();
519
520 State a = get_state(cell->getPort(ID::A))[0];
521 State en = get_state(cell->getPort(ID::EN))[0];
522
523 if (cell->type == ID($cover) && en == State::S1 && a != State::S1)
524 log("Cover %s.%s (%s) reached.\n", hiername().c_str(), log_id(cell), label.c_str());
525
526 if (cell->type == ID($assume) && en == State::S1 && a != State::S1)
527 log("Assumption %s.%s (%s) failed.\n", hiername().c_str(), log_id(cell), label.c_str());
528
529 if (cell->type == ID($assert) && en == State::S1 && a != State::S1)
530 log_warning("Assert %s.%s (%s) failed.\n", hiername().c_str(), log_id(cell), label.c_str());
531 }
532
533 for (auto it : children)
534 it.second->update_ph3();
535 }
536
537 void writeback(pool<Module*> &wbmods)
538 {
539 if (wbmods.count(module))
540 log_error("Instance %s of module %s is not unique: Writeback not possible. (Fix by running 'uniquify'.)\n", hiername().c_str(), log_id(module));
541
542 wbmods.insert(module);
543
544 for (auto wire : module->wires())
545 wire->attributes.erase(ID::init);
546
547 for (auto &it : ff_database)
548 {
549 Cell *cell = it.first;
550 SigSpec sig_q = cell->getPort(ID::Q);
551 Const initval = get_state(sig_q);
552
553 for (int i = 0; i < GetSize(sig_q); i++)
554 {
555 Wire *w = sig_q[i].wire;
556
557 if (w->attributes.count(ID::init) == 0)
558 w->attributes[ID::init] = Const(State::Sx, GetSize(w));
559
560 w->attributes[ID::init][sig_q[i].offset] = initval[i];
561 }
562 }
563
564 for (auto &it : mem_database)
565 {
566 Cell *cell = it.first;
567 mem_state_t &mem = it.second;
568 Const initval = mem.data;
569
570 while (GetSize(initval) >= 2) {
571 if (initval[GetSize(initval)-1] != State::Sx) break;
572 if (initval[GetSize(initval)-2] != State::Sx) break;
573 initval.bits.pop_back();
574 }
575
576 cell->setParam(ID::INIT, initval);
577 }
578
579 for (auto it : children)
580 it.second->writeback(wbmods);
581 }
582
583 void write_vcd_header(std::ofstream &f, int &id)
584 {
585 f << stringf("$scope module %s $end\n", log_id(name()));
586
587 for (auto wire : module->wires())
588 {
589 if (shared->hide_internal && wire->name[0] == '$')
590 continue;
591
592 f << stringf("$var wire %d n%d %s%s $end\n", GetSize(wire), id, wire->name[0] == '$' ? "\\" : "", log_id(wire));
593 vcd_database[wire] = make_pair(id++, Const());
594 }
595
596 for (auto child : children)
597 child.second->write_vcd_header(f, id);
598
599 f << stringf("$upscope $end\n");
600 }
601
602 void write_vcd_step(std::ofstream &f)
603 {
604 for (auto &it : vcd_database)
605 {
606 Wire *wire = it.first;
607 Const value = get_state(wire);
608 int id = it.second.first;
609
610 if (it.second.second == value)
611 continue;
612
613 it.second.second = value;
614
615 f << "b";
616 for (int i = GetSize(value)-1; i >= 0; i--) {
617 switch (value[i]) {
618 case State::S0: f << "0"; break;
619 case State::S1: f << "1"; break;
620 case State::Sx: f << "x"; break;
621 default: f << "z";
622 }
623 }
624
625 f << stringf(" n%d\n", id);
626 }
627
628 for (auto child : children)
629 child.second->write_vcd_step(f);
630 }
631 };
632
633 struct SimWorker : SimShared
634 {
635 SimInstance *top = nullptr;
636 std::ofstream vcdfile;
637 pool<IdString> clock, clockn, reset, resetn;
638 std::string timescale;
639
640 ~SimWorker()
641 {
642 delete top;
643 }
644
645 void write_vcd_header()
646 {
647 if (!vcdfile.is_open())
648 return;
649
650 vcdfile << stringf("$version %s $end\n", yosys_version_str);
651
652 std::time_t t = std::time(nullptr);
653 char mbstr[255];
654 if (std::strftime(mbstr, sizeof(mbstr), "%c", std::localtime(&t))) {
655 vcdfile << stringf("$date ") << mbstr << stringf(" $end\n");
656 }
657
658 if (!timescale.empty())
659 vcdfile << stringf("$timescale %s $end\n", timescale.c_str());
660
661 int id = 1;
662 top->write_vcd_header(vcdfile, id);
663
664 vcdfile << stringf("$enddefinitions $end\n");
665 }
666
667 void write_vcd_step(int t)
668 {
669 if (!vcdfile.is_open())
670 return;
671
672 vcdfile << stringf("#%d\n", t);
673 top->write_vcd_step(vcdfile);
674 }
675
676 void update()
677 {
678 while (1)
679 {
680 if (debug)
681 log("\n-- ph1 --\n");
682
683 top->update_ph1();
684
685 if (debug)
686 log("\n-- ph2 --\n");
687
688 if (!top->update_ph2())
689 break;
690 }
691
692 if (debug)
693 log("\n-- ph3 --\n");
694
695 top->update_ph3();
696 }
697
698 void set_inports(pool<IdString> ports, State value)
699 {
700 for (auto portname : ports)
701 {
702 Wire *w = top->module->wire(portname);
703
704 if (w == nullptr)
705 log_error("Can't find port %s on module %s.\n", log_id(portname), log_id(top->module));
706
707 top->set_state(w, value);
708 }
709 }
710
711 void run(Module *topmod, int numcycles)
712 {
713 log_assert(top == nullptr);
714 top = new SimInstance(this, topmod);
715
716 if (debug)
717 log("\n===== 0 =====\n");
718 else
719 log("Simulating cycle 0.\n");
720
721 set_inports(reset, State::S1);
722 set_inports(resetn, State::S0);
723
724 set_inports(clock, State::Sx);
725 set_inports(clockn, State::Sx);
726
727 update();
728
729 write_vcd_header();
730 write_vcd_step(0);
731
732 for (int cycle = 0; cycle < numcycles; cycle++)
733 {
734 if (debug)
735 log("\n===== %d =====\n", 10*cycle + 5);
736
737 set_inports(clock, State::S0);
738 set_inports(clockn, State::S1);
739
740 update();
741 write_vcd_step(10*cycle + 5);
742
743 if (debug)
744 log("\n===== %d =====\n", 10*cycle + 10);
745 else
746 log("Simulating cycle %d.\n", cycle+1);
747
748 set_inports(clock, State::S1);
749 set_inports(clockn, State::S0);
750
751 if (cycle+1 == rstlen) {
752 set_inports(reset, State::S0);
753 set_inports(resetn, State::S1);
754 }
755
756 update();
757 write_vcd_step(10*cycle + 10);
758 }
759
760 write_vcd_step(10*numcycles + 2);
761
762 if (writeback) {
763 pool<Module*> wbmods;
764 top->writeback(wbmods);
765 }
766 }
767 };
768
769 struct SimPass : public Pass {
770 SimPass() : Pass("sim", "simulate the circuit") { }
771 void help() override
772 {
773 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
774 log("\n");
775 log(" sim [options] [top-level]\n");
776 log("\n");
777 log("This command simulates the circuit using the given top-level module.\n");
778 log("\n");
779 log(" -vcd <filename>\n");
780 log(" write the simulation results to the given VCD file\n");
781 log("\n");
782 log(" -clock <portname>\n");
783 log(" name of top-level clock input\n");
784 log("\n");
785 log(" -clockn <portname>\n");
786 log(" name of top-level clock input (inverse polarity)\n");
787 log("\n");
788 log(" -reset <portname>\n");
789 log(" name of top-level reset input (active high)\n");
790 log("\n");
791 log(" -resetn <portname>\n");
792 log(" name of top-level inverted reset input (active low)\n");
793 log("\n");
794 log(" -rstlen <integer>\n");
795 log(" number of cycles reset should stay active (default: 1)\n");
796 log("\n");
797 log(" -zinit\n");
798 log(" zero-initialize all uninitialized regs and memories\n");
799 log("\n");
800 log(" -timescale <string>\n");
801 log(" include the specified timescale declaration in the vcd\n");
802 log("\n");
803 log(" -n <integer>\n");
804 log(" number of cycles to simulate (default: 20)\n");
805 log("\n");
806 log(" -a\n");
807 log(" include all nets in VCD output, not just those with public names\n");
808 log("\n");
809 log(" -w\n");
810 log(" writeback mode: use final simulation state as new init state\n");
811 log("\n");
812 log(" -d\n");
813 log(" enable debug output\n");
814 log("\n");
815 }
816 void execute(std::vector<std::string> args, RTLIL::Design *design) override
817 {
818 SimWorker worker;
819 int numcycles = 20;
820
821 log_header(design, "Executing SIM pass (simulate the circuit).\n");
822
823 size_t argidx;
824 for (argidx = 1; argidx < args.size(); argidx++) {
825 if (args[argidx] == "-vcd" && argidx+1 < args.size()) {
826 worker.vcdfile.open(args[++argidx].c_str());
827 continue;
828 }
829 if (args[argidx] == "-n" && argidx+1 < args.size()) {
830 numcycles = atoi(args[++argidx].c_str());
831 continue;
832 }
833 if (args[argidx] == "-rstlen" && argidx+1 < args.size()) {
834 worker.rstlen = atoi(args[++argidx].c_str());
835 continue;
836 }
837 if (args[argidx] == "-clock" && argidx+1 < args.size()) {
838 worker.clock.insert(RTLIL::escape_id(args[++argidx]));
839 continue;
840 }
841 if (args[argidx] == "-clockn" && argidx+1 < args.size()) {
842 worker.clockn.insert(RTLIL::escape_id(args[++argidx]));
843 continue;
844 }
845 if (args[argidx] == "-reset" && argidx+1 < args.size()) {
846 worker.reset.insert(RTLIL::escape_id(args[++argidx]));
847 continue;
848 }
849 if (args[argidx] == "-resetn" && argidx+1 < args.size()) {
850 worker.resetn.insert(RTLIL::escape_id(args[++argidx]));
851 continue;
852 }
853 if (args[argidx] == "-timescale" && argidx+1 < args.size()) {
854 worker.timescale = args[++argidx];
855 continue;
856 }
857 if (args[argidx] == "-a") {
858 worker.hide_internal = false;
859 continue;
860 }
861 if (args[argidx] == "-d") {
862 worker.debug = true;
863 continue;
864 }
865 if (args[argidx] == "-w") {
866 worker.writeback = true;
867 continue;
868 }
869 if (args[argidx] == "-zinit") {
870 worker.zinit = true;
871 continue;
872 }
873 break;
874 }
875 extra_args(args, argidx, design);
876
877 Module *top_mod = nullptr;
878
879 if (design->full_selection()) {
880 top_mod = design->top_module();
881
882 if (!top_mod)
883 log_cmd_error("Design has no top module, use the 'hierarchy' command to specify one.\n");
884 } else {
885 auto mods = design->selected_whole_modules();
886 if (GetSize(mods) != 1)
887 log_cmd_error("Only one top module must be selected.\n");
888 top_mod = mods.front();
889 }
890
891 worker.run(top_mod, numcycles);
892 }
893 } SimPass;
894
895 PRIVATE_NAMESPACE_END