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