AIM file could have gaps in or between inputs and inits
[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 SimWorker;
69 struct OutputWriter
70 {
71 OutputWriter(SimWorker *w) { worker = w;};
72 virtual ~OutputWriter() {};
73 virtual void write(std::map<int, bool> &use_signal) = 0;
74 SimWorker *worker;
75 };
76
77 struct SimShared
78 {
79 bool debug = false;
80 bool verbose = true;
81 bool hide_internal = true;
82 bool writeback = false;
83 bool zinit = false;
84 int rstlen = 1;
85 FstData *fst = nullptr;
86 double start_time = 0;
87 double stop_time = -1;
88 SimulationMode sim_mode = SimulationMode::sim;
89 bool cycles_set = false;
90 std::vector<std::unique_ptr<OutputWriter>> outputfiles;
91 std::vector<std::pair<int,std::map<int,Const>>> output_data;
92 bool ignore_x = false;
93 bool date = false;
94 bool multiclock = false;
95 };
96
97 void zinit(State &v)
98 {
99 if (v != State::S1)
100 v = State::S0;
101 }
102
103 void zinit(Const &v)
104 {
105 for (auto &bit : v.bits)
106 zinit(bit);
107 }
108
109 struct SimInstance
110 {
111 SimShared *shared;
112
113 std::string scope;
114 Module *module;
115 Cell *instance;
116
117 SimInstance *parent;
118 dict<Cell*, SimInstance*> children;
119
120 SigMap sigmap;
121 dict<SigBit, State> state_nets;
122 dict<SigBit, pool<Cell*>> upd_cells;
123 dict<SigBit, pool<Wire*>> upd_outports;
124
125 pool<SigBit> dirty_bits;
126 pool<Cell*> dirty_cells;
127 pool<IdString> dirty_memories;
128 pool<SimInstance*, hash_ptr_ops> dirty_children;
129
130 struct ff_state_t
131 {
132 Const past_d;
133 Const past_ad;
134 State past_clk;
135 State past_ce;
136 State past_srst;
137
138 FfData data;
139 };
140
141 struct mem_state_t
142 {
143 Mem *mem;
144 std::vector<Const> past_wr_clk;
145 std::vector<Const> past_wr_en;
146 std::vector<Const> past_wr_addr;
147 std::vector<Const> past_wr_data;
148 Const data;
149 };
150
151 dict<Cell*, ff_state_t> ff_database;
152 dict<IdString, mem_state_t> mem_database;
153 pool<Cell*> formal_database;
154 dict<Cell*, IdString> mem_cells;
155
156 std::vector<Mem> memories;
157
158 dict<Wire*, pair<int, Const>> signal_database;
159 dict<Wire*, fstHandle> fst_handles;
160
161 SimInstance(SimShared *shared, std::string scope, Module *module, Cell *instance = nullptr, SimInstance *parent = nullptr) :
162 shared(shared), scope(scope), module(module), instance(instance), parent(parent), sigmap(module)
163 {
164 log_assert(module);
165
166 if (parent) {
167 log_assert(parent->children.count(instance) == 0);
168 parent->children[instance] = this;
169 }
170
171 for (auto wire : module->wires())
172 {
173 SigSpec sig = sigmap(wire);
174
175 for (int i = 0; i < GetSize(sig); i++) {
176 if (state_nets.count(sig[i]) == 0)
177 state_nets[sig[i]] = State::Sx;
178 if (wire->port_output) {
179 upd_outports[sig[i]].insert(wire);
180 dirty_bits.insert(sig[i]);
181 }
182 }
183
184 if ((shared->fst) && !(shared->hide_internal && wire->name[0] == '$')) {
185 fstHandle id = shared->fst->getHandle(scope + "." + RTLIL::unescape_id(wire->name));
186 if (id==0 && wire->name.isPublic())
187 log_warning("Unable to find wire %s in input file.\n", (scope + "." + RTLIL::unescape_id(wire->name)).c_str());
188 fst_handles[wire] = id;
189 }
190
191 if (wire->attributes.count(ID::init)) {
192 Const initval = wire->attributes.at(ID::init);
193 for (int i = 0; i < GetSize(sig) && i < GetSize(initval); i++)
194 if (initval[i] == State::S0 || initval[i] == State::S1) {
195 state_nets[sig[i]] = initval[i];
196 dirty_bits.insert(sig[i]);
197 }
198 }
199 }
200
201 memories = Mem::get_all_memories(module);
202 for (auto &mem : memories) {
203 auto &mdb = mem_database[mem.memid];
204 mdb.mem = &mem;
205 for (auto &port : mem.wr_ports) {
206 mdb.past_wr_clk.push_back(Const(State::Sx));
207 mdb.past_wr_en.push_back(Const(State::Sx, GetSize(port.en)));
208 mdb.past_wr_addr.push_back(Const(State::Sx, GetSize(port.addr)));
209 mdb.past_wr_data.push_back(Const(State::Sx, GetSize(port.data)));
210 }
211 mdb.data = mem.get_init_data();
212 }
213
214 for (auto cell : module->cells())
215 {
216 Module *mod = module->design->module(cell->type);
217
218 if (mod != nullptr) {
219 dirty_children.insert(new SimInstance(shared, scope + "." + RTLIL::unescape_id(cell->name), mod, cell, this));
220 }
221
222 for (auto &port : cell->connections()) {
223 if (cell->input(port.first))
224 for (auto bit : sigmap(port.second)) {
225 upd_cells[bit].insert(cell);
226 // Make sure cell inputs connected to constants are updated in the first cycle
227 if (bit.wire == nullptr)
228 dirty_bits.insert(bit);
229 }
230 }
231
232 if (RTLIL::builtin_ff_cell_types().count(cell->type)) {
233 FfData ff_data(nullptr, cell);
234 ff_state_t ff;
235 ff.past_d = Const(State::Sx, ff_data.width);
236 ff.past_ad = Const(State::Sx, ff_data.width);
237 ff.past_clk = State::Sx;
238 ff.past_ce = State::Sx;
239 ff.past_srst = State::Sx;
240 ff.data = ff_data;
241 ff_database[cell] = ff;
242 }
243
244 if (cell->is_mem_cell())
245 {
246 mem_cells[cell] = cell->parameters.at(ID::MEMID).decode_string();
247 }
248 if (cell->type.in(ID($assert), ID($cover), ID($assume))) {
249 formal_database.insert(cell);
250 }
251 }
252
253 if (shared->zinit)
254 {
255 for (auto &it : ff_database)
256 {
257 ff_state_t &ff = it.second;
258 zinit(ff.past_d);
259 zinit(ff.past_ad);
260
261 SigSpec qsig = it.second.data.sig_q;
262 Const qdata = get_state(qsig);
263 zinit(qdata);
264 set_state(qsig, qdata);
265 }
266
267 for (auto &it : mem_database) {
268 mem_state_t &mem = it.second;
269 for (auto &val : mem.past_wr_en)
270 zinit(val);
271 zinit(mem.data);
272 }
273 }
274 }
275
276 ~SimInstance()
277 {
278 for (auto child : children)
279 delete child.second;
280 }
281
282 IdString name() const
283 {
284 if (instance != nullptr)
285 return instance->name;
286 return module->name;
287 }
288
289 std::string hiername() const
290 {
291 if (instance != nullptr)
292 return parent->hiername() + "." + log_id(instance->name);
293
294 return log_id(module->name);
295 }
296
297 Const get_state(SigSpec sig)
298 {
299 Const value;
300
301 for (auto bit : sigmap(sig))
302 if (bit.wire == nullptr)
303 value.bits.push_back(bit.data);
304 else if (state_nets.count(bit))
305 value.bits.push_back(state_nets.at(bit));
306 else
307 value.bits.push_back(State::Sz);
308
309 if (shared->debug)
310 log("[%s] get %s: %s\n", hiername().c_str(), log_signal(sig), log_signal(value));
311 return value;
312 }
313
314 bool set_state(SigSpec sig, Const value)
315 {
316 bool did_something = false;
317
318 sig = sigmap(sig);
319 log_assert(GetSize(sig) <= GetSize(value));
320
321 for (int i = 0; i < GetSize(sig); i++)
322 if (state_nets.at(sig[i]) != value[i]) {
323 state_nets.at(sig[i]) = value[i];
324 dirty_bits.insert(sig[i]);
325 did_something = true;
326 }
327
328 if (shared->debug)
329 log("[%s] set %s: %s\n", hiername().c_str(), log_signal(sig), log_signal(value));
330 return did_something;
331 }
332
333 void set_memory_state(IdString memid, Const addr, Const data)
334 {
335 auto &state = mem_database[memid];
336
337 int offset = (addr.as_int() - state.mem->start_offset) * state.mem->width;
338 for (int i = 0; i < GetSize(data); i++)
339 if (0 <= i+offset && i+offset < GetSize(data))
340 state.data.bits[i+offset] = data.bits[i];
341 }
342
343 void set_memory_state_bit(IdString memid, int offset, State data)
344 {
345 auto &state = mem_database[memid];
346 if (offset >= state.mem->size * state.mem->width)
347 log_error("Addressing out of bounds bit %d/%d of memory %s\n", offset, state.mem->size * state.mem->width, log_id(memid));
348 state.data.bits[offset] = data;
349 }
350
351 void update_cell(Cell *cell)
352 {
353 if (ff_database.count(cell))
354 return;
355
356 if (formal_database.count(cell))
357 return;
358
359 if (mem_cells.count(cell))
360 {
361 dirty_memories.insert(mem_cells[cell]);
362 return;
363 }
364
365 if (children.count(cell))
366 {
367 auto child = children.at(cell);
368 for (auto &conn: cell->connections())
369 if (cell->input(conn.first) && GetSize(conn.second)) {
370 Const value = get_state(conn.second);
371 child->set_state(child->module->wire(conn.first), value);
372 }
373 dirty_children.insert(child);
374 return;
375 }
376
377 if (yosys_celltypes.cell_evaluable(cell->type))
378 {
379 RTLIL::SigSpec sig_a, sig_b, sig_c, sig_d, sig_s, sig_y;
380 bool has_a, has_b, has_c, has_d, has_s, has_y;
381
382 has_a = cell->hasPort(ID::A);
383 has_b = cell->hasPort(ID::B);
384 has_c = cell->hasPort(ID::C);
385 has_d = cell->hasPort(ID::D);
386 has_s = cell->hasPort(ID::S);
387 has_y = cell->hasPort(ID::Y);
388
389 if (has_a) sig_a = cell->getPort(ID::A);
390 if (has_b) sig_b = cell->getPort(ID::B);
391 if (has_c) sig_c = cell->getPort(ID::C);
392 if (has_d) sig_d = cell->getPort(ID::D);
393 if (has_s) sig_s = cell->getPort(ID::S);
394 if (has_y) sig_y = cell->getPort(ID::Y);
395
396 if (shared->debug)
397 log("[%s] eval %s (%s)\n", hiername().c_str(), log_id(cell), log_id(cell->type));
398
399 // Simple (A -> Y) and (A,B -> Y) cells
400 if (has_a && !has_c && !has_d && !has_s && has_y) {
401 set_state(sig_y, CellTypes::eval(cell, get_state(sig_a), get_state(sig_b)));
402 return;
403 }
404
405 // (A,B,C -> Y) cells
406 if (has_a && has_b && has_c && !has_d && !has_s && has_y) {
407 set_state(sig_y, CellTypes::eval(cell, get_state(sig_a), get_state(sig_b), get_state(sig_c)));
408 return;
409 }
410
411 // (A,S -> Y) cells
412 if (has_a && !has_b && !has_c && !has_d && has_s && has_y) {
413 set_state(sig_y, CellTypes::eval(cell, get_state(sig_a), get_state(sig_s)));
414 return;
415 }
416
417 // (A,B,S -> Y) cells
418 if (has_a && has_b && !has_c && !has_d && has_s && has_y) {
419 set_state(sig_y, CellTypes::eval(cell, get_state(sig_a), get_state(sig_b), get_state(sig_s)));
420 return;
421 }
422
423 log_warning("Unsupported evaluable cell type: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell));
424 return;
425 }
426
427 log_error("Unsupported cell type: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell));
428 }
429
430 void update_memory(IdString id) {
431 auto &mdb = mem_database[id];
432 auto &mem = *mdb.mem;
433
434 for (int port_idx = 0; port_idx < GetSize(mem.rd_ports); port_idx++)
435 {
436 auto &port = mem.rd_ports[port_idx];
437 Const addr = get_state(port.addr);
438 Const data = Const(State::Sx, mem.width << port.wide_log2);
439
440 if (port.clk_enable)
441 log_error("Memory %s.%s has clocked read ports. Run 'memory' with -nordff.\n", log_id(module), log_id(mem.memid));
442
443 if (addr.is_fully_def()) {
444 int index = addr.as_int() - mem.start_offset;
445 if (index >= 0 && index < mem.size)
446 data = mdb.data.extract(index*mem.width, mem.width << port.wide_log2);
447 }
448
449 set_state(port.data, data);
450 }
451 }
452
453 void update_ph1()
454 {
455 pool<Cell*> queue_cells;
456 pool<Wire*> queue_outports;
457
458 queue_cells.swap(dirty_cells);
459
460 while (1)
461 {
462 for (auto bit : dirty_bits)
463 {
464 if (upd_cells.count(bit))
465 for (auto cell : upd_cells.at(bit))
466 queue_cells.insert(cell);
467
468 if (upd_outports.count(bit) && parent != nullptr)
469 for (auto wire : upd_outports.at(bit))
470 queue_outports.insert(wire);
471 }
472
473 dirty_bits.clear();
474
475 if (!queue_cells.empty())
476 {
477 for (auto cell : queue_cells)
478 update_cell(cell);
479
480 queue_cells.clear();
481 continue;
482 }
483
484 for (auto &memid : dirty_memories)
485 update_memory(memid);
486 dirty_memories.clear();
487
488 for (auto wire : queue_outports)
489 if (instance->hasPort(wire->name)) {
490 Const value = get_state(wire);
491 parent->set_state(instance->getPort(wire->name), value);
492 }
493
494 queue_outports.clear();
495
496 for (auto child : dirty_children)
497 child->update_ph1();
498
499 dirty_children.clear();
500
501 if (dirty_bits.empty())
502 break;
503 }
504 }
505
506 bool update_ph2()
507 {
508 bool did_something = false;
509
510 for (auto &it : ff_database)
511 {
512 ff_state_t &ff = it.second;
513 FfData &ff_data = ff.data;
514
515 Const current_q = get_state(ff.data.sig_q);
516
517 if (ff_data.has_clk) {
518 // flip-flops
519 State current_clk = get_state(ff_data.sig_clk)[0];
520 if (ff_data.pol_clk ? (ff.past_clk == State::S0 && current_clk != State::S0) :
521 (ff.past_clk == State::S1 && current_clk != State::S1)) {
522 bool ce = ff.past_ce == (ff_data.pol_ce ? State::S1 : State::S0);
523 // set if no ce, or ce is enabled
524 if (!ff_data.has_ce || (ff_data.has_ce && ce)) {
525 current_q = ff.past_d;
526 }
527 // override if sync reset
528 if ((ff_data.has_srst) && (ff.past_srst == (ff_data.pol_srst ? State::S1 : State::S0)) &&
529 ((!ff_data.ce_over_srst) || (ff_data.ce_over_srst && ce))) {
530 current_q = ff_data.val_srst;
531 }
532 }
533 }
534 // async load
535 if (ff_data.has_aload) {
536 State current_aload = get_state(ff_data.sig_aload)[0];
537 if (current_aload == (ff_data.pol_aload ? State::S1 : State::S0)) {
538 current_q = ff_data.has_clk ? ff.past_ad : get_state(ff.data.sig_ad);
539 }
540 }
541 // async reset
542 if (ff_data.has_arst) {
543 State current_arst = get_state(ff_data.sig_arst)[0];
544 if (current_arst == (ff_data.pol_arst ? State::S1 : State::S0)) {
545 current_q = ff_data.val_arst;
546 }
547 }
548 // handle set/reset
549 if (ff.data.has_sr) {
550 Const current_clr = get_state(ff.data.sig_clr);
551 Const current_set = get_state(ff.data.sig_set);
552
553 for(int i=0;i<ff.past_d.size();i++) {
554 if (current_clr[i] == (ff_data.pol_clr ? State::S1 : State::S0)) {
555 current_q[i] = State::S0;
556 }
557 else if (current_set[i] == (ff_data.pol_set ? State::S1 : State::S0)) {
558 current_q[i] = State::S1;
559 }
560 }
561 }
562 if (ff_data.has_gclk) {
563 // $ff
564 current_q = ff.past_d;
565 }
566 if (set_state(ff_data.sig_q, current_q))
567 did_something = true;
568 }
569
570 for (auto &it : mem_database)
571 {
572 mem_state_t &mdb = it.second;
573 auto &mem = *mdb.mem;
574
575 for (int port_idx = 0; port_idx < GetSize(mem.wr_ports); port_idx++)
576 {
577 auto &port = mem.wr_ports[port_idx];
578 Const addr, data, enable;
579
580 if (!port.clk_enable)
581 {
582 addr = get_state(port.addr);
583 data = get_state(port.data);
584 enable = get_state(port.en);
585 }
586 else
587 {
588 if (port.clk_polarity ?
589 (mdb.past_wr_clk[port_idx] == State::S1 || get_state(port.clk) != State::S1) :
590 (mdb.past_wr_clk[port_idx] == State::S0 || get_state(port.clk) != State::S0))
591 continue;
592
593 addr = mdb.past_wr_addr[port_idx];
594 data = mdb.past_wr_data[port_idx];
595 enable = mdb.past_wr_en[port_idx];
596 }
597
598 if (addr.is_fully_def())
599 {
600 int index = addr.as_int() - mem.start_offset;
601 if (index >= 0 && index < mem.size)
602 for (int i = 0; i < (mem.width << port.wide_log2); i++)
603 if (enable[i] == State::S1 && mdb.data.bits.at(index*mem.width+i) != data[i]) {
604 mdb.data.bits.at(index*mem.width+i) = data[i];
605 dirty_memories.insert(mem.memid);
606 did_something = true;
607 }
608 }
609 }
610 }
611
612 for (auto it : children)
613 if (it.second->update_ph2()) {
614 dirty_children.insert(it.second);
615 did_something = true;
616 }
617
618 return did_something;
619 }
620
621 void update_ph3()
622 {
623 for (auto &it : ff_database)
624 {
625 ff_state_t &ff = it.second;
626
627 if (ff.data.has_aload)
628 ff.past_ad = get_state(ff.data.sig_ad);
629
630 if (ff.data.has_clk || ff.data.has_gclk)
631 ff.past_d = get_state(ff.data.sig_d);
632
633 if (ff.data.has_clk)
634 ff.past_clk = get_state(ff.data.sig_clk)[0];
635
636 if (ff.data.has_ce)
637 ff.past_ce = get_state(ff.data.sig_ce)[0];
638
639 if (ff.data.has_srst)
640 ff.past_srst = get_state(ff.data.sig_srst)[0];
641 }
642
643 for (auto &it : mem_database)
644 {
645 mem_state_t &mem = it.second;
646
647 for (int i = 0; i < GetSize(mem.mem->wr_ports); i++) {
648 auto &port = mem.mem->wr_ports[i];
649 mem.past_wr_clk[i] = get_state(port.clk);
650 mem.past_wr_en[i] = get_state(port.en);
651 mem.past_wr_addr[i] = get_state(port.addr);
652 mem.past_wr_data[i] = get_state(port.data);
653 }
654 }
655
656 for (auto cell : formal_database)
657 {
658 string label = log_id(cell);
659 if (cell->attributes.count(ID::src))
660 label = cell->attributes.at(ID::src).decode_string();
661
662 State a = get_state(cell->getPort(ID::A))[0];
663 State en = get_state(cell->getPort(ID::EN))[0];
664
665 if (cell->type == ID($cover) && en == State::S1 && a != State::S1)
666 log("Cover %s.%s (%s) reached.\n", hiername().c_str(), log_id(cell), label.c_str());
667
668 if (cell->type == ID($assume) && en == State::S1 && a != State::S1)
669 log("Assumption %s.%s (%s) failed.\n", hiername().c_str(), log_id(cell), label.c_str());
670
671 if (cell->type == ID($assert) && en == State::S1 && a != State::S1)
672 log_warning("Assert %s.%s (%s) failed.\n", hiername().c_str(), log_id(cell), label.c_str());
673 }
674
675 for (auto it : children)
676 it.second->update_ph3();
677 }
678
679 void writeback(pool<Module*> &wbmods)
680 {
681 if (wbmods.count(module))
682 log_error("Instance %s of module %s is not unique: Writeback not possible. (Fix by running 'uniquify'.)\n", hiername().c_str(), log_id(module));
683
684 wbmods.insert(module);
685
686 for (auto wire : module->wires())
687 wire->attributes.erase(ID::init);
688
689 for (auto &it : ff_database)
690 {
691 SigSpec sig_q = it.second.data.sig_q;
692 Const initval = get_state(sig_q);
693
694 for (int i = 0; i < GetSize(sig_q); i++)
695 {
696 Wire *w = sig_q[i].wire;
697
698 if (w->attributes.count(ID::init) == 0)
699 w->attributes[ID::init] = Const(State::Sx, GetSize(w));
700
701 w->attributes[ID::init][sig_q[i].offset] = initval[i];
702 }
703 }
704
705 for (auto &it : mem_database)
706 {
707 mem_state_t &mem = it.second;
708 mem.mem->clear_inits();
709 MemInit minit;
710 minit.addr = mem.mem->start_offset;
711 minit.data = mem.data;
712 minit.en = Const(State::S1, mem.mem->width);
713 mem.mem->inits.push_back(minit);
714 mem.mem->emit();
715 }
716
717 for (auto it : children)
718 it.second->writeback(wbmods);
719 }
720
721 void register_signals(int &id)
722 {
723 for (auto wire : module->wires())
724 {
725 if (shared->hide_internal && wire->name[0] == '$')
726 continue;
727
728 signal_database[wire] = make_pair(id, Const());
729 id++;
730 }
731
732 for (auto child : children)
733 child.second->register_signals(id);
734 }
735
736 void write_output_header(std::function<void(IdString)> enter_scope, std::function<void()> exit_scope, std::function<void(Wire*, int, bool)> register_signal)
737 {
738 enter_scope(name());
739
740 dict<Wire*,bool> registers;
741 for (auto cell : module->cells())
742 {
743 if (RTLIL::builtin_ff_cell_types().count(cell->type)) {
744 FfData ff_data(nullptr, cell);
745 SigSpec q = sigmap(ff_data.sig_q);
746 if (q.is_wire() && signal_database.count(q.as_wire()) != 0) {
747 registers[q.as_wire()] = true;
748 }
749 }
750 }
751
752 for (auto signal : signal_database)
753 {
754 register_signal(signal.first, signal.second.first, registers.count(signal.first)!=0);
755 }
756
757 for (auto child : children)
758 child.second->write_output_header(enter_scope, exit_scope, register_signal);
759
760 exit_scope();
761 }
762
763 void register_output_step_values(std::map<int,Const> *data)
764 {
765 for (auto &it : signal_database)
766 {
767 Wire *wire = it.first;
768 Const value = get_state(wire);
769 int id = it.second.first;
770
771 if (it.second.second == value)
772 continue;
773
774 it.second.second = value;
775 data->emplace(id, value);
776 }
777
778 for (auto child : children)
779 child.second->register_output_step_values(data);
780 }
781
782 bool setInitState()
783 {
784 bool did_something = false;
785 for(auto &item : fst_handles) {
786 if (item.second==0) continue; // Ignore signals not found
787 std::string v = shared->fst->valueOf(item.second);
788 did_something |= set_state(item.first, Const::from_string(v));
789 }
790 for (auto &it : ff_database)
791 {
792 ff_state_t &ff = it.second;
793 SigSpec dsig = it.second.data.sig_d;
794 Const value = get_state(dsig);
795 if (dsig.is_wire()) {
796 ff.past_d = value;
797 if (ff.data.has_aload)
798 ff.past_ad = value;
799 did_something |= true;
800 }
801 }
802 for (auto child : children)
803 did_something |= child.second->setInitState();
804 return did_something;
805 }
806
807 void addAdditionalInputs(std::map<Wire*,fstHandle> &inputs)
808 {
809 for (auto cell : module->cells())
810 {
811 if (cell->type.in(ID($anyseq))) {
812 SigSpec sig_y = sigmap(cell->getPort(ID::Y));
813 if (sig_y.is_wire()) {
814 bool found = false;
815 for(auto &item : fst_handles) {
816 if (item.second==0) continue; // Ignore signals not found
817 if (sig_y == sigmap(item.first)) {
818 inputs[sig_y.as_wire()] = item.second;
819 found = true;
820 break;
821 }
822 }
823 if (!found)
824 log_error("Unable to find required '%s' signal in file\n",(scope + "." + RTLIL::unescape_id(sig_y.as_wire()->name)).c_str());
825 }
826 }
827 }
828 for (auto child : children)
829 child.second->addAdditionalInputs(inputs);
830 }
831
832 void setState(dict<int, std::pair<SigBit,bool>> bits, std::string values)
833 {
834 for(auto bit : bits) {
835 if (bit.first >= GetSize(values))
836 log_error("Too few input data bits in file.\n");
837 switch(values.at(bit.first)) {
838 case '0': set_state(bit.second.first, bit.second.second ? State::S1 : State::S0); break;
839 case '1': set_state(bit.second.first, bit.second.second ? State::S0 : State::S1); break;
840 default: set_state(bit.second.first, State::Sx); break;
841 }
842 }
843 }
844
845 void setMemState(dict<int, std::pair<std::string,int>> bits, std::string values)
846 {
847 for(auto bit : bits) {
848 if (bit.first >= GetSize(values))
849 log_error("Too few input data bits in file.\n");
850 switch(values.at(bit.first)) {
851 case '0': set_memory_state_bit(bit.second.first, bit.second.second, State::S0); break;
852 case '1': set_memory_state_bit(bit.second.first, bit.second.second, State::S1); break;
853 default: set_memory_state_bit(bit.second.first, bit.second.second, State::Sx); break;
854 }
855 }
856 }
857
858 bool checkSignals()
859 {
860 bool retVal = false;
861 for(auto &item : fst_handles) {
862 if (item.second==0) continue; // Ignore signals not found
863 Const fst_val = Const::from_string(shared->fst->valueOf(item.second));
864 Const sim_val = get_state(item.first);
865 if (sim_val.size()!=fst_val.size()) {
866 log_warning("Signal '%s.%s' size is different in gold and gate.\n", scope.c_str(), log_id(item.first));
867 continue;
868 }
869 if (shared->sim_mode == SimulationMode::sim) {
870 // No checks performed when using stimulus
871 } else if (shared->sim_mode == SimulationMode::gate && !fst_val.is_fully_def()) { // FST data contains X
872 for(int i=0;i<fst_val.size();i++) {
873 if (fst_val[i]!=State::Sx && fst_val[i]!=sim_val[i]) {
874 log_warning("Signal '%s.%s' in file %s in simulation %s\n", scope.c_str(), log_id(item.first), log_signal(fst_val), log_signal(sim_val));
875 retVal = true;
876 break;
877 }
878 }
879 } else if (shared->sim_mode == SimulationMode::gold && !sim_val.is_fully_def()) { // sim data contains X
880 for(int i=0;i<sim_val.size();i++) {
881 if (sim_val[i]!=State::Sx && fst_val[i]!=sim_val[i]) {
882 log_warning("Signal '%s.%s' in file %s in simulation %s\n", scope.c_str(), log_id(item.first), log_signal(fst_val), log_signal(sim_val));
883 retVal = true;
884 break;
885 }
886 }
887 } else {
888 if (fst_val!=sim_val) {
889 log_warning("Signal '%s.%s' in file %s in simulation '%s'\n", scope.c_str(), log_id(item.first), log_signal(fst_val), log_signal(sim_val));
890 retVal = true;
891 }
892 }
893 }
894 for (auto child : children)
895 retVal |= child.second->checkSignals();
896 return retVal;
897 }
898 };
899
900 struct SimWorker : SimShared
901 {
902 SimInstance *top = nullptr;
903 pool<IdString> clock, clockn, reset, resetn;
904 std::string timescale;
905 std::string sim_filename;
906 std::string map_filename;
907 std::string scope;
908
909 ~SimWorker()
910 {
911 outputfiles.clear();
912 delete top;
913 }
914
915 void register_signals()
916 {
917 int id = 1;
918 top->register_signals(id);
919 }
920
921 void register_output_step(int t)
922 {
923 std::map<int,Const> data;
924 top->register_output_step_values(&data);
925 output_data.emplace_back(t, data);
926 }
927
928 void write_output_files()
929 {
930 std::map<int, bool> use_signal;
931 bool first = ignore_x;
932 for(auto& d : output_data)
933 {
934 if (first) {
935 for (auto &data : d.second)
936 use_signal[data.first] = !data.second.is_fully_undef();
937 first = false;
938 } else {
939 for (auto &data : d.second)
940 use_signal[data.first] = true;
941 }
942 if (!ignore_x) break;
943 }
944 for(auto& writer : outputfiles)
945 writer->write(use_signal);
946 }
947
948 void update()
949 {
950 while (1)
951 {
952 if (debug)
953 log("\n-- ph1 --\n");
954
955 top->update_ph1();
956
957 if (debug)
958 log("\n-- ph2 --\n");
959
960 if (!top->update_ph2())
961 break;
962 }
963
964 if (debug)
965 log("\n-- ph3 --\n");
966
967 top->update_ph3();
968 }
969
970 void set_inports(pool<IdString> ports, State value)
971 {
972 for (auto portname : ports)
973 {
974 Wire *w = top->module->wire(portname);
975
976 if (w == nullptr)
977 log_error("Can't find port %s on module %s.\n", log_id(portname), log_id(top->module));
978
979 top->set_state(w, value);
980 }
981 }
982
983 void run(Module *topmod, int numcycles)
984 {
985 log_assert(top == nullptr);
986 top = new SimInstance(this, scope, topmod);
987 register_signals();
988
989 if (debug)
990 log("\n===== 0 =====\n");
991 else if (verbose)
992 log("Simulating cycle 0.\n");
993
994 set_inports(reset, State::S1);
995 set_inports(resetn, State::S0);
996
997 set_inports(clock, State::Sx);
998 set_inports(clockn, State::Sx);
999
1000 update();
1001
1002 register_output_step(0);
1003
1004 for (int cycle = 0; cycle < numcycles; cycle++)
1005 {
1006 if (debug)
1007 log("\n===== %d =====\n", 10*cycle + 5);
1008 else if (verbose)
1009 log("Simulating cycle %d.\n", (cycle*2)+1);
1010 set_inports(clock, State::S0);
1011 set_inports(clockn, State::S1);
1012
1013 update();
1014 register_output_step(10*cycle + 5);
1015
1016 if (debug)
1017 log("\n===== %d =====\n", 10*cycle + 10);
1018 else if (verbose)
1019 log("Simulating cycle %d.\n", (cycle*2)+2);
1020
1021 set_inports(clock, State::S1);
1022 set_inports(clockn, State::S0);
1023
1024 if (cycle+1 == rstlen) {
1025 set_inports(reset, State::S0);
1026 set_inports(resetn, State::S1);
1027 }
1028
1029 update();
1030 register_output_step(10*cycle + 10);
1031 }
1032
1033 register_output_step(10*numcycles + 2);
1034
1035 write_output_files();
1036
1037 if (writeback) {
1038 pool<Module*> wbmods;
1039 top->writeback(wbmods);
1040 }
1041 }
1042
1043 void run_cosim_fst(Module *topmod, int numcycles)
1044 {
1045 log_assert(top == nullptr);
1046 fst = new FstData(sim_filename);
1047
1048 if (scope.empty())
1049 log_error("Scope must be defined for co-simulation.\n");
1050
1051 top = new SimInstance(this, scope, topmod);
1052 register_signals();
1053
1054 std::vector<fstHandle> fst_clock;
1055
1056 for (auto portname : clock)
1057 {
1058 Wire *w = topmod->wire(portname);
1059 if (!w)
1060 log_error("Can't find port %s on module %s.\n", log_id(portname), log_id(top->module));
1061 if (!w->port_input)
1062 log_error("Clock port %s on module %s is not input.\n", log_id(portname), log_id(top->module));
1063 fstHandle id = fst->getHandle(scope + "." + RTLIL::unescape_id(portname));
1064 if (id==0)
1065 log_error("Can't find port %s.%s in FST.\n", scope.c_str(), log_id(portname));
1066 fst_clock.push_back(id);
1067 }
1068 for (auto portname : clockn)
1069 {
1070 Wire *w = topmod->wire(portname);
1071 if (!w)
1072 log_error("Can't find port %s on module %s.\n", log_id(portname), log_id(top->module));
1073 if (!w->port_input)
1074 log_error("Clock port %s on module %s is not input.\n", log_id(portname), log_id(top->module));
1075 fstHandle id = fst->getHandle(scope + "." + RTLIL::unescape_id(portname));
1076 if (id==0)
1077 log_error("Can't find port %s.%s in FST.\n", scope.c_str(), log_id(portname));
1078 fst_clock.push_back(id);
1079 }
1080
1081 SigMap sigmap(topmod);
1082 std::map<Wire*,fstHandle> inputs;
1083
1084 for (auto wire : topmod->wires()) {
1085 if (wire->port_input) {
1086 fstHandle id = fst->getHandle(scope + "." + RTLIL::unescape_id(wire->name));
1087 if (id==0)
1088 log_error("Unable to find required '%s' signal in file\n",(scope + "." + RTLIL::unescape_id(wire->name)).c_str());
1089 inputs[wire] = id;
1090 }
1091 }
1092
1093 top->addAdditionalInputs(inputs);
1094
1095 uint64_t startCount = 0;
1096 uint64_t stopCount = 0;
1097 if (start_time==0) {
1098 if (start_time < fst->getStartTime())
1099 log_warning("Start time is before simulation file start time\n");
1100 startCount = fst->getStartTime();
1101 } else if (start_time==-1)
1102 startCount = fst->getEndTime();
1103 else {
1104 startCount = start_time / fst->getTimescale();
1105 if (startCount > fst->getEndTime()) {
1106 startCount = fst->getEndTime();
1107 log_warning("Start time is after simulation file end time\n");
1108 }
1109 }
1110 if (stop_time==0) {
1111 if (stop_time < fst->getStartTime())
1112 log_warning("Stop time is before simulation file start time\n");
1113 stopCount = fst->getStartTime();
1114 } else if (stop_time==-1)
1115 stopCount = fst->getEndTime();
1116 else {
1117 stopCount = stop_time / fst->getTimescale();
1118 if (stopCount > fst->getEndTime()) {
1119 stopCount = fst->getEndTime();
1120 log_warning("Stop time is after simulation file end time\n");
1121 }
1122 }
1123 if (stopCount<startCount) {
1124 log_error("Stop time is before start time\n");
1125 }
1126
1127 bool initial = true;
1128 int cycle = 0;
1129 log("Co-simulation from %lu%s to %lu%s", (unsigned long)startCount, fst->getTimescaleString(), (unsigned long)stopCount, fst->getTimescaleString());
1130 if (cycles_set)
1131 log(" for %d clock cycle(s)",numcycles);
1132 log("\n");
1133 bool all_samples = fst_clock.empty();
1134
1135 try {
1136 fst->reconstructAllAtTimes(fst_clock, startCount, stopCount, [&](uint64_t time) {
1137 if (verbose)
1138 log("Co-simulating %s %d [%lu%s].\n", (all_samples ? "sample" : "cycle"), cycle, (unsigned long)time, fst->getTimescaleString());
1139 bool did_something = false;
1140 for(auto &item : inputs) {
1141 std::string v = fst->valueOf(item.second);
1142 did_something |= top->set_state(item.first, Const::from_string(v));
1143 }
1144
1145 if (initial) {
1146 did_something |= top->setInitState();
1147 initial = false;
1148 }
1149 if (did_something)
1150 update();
1151 register_output_step(time);
1152
1153 bool status = top->checkSignals();
1154 if (status)
1155 log_error("Signal difference\n");
1156 cycle++;
1157
1158 // Limit to number of cycles if provided
1159 if (cycles_set && cycle > numcycles *2)
1160 throw fst_end_of_data_exception();
1161 if (time==stopCount)
1162 throw fst_end_of_data_exception();
1163 });
1164 } catch(fst_end_of_data_exception) {
1165 // end of data detected
1166 }
1167
1168 write_output_files();
1169
1170 if (writeback) {
1171 pool<Module*> wbmods;
1172 top->writeback(wbmods);
1173 }
1174 delete fst;
1175 }
1176
1177 std::string cell_name(std::string const & name)
1178 {
1179 size_t pos = name.find_last_of("[");
1180 if (pos!=std::string::npos)
1181 return name.substr(0, pos);
1182 return name;
1183 }
1184
1185 int mem_cell_addr(std::string const & name)
1186 {
1187 size_t pos = name.find_last_of("[");
1188 return atoi(name.substr(pos+1).c_str());
1189 }
1190
1191 void run_cosim_aiger_witness(Module *topmod)
1192 {
1193 log_assert(top == nullptr);
1194 if (!multiclock && (clock.size()+clockn.size())==0)
1195 log_error("Clock signal must be specified.\n");
1196 if (multiclock && (clock.size()+clockn.size())>0)
1197 log_error("For multiclock witness there should be no clock signal.\n");
1198
1199 top = new SimInstance(this, scope, topmod);
1200 register_signals();
1201
1202 std::ifstream mf(map_filename);
1203 std::string type, symbol;
1204 int variable, index;
1205 dict<int, std::pair<SigBit,bool>> inputs, inits, latches;
1206 dict<int, std::pair<std::string,int>> mem_inits, mem_latches;
1207 if (mf.fail())
1208 log_cmd_error("Not able to read AIGER witness map file.\n");
1209 while (mf >> type >> variable >> index >> symbol) {
1210 RTLIL::IdString escaped_s = RTLIL::escape_id(symbol);
1211 Wire *w = topmod->wire(escaped_s);
1212 if (!w) {
1213 escaped_s = RTLIL::escape_id(cell_name(symbol));
1214 Cell *c = topmod->cell(escaped_s);
1215 if (!c)
1216 log_warning("Wire/cell %s not present in module %s\n",symbol.c_str(),log_id(topmod));
1217
1218 if (c->is_mem_cell()) {
1219 std::string memid = c->parameters.at(ID::MEMID).decode_string();
1220 auto &state = top->mem_database[memid];
1221
1222 int offset = (mem_cell_addr(symbol) - state.mem->start_offset) * state.mem->width + index;
1223 if (type == "init")
1224 mem_inits[variable] = { memid, offset };
1225 else if (type == "latch")
1226 mem_latches[variable] = { memid, offset };
1227 else
1228 log_error("Map file addressing cell %s as type %s\n", symbol.c_str(), type.c_str());
1229 } else {
1230 log_error("Cell %s in map file is not memory cell\n", symbol.c_str());
1231 }
1232 } else {
1233 if (index < w->start_offset || index > w->start_offset + w->width)
1234 log_error("Index %d for wire %s is out of range\n", index, log_signal(w));
1235 if (type == "input") {
1236 inputs[variable] = {SigBit(w,index-w->start_offset), false};
1237 } else if (type == "init") {
1238 inits[variable] = {SigBit(w,index-w->start_offset), false};
1239 } else if (type == "latch") {
1240 latches[variable] = {SigBit(w,index-w->start_offset), false};
1241 } else if (type == "invlatch") {
1242 latches[variable] = {SigBit(w,index-w->start_offset), true};
1243 }
1244 }
1245 }
1246
1247 std::ifstream f;
1248 f.open(sim_filename.c_str());
1249 if (f.fail() || GetSize(sim_filename) == 0)
1250 log_error("Can not open file `%s`\n", sim_filename.c_str());
1251
1252 int state = 0;
1253 std::string status;
1254 int cycle = 0;
1255
1256 while (!f.eof())
1257 {
1258 std::string line;
1259 std::getline(f, line);
1260 if (line.size()==0 || line[0]=='#' || line[0]=='c' || line[0]=='f' || line[0]=='u') continue;
1261 if (line[0]=='.') break;
1262 if (state==0 && line.size()!=1) {
1263 // old format detected, latch data
1264 state = 2;
1265 }
1266 if (state==1 && line[0]!='b' && line[0]!='j') {
1267 // was old format but with 1 bit latch
1268 top->setState(latches, status);
1269 state = 3;
1270 }
1271
1272 switch(state)
1273 {
1274 case 0:
1275 status = line;
1276 state = 1;
1277 break;
1278 case 1:
1279 state = 2;
1280 break;
1281 case 2:
1282 top->setState(latches, line);
1283 top->setMemState(mem_latches, line);
1284 state = 3;
1285 break;
1286 default:
1287 if (verbose)
1288 log("Simulating cycle %d.\n", cycle);
1289 top->setState(inputs, line);
1290 if (cycle) {
1291 set_inports(clock, State::S1);
1292 set_inports(clockn, State::S0);
1293 } else {
1294 top->setState(inits, line);
1295 top->setMemState(mem_inits, line);
1296 set_inports(clock, State::S0);
1297 set_inports(clockn, State::S1);
1298 }
1299 update();
1300 register_output_step(10*cycle);
1301 if (!multiclock && cycle) {
1302 set_inports(clock, State::S0);
1303 set_inports(clockn, State::S1);
1304 update();
1305 register_output_step(10*cycle + 5);
1306 }
1307 cycle++;
1308 break;
1309 }
1310 }
1311 register_output_step(10*cycle);
1312 write_output_files();
1313 }
1314
1315 std::vector<std::string> split(std::string text, const char *delim)
1316 {
1317 std::vector<std::string> list;
1318 char *p = strdup(text.c_str());
1319 char *t = strtok(p, delim);
1320 while (t != NULL) {
1321 list.push_back(t);
1322 t = strtok(NULL, delim);
1323 }
1324 free(p);
1325 return list;
1326 }
1327
1328 std::string signal_name(std::string const & name)
1329 {
1330 size_t pos = name.find_first_of("@");
1331 if (pos==std::string::npos) {
1332 pos = name.find_first_of("#");
1333 if (pos==std::string::npos)
1334 log_error("Line does not contain proper signal name `%s`\n", name.c_str());
1335 }
1336 return name.substr(0, pos);
1337 }
1338
1339 void run_cosim_btor2_witness(Module *topmod)
1340 {
1341 log_assert(top == nullptr);
1342 if (!multiclock && (clock.size()+clockn.size())==0)
1343 log_error("Clock signal must be specified.\n");
1344 if (multiclock && (clock.size()+clockn.size())>0)
1345 log_error("For multiclock witness there should be no clock signal.\n");
1346 std::ifstream f;
1347 f.open(sim_filename.c_str());
1348 if (f.fail() || GetSize(sim_filename) == 0)
1349 log_error("Can not open file `%s`\n", sim_filename.c_str());
1350
1351 int state = 0;
1352 int cycle = 0;
1353 top = new SimInstance(this, scope, topmod);
1354 register_signals();
1355 int prev_cycle = 0;
1356 int curr_cycle = 0;
1357 std::vector<std::string> parts;
1358 size_t len = 0;
1359 while (!f.eof())
1360 {
1361 std::string line;
1362 std::getline(f, line);
1363 if (line.size()==0) continue;
1364
1365 if (line[0]=='#' || line[0]=='@' || line[0]=='.') {
1366 if (line[0]!='.')
1367 curr_cycle = atoi(line.c_str()+1);
1368 else
1369 curr_cycle = -1; // force detect change
1370
1371 if (curr_cycle != prev_cycle) {
1372 if (verbose)
1373 log("Simulating cycle %d.\n", cycle);
1374 set_inports(clock, State::S1);
1375 set_inports(clockn, State::S0);
1376 update();
1377 register_output_step(10*cycle+0);
1378 if (!multiclock) {
1379 set_inports(clock, State::S0);
1380 set_inports(clockn, State::S1);
1381 update();
1382 register_output_step(10*cycle+5);
1383 }
1384 cycle++;
1385 prev_cycle = curr_cycle;
1386 }
1387 if (line[0]=='.') break;
1388 continue;
1389 }
1390
1391 switch(state)
1392 {
1393 case 0:
1394 if (line=="sat")
1395 state = 1;
1396 break;
1397 case 1:
1398 if (line[0]=='b' || line[0]=='j')
1399 state = 2;
1400 else
1401 log_error("Line does not contain property.\n");
1402 break;
1403 default: // set state or inputs
1404 parts = split(line, " ");
1405 len = parts.size();
1406 if (len<3 || len>4)
1407 log_error("Invalid set state line content.\n");
1408
1409 RTLIL::IdString escaped_s = RTLIL::escape_id(signal_name(parts[len-1]));
1410 if (len==3) {
1411 Wire *w = topmod->wire(escaped_s);
1412 if (!w) {
1413 Cell *c = topmod->cell(escaped_s);
1414 if (!c)
1415 log_warning("Wire/cell %s not present in module %s\n",log_id(escaped_s),log_id(topmod));
1416 else if (c->type.in(ID($anyconst), ID($anyseq))) {
1417 SigSpec sig_y= c->getPort(ID::Y);
1418 if ((int)parts[1].size() != GetSize(sig_y))
1419 log_error("Size of wire %s is different than provided data.\n", log_signal(sig_y));
1420 top->set_state(sig_y, Const::from_string(parts[1]));
1421 }
1422 } else {
1423 if ((int)parts[1].size() != w->width)
1424 log_error("Size of wire %s is different than provided data.\n", log_signal(w));
1425 top->set_state(w, Const::from_string(parts[1]));
1426 }
1427 } else {
1428 Cell *c = topmod->cell(escaped_s);
1429 if (!c)
1430 log_error("Cell %s not present in module %s\n",log_id(escaped_s),log_id(topmod));
1431 if (!c->is_mem_cell())
1432 log_error("Cell %s is not memory cell in module %s\n",log_id(escaped_s),log_id(topmod));
1433
1434 Const addr = Const::from_string(parts[1].substr(1,parts[1].size()-2));
1435 Const data = Const::from_string(parts[2]);
1436 top->set_memory_state(c->parameters.at(ID::MEMID).decode_string(), addr, data);
1437 }
1438 break;
1439 }
1440 }
1441 register_output_step(10*cycle);
1442 write_output_files();
1443 }
1444
1445 std::string define_signal(Wire *wire)
1446 {
1447 std::stringstream f;
1448
1449 if (wire->width==1)
1450 f << stringf("%s", RTLIL::unescape_id(wire->name).c_str());
1451 else
1452 if (wire->upto)
1453 f << stringf("[%d:%d] %s", wire->start_offset, wire->width - 1 + wire->start_offset, RTLIL::unescape_id(wire->name).c_str());
1454 else
1455 f << stringf("[%d:%d] %s", wire->width - 1 + wire->start_offset, wire->start_offset, RTLIL::unescape_id(wire->name).c_str());
1456 return f.str();
1457 }
1458
1459 std::string signal_list(std::map<Wire*,fstHandle> &signals)
1460 {
1461 std::stringstream f;
1462 for(auto item=signals.begin();item!=signals.end();item++)
1463 f << stringf("%c%s", (item==signals.begin() ? ' ' : ','), RTLIL::unescape_id(item->first->name).c_str());
1464 return f.str();
1465 }
1466
1467 void generate_tb(Module *topmod, std::string tb_filename, int numcycles)
1468 {
1469 fst = new FstData(sim_filename);
1470
1471 if (scope.empty())
1472 log_error("Scope must be defined for co-simulation.\n");
1473
1474 if ((clock.size()+clockn.size())==0)
1475 log_error("Clock signal must be specified.\n");
1476
1477 std::vector<fstHandle> fst_clock;
1478 std::map<Wire*,fstHandle> clocks;
1479
1480 for (auto portname : clock)
1481 {
1482 Wire *w = topmod->wire(portname);
1483 if (!w)
1484 log_error("Can't find port %s on module %s.\n", log_id(portname), log_id(top->module));
1485 if (!w->port_input)
1486 log_error("Clock port %s on module %s is not input.\n", log_id(portname), log_id(top->module));
1487 fstHandle id = fst->getHandle(scope + "." + RTLIL::unescape_id(portname));
1488 if (id==0)
1489 log_error("Can't find port %s.%s in FST.\n", scope.c_str(), log_id(portname));
1490 fst_clock.push_back(id);
1491 clocks[w] = id;
1492 }
1493 for (auto portname : clockn)
1494 {
1495 Wire *w = topmod->wire(portname);
1496 if (!w)
1497 log_error("Can't find port %s on module %s.\n", log_id(portname), log_id(top->module));
1498 if (!w->port_input)
1499 log_error("Clock port %s on module %s is not input.\n", log_id(portname), log_id(top->module));
1500 fstHandle id = fst->getHandle(scope + "." + RTLIL::unescape_id(portname));
1501 if (id==0)
1502 log_error("Can't find port %s.%s in FST.\n", scope.c_str(), log_id(portname));
1503 fst_clock.push_back(id);
1504 clocks[w] = id;
1505 }
1506
1507 SigMap sigmap(topmod);
1508 std::map<Wire*,fstHandle> inputs;
1509 std::map<Wire*,fstHandle> outputs;
1510
1511 for (auto wire : topmod->wires()) {
1512 fstHandle id = fst->getHandle(scope + "." + RTLIL::unescape_id(wire->name));
1513 if (id==0 && (wire->port_input || wire->port_output))
1514 log_error("Unable to find required '%s' signal in file\n",(scope + "." + RTLIL::unescape_id(wire->name)).c_str());
1515 if (wire->port_input)
1516 if (clocks.find(wire)==clocks.end())
1517 inputs[wire] = id;
1518 if (wire->port_output)
1519 outputs[wire] = id;
1520 }
1521
1522 uint64_t startCount = 0;
1523 uint64_t stopCount = 0;
1524 if (start_time==0) {
1525 if (start_time < fst->getStartTime())
1526 log_warning("Start time is before simulation file start time\n");
1527 startCount = fst->getStartTime();
1528 } else if (start_time==-1)
1529 startCount = fst->getEndTime();
1530 else {
1531 startCount = start_time / fst->getTimescale();
1532 if (startCount > fst->getEndTime()) {
1533 startCount = fst->getEndTime();
1534 log_warning("Start time is after simulation file end time\n");
1535 }
1536 }
1537 if (stop_time==0) {
1538 if (stop_time < fst->getStartTime())
1539 log_warning("Stop time is before simulation file start time\n");
1540 stopCount = fst->getStartTime();
1541 } else if (stop_time==-1)
1542 stopCount = fst->getEndTime();
1543 else {
1544 stopCount = stop_time / fst->getTimescale();
1545 if (stopCount > fst->getEndTime()) {
1546 stopCount = fst->getEndTime();
1547 log_warning("Stop time is after simulation file end time\n");
1548 }
1549 }
1550 if (stopCount<startCount) {
1551 log_error("Stop time is before start time\n");
1552 }
1553
1554 int cycle = 0;
1555 log("Generate testbench data from %lu%s to %lu%s", (unsigned long)startCount, fst->getTimescaleString(), (unsigned long)stopCount, fst->getTimescaleString());
1556 if (cycles_set)
1557 log(" for %d clock cycle(s)",numcycles);
1558 log("\n");
1559
1560 std::stringstream f;
1561 f << stringf("`timescale 1%s/1%s\n", fst->getTimescaleString(),fst->getTimescaleString());
1562 f << stringf("module %s();\n",tb_filename.c_str());
1563 int clk_len = 0;
1564 int inputs_len = 0;
1565 int outputs_len = 0;
1566 for(auto &item : clocks) {
1567 clk_len += item.first->width;
1568 f << "\treg " << define_signal(item.first) << ";\n";
1569 }
1570 for(auto &item : inputs) {
1571 inputs_len += item.first->width;
1572 f << "\treg " << define_signal(item.first) << ";\n";
1573 }
1574 for(auto &item : outputs) {
1575 outputs_len += item.first->width;
1576 f << "\twire " << define_signal(item.first) << ";\n";
1577 }
1578 int data_len = clk_len + inputs_len + outputs_len + 32;
1579 f << "\n";
1580 f << stringf("\t%s uut(",RTLIL::unescape_id(topmod->name).c_str());
1581 for(auto item=clocks.begin();item!=clocks.end();item++)
1582 f << stringf("%c.%s(%s)", (item==clocks.begin() ? ' ' : ','), RTLIL::unescape_id(item->first->name).c_str(), RTLIL::unescape_id(item->first->name).c_str());
1583 for(auto &item : inputs)
1584 f << stringf(",.%s(%s)", RTLIL::unescape_id(item.first->name).c_str(), RTLIL::unescape_id(item.first->name).c_str());
1585 for(auto &item : outputs)
1586 f << stringf(",.%s(%s)", RTLIL::unescape_id(item.first->name).c_str(), RTLIL::unescape_id(item.first->name).c_str());
1587 f << ");\n";
1588 f << "\n";
1589 f << "\tinteger i;\n";
1590 uint64_t prev_time = startCount;
1591 log("Writing data to `%s`\n", (tb_filename+".txt").c_str());
1592 std::ofstream data_file(tb_filename+".txt");
1593 std::stringstream initstate;
1594 try {
1595 fst->reconstructAllAtTimes(fst_clock, startCount, stopCount, [&](uint64_t time) {
1596 for(auto &item : clocks)
1597 data_file << stringf("%s",fst->valueOf(item.second).c_str());
1598 for(auto &item : inputs)
1599 data_file << stringf("%s",fst->valueOf(item.second).c_str());
1600 for(auto &item : outputs)
1601 data_file << stringf("%s",fst->valueOf(item.second).c_str());
1602 data_file << stringf("%s\n",Const(time-prev_time).as_string().c_str());
1603
1604 if (time==startCount) {
1605 // initial state
1606 for(auto var : fst->getVars()) {
1607 if (var.is_reg && !Const::from_string(fst->valueOf(var.id).c_str()).is_fully_undef()) {
1608 if (var.scope == scope) {
1609 initstate << stringf("\t\tuut.%s = %d'b%s;\n", var.name.c_str(), var.width, fst->valueOf(var.id).c_str());
1610 } else if (var.scope.find(scope+".")==0) {
1611 initstate << stringf("\t\tuut.%s.%s = %d'b%s;\n",var.scope.substr(scope.size()+1).c_str(), var.name.c_str(), var.width, fst->valueOf(var.id).c_str());
1612 }
1613 }
1614 }
1615 }
1616 cycle++;
1617 prev_time = time;
1618
1619 // Limit to number of cycles if provided
1620 if (cycles_set && cycle > numcycles *2)
1621 throw fst_end_of_data_exception();
1622 if (time==stopCount)
1623 throw fst_end_of_data_exception();
1624 });
1625 } catch(fst_end_of_data_exception) {
1626 // end of data detected
1627 }
1628
1629 f << stringf("\treg [0:%d] data [0:%d];\n", data_len-1, cycle-1);
1630 f << "\tinitial begin;\n";
1631 f << stringf("\t\t$dumpfile(\"%s\");\n",tb_filename.c_str());
1632 f << stringf("\t\t$dumpvars(0,%s);\n",tb_filename.c_str());
1633 f << initstate.str();
1634 f << stringf("\t\t$readmemb(\"%s.txt\", data);\n",tb_filename.c_str());
1635
1636 f << stringf("\t\t#(data[0][%d:%d]);\n", data_len-32, data_len-1);
1637 f << stringf("\t\t{%s } = data[0][%d:%d];\n", signal_list(clocks).c_str(), 0, clk_len-1);
1638 f << stringf("\t\t{%s } <= data[0][%d:%d];\n", signal_list(inputs).c_str(), clk_len, clk_len+inputs_len-1);
1639
1640 f << stringf("\t\tfor (i = 1; i < %d; i++) begin\n",cycle);
1641
1642 f << stringf("\t\t\t#(data[i][%d:%d]);\n", data_len-32, data_len-1);
1643 f << stringf("\t\t\t{%s } = data[i][%d:%d];\n", signal_list(clocks).c_str(), 0, clk_len-1);
1644 f << stringf("\t\t\t{%s } <= data[i][%d:%d];\n", signal_list(inputs).c_str(), clk_len, clk_len+inputs_len-1);
1645
1646 f << stringf("\t\t\tif ({%s } != data[i-1][%d:%d]) begin\n", signal_list(outputs).c_str(), clk_len+inputs_len, clk_len+inputs_len+outputs_len-1);
1647 f << "\t\t\t\t$error(\"Signal difference detected\\n\");\n";
1648 f << "\t\t\tend\n";
1649
1650 f << "\t\tend\n";
1651
1652 f << "\t\t$finish;\n";
1653 f << "\tend\n";
1654 f << "endmodule\n";
1655
1656 log("Writing testbench to `%s`\n", (tb_filename+".v").c_str());
1657 std::ofstream tb_file(tb_filename+".v");
1658 tb_file << f.str();
1659
1660 delete fst;
1661 }
1662 };
1663
1664 struct VCDWriter : public OutputWriter
1665 {
1666 VCDWriter(SimWorker *worker, std::string filename) : OutputWriter(worker) {
1667 vcdfile.open(filename.c_str());
1668 }
1669
1670 void write(std::map<int, bool> &use_signal) override
1671 {
1672 if (!vcdfile.is_open()) return;
1673 vcdfile << stringf("$version %s $end\n", worker->date ? yosys_version_str : "Yosys");
1674
1675 if (worker->date) {
1676 std::time_t t = std::time(nullptr);
1677 char mbstr[255];
1678 if (std::strftime(mbstr, sizeof(mbstr), "%c", std::localtime(&t))) {
1679 vcdfile << stringf("$date ") << mbstr << stringf(" $end\n");
1680 }
1681 }
1682
1683 if (!worker->timescale.empty())
1684 vcdfile << stringf("$timescale %s $end\n", worker->timescale.c_str());
1685
1686 worker->top->write_output_header(
1687 [this](IdString name) { vcdfile << stringf("$scope module %s $end\n", log_id(name)); },
1688 [this]() { vcdfile << stringf("$upscope $end\n");},
1689 [this,use_signal](Wire *wire, int id, bool is_reg) { if (use_signal.at(id)) vcdfile << stringf("$var %s %d n%d %s%s $end\n", is_reg ? "reg" : "wire", GetSize(wire), id, wire->name[0] == '$' ? "\\" : "", log_id(wire)); }
1690 );
1691
1692 vcdfile << stringf("$enddefinitions $end\n");
1693
1694 for(auto& d : worker->output_data)
1695 {
1696 vcdfile << stringf("#%d\n", d.first);
1697 for (auto &data : d.second)
1698 {
1699 if (!use_signal.at(data.first)) continue;
1700 Const value = data.second;
1701 vcdfile << "b";
1702 for (int i = GetSize(value)-1; i >= 0; i--) {
1703 switch (value[i]) {
1704 case State::S0: vcdfile << "0"; break;
1705 case State::S1: vcdfile << "1"; break;
1706 case State::Sx: vcdfile << "x"; break;
1707 default: vcdfile << "z";
1708 }
1709 }
1710 vcdfile << stringf(" n%d\n", data.first);
1711 }
1712 }
1713 }
1714
1715 std::ofstream vcdfile;
1716 };
1717
1718 struct FSTWriter : public OutputWriter
1719 {
1720 FSTWriter(SimWorker *worker, std::string filename) : OutputWriter(worker) {
1721 fstfile = (struct fstContext *)fstWriterCreate(filename.c_str(),1);
1722 }
1723
1724 virtual ~FSTWriter()
1725 {
1726 fstWriterClose(fstfile);
1727 }
1728
1729 void write(std::map<int, bool> &use_signal) override
1730 {
1731 if (!fstfile) return;
1732 std::time_t t = std::time(nullptr);
1733 fstWriterSetVersion(fstfile, worker->date ? yosys_version_str : "Yosys");
1734 if (worker->date)
1735 fstWriterSetDate(fstfile, asctime(std::localtime(&t)));
1736 else
1737 fstWriterSetDate(fstfile, "");
1738 if (!worker->timescale.empty())
1739 fstWriterSetTimescaleFromString(fstfile, worker->timescale.c_str());
1740
1741 fstWriterSetPackType(fstfile, FST_WR_PT_FASTLZ);
1742 fstWriterSetRepackOnClose(fstfile, 1);
1743
1744 worker->top->write_output_header(
1745 [this](IdString name) { fstWriterSetScope(fstfile, FST_ST_VCD_MODULE, stringf("%s",log_id(name)).c_str(), nullptr); },
1746 [this]() { fstWriterSetUpscope(fstfile); },
1747 [this,use_signal](Wire *wire, int id, bool is_reg) {
1748 if (!use_signal.at(id)) return;
1749 fstHandle fst_id = fstWriterCreateVar(fstfile, is_reg ? FST_VT_VCD_REG : FST_VT_VCD_WIRE, FST_VD_IMPLICIT, GetSize(wire),
1750 stringf("%s%s", wire->name[0] == '$' ? "\\" : "", log_id(wire)).c_str(), 0);
1751
1752 mapping.emplace(id, fst_id);
1753 }
1754 );
1755
1756 for(auto& d : worker->output_data)
1757 {
1758 fstWriterEmitTimeChange(fstfile, d.first);
1759 for (auto &data : d.second)
1760 {
1761 if (!use_signal.at(data.first)) continue;
1762 Const value = data.second;
1763 std::stringstream ss;
1764 for (int i = GetSize(value)-1; i >= 0; i--) {
1765 switch (value[i]) {
1766 case State::S0: ss << "0"; break;
1767 case State::S1: ss << "1"; break;
1768 case State::Sx: ss << "x"; break;
1769 default: ss << "z";
1770 }
1771 }
1772 fstWriterEmitValueChange(fstfile, mapping[data.first], ss.str().c_str());
1773 }
1774 }
1775 }
1776
1777 struct fstContext *fstfile = nullptr;
1778 std::map<int,fstHandle> mapping;
1779 };
1780
1781 struct AIWWriter : public OutputWriter
1782 {
1783 AIWWriter(SimWorker *worker, std::string filename) : OutputWriter(worker) {
1784 aiwfile.open(filename.c_str());
1785 }
1786
1787 virtual ~AIWWriter()
1788 {
1789 aiwfile << '.' << '\n';
1790 }
1791
1792 void write(std::map<int, bool> &) override
1793 {
1794 if (!aiwfile.is_open()) return;
1795 if (worker->map_filename.empty())
1796 log_cmd_error("For AIGER witness file map parameter is mandatory.\n");
1797
1798 std::ifstream mf(worker->map_filename);
1799 std::string type, symbol;
1800 int variable, index;
1801 int max_input = 0;
1802 if (mf.fail())
1803 log_cmd_error("Not able to read AIGER witness map file.\n");
1804 while (mf >> type >> variable >> index >> symbol) {
1805 RTLIL::IdString escaped_s = RTLIL::escape_id(symbol);
1806 Wire *w = worker->top->module->wire(escaped_s);
1807 if (!w)
1808 log_error("Wire %s not present in module %s\n",log_id(escaped_s),log_id(worker->top->module));
1809 if (index < w->start_offset || index > w->start_offset + w->width)
1810 log_error("Index %d for wire %s is out of range\n", index, log_signal(w));
1811 if (type == "input") {
1812 aiw_inputs[variable] = SigBit(w,index-w->start_offset);
1813 if (worker->clock.count(escaped_s)) {
1814 clocks[variable] = true;
1815 }
1816 if (worker->clockn.count(escaped_s)) {
1817 clocks[variable] = false;
1818 }
1819 max_input = max(max_input,variable);
1820 } else if (type == "init") {
1821 aiw_inits[variable] = SigBit(w,index-w->start_offset);
1822 max_input = max(max_input,variable);
1823 } else if (type == "latch") {
1824 aiw_latches[variable] = {SigBit(w,index-w->start_offset), false};
1825 } else if (type == "invlatch") {
1826 aiw_latches[variable] = {SigBit(w,index-w->start_offset), true};
1827 }
1828 }
1829
1830 worker->top->write_output_header(
1831 [](IdString) {},
1832 []() {},
1833 [this](Wire *wire, int id, bool) { mapping[wire] = id; }
1834 );
1835
1836 std::map<int, Yosys::RTLIL::Const> current;
1837 bool first = true;
1838 for (auto iter = worker->output_data.begin(); iter != std::prev(worker->output_data.end()); ++iter)
1839 {
1840 auto& d = *iter;
1841 for (auto &data : d.second)
1842 {
1843 current[data.first] = data.second;
1844 }
1845 if (first) {
1846 for (int i = 0;; i++)
1847 {
1848 if (aiw_latches.count(i)) {
1849 aiwfile << '0';
1850 continue;
1851 }
1852 aiwfile << '\n';
1853 break;
1854 }
1855 first = false;
1856 }
1857
1858 bool skip = false;
1859 for (auto it : clocks)
1860 {
1861 auto val = it.second ? State::S1 : State::S0;
1862 SigBit bit = aiw_inputs.at(it.first);
1863 auto v = current[mapping[bit.wire]].bits.at(bit.offset);
1864 if (v == val)
1865 skip = true;
1866 }
1867 if (skip)
1868 continue;
1869 for (int i = 0; i <= max_input; i++)
1870 {
1871 if (aiw_inputs.count(i)) {
1872 SigBit bit = aiw_inputs.at(i);
1873 auto v = current[mapping[bit.wire]].bits.at(bit.offset);
1874 if (v == State::S1)
1875 aiwfile << '1';
1876 else
1877 aiwfile << '0';
1878 continue;
1879 }
1880 if (aiw_inits.count(i)) {
1881 SigBit bit = aiw_inits.at(i);
1882 auto v = current[mapping[bit.wire]].bits.at(bit.offset);
1883 if (v == State::S1)
1884 aiwfile << '1';
1885 else
1886 aiwfile << '0';
1887 continue;
1888 }
1889 aiwfile << '0';
1890 }
1891 aiwfile << '\n';
1892 }
1893 }
1894
1895 std::ofstream aiwfile;
1896 dict<int, std::pair<SigBit, bool>> aiw_latches;
1897 dict<int, SigBit> aiw_inputs, aiw_inits;
1898 dict<int, bool> clocks;
1899 std::map<Wire*,int> mapping;
1900 };
1901
1902 struct SimPass : public Pass {
1903 SimPass() : Pass("sim", "simulate the circuit") { }
1904 void help() override
1905 {
1906 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1907 log("\n");
1908 log(" sim [options] [top-level]\n");
1909 log("\n");
1910 log("This command simulates the circuit using the given top-level module.\n");
1911 log("\n");
1912 log(" -vcd <filename>\n");
1913 log(" write the simulation results to the given VCD file\n");
1914 log("\n");
1915 log(" -fst <filename>\n");
1916 log(" write the simulation results to the given FST file\n");
1917 log("\n");
1918 log(" -aiw <filename>\n");
1919 log(" write the simulation results to an AIGER witness file\n");
1920 log(" (requires a *.aim file via -map)\n");
1921 log("\n");
1922 log(" -x\n");
1923 log(" ignore constant x outputs in simulation file.\n");
1924 log("\n");
1925 log(" -date\n");
1926 log(" include date and full version info in output.\n");
1927 log("\n");
1928 log(" -clock <portname>\n");
1929 log(" name of top-level clock input\n");
1930 log("\n");
1931 log(" -clockn <portname>\n");
1932 log(" name of top-level clock input (inverse polarity)\n");
1933 log("\n");
1934 log(" -multiclock\n");
1935 log(" mark that witness file is multiclock.\n");
1936 log("\n");
1937 log(" -reset <portname>\n");
1938 log(" name of top-level reset input (active high)\n");
1939 log("\n");
1940 log(" -resetn <portname>\n");
1941 log(" name of top-level inverted reset input (active low)\n");
1942 log("\n");
1943 log(" -rstlen <integer>\n");
1944 log(" number of cycles reset should stay active (default: 1)\n");
1945 log("\n");
1946 log(" -zinit\n");
1947 log(" zero-initialize all uninitialized regs and memories\n");
1948 log("\n");
1949 log(" -timescale <string>\n");
1950 log(" include the specified timescale declaration in the vcd\n");
1951 log("\n");
1952 log(" -n <integer>\n");
1953 log(" number of clock cycles to simulate (default: 20)\n");
1954 log("\n");
1955 log(" -a\n");
1956 log(" use all nets in VCD/FST operations, not just those with public names\n");
1957 log("\n");
1958 log(" -w\n");
1959 log(" writeback mode: use final simulation state as new init state\n");
1960 log("\n");
1961 log(" -r\n");
1962 log(" read simulation results file (file formats supported: FST, VCD, AIW and WIT)\n");
1963 log(" VCD support requires vcd2fst external tool to be present\n");
1964 log("\n");
1965 log(" -map <filename>\n");
1966 log(" read file with port and latch symbols, needed for AIGER witness input\n");
1967 log("\n");
1968 log(" -scope <name>\n");
1969 log(" scope of simulation top model\n");
1970 log("\n");
1971 log(" -at <time>\n");
1972 log(" sets start and stop time\n");
1973 log("\n");
1974 log(" -start <time>\n");
1975 log(" start co-simulation in arbitary time (default 0)\n");
1976 log("\n");
1977 log(" -stop <time>\n");
1978 log(" stop co-simulation in arbitary time (default END)\n");
1979 log("\n");
1980 log(" -sim\n");
1981 log(" simulation with stimulus from FST (default)\n");
1982 log("\n");
1983 log(" -sim-cmp\n");
1984 log(" co-simulation expect exact match\n");
1985 log("\n");
1986 log(" -sim-gold\n");
1987 log(" co-simulation, x in simulation can match any value in FST\n");
1988 log("\n");
1989 log(" -sim-gate\n");
1990 log(" co-simulation, x in FST can match any value in simulation\n");
1991 log("\n");
1992 log(" -q\n");
1993 log(" disable per-cycle/sample log message\n");
1994 log("\n");
1995 log(" -d\n");
1996 log(" enable debug output\n");
1997 log("\n");
1998 }
1999
2000
2001 static std::string file_base_name(std::string const & path)
2002 {
2003 return path.substr(path.find_last_of("/\\") + 1);
2004 }
2005
2006 void execute(std::vector<std::string> args, RTLIL::Design *design) override
2007 {
2008 SimWorker worker;
2009 int numcycles = 20;
2010 bool start_set = false, stop_set = false, at_set = false;
2011
2012 log_header(design, "Executing SIM pass (simulate the circuit).\n");
2013
2014 size_t argidx;
2015 for (argidx = 1; argidx < args.size(); argidx++) {
2016 if (args[argidx] == "-vcd" && argidx+1 < args.size()) {
2017 std::string vcd_filename = args[++argidx];
2018 rewrite_filename(vcd_filename);
2019 worker.outputfiles.emplace_back(std::unique_ptr<VCDWriter>(new VCDWriter(&worker, vcd_filename.c_str())));
2020 continue;
2021 }
2022 if (args[argidx] == "-fst" && argidx+1 < args.size()) {
2023 std::string fst_filename = args[++argidx];
2024 rewrite_filename(fst_filename);
2025 worker.outputfiles.emplace_back(std::unique_ptr<FSTWriter>(new FSTWriter(&worker, fst_filename.c_str())));
2026 continue;
2027 }
2028 if (args[argidx] == "-aiw" && argidx+1 < args.size()) {
2029 std::string aiw_filename = args[++argidx];
2030 rewrite_filename(aiw_filename);
2031 worker.outputfiles.emplace_back(std::unique_ptr<AIWWriter>(new AIWWriter(&worker, aiw_filename.c_str())));
2032 continue;
2033 }
2034 if (args[argidx] == "-n" && argidx+1 < args.size()) {
2035 numcycles = atoi(args[++argidx].c_str());
2036 worker.cycles_set = true;
2037 continue;
2038 }
2039 if (args[argidx] == "-rstlen" && argidx+1 < args.size()) {
2040 worker.rstlen = atoi(args[++argidx].c_str());
2041 continue;
2042 }
2043 if (args[argidx] == "-clock" && argidx+1 < args.size()) {
2044 worker.clock.insert(RTLIL::escape_id(args[++argidx]));
2045 continue;
2046 }
2047 if (args[argidx] == "-clockn" && argidx+1 < args.size()) {
2048 worker.clockn.insert(RTLIL::escape_id(args[++argidx]));
2049 continue;
2050 }
2051 if (args[argidx] == "-reset" && argidx+1 < args.size()) {
2052 worker.reset.insert(RTLIL::escape_id(args[++argidx]));
2053 continue;
2054 }
2055 if (args[argidx] == "-resetn" && argidx+1 < args.size()) {
2056 worker.resetn.insert(RTLIL::escape_id(args[++argidx]));
2057 continue;
2058 }
2059 if (args[argidx] == "-timescale" && argidx+1 < args.size()) {
2060 worker.timescale = args[++argidx];
2061 continue;
2062 }
2063 if (args[argidx] == "-a") {
2064 worker.hide_internal = false;
2065 continue;
2066 }
2067 if (args[argidx] == "-q") {
2068 worker.verbose = false;
2069 continue;
2070 }
2071 if (args[argidx] == "-d") {
2072 worker.debug = true;
2073 continue;
2074 }
2075 if (args[argidx] == "-w") {
2076 worker.writeback = true;
2077 continue;
2078 }
2079 if (args[argidx] == "-zinit") {
2080 worker.zinit = true;
2081 continue;
2082 }
2083 if (args[argidx] == "-r" && argidx+1 < args.size()) {
2084 std::string sim_filename = args[++argidx];
2085 rewrite_filename(sim_filename);
2086 worker.sim_filename = sim_filename;
2087 continue;
2088 }
2089 if (args[argidx] == "-map" && argidx+1 < args.size()) {
2090 std::string map_filename = args[++argidx];
2091 rewrite_filename(map_filename);
2092 worker.map_filename = map_filename;
2093 continue;
2094 }
2095 if (args[argidx] == "-scope" && argidx+1 < args.size()) {
2096 worker.scope = args[++argidx];
2097 continue;
2098 }
2099 if (args[argidx] == "-start" && argidx+1 < args.size()) {
2100 worker.start_time = stringToTime(args[++argidx]);
2101 start_set = true;
2102 continue;
2103 }
2104 if (args[argidx] == "-stop" && argidx+1 < args.size()) {
2105 worker.stop_time = stringToTime(args[++argidx]);
2106 stop_set = true;
2107 continue;
2108 }
2109 if (args[argidx] == "-at" && argidx+1 < args.size()) {
2110 worker.start_time = stringToTime(args[++argidx]);
2111 worker.stop_time = worker.start_time;
2112 at_set = true;
2113 continue;
2114 }
2115 if (args[argidx] == "-sim") {
2116 worker.sim_mode = SimulationMode::sim;
2117 continue;
2118 }
2119 if (args[argidx] == "-sim-cmp") {
2120 worker.sim_mode = SimulationMode::cmp;
2121 continue;
2122 }
2123 if (args[argidx] == "-sim-gold") {
2124 worker.sim_mode = SimulationMode::gold;
2125 continue;
2126 }
2127 if (args[argidx] == "-sim-gate") {
2128 worker.sim_mode = SimulationMode::gate;
2129 continue;
2130 }
2131 if (args[argidx] == "-x") {
2132 worker.ignore_x = true;
2133 continue;
2134 }
2135 if (args[argidx] == "-date") {
2136 worker.date = true;
2137 continue;
2138 }
2139 if (args[argidx] == "-multiclock") {
2140 worker.multiclock = true;
2141 continue;
2142 }
2143 break;
2144 }
2145 extra_args(args, argidx, design);
2146 if (at_set && (start_set || stop_set || worker.cycles_set))
2147 log_error("'at' option can only be defined separate of 'start','stop' and 'n'\n");
2148 if (stop_set && worker.cycles_set)
2149 log_error("'stop' and 'n' can only be used exclusively'\n");
2150
2151 Module *top_mod = nullptr;
2152
2153 if (design->full_selection()) {
2154 top_mod = design->top_module();
2155
2156 if (!top_mod)
2157 log_cmd_error("Design has no top module, use the 'hierarchy' command to specify one.\n");
2158 } else {
2159 auto mods = design->selected_whole_modules();
2160 if (GetSize(mods) != 1)
2161 log_cmd_error("Only one top module must be selected.\n");
2162 top_mod = mods.front();
2163 }
2164
2165 if (worker.sim_filename.empty())
2166 worker.run(top_mod, numcycles);
2167 else {
2168 std::string filename_trim = file_base_name(worker.sim_filename);
2169 if (filename_trim.size() > 4 && ((filename_trim.compare(filename_trim.size()-4, std::string::npos, ".fst") == 0) ||
2170 filename_trim.compare(filename_trim.size()-4, std::string::npos, ".vcd") == 0)) {
2171 worker.run_cosim_fst(top_mod, numcycles);
2172 } else if (filename_trim.size() > 4 && filename_trim.compare(filename_trim.size()-4, std::string::npos, ".aiw") == 0) {
2173 if (worker.map_filename.empty())
2174 log_cmd_error("For AIGER witness file map parameter is mandatory.\n");
2175 worker.run_cosim_aiger_witness(top_mod);
2176 } else if (filename_trim.size() > 4 && filename_trim.compare(filename_trim.size()-4, std::string::npos, ".wit") == 0) {
2177 worker.run_cosim_btor2_witness(top_mod);
2178 } else {
2179 log_cmd_error("Unhandled extension for simulation input file `%s`.\n", worker.sim_filename.c_str());
2180 }
2181 }
2182 }
2183 } SimPass;
2184
2185 struct Fst2TbPass : public Pass {
2186 Fst2TbPass() : Pass("fst2tb", "generate testbench out of fst file") { }
2187 void help() override
2188 {
2189 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
2190 log("\n");
2191 log(" fst2tb [options] [top-level]\n");
2192 log("\n");
2193 log("This command generates testbench for the circuit using the given top-level module\n");
2194 log("and simulus signal from FST file\n");
2195 log("\n");
2196 log(" -tb <name>\n");
2197 log(" generated testbench name.\n");
2198 log(" files <name>.v and <name>.txt are created as result.\n");
2199 log("\n");
2200 log(" -r <filename>\n");
2201 log(" read simulation FST file\n");
2202 log("\n");
2203 log(" -clock <portname>\n");
2204 log(" name of top-level clock input\n");
2205 log("\n");
2206 log(" -clockn <portname>\n");
2207 log(" name of top-level clock input (inverse polarity)\n");
2208 log("\n");
2209 log(" -scope <name>\n");
2210 log(" scope of simulation top model\n");
2211 log("\n");
2212 log(" -start <time>\n");
2213 log(" start co-simulation in arbitary time (default 0)\n");
2214 log("\n");
2215 log(" -stop <time>\n");
2216 log(" stop co-simulation in arbitary time (default END)\n");
2217 log("\n");
2218 log(" -n <integer>\n");
2219 log(" number of clock cycles to simulate (default: 20)\n");
2220 log("\n");
2221 }
2222
2223 void execute(std::vector<std::string> args, RTLIL::Design *design) override
2224 {
2225 SimWorker worker;
2226 int numcycles = 20;
2227 bool stop_set = false;
2228 std::string tb_filename;
2229
2230 log_header(design, "Executing FST2FB pass.\n");
2231
2232 size_t argidx;
2233 for (argidx = 1; argidx < args.size(); argidx++) {
2234 if (args[argidx] == "-clock" && argidx+1 < args.size()) {
2235 worker.clock.insert(RTLIL::escape_id(args[++argidx]));
2236 continue;
2237 }
2238 if (args[argidx] == "-clockn" && argidx+1 < args.size()) {
2239 worker.clockn.insert(RTLIL::escape_id(args[++argidx]));
2240 continue;
2241 }
2242 if (args[argidx] == "-r" && argidx+1 < args.size()) {
2243 std::string sim_filename = args[++argidx];
2244 rewrite_filename(sim_filename);
2245 worker.sim_filename = sim_filename;
2246 continue;
2247 }
2248 if (args[argidx] == "-n" && argidx+1 < args.size()) {
2249 numcycles = atoi(args[++argidx].c_str());
2250 worker.cycles_set = true;
2251 continue;
2252 }
2253 if (args[argidx] == "-scope" && argidx+1 < args.size()) {
2254 worker.scope = args[++argidx];
2255 continue;
2256 }
2257 if (args[argidx] == "-start" && argidx+1 < args.size()) {
2258 worker.start_time = stringToTime(args[++argidx]);
2259 continue;
2260 }
2261 if (args[argidx] == "-stop" && argidx+1 < args.size()) {
2262 worker.stop_time = stringToTime(args[++argidx]);
2263 stop_set = true;
2264 continue;
2265 }
2266 if (args[argidx] == "-tb" && argidx+1 < args.size()) {
2267 tb_filename = args[++argidx];
2268 continue;
2269 }
2270 break;
2271 }
2272 extra_args(args, argidx, design);
2273 if (stop_set && worker.cycles_set)
2274 log_error("'stop' and 'n' can only be used exclusively'\n");
2275
2276 Module *top_mod = nullptr;
2277
2278 if (design->full_selection()) {
2279 top_mod = design->top_module();
2280
2281 if (!top_mod)
2282 log_cmd_error("Design has no top module, use the 'hierarchy' command to specify one.\n");
2283 } else {
2284 auto mods = design->selected_whole_modules();
2285 if (GetSize(mods) != 1)
2286 log_cmd_error("Only one top module must be selected.\n");
2287 top_mod = mods.front();
2288 }
2289
2290 if (tb_filename.empty())
2291 log_cmd_error("Testbench name must be defined.\n");
2292
2293 if (worker.sim_filename.empty())
2294 log_cmd_error("Stimulus FST file must be defined.\n");
2295
2296 worker.generate_tb(top_mod, tb_filename, numcycles);
2297 }
2298 } Fst2TbPass;
2299
2300 PRIVATE_NAMESPACE_END