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