2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
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.
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.
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"
30 PRIVATE_NAMESPACE_BEGIN
32 enum class SimulationMode
{
39 static const std::map
<std::string
, int> g_units
=
41 { "", -9 }, // default is ns
52 static double stringToTime(std::string str
)
54 if (str
=="END") return -1;
57 long value
= strtol(str
.c_str(), &endptr
, 10);
59 if (g_units
.find(endptr
)==g_units
.end())
60 log_error("Cannot parse '%s', bad unit '%s'\n", str
.c_str(), endptr
);
63 log_error("Time value '%s' must be positive\n", str
.c_str());
65 return value
* pow(10.0, g_units
.at(endptr
));
71 OutputWriter(SimWorker
*w
) { worker
= w
;};
72 virtual ~OutputWriter() {};
73 virtual void write(std::map
<int, bool> &use_signal
) = 0;
80 bool hide_internal
= true;
81 bool writeback
= false;
84 FstData
*fst
= nullptr;
85 double start_time
= 0;
86 double stop_time
= -1;
87 SimulationMode sim_mode
= SimulationMode::sim
;
88 bool cycles_set
= false;
89 std::vector
<std::unique_ptr
<OutputWriter
>> outputfiles
;
90 std::vector
<std::pair
<int,std::map
<int,Const
>>> output_data
;
91 bool ignore_x
= false;
103 for (auto &bit
: v
.bits
)
116 dict
<Cell
*, SimInstance
*> children
;
119 dict
<SigBit
, State
> state_nets
;
120 dict
<SigBit
, pool
<Cell
*>> upd_cells
;
121 dict
<SigBit
, pool
<Wire
*>> upd_outports
;
123 pool
<SigBit
> dirty_bits
;
124 pool
<Cell
*> dirty_cells
;
125 pool
<IdString
> dirty_memories
;
126 pool
<SimInstance
*, hash_ptr_ops
> dirty_children
;
142 std::vector
<Const
> past_wr_clk
;
143 std::vector
<Const
> past_wr_en
;
144 std::vector
<Const
> past_wr_addr
;
145 std::vector
<Const
> past_wr_data
;
149 dict
<Cell
*, ff_state_t
> ff_database
;
150 dict
<IdString
, mem_state_t
> mem_database
;
151 pool
<Cell
*> formal_database
;
152 dict
<Cell
*, IdString
> mem_cells
;
154 std::vector
<Mem
> memories
;
156 dict
<Wire
*, pair
<int, Const
>> signal_database
;
157 dict
<Wire
*, fstHandle
> fst_handles
;
159 SimInstance(SimShared
*shared
, std::string scope
, Module
*module
, Cell
*instance
= nullptr, SimInstance
*parent
= nullptr) :
160 shared(shared
), scope(scope
), module(module
), instance(instance
), parent(parent
), sigmap(module
)
165 log_assert(parent
->children
.count(instance
) == 0);
166 parent
->children
[instance
] = this;
169 for (auto wire
: module
->wires())
171 SigSpec sig
= sigmap(wire
);
173 for (int i
= 0; i
< GetSize(sig
); i
++) {
174 if (state_nets
.count(sig
[i
]) == 0)
175 state_nets
[sig
[i
]] = State::Sx
;
176 if (wire
->port_output
) {
177 upd_outports
[sig
[i
]].insert(wire
);
178 dirty_bits
.insert(sig
[i
]);
182 if ((shared
->fst
) && !(shared
->hide_internal
&& wire
->name
[0] == '$')) {
183 fstHandle id
= shared
->fst
->getHandle(scope
+ "." + RTLIL::unescape_id(wire
->name
));
184 if (id
==0 && wire
->name
.isPublic())
185 log_warning("Unable to found wire %s in input file.\n", (scope
+ "." + RTLIL::unescape_id(wire
->name
)).c_str());
186 fst_handles
[wire
] = id
;
189 if (wire
->attributes
.count(ID::init
)) {
190 Const initval
= wire
->attributes
.at(ID::init
);
191 for (int i
= 0; i
< GetSize(sig
) && i
< GetSize(initval
); i
++)
192 if (initval
[i
] == State::S0
|| initval
[i
] == State::S1
) {
193 state_nets
[sig
[i
]] = initval
[i
];
194 dirty_bits
.insert(sig
[i
]);
199 memories
= Mem::get_all_memories(module
);
200 for (auto &mem
: memories
) {
201 auto &mdb
= mem_database
[mem
.memid
];
203 for (auto &port
: mem
.wr_ports
) {
204 mdb
.past_wr_clk
.push_back(Const(State::Sx
));
205 mdb
.past_wr_en
.push_back(Const(State::Sx
, GetSize(port
.en
)));
206 mdb
.past_wr_addr
.push_back(Const(State::Sx
, GetSize(port
.addr
)));
207 mdb
.past_wr_data
.push_back(Const(State::Sx
, GetSize(port
.data
)));
209 mdb
.data
= mem
.get_init_data();
212 for (auto cell
: module
->cells())
214 Module
*mod
= module
->design
->module(cell
->type
);
216 if (mod
!= nullptr) {
217 dirty_children
.insert(new SimInstance(shared
, scope
+ "." + RTLIL::unescape_id(cell
->name
), mod
, cell
, this));
220 for (auto &port
: cell
->connections()) {
221 if (cell
->input(port
.first
))
222 for (auto bit
: sigmap(port
.second
)) {
223 upd_cells
[bit
].insert(cell
);
224 // Make sure cell inputs connected to constants are updated in the first cycle
225 if (bit
.wire
== nullptr)
226 dirty_bits
.insert(bit
);
230 if (RTLIL::builtin_ff_cell_types().count(cell
->type
)) {
231 FfData
ff_data(nullptr, cell
);
233 ff
.past_d
= Const(State::Sx
, ff_data
.width
);
234 ff
.past_ad
= Const(State::Sx
, ff_data
.width
);
235 ff
.past_clk
= State::Sx
;
236 ff
.past_ce
= State::Sx
;
237 ff
.past_srst
= State::Sx
;
239 ff_database
[cell
] = ff
;
242 if (cell
->is_mem_cell())
244 mem_cells
[cell
] = cell
->parameters
.at(ID::MEMID
).decode_string();
246 if (cell
->type
.in(ID($
assert), ID($cover
), ID($assume
))) {
247 formal_database
.insert(cell
);
253 for (auto &it
: ff_database
)
255 ff_state_t
&ff
= it
.second
;
258 SigSpec qsig
= it
.second
.data
.sig_q
;
259 Const qdata
= get_state(qsig
);
261 set_state(qsig
, qdata
);
264 for (auto &it
: mem_database
) {
265 mem_state_t
&mem
= it
.second
;
266 for (auto &val
: mem
.past_wr_en
)
275 for (auto child
: children
)
279 IdString
name() const
281 if (instance
!= nullptr)
282 return instance
->name
;
286 std::string
hiername() const
288 if (instance
!= nullptr)
289 return parent
->hiername() + "." + log_id(instance
->name
);
291 return log_id(module
->name
);
294 Const
get_state(SigSpec sig
)
298 for (auto bit
: sigmap(sig
))
299 if (bit
.wire
== nullptr)
300 value
.bits
.push_back(bit
.data
);
301 else if (state_nets
.count(bit
))
302 value
.bits
.push_back(state_nets
.at(bit
));
304 value
.bits
.push_back(State::Sz
);
307 log("[%s] get %s: %s\n", hiername().c_str(), log_signal(sig
), log_signal(value
));
311 bool set_state(SigSpec sig
, Const value
)
313 bool did_something
= false;
316 log_assert(GetSize(sig
) <= GetSize(value
));
318 for (int i
= 0; i
< GetSize(sig
); i
++)
319 if (state_nets
.at(sig
[i
]) != value
[i
]) {
320 state_nets
.at(sig
[i
]) = value
[i
];
321 dirty_bits
.insert(sig
[i
]);
322 did_something
= true;
326 log("[%s] set %s: %s\n", hiername().c_str(), log_signal(sig
), log_signal(value
));
327 return did_something
;
330 void set_memory_state(IdString memid
, Const addr
, Const data
)
332 auto &state
= mem_database
[memid
];
334 int offset
= (addr
.as_int() - state
.mem
->start_offset
) * state
.mem
->width
;
335 for (int i
= 0; i
< GetSize(data
); i
++)
336 if (0 <= i
+offset
&& i
+offset
< GetSize(data
))
337 state
.data
.bits
[i
+offset
] = data
.bits
[i
];
340 void update_cell(Cell
*cell
)
342 if (ff_database
.count(cell
))
345 if (formal_database
.count(cell
))
348 if (mem_cells
.count(cell
))
350 dirty_memories
.insert(mem_cells
[cell
]);
354 if (children
.count(cell
))
356 auto child
= children
.at(cell
);
357 for (auto &conn
: cell
->connections())
358 if (cell
->input(conn
.first
) && GetSize(conn
.second
)) {
359 Const value
= get_state(conn
.second
);
360 child
->set_state(child
->module
->wire(conn
.first
), value
);
362 dirty_children
.insert(child
);
366 if (yosys_celltypes
.cell_evaluable(cell
->type
))
368 RTLIL::SigSpec sig_a
, sig_b
, sig_c
, sig_d
, sig_s
, sig_y
;
369 bool has_a
, has_b
, has_c
, has_d
, has_s
, has_y
;
371 has_a
= cell
->hasPort(ID::A
);
372 has_b
= cell
->hasPort(ID::B
);
373 has_c
= cell
->hasPort(ID::C
);
374 has_d
= cell
->hasPort(ID::D
);
375 has_s
= cell
->hasPort(ID::S
);
376 has_y
= cell
->hasPort(ID::Y
);
378 if (has_a
) sig_a
= cell
->getPort(ID::A
);
379 if (has_b
) sig_b
= cell
->getPort(ID::B
);
380 if (has_c
) sig_c
= cell
->getPort(ID::C
);
381 if (has_d
) sig_d
= cell
->getPort(ID::D
);
382 if (has_s
) sig_s
= cell
->getPort(ID::S
);
383 if (has_y
) sig_y
= cell
->getPort(ID::Y
);
386 log("[%s] eval %s (%s)\n", hiername().c_str(), log_id(cell
), log_id(cell
->type
));
388 // Simple (A -> Y) and (A,B -> Y) cells
389 if (has_a
&& !has_c
&& !has_d
&& !has_s
&& has_y
) {
390 set_state(sig_y
, CellTypes::eval(cell
, get_state(sig_a
), get_state(sig_b
)));
394 // (A,B,C -> Y) cells
395 if (has_a
&& has_b
&& has_c
&& !has_d
&& !has_s
&& has_y
) {
396 set_state(sig_y
, CellTypes::eval(cell
, get_state(sig_a
), get_state(sig_b
), get_state(sig_c
)));
401 if (has_a
&& !has_b
&& !has_c
&& !has_d
&& has_s
&& has_y
) {
402 set_state(sig_y
, CellTypes::eval(cell
, get_state(sig_a
), get_state(sig_s
)));
406 // (A,B,S -> Y) cells
407 if (has_a
&& has_b
&& !has_c
&& !has_d
&& has_s
&& has_y
) {
408 set_state(sig_y
, CellTypes::eval(cell
, get_state(sig_a
), get_state(sig_b
), get_state(sig_s
)));
412 log_warning("Unsupported evaluable cell type: %s (%s.%s)\n", log_id(cell
->type
), log_id(module
), log_id(cell
));
416 log_error("Unsupported cell type: %s (%s.%s)\n", log_id(cell
->type
), log_id(module
), log_id(cell
));
419 void update_memory(IdString id
) {
420 auto &mdb
= mem_database
[id
];
421 auto &mem
= *mdb
.mem
;
423 for (int port_idx
= 0; port_idx
< GetSize(mem
.rd_ports
); port_idx
++)
425 auto &port
= mem
.rd_ports
[port_idx
];
426 Const addr
= get_state(port
.addr
);
427 Const data
= Const(State::Sx
, mem
.width
<< port
.wide_log2
);
430 log_error("Memory %s.%s has clocked read ports. Run 'memory' with -nordff.\n", log_id(module
), log_id(mem
.memid
));
432 if (addr
.is_fully_def()) {
433 int index
= addr
.as_int() - mem
.start_offset
;
434 if (index
>= 0 && index
< mem
.size
)
435 data
= mdb
.data
.extract(index
*mem
.width
, mem
.width
<< port
.wide_log2
);
438 set_state(port
.data
, data
);
444 pool
<Cell
*> queue_cells
;
445 pool
<Wire
*> queue_outports
;
447 queue_cells
.swap(dirty_cells
);
451 for (auto bit
: dirty_bits
)
453 if (upd_cells
.count(bit
))
454 for (auto cell
: upd_cells
.at(bit
))
455 queue_cells
.insert(cell
);
457 if (upd_outports
.count(bit
) && parent
!= nullptr)
458 for (auto wire
: upd_outports
.at(bit
))
459 queue_outports
.insert(wire
);
464 if (!queue_cells
.empty())
466 for (auto cell
: queue_cells
)
473 for (auto &memid
: dirty_memories
)
474 update_memory(memid
);
475 dirty_memories
.clear();
477 for (auto wire
: queue_outports
)
478 if (instance
->hasPort(wire
->name
)) {
479 Const value
= get_state(wire
);
480 parent
->set_state(instance
->getPort(wire
->name
), value
);
483 queue_outports
.clear();
485 for (auto child
: dirty_children
)
488 dirty_children
.clear();
490 if (dirty_bits
.empty())
497 bool did_something
= false;
499 for (auto &it
: ff_database
)
501 ff_state_t
&ff
= it
.second
;
502 FfData
&ff_data
= ff
.data
;
504 Const current_q
= get_state(ff
.data
.sig_q
);
506 if (ff_data
.has_clk
) {
508 State current_clk
= get_state(ff_data
.sig_clk
)[0];
509 if (ff_data
.pol_clk
? (ff
.past_clk
== State::S0
&& current_clk
!= State::S0
) :
510 (ff
.past_clk
== State::S1
&& current_clk
!= State::S1
)) {
511 bool ce
= ff
.past_ce
== (ff_data
.pol_ce
? State::S1
: State::S0
);
512 // set if no ce, or ce is enabled
513 if (!ff_data
.has_ce
|| (ff_data
.has_ce
&& ce
)) {
514 current_q
= ff
.past_d
;
516 // override if sync reset
517 if ((ff_data
.has_srst
) && (ff
.past_srst
== (ff_data
.pol_srst
? State::S1
: State::S0
)) &&
518 ((!ff_data
.ce_over_srst
) || (ff_data
.ce_over_srst
&& ce
))) {
519 current_q
= ff_data
.val_srst
;
524 if (ff_data
.has_aload
) {
525 State current_aload
= get_state(ff_data
.sig_aload
)[0];
526 if (current_aload
== (ff_data
.pol_aload
? State::S1
: State::S0
)) {
527 current_q
= ff_data
.has_clk
? ff
.past_ad
: get_state(ff
.data
.sig_ad
);
531 if (ff_data
.has_arst
) {
532 State current_arst
= get_state(ff_data
.sig_arst
)[0];
533 if (current_arst
== (ff_data
.pol_arst
? State::S1
: State::S0
)) {
534 current_q
= ff_data
.val_arst
;
538 if (ff
.data
.has_sr
) {
539 Const current_clr
= get_state(ff
.data
.sig_clr
);
540 Const current_set
= get_state(ff
.data
.sig_set
);
542 for(int i
=0;i
<ff
.past_d
.size();i
++) {
543 if (current_clr
[i
] == (ff_data
.pol_clr
? State::S1
: State::S0
)) {
544 current_q
[i
] = State::S0
;
546 else if (current_set
[i
] == (ff_data
.pol_set
? State::S1
: State::S0
)) {
547 current_q
[i
] = State::S1
;
551 if (ff_data
.has_gclk
) {
553 current_q
= ff
.past_d
;
555 if (set_state(ff_data
.sig_q
, current_q
))
556 did_something
= true;
559 for (auto &it
: mem_database
)
561 mem_state_t
&mdb
= it
.second
;
562 auto &mem
= *mdb
.mem
;
564 for (int port_idx
= 0; port_idx
< GetSize(mem
.wr_ports
); port_idx
++)
566 auto &port
= mem
.wr_ports
[port_idx
];
567 Const addr
, data
, enable
;
569 if (!port
.clk_enable
)
571 addr
= get_state(port
.addr
);
572 data
= get_state(port
.data
);
573 enable
= get_state(port
.en
);
577 if (port
.clk_polarity
?
578 (mdb
.past_wr_clk
[port_idx
] == State::S1
|| get_state(port
.clk
) != State::S1
) :
579 (mdb
.past_wr_clk
[port_idx
] == State::S0
|| get_state(port
.clk
) != State::S0
))
582 addr
= mdb
.past_wr_addr
[port_idx
];
583 data
= mdb
.past_wr_data
[port_idx
];
584 enable
= mdb
.past_wr_en
[port_idx
];
587 if (addr
.is_fully_def())
589 int index
= addr
.as_int() - mem
.start_offset
;
590 if (index
>= 0 && index
< mem
.size
)
591 for (int i
= 0; i
< (mem
.width
<< port
.wide_log2
); i
++)
592 if (enable
[i
] == State::S1
&& mdb
.data
.bits
.at(index
*mem
.width
+i
) != data
[i
]) {
593 mdb
.data
.bits
.at(index
*mem
.width
+i
) = data
[i
];
594 dirty_memories
.insert(mem
.memid
);
595 did_something
= true;
601 for (auto it
: children
)
602 if (it
.second
->update_ph2()) {
603 dirty_children
.insert(it
.second
);
604 did_something
= true;
607 return did_something
;
612 for (auto &it
: ff_database
)
614 ff_state_t
&ff
= it
.second
;
616 if (ff
.data
.has_aload
)
617 ff
.past_ad
= get_state(ff
.data
.sig_ad
);
619 if (ff
.data
.has_clk
|| ff
.data
.has_gclk
)
620 ff
.past_d
= get_state(ff
.data
.sig_d
);
623 ff
.past_clk
= get_state(ff
.data
.sig_clk
)[0];
626 ff
.past_ce
= get_state(ff
.data
.sig_ce
)[0];
628 if (ff
.data
.has_srst
)
629 ff
.past_srst
= get_state(ff
.data
.sig_srst
)[0];
632 for (auto &it
: mem_database
)
634 mem_state_t
&mem
= it
.second
;
636 for (int i
= 0; i
< GetSize(mem
.mem
->wr_ports
); i
++) {
637 auto &port
= mem
.mem
->wr_ports
[i
];
638 mem
.past_wr_clk
[i
] = get_state(port
.clk
);
639 mem
.past_wr_en
[i
] = get_state(port
.en
);
640 mem
.past_wr_addr
[i
] = get_state(port
.addr
);
641 mem
.past_wr_data
[i
] = get_state(port
.data
);
645 for (auto cell
: formal_database
)
647 string label
= log_id(cell
);
648 if (cell
->attributes
.count(ID::src
))
649 label
= cell
->attributes
.at(ID::src
).decode_string();
651 State a
= get_state(cell
->getPort(ID::A
))[0];
652 State en
= get_state(cell
->getPort(ID::EN
))[0];
654 if (cell
->type
== ID($cover
) && en
== State::S1
&& a
!= State::S1
)
655 log("Cover %s.%s (%s) reached.\n", hiername().c_str(), log_id(cell
), label
.c_str());
657 if (cell
->type
== ID($assume
) && en
== State::S1
&& a
!= State::S1
)
658 log("Assumption %s.%s (%s) failed.\n", hiername().c_str(), log_id(cell
), label
.c_str());
660 if (cell
->type
== ID($
assert) && en
== State::S1
&& a
!= State::S1
)
661 log_warning("Assert %s.%s (%s) failed.\n", hiername().c_str(), log_id(cell
), label
.c_str());
664 for (auto it
: children
)
665 it
.second
->update_ph3();
668 void writeback(pool
<Module
*> &wbmods
)
670 if (wbmods
.count(module
))
671 log_error("Instance %s of module %s is not unique: Writeback not possible. (Fix by running 'uniquify'.)\n", hiername().c_str(), log_id(module
));
673 wbmods
.insert(module
);
675 for (auto wire
: module
->wires())
676 wire
->attributes
.erase(ID::init
);
678 for (auto &it
: ff_database
)
680 SigSpec sig_q
= it
.second
.data
.sig_q
;
681 Const initval
= get_state(sig_q
);
683 for (int i
= 0; i
< GetSize(sig_q
); i
++)
685 Wire
*w
= sig_q
[i
].wire
;
687 if (w
->attributes
.count(ID::init
) == 0)
688 w
->attributes
[ID::init
] = Const(State::Sx
, GetSize(w
));
690 w
->attributes
[ID::init
][sig_q
[i
].offset
] = initval
[i
];
694 for (auto &it
: mem_database
)
696 mem_state_t
&mem
= it
.second
;
697 mem
.mem
->clear_inits();
699 minit
.addr
= mem
.mem
->start_offset
;
700 minit
.data
= mem
.data
;
701 minit
.en
= Const(State::S1
, mem
.mem
->width
);
702 mem
.mem
->inits
.push_back(minit
);
706 for (auto it
: children
)
707 it
.second
->writeback(wbmods
);
710 void register_signals(int &id
)
712 for (auto wire
: module
->wires())
714 if (shared
->hide_internal
&& wire
->name
[0] == '$')
717 signal_database
[wire
] = make_pair(id
, Const());
721 for (auto child
: children
)
722 child
.second
->register_signals(id
);
725 void write_output_header(std::function
<void(IdString
)> enter_scope
, std::function
<void()> exit_scope
, std::function
<void(Wire
*, int)> register_signal
)
729 for (auto signal
: signal_database
)
731 register_signal(signal
.first
, signal
.second
.first
);
734 for (auto child
: children
)
735 child
.second
->write_output_header(enter_scope
, exit_scope
, register_signal
);
740 void register_output_step_values(std::map
<int,Const
> *data
)
742 for (auto &it
: signal_database
)
744 Wire
*wire
= it
.first
;
745 Const value
= get_state(wire
);
746 int id
= it
.second
.first
;
748 if (it
.second
.second
== value
)
751 it
.second
.second
= value
;
752 data
->emplace(id
, value
);
755 for (auto child
: children
)
756 child
.second
->register_output_step_values(data
);
761 for (auto &it
: ff_database
)
763 SigSpec qsig
= it
.second
.data
.sig_q
;
764 if (qsig
.is_wire()) {
765 IdString name
= qsig
.as_wire()->name
;
766 fstHandle id
= shared
->fst
->getHandle(scope
+ "." + RTLIL::unescape_id(name
));
767 if (id
==0 && name
.isPublic())
768 log_warning("Unable to found wire %s in input file.\n", (scope
+ "." + RTLIL::unescape_id(name
)).c_str());
770 Const fst_val
= Const::from_string(shared
->fst
->valueOf(id
));
771 set_state(qsig
, fst_val
);
775 for (auto child
: children
)
776 child
.second
->setInitState();
779 void setState(dict
<int, std::pair
<SigBit
,bool>> bits
, std::string values
)
781 for(auto bit
: bits
) {
782 if (bit
.first
>= GetSize(values
))
783 log_error("Too few input data bits in file.\n");
784 switch(values
.at(bit
.first
)) {
785 case '0': set_state(bit
.second
.first
, bit
.second
.second
? State::S1
: State::S0
); break;
786 case '1': set_state(bit
.second
.first
, bit
.second
.second
? State::S0
: State::S1
); break;
787 default: set_state(bit
.second
.first
, State::Sx
); break;
795 for(auto &item
: fst_handles
) {
796 if (item
.second
==0) continue; // Ignore signals not found
797 Const fst_val
= Const::from_string(shared
->fst
->valueOf(item
.second
));
798 Const sim_val
= get_state(item
.first
);
799 if (sim_val
.size()!=fst_val
.size())
800 log_error("Signal '%s' size is different in gold and gate.\n", log_id(item
.first
));
801 if (shared
->sim_mode
== SimulationMode::sim
) {
802 // No checks performed when using stimulus
803 } else if (shared
->sim_mode
== SimulationMode::gate
&& !fst_val
.is_fully_def()) { // FST data contains X
804 for(int i
=0;i
<fst_val
.size();i
++) {
805 if (fst_val
[i
]!=State::Sx
&& fst_val
[i
]!=sim_val
[i
]) {
806 log_warning("Signal '%s' in file %s in simulation %s\n", log_id(item
.first
), log_signal(fst_val
), log_signal(sim_val
));
811 } else if (shared
->sim_mode
== SimulationMode::gold
&& !sim_val
.is_fully_def()) { // sim data contains X
812 for(int i
=0;i
<sim_val
.size();i
++) {
813 if (sim_val
[i
]!=State::Sx
&& fst_val
[i
]!=sim_val
[i
]) {
814 log_warning("Signal '%s' in file %s in simulation %s\n", log_id(item
.first
), log_signal(fst_val
), log_signal(sim_val
));
820 if (fst_val
!=sim_val
) {
821 log_warning("Signal '%s' in file %s in simulation '%s'\n", log_id(item
.first
), log_signal(fst_val
), log_signal(sim_val
));
826 for (auto child
: children
)
827 retVal
|= child
.second
->checkSignals();
832 struct SimWorker
: SimShared
834 SimInstance
*top
= nullptr;
835 pool
<IdString
> clock
, clockn
, reset
, resetn
;
836 std::string timescale
;
837 std::string sim_filename
;
838 std::string map_filename
;
847 void register_signals()
850 top
->register_signals(id
);
853 void register_output_step(int t
)
855 std::map
<int,Const
> data
;
856 top
->register_output_step_values(&data
);
857 output_data
.emplace_back(t
, data
);
860 void write_output_files()
862 std::map
<int, bool> use_signal
;
863 bool first
= ignore_x
;
864 for(auto& d
: output_data
)
867 for (auto &data
: d
.second
)
868 use_signal
[data
.first
] = !data
.second
.is_fully_undef();
871 for (auto &data
: d
.second
)
872 use_signal
[data
.first
] = true;
874 if (!ignore_x
) break;
876 for(auto& writer
: outputfiles
)
877 writer
->write(use_signal
);
885 log("\n-- ph1 --\n");
890 log("\n-- ph2 --\n");
892 if (!top
->update_ph2())
897 log("\n-- ph3 --\n");
902 void set_inports(pool
<IdString
> ports
, State value
)
904 for (auto portname
: ports
)
906 Wire
*w
= top
->module
->wire(portname
);
909 log_error("Can't find port %s on module %s.\n", log_id(portname
), log_id(top
->module
));
911 top
->set_state(w
, value
);
915 void run(Module
*topmod
, int numcycles
)
917 log_assert(top
== nullptr);
918 top
= new SimInstance(this, scope
, topmod
);
922 log("\n===== 0 =====\n");
924 log("Simulating cycle 0.\n");
926 set_inports(reset
, State::S1
);
927 set_inports(resetn
, State::S0
);
929 set_inports(clock
, State::Sx
);
930 set_inports(clockn
, State::Sx
);
934 register_output_step(0);
936 for (int cycle
= 0; cycle
< numcycles
; cycle
++)
939 log("\n===== %d =====\n", 10*cycle
+ 5);
941 log("Simulating cycle %d.\n", (cycle
*2)+1);
942 set_inports(clock
, State::S0
);
943 set_inports(clockn
, State::S1
);
946 register_output_step(10*cycle
+ 5);
949 log("\n===== %d =====\n", 10*cycle
+ 10);
951 log("Simulating cycle %d.\n", (cycle
*2)+2);
953 set_inports(clock
, State::S1
);
954 set_inports(clockn
, State::S0
);
956 if (cycle
+1 == rstlen
) {
957 set_inports(reset
, State::S0
);
958 set_inports(resetn
, State::S1
);
962 register_output_step(10*cycle
+ 10);
965 register_output_step(10*numcycles
+ 2);
967 write_output_files();
970 pool
<Module
*> wbmods
;
971 top
->writeback(wbmods
);
975 void run_cosim_fst(Module
*topmod
, int numcycles
)
977 log_assert(top
== nullptr);
978 fst
= new FstData(sim_filename
);
981 log_error("Scope must be defined for co-simulation.\n");
983 top
= new SimInstance(this, scope
, topmod
);
986 std::vector
<fstHandle
> fst_clock
;
988 for (auto portname
: clock
)
990 Wire
*w
= topmod
->wire(portname
);
992 log_error("Can't find port %s on module %s.\n", log_id(portname
), log_id(top
->module
));
994 log_error("Clock port %s on module %s is not input.\n", log_id(portname
), log_id(top
->module
));
995 fstHandle id
= fst
->getHandle(scope
+ "." + RTLIL::unescape_id(portname
));
997 log_error("Can't find port %s.%s in FST.\n", scope
.c_str(), log_id(portname
));
998 fst_clock
.push_back(id
);
1000 for (auto portname
: clockn
)
1002 Wire
*w
= topmod
->wire(portname
);
1004 log_error("Can't find port %s on module %s.\n", log_id(portname
), log_id(top
->module
));
1006 log_error("Clock port %s on module %s is not input.\n", log_id(portname
), log_id(top
->module
));
1007 fstHandle id
= fst
->getHandle(scope
+ "." + RTLIL::unescape_id(portname
));
1009 log_error("Can't find port %s.%s in FST.\n", scope
.c_str(), log_id(portname
));
1010 fst_clock
.push_back(id
);
1013 SigMap
sigmap(topmod
);
1014 std::map
<Wire
*,fstHandle
> inputs
;
1016 for (auto wire
: topmod
->wires()) {
1017 if (wire
->port_input
) {
1018 fstHandle id
= fst
->getHandle(scope
+ "." + RTLIL::unescape_id(wire
->name
));
1020 log_error("Unable to find required '%s' signal in file\n",(scope
+ "." + RTLIL::unescape_id(wire
->name
)).c_str());
1025 uint64_t startCount
= 0;
1026 uint64_t stopCount
= 0;
1027 if (start_time
==0) {
1028 if (start_time
< fst
->getStartTime())
1029 log_warning("Start time is before simulation file start time\n");
1030 startCount
= fst
->getStartTime();
1031 } else if (start_time
==-1)
1032 startCount
= fst
->getEndTime();
1034 startCount
= start_time
/ fst
->getTimescale();
1035 if (startCount
> fst
->getEndTime()) {
1036 startCount
= fst
->getEndTime();
1037 log_warning("Start time is after simulation file end time\n");
1041 if (stop_time
< fst
->getStartTime())
1042 log_warning("Stop time is before simulation file start time\n");
1043 stopCount
= fst
->getStartTime();
1044 } else if (stop_time
==-1)
1045 stopCount
= fst
->getEndTime();
1047 stopCount
= stop_time
/ fst
->getTimescale();
1048 if (stopCount
> fst
->getEndTime()) {
1049 stopCount
= fst
->getEndTime();
1050 log_warning("Stop time is after simulation file end time\n");
1053 if (stopCount
<startCount
) {
1054 log_error("Stop time is before start time\n");
1057 bool initial
= true;
1059 log("Co-simulation from %lu%s to %lu%s", (unsigned long)startCount
, fst
->getTimescaleString(), (unsigned long)stopCount
, fst
->getTimescaleString());
1061 log(" for %d clock cycle(s)",numcycles
);
1063 bool all_samples
= fst_clock
.empty();
1066 fst
->reconstructAllAtTimes(fst_clock
, startCount
, stopCount
, [&](uint64_t time
) {
1067 log("Co-simulating %s %d [%lu%s].\n", (all_samples
? "sample" : "cycle"), cycle
, (unsigned long)time
, fst
->getTimescaleString());
1068 bool did_something
= false;
1069 for(auto &item
: inputs
) {
1070 std::string v
= fst
->valueOf(item
.second
);
1071 did_something
|= top
->set_state(item
.first
, Const::from_string(v
));
1075 top
->setInitState();
1080 register_output_step(time
);
1082 bool status
= top
->checkSignals();
1084 log_error("Signal difference\n");
1087 // Limit to number of cycles if provided
1088 if (cycles_set
&& cycle
> numcycles
*2)
1089 throw fst_end_of_data_exception();
1090 if (time
==stopCount
)
1091 throw fst_end_of_data_exception();
1093 } catch(fst_end_of_data_exception
) {
1094 // end of data detected
1097 write_output_files();
1100 pool
<Module
*> wbmods
;
1101 top
->writeback(wbmods
);
1106 void run_cosim_aiger_witness(Module
*topmod
)
1108 log_assert(top
== nullptr);
1109 if ((clock
.size()+clockn
.size())==0)
1110 log_error("Clock signal must be specified.\n");
1111 std::ifstream
mf(map_filename
);
1112 std::string type
, symbol
;
1113 int variable
, index
;
1114 dict
<int, std::pair
<SigBit
,bool>> inputs
, inits
, latches
;
1116 log_cmd_error("Not able to read AIGER witness map file.\n");
1117 while (mf
>> type
>> variable
>> index
>> symbol
) {
1118 RTLIL::IdString escaped_s
= RTLIL::escape_id(symbol
);
1119 Wire
*w
= topmod
->wire(escaped_s
);
1121 log_error("Wire %s not present in module %s\n",log_signal(w
),log_id(topmod
));
1122 if (index
< w
->start_offset
|| index
> w
->start_offset
+ w
->width
)
1123 log_error("Index %d for wire %s is out of range\n", index
, log_signal(w
));
1124 if (type
== "input") {
1125 inputs
[variable
] = {SigBit(w
,index
), false};
1126 } else if (type
== "init") {
1127 inits
[variable
] = {SigBit(w
,index
), false};
1128 } else if (type
== "latch") {
1129 latches
[variable
] = {SigBit(w
,index
), false};
1130 } else if (type
== "invlatch") {
1131 latches
[variable
] = {SigBit(w
,index
), true};
1136 f
.open(sim_filename
.c_str());
1137 if (f
.fail() || GetSize(sim_filename
) == 0)
1138 log_error("Can not open file `%s`\n", sim_filename
.c_str());
1143 top
= new SimInstance(this, scope
, topmod
);
1149 std::getline(f
, line
);
1150 if (line
.size()==0 || line
[0]=='#') continue;
1151 if (line
[0]=='.') break;
1152 if (state
==0 && line
.size()!=1) {
1153 // old format detected, latch data
1156 if (state
==1 && line
[0]!='b' && line
[0]!='c') {
1157 // was old format but with 1 bit latch
1158 top
->setState(latches
, status
);
1172 top
->setState(latches
, line
);
1176 log("Simulating cycle %d.\n", cycle
);
1177 top
->setState(inputs
, line
);
1179 set_inports(clock
, State::S1
);
1180 set_inports(clockn
, State::S0
);
1182 top
->setState(inits
, line
);
1183 set_inports(clock
, State::S0
);
1184 set_inports(clockn
, State::S1
);
1187 register_output_step(10*cycle
);
1189 set_inports(clock
, State::S0
);
1190 set_inports(clockn
, State::S1
);
1192 register_output_step(10*cycle
+ 5);
1198 register_output_step(10*cycle
);
1199 write_output_files();
1202 std::vector
<std::string
> split(std::string text
, const char *delim
)
1204 std::vector
<std::string
> list
;
1205 char *p
= strdup(text
.c_str());
1206 char *t
= strtok(p
, delim
);
1209 t
= strtok(NULL
, delim
);
1215 std::string
signal_name(std::string
const & name
)
1217 size_t pos
= name
.find_first_of("@");
1218 if (pos
==std::string::npos
) {
1219 pos
= name
.find_first_of("#");
1220 if (pos
==std::string::npos
)
1221 log_error("Line does not contain proper signal name `%s`\n", name
.c_str());
1223 return name
.substr(0, pos
);
1226 void run_cosim_btor2_witness(Module
*topmod
)
1228 log_assert(top
== nullptr);
1229 if ((clock
.size()+clockn
.size())==0)
1230 log_error("Clock signal must be specified.\n");
1232 f
.open(sim_filename
.c_str());
1233 if (f
.fail() || GetSize(sim_filename
) == 0)
1234 log_error("Can not open file `%s`\n", sim_filename
.c_str());
1238 top
= new SimInstance(this, scope
, topmod
);
1242 std::vector
<std::string
> parts
;
1247 std::getline(f
, line
);
1248 if (line
.size()==0) continue;
1250 if (line
[0]=='#' || line
[0]=='@' || line
[0]=='.') {
1252 curr_cycle
= atoi(line
.c_str()+1);
1254 curr_cycle
= -1; // force detect change
1256 if (curr_cycle
!= prev_cycle
) {
1257 log("Simulating cycle %d.\n", cycle
);
1258 set_inports(clock
, State::S1
);
1259 set_inports(clockn
, State::S0
);
1261 register_output_step(10*cycle
+0);
1262 set_inports(clock
, State::S0
);
1263 set_inports(clockn
, State::S1
);
1265 register_output_step(10*cycle
+5);
1267 prev_cycle
= curr_cycle
;
1269 if (line
[0]=='.') break;
1280 if (line
[0]=='b' || line
[0]=='j')
1283 log_error("Line does not contain property.\n");
1285 default: // set state or inputs
1286 parts
= split(line
, " ");
1289 log_error("Invalid set state line content.\n");
1291 RTLIL::IdString escaped_s
= RTLIL::escape_id(signal_name(parts
[len
-1]));
1293 Wire
*w
= topmod
->wire(escaped_s
);
1295 Cell
*c
= topmod
->cell(escaped_s
);
1297 log_warning("Wire/cell %s not present in module %s\n",log_id(escaped_s
),log_id(topmod
));
1298 else if (c
->type
.in(ID($anyconst
), ID($anyseq
))) {
1299 SigSpec sig_y
= c
->getPort(ID::Y
);
1300 if ((int)parts
[1].size() != GetSize(sig_y
))
1301 log_error("Size of wire %s is different than provided data.\n", log_signal(sig_y
));
1302 top
->set_state(sig_y
, Const::from_string(parts
[1]));
1305 if ((int)parts
[1].size() != w
->width
)
1306 log_error("Size of wire %s is different than provided data.\n", log_signal(w
));
1307 top
->set_state(w
, Const::from_string(parts
[1]));
1310 Cell
*c
= topmod
->cell(escaped_s
);
1312 log_error("Cell %s not present in module %s\n",log_id(escaped_s
),log_id(topmod
));
1313 if (!c
->is_mem_cell())
1314 log_error("Cell %s is not memory cell in module %s\n",log_id(escaped_s
),log_id(topmod
));
1316 Const addr
= Const::from_string(parts
[1].substr(1,parts
[1].size()-2));
1317 Const data
= Const::from_string(parts
[2]);
1318 top
->set_memory_state(c
->parameters
.at(ID::MEMID
).decode_string(), addr
, data
);
1323 register_output_step(10*cycle
);
1324 write_output_files();
1328 struct VCDWriter
: public OutputWriter
1330 VCDWriter(SimWorker
*worker
, std::string filename
) : OutputWriter(worker
) {
1331 vcdfile
.open(filename
.c_str());
1334 void write(std::map
<int, bool> &use_signal
) override
1336 if (!vcdfile
.is_open()) return;
1337 vcdfile
<< stringf("$version %s $end\n", worker
->date
? yosys_version_str
: "Yosys");
1340 std::time_t t
= std::time(nullptr);
1342 if (std::strftime(mbstr
, sizeof(mbstr
), "%c", std::localtime(&t
))) {
1343 vcdfile
<< stringf("$date ") << mbstr
<< stringf(" $end\n");
1347 if (!worker
->timescale
.empty())
1348 vcdfile
<< stringf("$timescale %s $end\n", worker
->timescale
.c_str());
1350 worker
->top
->write_output_header(
1351 [this](IdString name
) { vcdfile
<< stringf("$scope module %s $end\n", log_id(name
)); },
1352 [this]() { vcdfile
<< stringf("$upscope $end\n");},
1353 [this,use_signal
](Wire
*wire
, int id
) { if (use_signal
.at(id
)) vcdfile
<< stringf("$var wire %d n%d %s%s $end\n", GetSize(wire
), id
, wire
->name
[0] == '$' ? "\\" : "", log_id(wire
)); }
1356 vcdfile
<< stringf("$enddefinitions $end\n");
1358 for(auto& d
: worker
->output_data
)
1360 vcdfile
<< stringf("#%d\n", d
.first
);
1361 for (auto &data
: d
.second
)
1363 if (!use_signal
.at(data
.first
)) continue;
1364 Const value
= data
.second
;
1366 for (int i
= GetSize(value
)-1; i
>= 0; i
--) {
1368 case State::S0
: vcdfile
<< "0"; break;
1369 case State::S1
: vcdfile
<< "1"; break;
1370 case State::Sx
: vcdfile
<< "x"; break;
1371 default: vcdfile
<< "z";
1374 vcdfile
<< stringf(" n%d\n", data
.first
);
1379 std::ofstream vcdfile
;
1382 struct FSTWriter
: public OutputWriter
1384 FSTWriter(SimWorker
*worker
, std::string filename
) : OutputWriter(worker
) {
1385 fstfile
= (struct fstContext
*)fstWriterCreate(filename
.c_str(),1);
1388 virtual ~FSTWriter()
1390 fstWriterClose(fstfile
);
1393 void write(std::map
<int, bool> &use_signal
) override
1395 if (!fstfile
) return;
1396 std::time_t t
= std::time(nullptr);
1397 fstWriterSetVersion(fstfile
, worker
->date
? yosys_version_str
: "Yosys");
1399 fstWriterSetDate(fstfile
, asctime(std::localtime(&t
)));
1401 fstWriterSetDate(fstfile
, "");
1402 if (!worker
->timescale
.empty())
1403 fstWriterSetTimescaleFromString(fstfile
, worker
->timescale
.c_str());
1405 fstWriterSetPackType(fstfile
, FST_WR_PT_FASTLZ
);
1406 fstWriterSetRepackOnClose(fstfile
, 1);
1408 worker
->top
->write_output_header(
1409 [this](IdString name
) { fstWriterSetScope(fstfile
, FST_ST_VCD_MODULE
, stringf("%s",log_id(name
)).c_str(), nullptr); },
1410 [this]() { fstWriterSetUpscope(fstfile
); },
1411 [this,use_signal
](Wire
*wire
, int id
) {
1412 if (!use_signal
.at(id
)) return;
1413 fstHandle fst_id
= fstWriterCreateVar(fstfile
, FST_VT_VCD_WIRE
, FST_VD_IMPLICIT
, GetSize(wire
),
1414 stringf("%s%s", wire
->name
[0] == '$' ? "\\" : "", log_id(wire
)).c_str(), 0);
1416 mapping
.emplace(id
, fst_id
);
1420 for(auto& d
: worker
->output_data
)
1422 fstWriterEmitTimeChange(fstfile
, d
.first
);
1423 for (auto &data
: d
.second
)
1425 if (!use_signal
.at(data
.first
)) continue;
1426 Const value
= data
.second
;
1427 std::stringstream ss
;
1428 for (int i
= GetSize(value
)-1; i
>= 0; i
--) {
1430 case State::S0
: ss
<< "0"; break;
1431 case State::S1
: ss
<< "1"; break;
1432 case State::Sx
: ss
<< "x"; break;
1436 fstWriterEmitValueChange(fstfile
, mapping
[data
.first
], ss
.str().c_str());
1441 struct fstContext
*fstfile
= nullptr;
1442 std::map
<int,fstHandle
> mapping
;
1445 struct AIWWriter
: public OutputWriter
1447 AIWWriter(SimWorker
*worker
, std::string filename
) : OutputWriter(worker
) {
1448 aiwfile
.open(filename
.c_str());
1451 virtual ~AIWWriter()
1453 aiwfile
<< '.' << '\n';
1456 void write(std::map
<int, bool> &) override
1458 if (!aiwfile
.is_open()) return;
1459 if (worker
->map_filename
.empty())
1460 log_cmd_error("For AIGER witness file map parameter is mandatory.\n");
1462 std::ifstream
mf(worker
->map_filename
);
1463 std::string type
, symbol
;
1464 int variable
, index
;
1466 log_cmd_error("Not able to read AIGER witness map file.\n");
1467 while (mf
>> type
>> variable
>> index
>> symbol
) {
1468 RTLIL::IdString escaped_s
= RTLIL::escape_id(symbol
);
1469 Wire
*w
= worker
->top
->module
->wire(escaped_s
);
1471 log_error("Wire %s not present in module %s\n",log_id(escaped_s
),log_id(worker
->top
->module
));
1472 if (index
< w
->start_offset
|| index
> w
->start_offset
+ w
->width
)
1473 log_error("Index %d for wire %s is out of range\n", index
, log_signal(w
));
1474 if (type
== "input") {
1475 aiw_inputs
[variable
] = SigBit(w
,index
);
1476 } else if (type
== "init") {
1477 aiw_inits
[variable
] = SigBit(w
,index
);
1478 } else if (type
== "latch") {
1479 aiw_latches
[variable
] = {SigBit(w
,index
), false};
1480 } else if (type
== "invlatch") {
1481 aiw_latches
[variable
] = {SigBit(w
,index
), true};
1485 worker
->top
->write_output_header(
1488 [this](Wire
*wire
, int id
) { mapping
[wire
] = id
; }
1491 std::map
<int, Yosys::RTLIL::Const
> current
;
1493 for(auto& d
: worker
->output_data
)
1495 for (auto &data
: d
.second
)
1497 current
[data
.first
] = data
.second
;
1500 for (int i
= 0;; i
++)
1502 if (aiw_latches
.count(i
)) {
1503 SigBit bit
= aiw_latches
.at(i
).first
;
1504 auto v
= current
[mapping
[bit
.wire
]].bits
.at(bit
.offset
);
1506 aiwfile
<< (aiw_latches
.at(i
).second
? '0' : '1');
1508 aiwfile
<< (aiw_latches
.at(i
).second
? '1' : '0');
1517 for (int i
= 0;; i
++)
1519 if (aiw_inputs
.count(i
)) {
1520 SigBit bit
= aiw_inputs
.at(i
);
1521 auto v
= current
[mapping
[bit
.wire
]].bits
.at(bit
.offset
);
1528 if (aiw_inits
.count(i
)) {
1529 SigBit bit
= aiw_inits
.at(i
);
1530 auto v
= current
[mapping
[bit
.wire
]].bits
.at(bit
.offset
);
1543 std::ofstream aiwfile
;
1544 dict
<int, std::pair
<SigBit
, bool>> aiw_latches
;
1545 dict
<int, SigBit
> aiw_inputs
, aiw_inits
;
1546 std::map
<Wire
*,int> mapping
;
1549 struct SimPass
: public Pass
{
1550 SimPass() : Pass("sim", "simulate the circuit") { }
1551 void help() override
1553 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1555 log(" sim [options] [top-level]\n");
1557 log("This command simulates the circuit using the given top-level module.\n");
1559 log(" -vcd <filename>\n");
1560 log(" write the simulation results to the given VCD file\n");
1562 log(" -fst <filename>\n");
1563 log(" write the simulation results to the given FST file\n");
1565 log(" -aiw <filename>\n");
1566 log(" write the simulation results to an AIGER witness file\n");
1567 log(" (requires a *.aim file via -map)\n");
1570 log(" ignore constant x outputs in simulation file.\n");
1573 log(" include date and full version info in output.\n");
1575 log(" -clock <portname>\n");
1576 log(" name of top-level clock input\n");
1578 log(" -clockn <portname>\n");
1579 log(" name of top-level clock input (inverse polarity)\n");
1581 log(" -reset <portname>\n");
1582 log(" name of top-level reset input (active high)\n");
1584 log(" -resetn <portname>\n");
1585 log(" name of top-level inverted reset input (active low)\n");
1587 log(" -rstlen <integer>\n");
1588 log(" number of cycles reset should stay active (default: 1)\n");
1591 log(" zero-initialize all uninitialized regs and memories\n");
1593 log(" -timescale <string>\n");
1594 log(" include the specified timescale declaration in the vcd\n");
1596 log(" -n <integer>\n");
1597 log(" number of clock cycles to simulate (default: 20)\n");
1600 log(" use all nets in VCD/FST operations, not just those with public names\n");
1603 log(" writeback mode: use final simulation state as new init state\n");
1606 log(" read simulation results file (file formats supported: FST)\n");
1608 log(" -map <filename>\n");
1609 log(" read file with port and latch symbols, needed for AIGER witness input\n");
1611 log(" -scope <name>\n");
1612 log(" scope of simulation top model\n");
1614 log(" -at <time>\n");
1615 log(" sets start and stop time\n");
1617 log(" -start <time>\n");
1618 log(" start co-simulation in arbitary time (default 0)\n");
1620 log(" -stop <time>\n");
1621 log(" stop co-simulation in arbitary time (default END)\n");
1624 log(" simulation with stimulus from FST (default)\n");
1627 log(" co-simulation expect exact match\n");
1629 log(" -sim-gold\n");
1630 log(" co-simulation, x in simulation can match any value in FST\n");
1632 log(" -sim-gate\n");
1633 log(" co-simulation, x in FST can match any value in simulation\n");
1636 log(" enable debug output\n");
1641 static std::string
file_base_name(std::string
const & path
)
1643 return path
.substr(path
.find_last_of("/\\") + 1);
1646 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) override
1650 bool start_set
= false, stop_set
= false, at_set
= false;
1652 log_header(design
, "Executing SIM pass (simulate the circuit).\n");
1655 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
1656 if (args
[argidx
] == "-vcd" && argidx
+1 < args
.size()) {
1657 std::string vcd_filename
= args
[++argidx
];
1658 rewrite_filename(vcd_filename
);
1659 worker
.outputfiles
.emplace_back(std::unique_ptr
<VCDWriter
>(new VCDWriter(&worker
, vcd_filename
.c_str())));
1662 if (args
[argidx
] == "-fst" && argidx
+1 < args
.size()) {
1663 std::string fst_filename
= args
[++argidx
];
1664 rewrite_filename(fst_filename
);
1665 worker
.outputfiles
.emplace_back(std::unique_ptr
<FSTWriter
>(new FSTWriter(&worker
, fst_filename
.c_str())));
1668 if (args
[argidx
] == "-aiw" && argidx
+1 < args
.size()) {
1669 std::string aiw_filename
= args
[++argidx
];
1670 rewrite_filename(aiw_filename
);
1671 worker
.outputfiles
.emplace_back(std::unique_ptr
<AIWWriter
>(new AIWWriter(&worker
, aiw_filename
.c_str())));
1674 if (args
[argidx
] == "-n" && argidx
+1 < args
.size()) {
1675 numcycles
= atoi(args
[++argidx
].c_str());
1676 worker
.cycles_set
= true;
1679 if (args
[argidx
] == "-rstlen" && argidx
+1 < args
.size()) {
1680 worker
.rstlen
= atoi(args
[++argidx
].c_str());
1683 if (args
[argidx
] == "-clock" && argidx
+1 < args
.size()) {
1684 worker
.clock
.insert(RTLIL::escape_id(args
[++argidx
]));
1687 if (args
[argidx
] == "-clockn" && argidx
+1 < args
.size()) {
1688 worker
.clockn
.insert(RTLIL::escape_id(args
[++argidx
]));
1691 if (args
[argidx
] == "-reset" && argidx
+1 < args
.size()) {
1692 worker
.reset
.insert(RTLIL::escape_id(args
[++argidx
]));
1695 if (args
[argidx
] == "-resetn" && argidx
+1 < args
.size()) {
1696 worker
.resetn
.insert(RTLIL::escape_id(args
[++argidx
]));
1699 if (args
[argidx
] == "-timescale" && argidx
+1 < args
.size()) {
1700 worker
.timescale
= args
[++argidx
];
1703 if (args
[argidx
] == "-a") {
1704 worker
.hide_internal
= false;
1707 if (args
[argidx
] == "-d") {
1708 worker
.debug
= true;
1711 if (args
[argidx
] == "-w") {
1712 worker
.writeback
= true;
1715 if (args
[argidx
] == "-zinit") {
1716 worker
.zinit
= true;
1719 if (args
[argidx
] == "-r" && argidx
+1 < args
.size()) {
1720 std::string sim_filename
= args
[++argidx
];
1721 rewrite_filename(sim_filename
);
1722 worker
.sim_filename
= sim_filename
;
1725 if (args
[argidx
] == "-map" && argidx
+1 < args
.size()) {
1726 std::string map_filename
= args
[++argidx
];
1727 rewrite_filename(map_filename
);
1728 worker
.map_filename
= map_filename
;
1731 if (args
[argidx
] == "-scope" && argidx
+1 < args
.size()) {
1732 worker
.scope
= args
[++argidx
];
1735 if (args
[argidx
] == "-start" && argidx
+1 < args
.size()) {
1736 worker
.start_time
= stringToTime(args
[++argidx
]);
1740 if (args
[argidx
] == "-stop" && argidx
+1 < args
.size()) {
1741 worker
.stop_time
= stringToTime(args
[++argidx
]);
1745 if (args
[argidx
] == "-at" && argidx
+1 < args
.size()) {
1746 worker
.start_time
= stringToTime(args
[++argidx
]);
1747 worker
.stop_time
= worker
.start_time
;
1751 if (args
[argidx
] == "-sim") {
1752 worker
.sim_mode
= SimulationMode::sim
;
1755 if (args
[argidx
] == "-sim-cmp") {
1756 worker
.sim_mode
= SimulationMode::cmp
;
1759 if (args
[argidx
] == "-sim-gold") {
1760 worker
.sim_mode
= SimulationMode::gold
;
1763 if (args
[argidx
] == "-sim-gate") {
1764 worker
.sim_mode
= SimulationMode::gate
;
1767 if (args
[argidx
] == "-x") {
1768 worker
.ignore_x
= true;
1771 if (args
[argidx
] == "-date") {
1777 extra_args(args
, argidx
, design
);
1778 if (at_set
&& (start_set
|| stop_set
|| worker
.cycles_set
))
1779 log_error("'at' option can only be defined separate of 'start','stop' and 'n'\n");
1780 if (stop_set
&& worker
.cycles_set
)
1781 log_error("'stop' and 'n' can only be used exclusively'\n");
1783 Module
*top_mod
= nullptr;
1785 if (design
->full_selection()) {
1786 top_mod
= design
->top_module();
1789 log_cmd_error("Design has no top module, use the 'hierarchy' command to specify one.\n");
1791 auto mods
= design
->selected_whole_modules();
1792 if (GetSize(mods
) != 1)
1793 log_cmd_error("Only one top module must be selected.\n");
1794 top_mod
= mods
.front();
1797 if (worker
.sim_filename
.empty())
1798 worker
.run(top_mod
, numcycles
);
1800 std::string filename_trim
= file_base_name(worker
.sim_filename
);
1801 if (filename_trim
.size() > 4 && ((filename_trim
.compare(filename_trim
.size()-4, std::string::npos
, ".fst") == 0) ||
1802 filename_trim
.compare(filename_trim
.size()-4, std::string::npos
, ".vcd") == 0)) {
1803 worker
.run_cosim_fst(top_mod
, numcycles
);
1804 } else if (filename_trim
.size() > 4 && filename_trim
.compare(filename_trim
.size()-4, std::string::npos
, ".aiw") == 0) {
1805 if (worker
.map_filename
.empty())
1806 log_cmd_error("For AIGER witness file map parameter is mandatory.\n");
1807 worker
.run_cosim_aiger_witness(top_mod
);
1808 } else if (filename_trim
.size() > 4 && filename_trim
.compare(filename_trim
.size()-4, std::string::npos
, ".wit") == 0) {
1809 worker
.run_cosim_btor2_witness(top_mod
);
1811 log_cmd_error("Unhandled extension for simulation input file `%s`.\n", worker
.sim_filename
.c_str());
1817 PRIVATE_NAMESPACE_END