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