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