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