Display values of outputs
[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 #include "kernel/fstdata.h"
25
26 #include <ctime>
27
28 USING_YOSYS_NAMESPACE
29 PRIVATE_NAMESPACE_BEGIN
30
31 struct SimShared
32 {
33 bool debug = false;
34 bool hide_internal = true;
35 bool writeback = false;
36 bool zinit = false;
37 int rstlen = 1;
38 FstData *fst = nullptr;
39 };
40
41 void zinit(State &v)
42 {
43 if (v != State::S1)
44 v = State::S0;
45 }
46
47 void zinit(Const &v)
48 {
49 for (auto &bit : v.bits)
50 zinit(bit);
51 }
52
53 struct SimInstance
54 {
55 SimShared *shared;
56
57 std::string scope;
58 Module *module;
59 Cell *instance;
60
61 SimInstance *parent;
62 dict<Cell*, SimInstance*> children;
63
64 SigMap sigmap;
65 dict<SigBit, State> state_nets;
66 dict<SigBit, pool<Cell*>> upd_cells;
67 dict<SigBit, pool<Wire*>> upd_outports;
68
69 pool<SigBit> dirty_bits;
70 pool<Cell*> dirty_cells;
71 pool<IdString> dirty_memories;
72 pool<SimInstance*, hash_ptr_ops> dirty_children;
73
74 struct ff_state_t
75 {
76 State past_clock;
77 Const past_d;
78 };
79
80 struct mem_state_t
81 {
82 Mem *mem;
83 std::vector<Const> past_wr_clk;
84 std::vector<Const> past_wr_en;
85 std::vector<Const> past_wr_addr;
86 std::vector<Const> past_wr_data;
87 Const data;
88 };
89
90 dict<Cell*, ff_state_t> ff_database;
91 dict<IdString, mem_state_t> mem_database;
92 pool<Cell*> formal_database;
93 dict<Cell*, IdString> mem_cells;
94
95 std::vector<Mem> memories;
96
97 dict<Wire*, pair<int, Const>> vcd_database;
98 dict<Wire*, pair<fstHandle, Const>> fst_database;
99
100 SimInstance(SimShared *shared, std::string scope, Module *module, Cell *instance = nullptr, SimInstance *parent = nullptr) :
101 shared(shared), scope(scope), module(module), instance(instance), parent(parent), sigmap(module)
102 {
103 log_assert(module);
104
105 if (parent) {
106 log_assert(parent->children.count(instance) == 0);
107 parent->children[instance] = this;
108 }
109
110 for (auto wire : module->wires())
111 {
112 SigSpec sig = sigmap(wire);
113
114 for (int i = 0; i < GetSize(sig); i++) {
115 if (state_nets.count(sig[i]) == 0)
116 state_nets[sig[i]] = State::Sx;
117 if (wire->port_output) {
118 upd_outports[sig[i]].insert(wire);
119 dirty_bits.insert(sig[i]);
120 }
121 }
122
123 if (wire->attributes.count(ID::init)) {
124 Const initval = wire->attributes.at(ID::init);
125 for (int i = 0; i < GetSize(sig) && i < GetSize(initval); i++)
126 if (initval[i] == State::S0 || initval[i] == State::S1) {
127 state_nets[sig[i]] = initval[i];
128 dirty_bits.insert(sig[i]);
129 }
130 }
131 }
132
133 memories = Mem::get_all_memories(module);
134 for (auto &mem : memories) {
135 auto &mdb = mem_database[mem.memid];
136 mdb.mem = &mem;
137 for (auto &port : mem.wr_ports) {
138 mdb.past_wr_clk.push_back(Const(State::Sx));
139 mdb.past_wr_en.push_back(Const(State::Sx, GetSize(port.en)));
140 mdb.past_wr_addr.push_back(Const(State::Sx, GetSize(port.addr)));
141 mdb.past_wr_data.push_back(Const(State::Sx, GetSize(port.data)));
142 }
143 mdb.data = mem.get_init_data();
144 }
145
146 for (auto cell : module->cells())
147 {
148 Module *mod = module->design->module(cell->type);
149
150 if (mod != nullptr) {
151 dirty_children.insert(new SimInstance(shared, scope + "." + RTLIL::unescape_id(module->name), mod, cell, this));
152 }
153
154 for (auto &port : cell->connections()) {
155 if (cell->input(port.first))
156 for (auto bit : sigmap(port.second)) {
157 upd_cells[bit].insert(cell);
158 // Make sure cell inputs connected to constants are updated in the first cycle
159 if (bit.wire == nullptr)
160 dirty_bits.insert(bit);
161 }
162 }
163
164 if (cell->type.in(ID($dff))) {
165 ff_state_t ff;
166 ff.past_clock = State::Sx;
167 ff.past_d = Const(State::Sx, cell->getParam(ID::WIDTH).as_int());
168 ff_database[cell] = ff;
169 }
170
171 if (cell->is_mem_cell())
172 {
173 mem_cells[cell] = cell->parameters.at(ID::MEMID).decode_string();
174 }
175 if (cell->type.in(ID($assert), ID($cover), ID($assume))) {
176 formal_database.insert(cell);
177 }
178 }
179
180 if (shared->zinit)
181 {
182 for (auto &it : ff_database)
183 {
184 Cell *cell = it.first;
185 ff_state_t &ff = it.second;
186 zinit(ff.past_d);
187
188 SigSpec qsig = cell->getPort(ID::Q);
189 Const qdata = get_state(qsig);
190 zinit(qdata);
191 set_state(qsig, qdata);
192 }
193
194 for (auto &it : mem_database) {
195 mem_state_t &mem = it.second;
196 for (auto &val : mem.past_wr_en)
197 zinit(val);
198 zinit(mem.data);
199 }
200 }
201 }
202
203 ~SimInstance()
204 {
205 for (auto child : children)
206 delete child.second;
207 }
208
209 IdString name() const
210 {
211 if (instance != nullptr)
212 return instance->name;
213 return module->name;
214 }
215
216 std::string hiername() const
217 {
218 if (instance != nullptr)
219 return parent->hiername() + "." + log_id(instance->name);
220
221 return log_id(module->name);
222 }
223
224 Const get_state(SigSpec sig)
225 {
226 Const value;
227
228 for (auto bit : sigmap(sig))
229 if (bit.wire == nullptr)
230 value.bits.push_back(bit.data);
231 else if (state_nets.count(bit))
232 value.bits.push_back(state_nets.at(bit));
233 else
234 value.bits.push_back(State::Sz);
235
236 if (shared->debug)
237 log("[%s] get %s: %s\n", hiername().c_str(), log_signal(sig), log_signal(value));
238 return value;
239 }
240
241 bool set_state(SigSpec sig, Const value)
242 {
243 bool did_something = false;
244
245 sig = sigmap(sig);
246 log_assert(GetSize(sig) <= GetSize(value));
247
248 for (int i = 0; i < GetSize(sig); i++)
249 if (state_nets.at(sig[i]) != value[i]) {
250 state_nets.at(sig[i]) = value[i];
251 dirty_bits.insert(sig[i]);
252 did_something = true;
253 }
254
255 if (shared->debug)
256 log("[%s] set %s: %s\n", hiername().c_str(), log_signal(sig), log_signal(value));
257 return did_something;
258 }
259
260 void update_cell(Cell *cell)
261 {
262 if (ff_database.count(cell))
263 return;
264
265 if (formal_database.count(cell))
266 return;
267
268 if (mem_cells.count(cell))
269 {
270 dirty_memories.insert(mem_cells[cell]);
271 return;
272 }
273
274 if (children.count(cell))
275 {
276 auto child = children.at(cell);
277 for (auto &conn: cell->connections())
278 if (cell->input(conn.first) && GetSize(conn.second)) {
279 Const value = get_state(conn.second);
280 child->set_state(child->module->wire(conn.first), value);
281 }
282 dirty_children.insert(child);
283 return;
284 }
285
286 if (yosys_celltypes.cell_evaluable(cell->type))
287 {
288 RTLIL::SigSpec sig_a, sig_b, sig_c, sig_d, sig_s, sig_y;
289 bool has_a, has_b, has_c, has_d, has_s, has_y;
290
291 has_a = cell->hasPort(ID::A);
292 has_b = cell->hasPort(ID::B);
293 has_c = cell->hasPort(ID::C);
294 has_d = cell->hasPort(ID::D);
295 has_s = cell->hasPort(ID::S);
296 has_y = cell->hasPort(ID::Y);
297
298 if (has_a) sig_a = cell->getPort(ID::A);
299 if (has_b) sig_b = cell->getPort(ID::B);
300 if (has_c) sig_c = cell->getPort(ID::C);
301 if (has_d) sig_d = cell->getPort(ID::D);
302 if (has_s) sig_s = cell->getPort(ID::S);
303 if (has_y) sig_y = cell->getPort(ID::Y);
304
305 if (shared->debug)
306 log("[%s] eval %s (%s)\n", hiername().c_str(), log_id(cell), log_id(cell->type));
307
308 // Simple (A -> Y) and (A,B -> Y) cells
309 if (has_a && !has_c && !has_d && !has_s && has_y) {
310 set_state(sig_y, CellTypes::eval(cell, get_state(sig_a), get_state(sig_b)));
311 return;
312 }
313
314 // (A,B,C -> Y) cells
315 if (has_a && has_b && has_c && !has_d && !has_s && has_y) {
316 set_state(sig_y, CellTypes::eval(cell, get_state(sig_a), get_state(sig_b), get_state(sig_c)));
317 return;
318 }
319
320 // (A,B,S -> Y) cells
321 if (has_a && has_b && !has_c && !has_d && has_s && has_y) {
322 set_state(sig_y, CellTypes::eval(cell, get_state(sig_a), get_state(sig_b), get_state(sig_s)));
323 return;
324 }
325
326 log_warning("Unsupported evaluable cell type: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell));
327 return;
328 }
329
330 log_error("Unsupported cell type: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell));
331 }
332
333 void update_memory(IdString id) {
334 auto &mdb = mem_database[id];
335 auto &mem = *mdb.mem;
336
337 for (int port_idx = 0; port_idx < GetSize(mem.rd_ports); port_idx++)
338 {
339 auto &port = mem.rd_ports[port_idx];
340 Const addr = get_state(port.addr);
341 Const data = Const(State::Sx, mem.width << port.wide_log2);
342
343 if (port.clk_enable)
344 log_error("Memory %s.%s has clocked read ports. Run 'memory' with -nordff.\n", log_id(module), log_id(mem.memid));
345
346 if (addr.is_fully_def()) {
347 int index = addr.as_int() - mem.start_offset;
348 if (index >= 0 && index < mem.size)
349 data = mdb.data.extract(index*mem.width, mem.width << port.wide_log2);
350 }
351
352 set_state(port.data, data);
353 }
354 }
355
356 void update_ph1()
357 {
358 pool<Cell*> queue_cells;
359 pool<Wire*> queue_outports;
360
361 queue_cells.swap(dirty_cells);
362
363 while (1)
364 {
365 for (auto bit : dirty_bits)
366 {
367 if (upd_cells.count(bit))
368 for (auto cell : upd_cells.at(bit))
369 queue_cells.insert(cell);
370
371 if (upd_outports.count(bit) && parent != nullptr)
372 for (auto wire : upd_outports.at(bit))
373 queue_outports.insert(wire);
374 }
375
376 dirty_bits.clear();
377
378 if (!queue_cells.empty())
379 {
380 for (auto cell : queue_cells)
381 update_cell(cell);
382
383 queue_cells.clear();
384 continue;
385 }
386
387 for (auto &memid : dirty_memories)
388 update_memory(memid);
389 dirty_memories.clear();
390
391 for (auto wire : queue_outports)
392 if (instance->hasPort(wire->name)) {
393 Const value = get_state(wire);
394 parent->set_state(instance->getPort(wire->name), value);
395 }
396
397 queue_outports.clear();
398
399 for (auto child : dirty_children)
400 child->update_ph1();
401
402 dirty_children.clear();
403
404 if (dirty_bits.empty())
405 break;
406 }
407 }
408
409 bool update_ph2()
410 {
411 bool did_something = false;
412
413 for (auto &it : ff_database)
414 {
415 Cell *cell = it.first;
416 ff_state_t &ff = it.second;
417
418 if (cell->type.in(ID($dff)))
419 {
420 bool clkpol = cell->getParam(ID::CLK_POLARITY).as_bool();
421 State current_clock = get_state(cell->getPort(ID::CLK))[0];
422
423 if (clkpol ? (ff.past_clock == State::S1 || current_clock != State::S1) :
424 (ff.past_clock == State::S0 || current_clock != State::S0))
425 continue;
426
427 if (set_state(cell->getPort(ID::Q), ff.past_d))
428 did_something = true;
429 }
430 }
431
432 for (auto &it : mem_database)
433 {
434 mem_state_t &mdb = it.second;
435 auto &mem = *mdb.mem;
436
437 for (int port_idx = 0; port_idx < GetSize(mem.wr_ports); port_idx++)
438 {
439 auto &port = mem.wr_ports[port_idx];
440 Const addr, data, enable;
441
442 if (!port.clk_enable)
443 {
444 addr = get_state(port.addr);
445 data = get_state(port.data);
446 enable = get_state(port.en);
447 }
448 else
449 {
450 if (port.clk_polarity ?
451 (mdb.past_wr_clk[port_idx] == State::S1 || get_state(port.clk) != State::S1) :
452 (mdb.past_wr_clk[port_idx] == State::S0 || get_state(port.clk) != State::S0))
453 continue;
454
455 addr = mdb.past_wr_addr[port_idx];
456 data = mdb.past_wr_data[port_idx];
457 enable = mdb.past_wr_en[port_idx];
458 }
459
460 if (addr.is_fully_def())
461 {
462 int index = addr.as_int() - mem.start_offset;
463 if (index >= 0 && index < mem.size)
464 for (int i = 0; i < (mem.width << port.wide_log2); i++)
465 if (enable[i] == State::S1 && mdb.data.bits.at(index*mem.width+i) != data[i]) {
466 mdb.data.bits.at(index*mem.width+i) = data[i];
467 dirty_memories.insert(mem.memid);
468 did_something = true;
469 }
470 }
471 }
472 }
473
474 for (auto it : children)
475 if (it.second->update_ph2()) {
476 dirty_children.insert(it.second);
477 did_something = true;
478 }
479
480 return did_something;
481 }
482
483 void update_ph3()
484 {
485 for (auto &it : ff_database)
486 {
487 Cell *cell = it.first;
488 ff_state_t &ff = it.second;
489
490 if (cell->type.in(ID($dff))) {
491 ff.past_clock = get_state(cell->getPort(ID::CLK))[0];
492 ff.past_d = get_state(cell->getPort(ID::D));
493 }
494 }
495
496 for (auto &it : mem_database)
497 {
498 mem_state_t &mem = it.second;
499
500 for (int i = 0; i < GetSize(mem.mem->wr_ports); i++) {
501 auto &port = mem.mem->wr_ports[i];
502 mem.past_wr_clk[i] = get_state(port.clk);
503 mem.past_wr_en[i] = get_state(port.en);
504 mem.past_wr_addr[i] = get_state(port.addr);
505 mem.past_wr_data[i] = get_state(port.data);
506 }
507 }
508
509 for (auto cell : formal_database)
510 {
511 string label = log_id(cell);
512 if (cell->attributes.count(ID::src))
513 label = cell->attributes.at(ID::src).decode_string();
514
515 State a = get_state(cell->getPort(ID::A))[0];
516 State en = get_state(cell->getPort(ID::EN))[0];
517
518 if (cell->type == ID($cover) && en == State::S1 && a != State::S1)
519 log("Cover %s.%s (%s) reached.\n", hiername().c_str(), log_id(cell), label.c_str());
520
521 if (cell->type == ID($assume) && en == State::S1 && a != State::S1)
522 log("Assumption %s.%s (%s) failed.\n", hiername().c_str(), log_id(cell), label.c_str());
523
524 if (cell->type == ID($assert) && en == State::S1 && a != State::S1)
525 log_warning("Assert %s.%s (%s) failed.\n", hiername().c_str(), log_id(cell), label.c_str());
526 }
527
528 for (auto it : children)
529 it.second->update_ph3();
530 }
531
532 void writeback(pool<Module*> &wbmods)
533 {
534 if (wbmods.count(module))
535 log_error("Instance %s of module %s is not unique: Writeback not possible. (Fix by running 'uniquify'.)\n", hiername().c_str(), log_id(module));
536
537 wbmods.insert(module);
538
539 for (auto wire : module->wires())
540 wire->attributes.erase(ID::init);
541
542 for (auto &it : ff_database)
543 {
544 Cell *cell = it.first;
545 SigSpec sig_q = cell->getPort(ID::Q);
546 Const initval = get_state(sig_q);
547
548 for (int i = 0; i < GetSize(sig_q); i++)
549 {
550 Wire *w = sig_q[i].wire;
551
552 if (w->attributes.count(ID::init) == 0)
553 w->attributes[ID::init] = Const(State::Sx, GetSize(w));
554
555 w->attributes[ID::init][sig_q[i].offset] = initval[i];
556 }
557 }
558
559 for (auto &it : mem_database)
560 {
561 mem_state_t &mem = it.second;
562 mem.mem->clear_inits();
563 MemInit minit;
564 minit.addr = mem.mem->start_offset;
565 minit.data = mem.data;
566 minit.en = Const(State::S1, mem.mem->width);
567 mem.mem->inits.push_back(minit);
568 mem.mem->emit();
569 }
570
571 for (auto it : children)
572 it.second->writeback(wbmods);
573 }
574
575 void write_vcd_header(std::ofstream &f, int &id)
576 {
577 f << stringf("$scope module %s $end\n", log_id(name()));
578
579 for (auto wire : module->wires())
580 {
581 if (shared->hide_internal && wire->name[0] == '$')
582 continue;
583
584 f << stringf("$var wire %d n%d %s%s $end\n", GetSize(wire), id, wire->name[0] == '$' ? "\\" : "", log_id(wire));
585 vcd_database[wire] = make_pair(id++, Const());
586 }
587
588 for (auto child : children)
589 child.second->write_vcd_header(f, id);
590
591 f << stringf("$upscope $end\n");
592 }
593
594 void write_vcd_step(std::ofstream &f)
595 {
596 for (auto &it : vcd_database)
597 {
598 Wire *wire = it.first;
599 Const value = get_state(wire);
600 int id = it.second.first;
601
602 if (it.second.second == value)
603 continue;
604
605 it.second.second = value;
606
607 f << "b";
608 for (int i = GetSize(value)-1; i >= 0; i--) {
609 switch (value[i]) {
610 case State::S0: f << "0"; break;
611 case State::S1: f << "1"; break;
612 case State::Sx: f << "x"; break;
613 default: f << "z";
614 }
615 }
616
617 f << stringf(" n%d\n", id);
618 }
619
620 for (auto child : children)
621 child.second->write_vcd_step(f);
622 }
623
624 void write_fst_header(struct fstContext *f)
625 {
626 fstWriterSetScope(f, FST_ST_VCD_MODULE, stringf("%s",log_id(name())).c_str(), nullptr);
627 for (auto wire : module->wires())
628 {
629 if (shared->hide_internal && wire->name[0] == '$')
630 continue;
631
632 fstHandle id = fstWriterCreateVar(f, FST_VT_VCD_WIRE, FST_VD_IMPLICIT, GetSize(wire),
633 stringf("%s%s", wire->name[0] == '$' ? "\\" : "", log_id(wire)).c_str(), 0);
634 fst_database[wire] = make_pair(id, Const());
635 }
636
637 for (auto child : children)
638 child.second->write_fst_header(f);
639
640 fstWriterSetUpscope(f);
641 }
642
643 void write_fst_step(struct fstContext *f)
644 {
645 for (auto &it : fst_database)
646 {
647 Wire *wire = it.first;
648 Const value = get_state(wire);
649 fstHandle id = it.second.first;
650
651 if (it.second.second == value)
652 continue;
653
654 it.second.second = value;
655 std::stringstream ss;
656 for (int i = GetSize(value)-1; i >= 0; i--) {
657 switch (value[i]) {
658 case State::S0: ss << "0"; break;
659 case State::S1: ss << "1"; break;
660 case State::Sx: ss << "x"; break;
661 default: ss << "z";
662 }
663 }
664 fstWriterEmitValueChange(f, id, ss.str().c_str());
665 }
666
667 for (auto child : children)
668 child.second->write_fst_step(f);
669 }
670 };
671
672 struct SimWorker : SimShared
673 {
674 SimInstance *top = nullptr;
675 std::ofstream vcdfile;
676 struct fstContext *fstfile = nullptr;
677 pool<IdString> clock, clockn, reset, resetn;
678 std::string timescale;
679 std::string sim_filename;
680 std::string scope;
681
682 ~SimWorker()
683 {
684 delete top;
685 }
686
687 void write_vcd_header()
688 {
689 vcdfile << stringf("$version %s $end\n", yosys_version_str);
690
691 std::time_t t = std::time(nullptr);
692 char mbstr[255];
693 if (std::strftime(mbstr, sizeof(mbstr), "%c", std::localtime(&t))) {
694 vcdfile << stringf("$date ") << mbstr << stringf(" $end\n");
695 }
696
697 if (!timescale.empty())
698 vcdfile << stringf("$timescale %s $end\n", timescale.c_str());
699
700 int id = 1;
701 top->write_vcd_header(vcdfile, id);
702
703 vcdfile << stringf("$enddefinitions $end\n");
704 }
705
706 void write_vcd_step(int t)
707 {
708 vcdfile << stringf("#%d\n", t);
709 top->write_vcd_step(vcdfile);
710 }
711
712 void write_fst_header()
713 {
714 std::time_t t = std::time(nullptr);
715 fstWriterSetDate(fstfile, asctime(std::localtime(&t)));
716 fstWriterSetVersion(fstfile, yosys_version_str);
717 if (!timescale.empty())
718 fstWriterSetTimescaleFromString(fstfile, timescale.c_str());
719
720 fstWriterSetPackType(fstfile, FST_WR_PT_FASTLZ);
721 fstWriterSetRepackOnClose(fstfile, 1);
722
723 top->write_fst_header(fstfile);
724 }
725
726 void write_fst_step(int t)
727 {
728 fstWriterEmitTimeChange(fstfile, t);
729
730 top->write_fst_step(fstfile);
731 }
732
733 void write_output_header()
734 {
735 if (vcdfile.is_open())
736 write_vcd_header();
737 if (fstfile)
738 write_fst_header();
739 }
740
741 void write_output_step(int t)
742 {
743 if (vcdfile.is_open())
744 write_vcd_step(t);
745 if (fstfile)
746 write_fst_step(t);
747 }
748
749 void write_output_end()
750 {
751 if (fstfile)
752 fstWriterClose(fstfile);
753 }
754
755 void update()
756 {
757 while (1)
758 {
759 if (debug)
760 log("\n-- ph1 --\n");
761
762 top->update_ph1();
763
764 if (debug)
765 log("\n-- ph2 --\n");
766
767 if (!top->update_ph2())
768 break;
769 }
770
771 if (debug)
772 log("\n-- ph3 --\n");
773
774 top->update_ph3();
775 }
776
777 void set_inports(pool<IdString> ports, State value)
778 {
779 for (auto portname : ports)
780 {
781 Wire *w = top->module->wire(portname);
782
783 if (w == nullptr)
784 log_error("Can't find port %s on module %s.\n", log_id(portname), log_id(top->module));
785
786 top->set_state(w, value);
787 }
788 }
789
790 void run(Module *topmod, int numcycles)
791 {
792 log_assert(top == nullptr);
793 top = new SimInstance(this, scope, topmod);
794
795 if (debug)
796 log("\n===== 0 =====\n");
797 else
798 log("Simulating cycle 0.\n");
799
800 set_inports(reset, State::S1);
801 set_inports(resetn, State::S0);
802
803 set_inports(clock, State::Sx);
804 set_inports(clockn, State::Sx);
805
806 update();
807
808 write_output_header();
809 write_output_step(0);
810
811 for (int cycle = 0; cycle < numcycles; cycle++)
812 {
813 if (debug)
814 log("\n===== %d =====\n", 10*cycle + 5);
815
816 set_inports(clock, State::S0);
817 set_inports(clockn, State::S1);
818
819 update();
820 write_output_step(10*cycle + 5);
821
822 if (debug)
823 log("\n===== %d =====\n", 10*cycle + 10);
824 else
825 log("Simulating cycle %d.\n", cycle+1);
826
827 set_inports(clock, State::S1);
828 set_inports(clockn, State::S0);
829
830 if (cycle+1 == rstlen) {
831 set_inports(reset, State::S0);
832 set_inports(resetn, State::S1);
833 }
834
835 update();
836 write_output_step(10*cycle + 10);
837 }
838
839 write_output_step(10*numcycles + 2);
840
841 write_output_end();
842
843 if (writeback) {
844 pool<Module*> wbmods;
845 top->writeback(wbmods);
846 }
847 }
848
849 void run_cosim(Module *topmod, int numcycles)
850 {
851 log_assert(top == nullptr);
852 top = new SimInstance(this, scope, topmod);
853
854 fst = new FstData(sim_filename);
855
856 std::vector<fstHandle> fst_clock;
857
858 for (auto portname : clock)
859 {
860 Wire *w = topmod->wire(portname);
861 if (!w)
862 log_error("Can't find port %s on module %s.\n", log_id(portname), log_id(top->module));
863 if (!w->port_input)
864 log_error("Clock port %s on module %s is not input.\n", log_id(portname), log_id(top->module));
865 fstHandle id = fst->getHandle(scope + "." + RTLIL::unescape_id(portname));
866 if (id==0)
867 log_error("Can't find port %s.%s in FST.\n", scope.c_str(), log_id(portname));
868 fst_clock.push_back(id);
869 }
870 for (auto portname : clockn)
871 {
872 Wire *w = topmod->wire(portname);
873 if (!w)
874 log_error("Can't find port %s on module %s.\n", log_id(portname), log_id(top->module));
875 if (!w->port_input)
876 log_error("Clock port %s on module %s is not input.\n", log_id(portname), log_id(top->module));
877 fstHandle id = fst->getHandle(scope + "." + RTLIL::unescape_id(portname));
878 if (id==0)
879 log_error("Can't find port %s.%s in FST.\n", scope.c_str(), log_id(portname));
880 fst_clock.push_back(id);
881 }
882 if (fst_clock.size()==0)
883 log_error("No clock signals defined for input file\n");
884
885 SigMap sigmap(topmod);
886 log ("Get inputs\n");
887 std::map<Wire*,fstHandle> inputs;
888 std::map<Wire*,fstHandle> outputs;
889
890 for (auto wire : topmod->wires()) {
891 if (wire->port_input) {
892 fstHandle id = fst->getHandle(scope + "." + RTLIL::unescape_id(wire->name));
893 log("Input %s\n",log_id(wire));
894 inputs[wire] = id;
895 }
896 if (wire->port_output) {
897 fstHandle id = fst->getHandle(scope + "." + RTLIL::unescape_id(wire->name));
898 log("Output %s %d\n",log_id(wire), id);
899 outputs[wire] = id;
900 }
901 }
902
903 fst->reconstruct(fst_clock);
904 auto edges = fst->edges(fst_clock.back(), true, true);
905 fst->reconstructAllAtTimes(edges);
906 for(auto &time : edges) {
907 for(auto &item : inputs) {
908 std::string v = fst->valueAt(item.second, time);
909 top->set_state(item.first, Const::from_string(v));
910 }
911 update();
912 for(auto &item : outputs) {
913 Const fst_val = Const::from_string(fst->valueAt(item.second, time));
914 Const sim_val = top->get_state(item.first);
915 log("%s %s\n", log_signal(fst_val), log_signal(sim_val));
916 }
917 }
918 }
919 };
920
921 struct SimPass : public Pass {
922 SimPass() : Pass("sim", "simulate the circuit") { }
923 void help() override
924 {
925 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
926 log("\n");
927 log(" sim [options] [top-level]\n");
928 log("\n");
929 log("This command simulates the circuit using the given top-level module.\n");
930 log("\n");
931 log(" -vcd <filename>\n");
932 log(" write the simulation results to the given VCD file\n");
933 log("\n");
934 log(" -fst <filename>\n");
935 log(" write the simulation results to the given FST file\n");
936 log("\n");
937 log(" -clock <portname>\n");
938 log(" name of top-level clock input\n");
939 log("\n");
940 log(" -clockn <portname>\n");
941 log(" name of top-level clock input (inverse polarity)\n");
942 log("\n");
943 log(" -reset <portname>\n");
944 log(" name of top-level reset input (active high)\n");
945 log("\n");
946 log(" -resetn <portname>\n");
947 log(" name of top-level inverted reset input (active low)\n");
948 log("\n");
949 log(" -rstlen <integer>\n");
950 log(" number of cycles reset should stay active (default: 1)\n");
951 log("\n");
952 log(" -zinit\n");
953 log(" zero-initialize all uninitialized regs and memories\n");
954 log("\n");
955 log(" -timescale <string>\n");
956 log(" include the specified timescale declaration in the vcd\n");
957 log("\n");
958 log(" -n <integer>\n");
959 log(" number of cycles to simulate (default: 20)\n");
960 log("\n");
961 log(" -a\n");
962 log(" include all nets in VCD output, not just those with public names\n");
963 log("\n");
964 log(" -w\n");
965 log(" writeback mode: use final simulation state as new init state\n");
966 log("\n");
967 log(" -r\n");
968 log(" read simulation results file (file formats supported: FST)\n");
969 log("\n");
970 log(" -scope\n");
971 log(" scope of simulation top model\n");
972 log("\n");
973 log(" -d\n");
974 log(" enable debug output\n");
975 log("\n");
976 }
977 void execute(std::vector<std::string> args, RTLIL::Design *design) override
978 {
979 SimWorker worker;
980 int numcycles = 20;
981
982 log_header(design, "Executing SIM pass (simulate the circuit).\n");
983
984 size_t argidx;
985 for (argidx = 1; argidx < args.size(); argidx++) {
986 if (args[argidx] == "-vcd" && argidx+1 < args.size()) {
987 std::string vcd_filename = args[++argidx];
988 rewrite_filename(vcd_filename);
989 worker.vcdfile.open(vcd_filename.c_str());
990 continue;
991 }
992 if (args[argidx] == "-fst" && argidx+1 < args.size()) {
993 std::string fst_filename = args[++argidx];
994 rewrite_filename(fst_filename);
995 worker.fstfile = (struct fstContext *)fstWriterCreate(fst_filename.c_str(),1);
996 continue;
997 }
998 if (args[argidx] == "-n" && argidx+1 < args.size()) {
999 numcycles = atoi(args[++argidx].c_str());
1000 continue;
1001 }
1002 if (args[argidx] == "-rstlen" && argidx+1 < args.size()) {
1003 worker.rstlen = atoi(args[++argidx].c_str());
1004 continue;
1005 }
1006 if (args[argidx] == "-clock" && argidx+1 < args.size()) {
1007 worker.clock.insert(RTLIL::escape_id(args[++argidx]));
1008 continue;
1009 }
1010 if (args[argidx] == "-clockn" && argidx+1 < args.size()) {
1011 worker.clockn.insert(RTLIL::escape_id(args[++argidx]));
1012 continue;
1013 }
1014 if (args[argidx] == "-reset" && argidx+1 < args.size()) {
1015 worker.reset.insert(RTLIL::escape_id(args[++argidx]));
1016 continue;
1017 }
1018 if (args[argidx] == "-resetn" && argidx+1 < args.size()) {
1019 worker.resetn.insert(RTLIL::escape_id(args[++argidx]));
1020 continue;
1021 }
1022 if (args[argidx] == "-timescale" && argidx+1 < args.size()) {
1023 worker.timescale = args[++argidx];
1024 continue;
1025 }
1026 if (args[argidx] == "-a") {
1027 worker.hide_internal = false;
1028 continue;
1029 }
1030 if (args[argidx] == "-d") {
1031 worker.debug = true;
1032 continue;
1033 }
1034 if (args[argidx] == "-w") {
1035 worker.writeback = true;
1036 continue;
1037 }
1038 if (args[argidx] == "-zinit") {
1039 worker.zinit = true;
1040 continue;
1041 }
1042 if (args[argidx] == "-r" && argidx+1 < args.size()) {
1043 std::string sim_filename = args[++argidx];
1044 rewrite_filename(sim_filename);
1045 worker.sim_filename = sim_filename;
1046 continue;
1047 }
1048 if (args[argidx] == "-scope" && argidx+1 < args.size()) {
1049 worker.scope = args[++argidx];
1050 continue;
1051 }
1052 break;
1053 }
1054 extra_args(args, argidx, design);
1055
1056 Module *top_mod = nullptr;
1057
1058 if (design->full_selection()) {
1059 top_mod = design->top_module();
1060
1061 if (!top_mod)
1062 log_cmd_error("Design has no top module, use the 'hierarchy' command to specify one.\n");
1063 } else {
1064 auto mods = design->selected_whole_modules();
1065 if (GetSize(mods) != 1)
1066 log_cmd_error("Only one top module must be selected.\n");
1067 top_mod = mods.front();
1068 }
1069
1070 if (worker.sim_filename.empty())
1071 worker.run(top_mod, numcycles);
1072 else
1073 worker.run_cosim(top_mod, numcycles);
1074 }
1075 } SimPass;
1076
1077 PRIVATE_NAMESPACE_END