Merge pull request #3203 from YosysHQ/micko/sim_ff
[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 // set if no ce, or ce is enabled
491 if (!ff_data.has_ce || (ff_data.has_ce && ce)) {
492 current_q = ff.past_d;
493 }
494 // override if sync reset
495 if ((ff_data.has_srst) && (ff.past_srst == (ff_data.pol_srst ? State::S1 : State::S0)) &&
496 ((!ff_data.ce_over_srst) || (ff_data.ce_over_srst && ce))) {
497 current_q = ff_data.val_srst;
498 }
499 }
500 }
501 // async load
502 if (ff_data.has_aload) {
503 State current_aload = get_state(ff_data.sig_aload)[0];
504 if (current_aload == (ff_data.pol_aload ? State::S1 : State::S0)) {
505 current_q = ff_data.has_clk ? ff.past_ad : get_state(ff.data.sig_ad);
506 }
507 }
508 // async reset
509 if (ff_data.has_arst) {
510 State current_arst = get_state(ff_data.sig_arst)[0];
511 if (current_arst == (ff_data.pol_arst ? State::S1 : State::S0)) {
512 current_q = ff_data.val_arst;
513 }
514 }
515 // handle set/reset
516 if (ff.data.has_sr) {
517 Const current_clr = get_state(ff.data.sig_clr);
518 Const current_set = get_state(ff.data.sig_set);
519
520 for(int i=0;i<ff.past_d.size();i++) {
521 if (current_clr[i] == (ff_data.pol_clr ? State::S1 : State::S0)) {
522 current_q[i] = State::S0;
523 }
524 else if (current_set[i] == (ff_data.pol_set ? State::S1 : State::S0)) {
525 current_q[i] = State::S1;
526 }
527 }
528 }
529 if (ff_data.has_gclk) {
530 // $ff
531 current_q = ff.past_d;
532 }
533 if (set_state(ff_data.sig_q, current_q))
534 did_something = true;
535 }
536
537 for (auto &it : mem_database)
538 {
539 mem_state_t &mdb = it.second;
540 auto &mem = *mdb.mem;
541
542 for (int port_idx = 0; port_idx < GetSize(mem.wr_ports); port_idx++)
543 {
544 auto &port = mem.wr_ports[port_idx];
545 Const addr, data, enable;
546
547 if (!port.clk_enable)
548 {
549 addr = get_state(port.addr);
550 data = get_state(port.data);
551 enable = get_state(port.en);
552 }
553 else
554 {
555 if (port.clk_polarity ?
556 (mdb.past_wr_clk[port_idx] == State::S1 || get_state(port.clk) != State::S1) :
557 (mdb.past_wr_clk[port_idx] == State::S0 || get_state(port.clk) != State::S0))
558 continue;
559
560 addr = mdb.past_wr_addr[port_idx];
561 data = mdb.past_wr_data[port_idx];
562 enable = mdb.past_wr_en[port_idx];
563 }
564
565 if (addr.is_fully_def())
566 {
567 int index = addr.as_int() - mem.start_offset;
568 if (index >= 0 && index < mem.size)
569 for (int i = 0; i < (mem.width << port.wide_log2); i++)
570 if (enable[i] == State::S1 && mdb.data.bits.at(index*mem.width+i) != data[i]) {
571 mdb.data.bits.at(index*mem.width+i) = data[i];
572 dirty_memories.insert(mem.memid);
573 did_something = true;
574 }
575 }
576 }
577 }
578
579 for (auto it : children)
580 if (it.second->update_ph2()) {
581 dirty_children.insert(it.second);
582 did_something = true;
583 }
584
585 return did_something;
586 }
587
588 void update_ph3()
589 {
590 for (auto &it : ff_database)
591 {
592 ff_state_t &ff = it.second;
593
594 if (ff.data.has_aload)
595 ff.past_ad = get_state(ff.data.sig_ad);
596
597 if (ff.data.has_clk || ff.data.has_gclk)
598 ff.past_d = get_state(ff.data.sig_d);
599
600 if (ff.data.has_clk)
601 ff.past_clk = get_state(ff.data.sig_clk)[0];
602
603 if (ff.data.has_ce)
604 ff.past_ce = get_state(ff.data.sig_ce)[0];
605
606 if (ff.data.has_srst)
607 ff.past_srst = get_state(ff.data.sig_srst)[0];
608 }
609
610 for (auto &it : mem_database)
611 {
612 mem_state_t &mem = it.second;
613
614 for (int i = 0; i < GetSize(mem.mem->wr_ports); i++) {
615 auto &port = mem.mem->wr_ports[i];
616 mem.past_wr_clk[i] = get_state(port.clk);
617 mem.past_wr_en[i] = get_state(port.en);
618 mem.past_wr_addr[i] = get_state(port.addr);
619 mem.past_wr_data[i] = get_state(port.data);
620 }
621 }
622
623 for (auto cell : formal_database)
624 {
625 string label = log_id(cell);
626 if (cell->attributes.count(ID::src))
627 label = cell->attributes.at(ID::src).decode_string();
628
629 State a = get_state(cell->getPort(ID::A))[0];
630 State en = get_state(cell->getPort(ID::EN))[0];
631
632 if (cell->type == ID($cover) && en == State::S1 && a != State::S1)
633 log("Cover %s.%s (%s) reached.\n", hiername().c_str(), log_id(cell), label.c_str());
634
635 if (cell->type == ID($assume) && en == State::S1 && a != State::S1)
636 log("Assumption %s.%s (%s) failed.\n", hiername().c_str(), log_id(cell), label.c_str());
637
638 if (cell->type == ID($assert) && en == State::S1 && a != State::S1)
639 log_warning("Assert %s.%s (%s) failed.\n", hiername().c_str(), log_id(cell), label.c_str());
640 }
641
642 for (auto it : children)
643 it.second->update_ph3();
644 }
645
646 void writeback(pool<Module*> &wbmods)
647 {
648 if (wbmods.count(module))
649 log_error("Instance %s of module %s is not unique: Writeback not possible. (Fix by running 'uniquify'.)\n", hiername().c_str(), log_id(module));
650
651 wbmods.insert(module);
652
653 for (auto wire : module->wires())
654 wire->attributes.erase(ID::init);
655
656 for (auto &it : ff_database)
657 {
658 SigSpec sig_q = it.second.data.sig_q;
659 Const initval = get_state(sig_q);
660
661 for (int i = 0; i < GetSize(sig_q); i++)
662 {
663 Wire *w = sig_q[i].wire;
664
665 if (w->attributes.count(ID::init) == 0)
666 w->attributes[ID::init] = Const(State::Sx, GetSize(w));
667
668 w->attributes[ID::init][sig_q[i].offset] = initval[i];
669 }
670 }
671
672 for (auto &it : mem_database)
673 {
674 mem_state_t &mem = it.second;
675 mem.mem->clear_inits();
676 MemInit minit;
677 minit.addr = mem.mem->start_offset;
678 minit.data = mem.data;
679 minit.en = Const(State::S1, mem.mem->width);
680 mem.mem->inits.push_back(minit);
681 mem.mem->emit();
682 }
683
684 for (auto it : children)
685 it.second->writeback(wbmods);
686 }
687
688 void write_vcd_header(std::ofstream &f, int &id)
689 {
690 f << stringf("$scope module %s $end\n", log_id(name()));
691
692 for (auto wire : module->wires())
693 {
694 if (shared->hide_internal && wire->name[0] == '$')
695 continue;
696
697 f << stringf("$var wire %d n%d %s%s $end\n", GetSize(wire), id, wire->name[0] == '$' ? "\\" : "", log_id(wire));
698 vcd_database[wire] = make_pair(id++, Const());
699 }
700
701 for (auto child : children)
702 child.second->write_vcd_header(f, id);
703
704 f << stringf("$upscope $end\n");
705 }
706
707 void write_vcd_step(std::ofstream &f)
708 {
709 for (auto &it : vcd_database)
710 {
711 Wire *wire = it.first;
712 Const value = get_state(wire);
713 int id = it.second.first;
714
715 if (it.second.second == value)
716 continue;
717
718 it.second.second = value;
719
720 f << "b";
721 for (int i = GetSize(value)-1; i >= 0; i--) {
722 switch (value[i]) {
723 case State::S0: f << "0"; break;
724 case State::S1: f << "1"; break;
725 case State::Sx: f << "x"; break;
726 default: f << "z";
727 }
728 }
729
730 f << stringf(" n%d\n", id);
731 }
732
733 for (auto child : children)
734 child.second->write_vcd_step(f);
735 }
736
737 void write_fst_header(struct fstContext *f)
738 {
739 fstWriterSetScope(f, FST_ST_VCD_MODULE, stringf("%s",log_id(name())).c_str(), nullptr);
740 for (auto wire : module->wires())
741 {
742 if (shared->hide_internal && wire->name[0] == '$')
743 continue;
744
745 fstHandle id = fstWriterCreateVar(f, FST_VT_VCD_WIRE, FST_VD_IMPLICIT, GetSize(wire),
746 stringf("%s%s", wire->name[0] == '$' ? "\\" : "", log_id(wire)).c_str(), 0);
747 fst_database[wire] = make_pair(id, Const());
748 }
749
750 for (auto child : children)
751 child.second->write_fst_header(f);
752
753 fstWriterSetUpscope(f);
754 }
755
756 void write_fst_step(struct fstContext *f)
757 {
758 for (auto &it : fst_database)
759 {
760 Wire *wire = it.first;
761 Const value = get_state(wire);
762 fstHandle id = it.second.first;
763
764 if (it.second.second == value)
765 continue;
766
767 it.second.second = value;
768 std::stringstream ss;
769 for (int i = GetSize(value)-1; i >= 0; i--) {
770 switch (value[i]) {
771 case State::S0: ss << "0"; break;
772 case State::S1: ss << "1"; break;
773 case State::Sx: ss << "x"; break;
774 default: ss << "z";
775 }
776 }
777 fstWriterEmitValueChange(f, id, ss.str().c_str());
778 }
779
780 for (auto child : children)
781 child.second->write_fst_step(f);
782 }
783
784 void setInitState()
785 {
786 for (auto &it : ff_database)
787 {
788 SigSpec qsig = it.second.data.sig_q;
789 if (qsig.is_wire()) {
790 IdString name = qsig.as_wire()->name;
791 fstHandle id = shared->fst->getHandle(scope + "." + RTLIL::unescape_id(name));
792 if (id==0 && name.isPublic())
793 log_warning("Unable to found wire %s in input file.\n", (scope + "." + RTLIL::unescape_id(name)).c_str());
794 if (id!=0) {
795 Const fst_val = Const::from_string(shared->fst->valueOf(id));
796 set_state(qsig, fst_val);
797 }
798 }
799 }
800 for (auto child : children)
801 child.second->setInitState();
802 }
803
804 bool checkSignals()
805 {
806 bool retVal = false;
807 for(auto &item : fst_handles) {
808 if (item.second==0) continue; // Ignore signals not found
809 Const fst_val = Const::from_string(shared->fst->valueOf(item.second));
810 Const sim_val = get_state(item.first);
811 if (sim_val.size()!=fst_val.size())
812 log_error("Signal '%s' size is different in gold and gate.\n", log_id(item.first));
813 if (shared->sim_mode == SimulationMode::sim) {
814 // No checks performed when using stimulus
815 } else if (shared->sim_mode == SimulationMode::gate && !fst_val.is_fully_def()) { // FST data contains X
816 for(int i=0;i<fst_val.size();i++) {
817 if (fst_val[i]!=State::Sx && fst_val[i]!=sim_val[i]) {
818 log_warning("Signal '%s' in file %s in simulation %s\n", log_id(item.first), log_signal(fst_val), log_signal(sim_val));
819 retVal = true;
820 break;
821 }
822 }
823 } else if (shared->sim_mode == SimulationMode::gold && !sim_val.is_fully_def()) { // sim data contains X
824 for(int i=0;i<sim_val.size();i++) {
825 if (sim_val[i]!=State::Sx && fst_val[i]!=sim_val[i]) {
826 log_warning("Signal '%s' in file %s in simulation %s\n", log_id(item.first), log_signal(fst_val), log_signal(sim_val));
827 retVal = true;
828 break;
829 }
830 }
831 } else {
832 if (fst_val!=sim_val) {
833 log_warning("Signal '%s' in file %s in simulation '%s'\n", log_id(item.first), log_signal(fst_val), log_signal(sim_val));
834 retVal = true;
835 }
836 }
837 }
838 for (auto child : children)
839 retVal |= child.second->checkSignals();
840 return retVal;
841 }
842 };
843
844 struct SimWorker : SimShared
845 {
846 SimInstance *top = nullptr;
847 std::ofstream vcdfile;
848 struct fstContext *fstfile = nullptr;
849 pool<IdString> clock, clockn, reset, resetn;
850 std::string timescale;
851 std::string sim_filename;
852 std::string scope;
853
854 ~SimWorker()
855 {
856 delete top;
857 }
858
859 void write_vcd_header()
860 {
861 vcdfile << stringf("$version %s $end\n", yosys_version_str);
862
863 std::time_t t = std::time(nullptr);
864 char mbstr[255];
865 if (std::strftime(mbstr, sizeof(mbstr), "%c", std::localtime(&t))) {
866 vcdfile << stringf("$date ") << mbstr << stringf(" $end\n");
867 }
868
869 if (!timescale.empty())
870 vcdfile << stringf("$timescale %s $end\n", timescale.c_str());
871
872 int id = 1;
873 top->write_vcd_header(vcdfile, id);
874
875 vcdfile << stringf("$enddefinitions $end\n");
876 }
877
878 void write_vcd_step(int t)
879 {
880 vcdfile << stringf("#%d\n", t);
881 top->write_vcd_step(vcdfile);
882 }
883
884 void write_fst_header()
885 {
886 std::time_t t = std::time(nullptr);
887 fstWriterSetDate(fstfile, asctime(std::localtime(&t)));
888 fstWriterSetVersion(fstfile, yosys_version_str);
889 if (!timescale.empty())
890 fstWriterSetTimescaleFromString(fstfile, timescale.c_str());
891
892 fstWriterSetPackType(fstfile, FST_WR_PT_FASTLZ);
893 fstWriterSetRepackOnClose(fstfile, 1);
894
895 top->write_fst_header(fstfile);
896 }
897
898 void write_fst_step(int t)
899 {
900 fstWriterEmitTimeChange(fstfile, t);
901
902 top->write_fst_step(fstfile);
903 }
904
905 void write_output_header()
906 {
907 if (vcdfile.is_open())
908 write_vcd_header();
909 if (fstfile)
910 write_fst_header();
911 }
912
913 void write_output_step(int t)
914 {
915 if (vcdfile.is_open())
916 write_vcd_step(t);
917 if (fstfile)
918 write_fst_step(t);
919 }
920
921 void write_output_end()
922 {
923 if (fstfile)
924 fstWriterClose(fstfile);
925 }
926
927 void update()
928 {
929 while (1)
930 {
931 if (debug)
932 log("\n-- ph1 --\n");
933
934 top->update_ph1();
935
936 if (debug)
937 log("\n-- ph2 --\n");
938
939 if (!top->update_ph2())
940 break;
941 }
942
943 if (debug)
944 log("\n-- ph3 --\n");
945
946 top->update_ph3();
947 }
948
949 void set_inports(pool<IdString> ports, State value)
950 {
951 for (auto portname : ports)
952 {
953 Wire *w = top->module->wire(portname);
954
955 if (w == nullptr)
956 log_error("Can't find port %s on module %s.\n", log_id(portname), log_id(top->module));
957
958 top->set_state(w, value);
959 }
960 }
961
962 void run(Module *topmod, int numcycles)
963 {
964 log_assert(top == nullptr);
965 top = new SimInstance(this, scope, topmod);
966
967 if (debug)
968 log("\n===== 0 =====\n");
969 else
970 log("Simulating cycle 0.\n");
971
972 set_inports(reset, State::S1);
973 set_inports(resetn, State::S0);
974
975 set_inports(clock, State::Sx);
976 set_inports(clockn, State::Sx);
977
978 update();
979
980 write_output_header();
981 write_output_step(0);
982
983 for (int cycle = 0; cycle < numcycles; cycle++)
984 {
985 if (debug)
986 log("\n===== %d =====\n", 10*cycle + 5);
987 else
988 log("Simulating cycle %d.\n", (cycle*2)+1);
989 set_inports(clock, State::S0);
990 set_inports(clockn, State::S1);
991
992 update();
993 write_output_step(10*cycle + 5);
994
995 if (debug)
996 log("\n===== %d =====\n", 10*cycle + 10);
997 else
998 log("Simulating cycle %d.\n", (cycle*2)+2);
999
1000 set_inports(clock, State::S1);
1001 set_inports(clockn, State::S0);
1002
1003 if (cycle+1 == rstlen) {
1004 set_inports(reset, State::S0);
1005 set_inports(resetn, State::S1);
1006 }
1007
1008 update();
1009 write_output_step(10*cycle + 10);
1010 }
1011
1012 write_output_step(10*numcycles + 2);
1013
1014 write_output_end();
1015
1016 if (writeback) {
1017 pool<Module*> wbmods;
1018 top->writeback(wbmods);
1019 }
1020 }
1021
1022 void run_cosim(Module *topmod, int numcycles)
1023 {
1024 log_assert(top == nullptr);
1025 fst = new FstData(sim_filename);
1026
1027 if (scope.empty())
1028 log_error("Scope must be defined for co-simulation.\n");
1029
1030 top = new SimInstance(this, scope, topmod);
1031
1032 std::vector<fstHandle> fst_clock;
1033
1034 for (auto portname : clock)
1035 {
1036 Wire *w = topmod->wire(portname);
1037 if (!w)
1038 log_error("Can't find port %s on module %s.\n", log_id(portname), log_id(top->module));
1039 if (!w->port_input)
1040 log_error("Clock port %s on module %s is not input.\n", log_id(portname), log_id(top->module));
1041 fstHandle id = fst->getHandle(scope + "." + RTLIL::unescape_id(portname));
1042 if (id==0)
1043 log_error("Can't find port %s.%s in FST.\n", scope.c_str(), log_id(portname));
1044 fst_clock.push_back(id);
1045 }
1046 for (auto portname : clockn)
1047 {
1048 Wire *w = topmod->wire(portname);
1049 if (!w)
1050 log_error("Can't find port %s on module %s.\n", log_id(portname), log_id(top->module));
1051 if (!w->port_input)
1052 log_error("Clock port %s on module %s is not input.\n", log_id(portname), log_id(top->module));
1053 fstHandle id = fst->getHandle(scope + "." + RTLIL::unescape_id(portname));
1054 if (id==0)
1055 log_error("Can't find port %s.%s in FST.\n", scope.c_str(), log_id(portname));
1056 fst_clock.push_back(id);
1057 }
1058
1059 SigMap sigmap(topmod);
1060 std::map<Wire*,fstHandle> inputs;
1061
1062 for (auto wire : topmod->wires()) {
1063 if (wire->port_input) {
1064 fstHandle id = fst->getHandle(scope + "." + RTLIL::unescape_id(wire->name));
1065 if (id==0)
1066 log_error("Unable to find required '%s' signal in file\n",(scope + "." + RTLIL::unescape_id(wire->name)).c_str());
1067 inputs[wire] = id;
1068 }
1069 }
1070
1071 uint64_t startCount = 0;
1072 uint64_t stopCount = 0;
1073 if (start_time==0) {
1074 if (start_time < fst->getStartTime())
1075 log_warning("Start time is before simulation file start time\n");
1076 startCount = fst->getStartTime();
1077 } else if (start_time==-1)
1078 startCount = fst->getEndTime();
1079 else {
1080 startCount = start_time / fst->getTimescale();
1081 if (startCount > fst->getEndTime()) {
1082 startCount = fst->getEndTime();
1083 log_warning("Start time is after simulation file end time\n");
1084 }
1085 }
1086 if (stop_time==0) {
1087 if (stop_time < fst->getStartTime())
1088 log_warning("Stop time is before simulation file start time\n");
1089 stopCount = fst->getStartTime();
1090 } else if (stop_time==-1)
1091 stopCount = fst->getEndTime();
1092 else {
1093 stopCount = stop_time / fst->getTimescale();
1094 if (stopCount > fst->getEndTime()) {
1095 stopCount = fst->getEndTime();
1096 log_warning("Stop time is after simulation file end time\n");
1097 }
1098 }
1099 if (stopCount<startCount) {
1100 log_error("Stop time is before start time\n");
1101 }
1102
1103 bool initial = true;
1104 int cycle = 0;
1105 log("Co-simulation from %lu%s to %lu%s", (unsigned long)startCount, fst->getTimescaleString(), (unsigned long)stopCount, fst->getTimescaleString());
1106 if (cycles_set)
1107 log(" for %d clock cycle(s)",numcycles);
1108 log("\n");
1109 bool all_samples = fst_clock.empty();
1110
1111 try {
1112 fst->reconstructAllAtTimes(fst_clock, startCount, stopCount, [&](uint64_t time) {
1113 log("Co-simulating %s %d [%lu%s].\n", (all_samples ? "sample" : "cycle"), cycle, (unsigned long)time, fst->getTimescaleString());
1114 for(auto &item : inputs) {
1115 std::string v = fst->valueOf(item.second);
1116 top->set_state(item.first, Const::from_string(v));
1117 }
1118
1119 if (initial) {
1120 top->setInitState();
1121 write_output_header();
1122 initial = false;
1123 }
1124 update();
1125 write_output_step(5*cycle);
1126
1127 bool status = top->checkSignals();
1128 if (status)
1129 log_error("Signal difference\n");
1130 cycle++;
1131
1132 // Limit to number of cycles if provided
1133 if (cycles_set && cycle > numcycles *2)
1134 throw fst_end_of_data_exception();
1135 if (time==stopCount)
1136 throw fst_end_of_data_exception();
1137 });
1138 } catch(fst_end_of_data_exception) {
1139 // end of data detected
1140 }
1141 write_output_step(5*(cycle-1)+2);
1142 write_output_end();
1143
1144 if (writeback) {
1145 pool<Module*> wbmods;
1146 top->writeback(wbmods);
1147 }
1148 }
1149 };
1150
1151 struct SimPass : public Pass {
1152 SimPass() : Pass("sim", "simulate the circuit") { }
1153 void help() override
1154 {
1155 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1156 log("\n");
1157 log(" sim [options] [top-level]\n");
1158 log("\n");
1159 log("This command simulates the circuit using the given top-level module.\n");
1160 log("\n");
1161 log(" -vcd <filename>\n");
1162 log(" write the simulation results to the given VCD file\n");
1163 log("\n");
1164 log(" -fst <filename>\n");
1165 log(" write the simulation results to the given FST file\n");
1166 log("\n");
1167 log(" -clock <portname>\n");
1168 log(" name of top-level clock input\n");
1169 log("\n");
1170 log(" -clockn <portname>\n");
1171 log(" name of top-level clock input (inverse polarity)\n");
1172 log("\n");
1173 log(" -reset <portname>\n");
1174 log(" name of top-level reset input (active high)\n");
1175 log("\n");
1176 log(" -resetn <portname>\n");
1177 log(" name of top-level inverted reset input (active low)\n");
1178 log("\n");
1179 log(" -rstlen <integer>\n");
1180 log(" number of cycles reset should stay active (default: 1)\n");
1181 log("\n");
1182 log(" -zinit\n");
1183 log(" zero-initialize all uninitialized regs and memories\n");
1184 log("\n");
1185 log(" -timescale <string>\n");
1186 log(" include the specified timescale declaration in the vcd\n");
1187 log("\n");
1188 log(" -n <integer>\n");
1189 log(" number of clock cycles to simulate (default: 20)\n");
1190 log("\n");
1191 log(" -a\n");
1192 log(" use all nets in VCD/FST operations, not just those with public names\n");
1193 log("\n");
1194 log(" -w\n");
1195 log(" writeback mode: use final simulation state as new init state\n");
1196 log("\n");
1197 log(" -r\n");
1198 log(" read simulation results file (file formats supported: FST)\n");
1199 log("\n");
1200 log(" -scope\n");
1201 log(" scope of simulation top model\n");
1202 log("\n");
1203 log(" -at <time>\n");
1204 log(" sets start and stop time\n");
1205 log("\n");
1206 log(" -start <time>\n");
1207 log(" start co-simulation in arbitary time (default 0)\n");
1208 log("\n");
1209 log(" -stop <time>\n");
1210 log(" stop co-simulation in arbitary time (default END)\n");
1211 log("\n");
1212 log(" -sim\n");
1213 log(" simulation with stimulus from FST (default)\n");
1214 log("\n");
1215 log(" -sim-cmp\n");
1216 log(" co-simulation expect exact match\n");
1217 log("\n");
1218 log(" -sim-gold\n");
1219 log(" co-simulation, x in simulation can match any value in FST\n");
1220 log("\n");
1221 log(" -sim-gate\n");
1222 log(" co-simulation, x in FST can match any value in simulation\n");
1223 log("\n");
1224 log(" -d\n");
1225 log(" enable debug output\n");
1226 log("\n");
1227 }
1228 void execute(std::vector<std::string> args, RTLIL::Design *design) override
1229 {
1230 SimWorker worker;
1231 int numcycles = 20;
1232 bool start_set = false, stop_set = false, at_set = false;
1233
1234 log_header(design, "Executing SIM pass (simulate the circuit).\n");
1235
1236 size_t argidx;
1237 for (argidx = 1; argidx < args.size(); argidx++) {
1238 if (args[argidx] == "-vcd" && argidx+1 < args.size()) {
1239 std::string vcd_filename = args[++argidx];
1240 rewrite_filename(vcd_filename);
1241 worker.vcdfile.open(vcd_filename.c_str());
1242 continue;
1243 }
1244 if (args[argidx] == "-fst" && argidx+1 < args.size()) {
1245 std::string fst_filename = args[++argidx];
1246 rewrite_filename(fst_filename);
1247 worker.fstfile = (struct fstContext *)fstWriterCreate(fst_filename.c_str(),1);
1248 continue;
1249 }
1250 if (args[argidx] == "-n" && argidx+1 < args.size()) {
1251 numcycles = atoi(args[++argidx].c_str());
1252 worker.cycles_set = true;
1253 continue;
1254 }
1255 if (args[argidx] == "-rstlen" && argidx+1 < args.size()) {
1256 worker.rstlen = atoi(args[++argidx].c_str());
1257 continue;
1258 }
1259 if (args[argidx] == "-clock" && argidx+1 < args.size()) {
1260 worker.clock.insert(RTLIL::escape_id(args[++argidx]));
1261 continue;
1262 }
1263 if (args[argidx] == "-clockn" && argidx+1 < args.size()) {
1264 worker.clockn.insert(RTLIL::escape_id(args[++argidx]));
1265 continue;
1266 }
1267 if (args[argidx] == "-reset" && argidx+1 < args.size()) {
1268 worker.reset.insert(RTLIL::escape_id(args[++argidx]));
1269 continue;
1270 }
1271 if (args[argidx] == "-resetn" && argidx+1 < args.size()) {
1272 worker.resetn.insert(RTLIL::escape_id(args[++argidx]));
1273 continue;
1274 }
1275 if (args[argidx] == "-timescale" && argidx+1 < args.size()) {
1276 worker.timescale = args[++argidx];
1277 continue;
1278 }
1279 if (args[argidx] == "-a") {
1280 worker.hide_internal = false;
1281 continue;
1282 }
1283 if (args[argidx] == "-d") {
1284 worker.debug = true;
1285 continue;
1286 }
1287 if (args[argidx] == "-w") {
1288 worker.writeback = true;
1289 continue;
1290 }
1291 if (args[argidx] == "-zinit") {
1292 worker.zinit = true;
1293 continue;
1294 }
1295 if (args[argidx] == "-r" && argidx+1 < args.size()) {
1296 std::string sim_filename = args[++argidx];
1297 rewrite_filename(sim_filename);
1298 worker.sim_filename = sim_filename;
1299 continue;
1300 }
1301 if (args[argidx] == "-scope" && argidx+1 < args.size()) {
1302 worker.scope = args[++argidx];
1303 continue;
1304 }
1305 if (args[argidx] == "-start" && argidx+1 < args.size()) {
1306 worker.start_time = stringToTime(args[++argidx]);
1307 start_set = true;
1308 continue;
1309 }
1310 if (args[argidx] == "-stop" && argidx+1 < args.size()) {
1311 worker.stop_time = stringToTime(args[++argidx]);
1312 stop_set = true;
1313 continue;
1314 }
1315 if (args[argidx] == "-at" && argidx+1 < args.size()) {
1316 worker.start_time = stringToTime(args[++argidx]);
1317 worker.stop_time = worker.start_time;
1318 at_set = true;
1319 continue;
1320 }
1321 if (args[argidx] == "-sim") {
1322 worker.sim_mode = SimulationMode::sim;
1323 continue;
1324 }
1325 if (args[argidx] == "-sim-cmp") {
1326 worker.sim_mode = SimulationMode::cmp;
1327 continue;
1328 }
1329 if (args[argidx] == "-sim-gold") {
1330 worker.sim_mode = SimulationMode::gold;
1331 continue;
1332 }
1333 if (args[argidx] == "-sim-gate") {
1334 worker.sim_mode = SimulationMode::gate;
1335 continue;
1336 }
1337 break;
1338 }
1339 extra_args(args, argidx, design);
1340 if (at_set && (start_set || stop_set || worker.cycles_set))
1341 log_error("'at' option can only be defined separate of 'start','stop' and 'n'\n");
1342 if (stop_set && worker.cycles_set)
1343 log_error("'stop' and 'n' can only be used exclusively'\n");
1344
1345 Module *top_mod = nullptr;
1346
1347 if (design->full_selection()) {
1348 top_mod = design->top_module();
1349
1350 if (!top_mod)
1351 log_cmd_error("Design has no top module, use the 'hierarchy' command to specify one.\n");
1352 } else {
1353 auto mods = design->selected_whole_modules();
1354 if (GetSize(mods) != 1)
1355 log_cmd_error("Only one top module must be selected.\n");
1356 top_mod = mods.front();
1357 }
1358
1359 if (worker.sim_filename.empty())
1360 worker.run(top_mod, numcycles);
1361 else
1362 worker.run_cosim(top_mod, numcycles);
1363 }
1364 } SimPass;
1365
1366 PRIVATE_NAMESPACE_END