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