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