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