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;
81 bool hide_internal
= true;
82 bool writeback
= false;
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;
94 bool multiclock
= false;
105 for (auto &bit
: v
.bits
)
118 dict
<Cell
*, SimInstance
*> children
;
121 dict
<SigBit
, State
> state_nets
;
122 dict
<SigBit
, pool
<Cell
*>> upd_cells
;
123 dict
<SigBit
, pool
<Wire
*>> upd_outports
;
125 pool
<SigBit
> dirty_bits
;
126 pool
<Cell
*> dirty_cells
;
127 pool
<IdString
> dirty_memories
;
128 pool
<SimInstance
*, hash_ptr_ops
> dirty_children
;
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
;
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
;
156 std::vector
<Mem
> memories
;
158 dict
<Wire
*, pair
<int, Const
>> signal_database
;
159 dict
<Wire
*, fstHandle
> fst_handles
;
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
)
167 log_assert(parent
->children
.count(instance
) == 0);
168 parent
->children
[instance
] = this;
171 for (auto wire
: module
->wires())
173 SigSpec sig
= sigmap(wire
);
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
]);
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
;
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
]);
201 memories
= Mem::get_all_memories(module
);
202 for (auto &mem
: memories
) {
203 auto &mdb
= mem_database
[mem
.memid
];
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
)));
211 mdb
.data
= mem
.get_init_data();
214 for (auto cell
: module
->cells())
216 Module
*mod
= module
->design
->module(cell
->type
);
218 if (mod
!= nullptr) {
219 dirty_children
.insert(new SimInstance(shared
, scope
+ "." + RTLIL::unescape_id(cell
->name
), mod
, cell
, this));
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
);
232 if (RTLIL::builtin_ff_cell_types().count(cell
->type
)) {
233 FfData
ff_data(nullptr, cell
);
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
;
241 ff_database
[cell
] = ff
;
244 if (cell
->is_mem_cell())
246 mem_cells
[cell
] = cell
->parameters
.at(ID::MEMID
).decode_string();
248 if (cell
->type
.in(ID($
assert), ID($cover
), ID($assume
))) {
249 formal_database
.insert(cell
);
255 for (auto &it
: ff_database
)
257 ff_state_t
&ff
= it
.second
;
261 SigSpec qsig
= it
.second
.data
.sig_q
;
262 Const qdata
= get_state(qsig
);
264 set_state(qsig
, qdata
);
267 for (auto &it
: mem_database
) {
268 mem_state_t
&mem
= it
.second
;
269 for (auto &val
: mem
.past_wr_en
)
278 for (auto child
: children
)
282 IdString
name() const
284 if (instance
!= nullptr)
285 return instance
->name
;
289 std::string
hiername() const
291 if (instance
!= nullptr)
292 return parent
->hiername() + "." + log_id(instance
->name
);
294 return log_id(module
->name
);
297 Const
get_state(SigSpec sig
)
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
));
307 value
.bits
.push_back(State::Sz
);
310 log("[%s] get %s: %s\n", hiername().c_str(), log_signal(sig
), log_signal(value
));
314 bool set_state(SigSpec sig
, Const value
)
316 bool did_something
= false;
319 log_assert(GetSize(sig
) <= GetSize(value
));
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;
329 log("[%s] set %s: %s\n", hiername().c_str(), log_signal(sig
), log_signal(value
));
330 return did_something
;
333 void set_memory_state(IdString memid
, Const addr
, Const data
)
335 auto &state
= mem_database
[memid
];
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
];
343 void set_memory_state_bit(IdString memid
, int offset
, State data
)
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
;
351 void update_cell(Cell
*cell
)
353 if (ff_database
.count(cell
))
356 if (formal_database
.count(cell
))
359 if (mem_cells
.count(cell
))
361 dirty_memories
.insert(mem_cells
[cell
]);
365 if (children
.count(cell
))
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
);
373 dirty_children
.insert(child
);
377 if (yosys_celltypes
.cell_evaluable(cell
->type
))
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
;
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
);
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
);
397 log("[%s] eval %s (%s)\n", hiername().c_str(), log_id(cell
), log_id(cell
->type
));
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
)));
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
)));
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
)));
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
)));
423 log_warning("Unsupported evaluable cell type: %s (%s.%s)\n", log_id(cell
->type
), log_id(module
), log_id(cell
));
427 log_error("Unsupported cell type: %s (%s.%s)\n", log_id(cell
->type
), log_id(module
), log_id(cell
));
430 void update_memory(IdString id
) {
431 auto &mdb
= mem_database
[id
];
432 auto &mem
= *mdb
.mem
;
434 for (int port_idx
= 0; port_idx
< GetSize(mem
.rd_ports
); port_idx
++)
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
);
441 log_error("Memory %s.%s has clocked read ports. Run 'memory' with -nordff.\n", log_id(module
), log_id(mem
.memid
));
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
);
449 set_state(port
.data
, data
);
455 pool
<Cell
*> queue_cells
;
456 pool
<Wire
*> queue_outports
;
458 queue_cells
.swap(dirty_cells
);
462 for (auto bit
: dirty_bits
)
464 if (upd_cells
.count(bit
))
465 for (auto cell
: upd_cells
.at(bit
))
466 queue_cells
.insert(cell
);
468 if (upd_outports
.count(bit
) && parent
!= nullptr)
469 for (auto wire
: upd_outports
.at(bit
))
470 queue_outports
.insert(wire
);
475 if (!queue_cells
.empty())
477 for (auto cell
: queue_cells
)
484 for (auto &memid
: dirty_memories
)
485 update_memory(memid
);
486 dirty_memories
.clear();
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
);
494 queue_outports
.clear();
496 for (auto child
: dirty_children
)
499 dirty_children
.clear();
501 if (dirty_bits
.empty())
508 bool did_something
= false;
510 for (auto &it
: ff_database
)
512 ff_state_t
&ff
= it
.second
;
513 FfData
&ff_data
= ff
.data
;
515 Const current_q
= get_state(ff
.data
.sig_q
);
517 if (ff_data
.has_clk
) {
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
;
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
;
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
);
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
;
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
);
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
;
557 else if (current_set
[i
] == (ff_data
.pol_set
? State::S1
: State::S0
)) {
558 current_q
[i
] = State::S1
;
562 if (ff_data
.has_gclk
) {
564 current_q
= ff
.past_d
;
566 if (set_state(ff_data
.sig_q
, current_q
))
567 did_something
= true;
570 for (auto &it
: mem_database
)
572 mem_state_t
&mdb
= it
.second
;
573 auto &mem
= *mdb
.mem
;
575 for (int port_idx
= 0; port_idx
< GetSize(mem
.wr_ports
); port_idx
++)
577 auto &port
= mem
.wr_ports
[port_idx
];
578 Const addr
, data
, enable
;
580 if (!port
.clk_enable
)
582 addr
= get_state(port
.addr
);
583 data
= get_state(port
.data
);
584 enable
= get_state(port
.en
);
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
))
593 addr
= mdb
.past_wr_addr
[port_idx
];
594 data
= mdb
.past_wr_data
[port_idx
];
595 enable
= mdb
.past_wr_en
[port_idx
];
598 if (addr
.is_fully_def())
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;
612 for (auto it
: children
)
613 if (it
.second
->update_ph2()) {
614 dirty_children
.insert(it
.second
);
615 did_something
= true;
618 return did_something
;
623 for (auto &it
: ff_database
)
625 ff_state_t
&ff
= it
.second
;
627 if (ff
.data
.has_aload
)
628 ff
.past_ad
= get_state(ff
.data
.sig_ad
);
630 if (ff
.data
.has_clk
|| ff
.data
.has_gclk
)
631 ff
.past_d
= get_state(ff
.data
.sig_d
);
634 ff
.past_clk
= get_state(ff
.data
.sig_clk
)[0];
637 ff
.past_ce
= get_state(ff
.data
.sig_ce
)[0];
639 if (ff
.data
.has_srst
)
640 ff
.past_srst
= get_state(ff
.data
.sig_srst
)[0];
643 for (auto &it
: mem_database
)
645 mem_state_t
&mem
= it
.second
;
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
);
656 for (auto cell
: formal_database
)
658 string label
= log_id(cell
);
659 if (cell
->attributes
.count(ID::src
))
660 label
= cell
->attributes
.at(ID::src
).decode_string();
662 State a
= get_state(cell
->getPort(ID::A
))[0];
663 State en
= get_state(cell
->getPort(ID::EN
))[0];
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());
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());
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());
675 for (auto it
: children
)
676 it
.second
->update_ph3();
679 void writeback(pool
<Module
*> &wbmods
)
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
));
684 wbmods
.insert(module
);
686 for (auto wire
: module
->wires())
687 wire
->attributes
.erase(ID::init
);
689 for (auto &it
: ff_database
)
691 SigSpec sig_q
= it
.second
.data
.sig_q
;
692 Const initval
= get_state(sig_q
);
694 for (int i
= 0; i
< GetSize(sig_q
); i
++)
696 Wire
*w
= sig_q
[i
].wire
;
698 if (w
->attributes
.count(ID::init
) == 0)
699 w
->attributes
[ID::init
] = Const(State::Sx
, GetSize(w
));
701 w
->attributes
[ID::init
][sig_q
[i
].offset
] = initval
[i
];
705 for (auto &it
: mem_database
)
707 mem_state_t
&mem
= it
.second
;
708 mem
.mem
->clear_inits();
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
);
717 for (auto it
: children
)
718 it
.second
->writeback(wbmods
);
721 void register_signals(int &id
)
723 for (auto wire
: module
->wires())
725 if (shared
->hide_internal
&& wire
->name
[0] == '$')
728 signal_database
[wire
] = make_pair(id
, Const());
732 for (auto child
: children
)
733 child
.second
->register_signals(id
);
736 void write_output_header(std::function
<void(IdString
)> enter_scope
, std::function
<void()> exit_scope
, std::function
<void(Wire
*, int, bool)> register_signal
)
740 dict
<Wire
*,bool> registers
;
741 for (auto cell
: module
->cells())
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;
752 for (auto signal
: signal_database
)
754 register_signal(signal
.first
, signal
.second
.first
, registers
.count(signal
.first
)!=0);
757 for (auto child
: children
)
758 child
.second
->write_output_header(enter_scope
, exit_scope
, register_signal
);
763 void register_output_step_values(std::map
<int,Const
> *data
)
765 for (auto &it
: signal_database
)
767 Wire
*wire
= it
.first
;
768 Const value
= get_state(wire
);
769 int id
= it
.second
.first
;
771 if (it
.second
.second
== value
)
774 it
.second
.second
= value
;
775 data
->emplace(id
, value
);
778 for (auto child
: children
)
779 child
.second
->register_output_step_values(data
);
784 bool did_something
= false;
785 for (auto &it
: ff_database
)
787 ff_state_t
&ff
= it
.second
;
788 SigSpec qsig
= it
.second
.data
.sig_q
;
789 if (qsig
.is_wire()) {
790 IdString name
= qsig
.as_wire()->name
;
791 fstHandle id
= shared
->fst
->getHandle(scope
+ "." + RTLIL::unescape_id(name
));
792 if (id
==0 && name
.isPublic())
793 log_warning("Unable to find wire %s in input file.\n", (scope
+ "." + RTLIL::unescape_id(name
)).c_str());
795 Const fst_val
= Const::from_string(shared
->fst
->valueOf(id
));
797 if (ff
.data
.has_aload
)
798 ff
.past_ad
= fst_val
;
799 did_something
= set_state(qsig
, fst_val
);
803 for (auto child
: children
)
804 did_something
|= child
.second
->setInitState();
805 return did_something
;
808 void setState(dict
<int, std::pair
<SigBit
,bool>> bits
, std::string values
)
810 for(auto bit
: bits
) {
811 if (bit
.first
>= GetSize(values
))
812 log_error("Too few input data bits in file.\n");
813 switch(values
.at(bit
.first
)) {
814 case '0': set_state(bit
.second
.first
, bit
.second
.second
? State::S1
: State::S0
); break;
815 case '1': set_state(bit
.second
.first
, bit
.second
.second
? State::S0
: State::S1
); break;
816 default: set_state(bit
.second
.first
, State::Sx
); break;
821 void setMemState(dict
<int, std::pair
<std::string
,int>> bits
, std::string values
)
823 for(auto bit
: bits
) {
824 if (bit
.first
>= GetSize(values
))
825 log_error("Too few input data bits in file.\n");
826 switch(values
.at(bit
.first
)) {
827 case '0': set_memory_state_bit(bit
.second
.first
, bit
.second
.second
, State::S0
); break;
828 case '1': set_memory_state_bit(bit
.second
.first
, bit
.second
.second
, State::S1
); break;
829 default: set_memory_state_bit(bit
.second
.first
, bit
.second
.second
, State::Sx
); break;
837 for(auto &item
: fst_handles
) {
838 if (item
.second
==0) continue; // Ignore signals not found
839 Const fst_val
= Const::from_string(shared
->fst
->valueOf(item
.second
));
840 Const sim_val
= get_state(item
.first
);
841 if (sim_val
.size()!=fst_val
.size()) {
842 log_warning("Signal '%s.%s' size is different in gold and gate.\n", scope
.c_str(), log_id(item
.first
));
845 if (shared
->sim_mode
== SimulationMode::sim
) {
846 // No checks performed when using stimulus
847 } else if (shared
->sim_mode
== SimulationMode::gate
&& !fst_val
.is_fully_def()) { // FST data contains X
848 for(int i
=0;i
<fst_val
.size();i
++) {
849 if (fst_val
[i
]!=State::Sx
&& fst_val
[i
]!=sim_val
[i
]) {
850 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
));
855 } else if (shared
->sim_mode
== SimulationMode::gold
&& !sim_val
.is_fully_def()) { // sim data contains X
856 for(int i
=0;i
<sim_val
.size();i
++) {
857 if (sim_val
[i
]!=State::Sx
&& fst_val
[i
]!=sim_val
[i
]) {
858 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
));
864 if (fst_val
!=sim_val
) {
865 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
));
870 for (auto child
: children
)
871 retVal
|= child
.second
->checkSignals();
876 struct SimWorker
: SimShared
878 SimInstance
*top
= nullptr;
879 pool
<IdString
> clock
, clockn
, reset
, resetn
;
880 std::string timescale
;
881 std::string sim_filename
;
882 std::string map_filename
;
891 void register_signals()
894 top
->register_signals(id
);
897 void register_output_step(int t
)
899 std::map
<int,Const
> data
;
900 top
->register_output_step_values(&data
);
901 output_data
.emplace_back(t
, data
);
904 void write_output_files()
906 std::map
<int, bool> use_signal
;
907 bool first
= ignore_x
;
908 for(auto& d
: output_data
)
911 for (auto &data
: d
.second
)
912 use_signal
[data
.first
] = !data
.second
.is_fully_undef();
915 for (auto &data
: d
.second
)
916 use_signal
[data
.first
] = true;
918 if (!ignore_x
) break;
920 for(auto& writer
: outputfiles
)
921 writer
->write(use_signal
);
929 log("\n-- ph1 --\n");
934 log("\n-- ph2 --\n");
936 if (!top
->update_ph2())
941 log("\n-- ph3 --\n");
946 void set_inports(pool
<IdString
> ports
, State value
)
948 for (auto portname
: ports
)
950 Wire
*w
= top
->module
->wire(portname
);
953 log_error("Can't find port %s on module %s.\n", log_id(portname
), log_id(top
->module
));
955 top
->set_state(w
, value
);
959 void run(Module
*topmod
, int numcycles
)
961 log_assert(top
== nullptr);
962 top
= new SimInstance(this, scope
, topmod
);
966 log("\n===== 0 =====\n");
968 log("Simulating cycle 0.\n");
970 set_inports(reset
, State::S1
);
971 set_inports(resetn
, State::S0
);
973 set_inports(clock
, State::Sx
);
974 set_inports(clockn
, State::Sx
);
978 register_output_step(0);
980 for (int cycle
= 0; cycle
< numcycles
; cycle
++)
983 log("\n===== %d =====\n", 10*cycle
+ 5);
985 log("Simulating cycle %d.\n", (cycle
*2)+1);
986 set_inports(clock
, State::S0
);
987 set_inports(clockn
, State::S1
);
990 register_output_step(10*cycle
+ 5);
993 log("\n===== %d =====\n", 10*cycle
+ 10);
995 log("Simulating cycle %d.\n", (cycle
*2)+2);
997 set_inports(clock
, State::S1
);
998 set_inports(clockn
, State::S0
);
1000 if (cycle
+1 == rstlen
) {
1001 set_inports(reset
, State::S0
);
1002 set_inports(resetn
, State::S1
);
1006 register_output_step(10*cycle
+ 10);
1009 register_output_step(10*numcycles
+ 2);
1011 write_output_files();
1014 pool
<Module
*> wbmods
;
1015 top
->writeback(wbmods
);
1019 void run_cosim_fst(Module
*topmod
, int numcycles
)
1021 log_assert(top
== nullptr);
1022 fst
= new FstData(sim_filename
);
1025 log_error("Scope must be defined for co-simulation.\n");
1027 top
= new SimInstance(this, scope
, topmod
);
1030 std::vector
<fstHandle
> fst_clock
;
1032 for (auto portname
: clock
)
1034 Wire
*w
= topmod
->wire(portname
);
1036 log_error("Can't find port %s on module %s.\n", log_id(portname
), log_id(top
->module
));
1038 log_error("Clock port %s on module %s is not input.\n", log_id(portname
), log_id(top
->module
));
1039 fstHandle id
= fst
->getHandle(scope
+ "." + RTLIL::unescape_id(portname
));
1041 log_error("Can't find port %s.%s in FST.\n", scope
.c_str(), log_id(portname
));
1042 fst_clock
.push_back(id
);
1044 for (auto portname
: clockn
)
1046 Wire
*w
= topmod
->wire(portname
);
1048 log_error("Can't find port %s on module %s.\n", log_id(portname
), log_id(top
->module
));
1050 log_error("Clock port %s on module %s is not input.\n", log_id(portname
), log_id(top
->module
));
1051 fstHandle id
= fst
->getHandle(scope
+ "." + RTLIL::unescape_id(portname
));
1053 log_error("Can't find port %s.%s in FST.\n", scope
.c_str(), log_id(portname
));
1054 fst_clock
.push_back(id
);
1057 SigMap
sigmap(topmod
);
1058 std::map
<Wire
*,fstHandle
> inputs
;
1060 for (auto wire
: topmod
->wires()) {
1061 if (wire
->port_input
) {
1062 fstHandle id
= fst
->getHandle(scope
+ "." + RTLIL::unescape_id(wire
->name
));
1064 log_error("Unable to find required '%s' signal in file\n",(scope
+ "." + RTLIL::unescape_id(wire
->name
)).c_str());
1069 uint64_t startCount
= 0;
1070 uint64_t stopCount
= 0;
1071 if (start_time
==0) {
1072 if (start_time
< fst
->getStartTime())
1073 log_warning("Start time is before simulation file start time\n");
1074 startCount
= fst
->getStartTime();
1075 } else if (start_time
==-1)
1076 startCount
= fst
->getEndTime();
1078 startCount
= start_time
/ fst
->getTimescale();
1079 if (startCount
> fst
->getEndTime()) {
1080 startCount
= fst
->getEndTime();
1081 log_warning("Start time is after simulation file end time\n");
1085 if (stop_time
< fst
->getStartTime())
1086 log_warning("Stop time is before simulation file start time\n");
1087 stopCount
= fst
->getStartTime();
1088 } else if (stop_time
==-1)
1089 stopCount
= fst
->getEndTime();
1091 stopCount
= stop_time
/ fst
->getTimescale();
1092 if (stopCount
> fst
->getEndTime()) {
1093 stopCount
= fst
->getEndTime();
1094 log_warning("Stop time is after simulation file end time\n");
1097 if (stopCount
<startCount
) {
1098 log_error("Stop time is before start time\n");
1101 bool initial
= true;
1103 log("Co-simulation from %lu%s to %lu%s", (unsigned long)startCount
, fst
->getTimescaleString(), (unsigned long)stopCount
, fst
->getTimescaleString());
1105 log(" for %d clock cycle(s)",numcycles
);
1107 bool all_samples
= fst_clock
.empty();
1110 fst
->reconstructAllAtTimes(fst_clock
, startCount
, stopCount
, [&](uint64_t time
) {
1112 log("Co-simulating %s %d [%lu%s].\n", (all_samples
? "sample" : "cycle"), cycle
, (unsigned long)time
, fst
->getTimescaleString());
1113 bool did_something
= false;
1114 for(auto &item
: inputs
) {
1115 std::string v
= fst
->valueOf(item
.second
);
1116 did_something
|= top
->set_state(item
.first
, Const::from_string(v
));
1120 did_something
|= top
->setInitState();
1125 register_output_step(time
);
1127 bool status
= top
->checkSignals();
1129 log_error("Signal difference\n");
1132 // Limit to number of cycles if provided
1133 if (cycles_set
&& cycle
> numcycles
*2)
1134 throw fst_end_of_data_exception();
1135 if (time
==stopCount
)
1136 throw fst_end_of_data_exception();
1138 } catch(fst_end_of_data_exception
) {
1139 // end of data detected
1142 write_output_files();
1145 pool
<Module
*> wbmods
;
1146 top
->writeback(wbmods
);
1151 std::string
cell_name(std::string
const & name
)
1153 size_t pos
= name
.find_last_of("[");
1154 if (pos
!=std::string::npos
)
1155 return name
.substr(0, pos
);
1159 int mem_cell_addr(std::string
const & name
)
1161 size_t pos
= name
.find_last_of("[");
1162 return atoi(name
.substr(pos
+1).c_str());
1165 void run_cosim_aiger_witness(Module
*topmod
)
1167 log_assert(top
== nullptr);
1168 if (!multiclock
&& (clock
.size()+clockn
.size())==0)
1169 log_error("Clock signal must be specified.\n");
1170 if (multiclock
&& (clock
.size()+clockn
.size())>0)
1171 log_error("For multiclock witness there should be no clock signal.\n");
1173 top
= new SimInstance(this, scope
, topmod
);
1176 std::ifstream
mf(map_filename
);
1177 std::string type
, symbol
;
1178 int variable
, index
;
1179 dict
<int, std::pair
<SigBit
,bool>> inputs
, inits
, latches
;
1180 dict
<int, std::pair
<std::string
,int>> mem_inits
, mem_latches
;
1182 log_cmd_error("Not able to read AIGER witness map file.\n");
1183 while (mf
>> type
>> variable
>> index
>> symbol
) {
1184 RTLIL::IdString escaped_s
= RTLIL::escape_id(symbol
);
1185 Wire
*w
= topmod
->wire(escaped_s
);
1187 escaped_s
= RTLIL::escape_id(cell_name(symbol
));
1188 Cell
*c
= topmod
->cell(escaped_s
);
1190 log_warning("Wire/cell %s not present in module %s\n",symbol
.c_str(),log_id(topmod
));
1192 if (c
->is_mem_cell()) {
1193 std::string memid
= c
->parameters
.at(ID::MEMID
).decode_string();
1194 auto &state
= top
->mem_database
[memid
];
1196 int offset
= (mem_cell_addr(symbol
) - state
.mem
->start_offset
) * state
.mem
->width
+ index
;
1198 mem_inits
[variable
] = { memid
, offset
};
1199 else if (type
== "latch")
1200 mem_latches
[variable
] = { memid
, offset
};
1202 log_error("Map file addressing cell %s as type %s\n", symbol
.c_str(), type
.c_str());
1204 log_error("Cell %s in map file is not memory cell\n", symbol
.c_str());
1207 if (index
< w
->start_offset
|| index
> w
->start_offset
+ w
->width
)
1208 log_error("Index %d for wire %s is out of range\n", index
, log_signal(w
));
1209 if (type
== "input") {
1210 inputs
[variable
] = {SigBit(w
,index
-w
->start_offset
), false};
1211 } else if (type
== "init") {
1212 inits
[variable
] = {SigBit(w
,index
-w
->start_offset
), false};
1213 } else if (type
== "latch") {
1214 latches
[variable
] = {SigBit(w
,index
-w
->start_offset
), false};
1215 } else if (type
== "invlatch") {
1216 latches
[variable
] = {SigBit(w
,index
-w
->start_offset
), true};
1222 f
.open(sim_filename
.c_str());
1223 if (f
.fail() || GetSize(sim_filename
) == 0)
1224 log_error("Can not open file `%s`\n", sim_filename
.c_str());
1233 std::getline(f
, line
);
1234 if (line
.size()==0 || line
[0]=='#' || line
[0]=='c' || line
[0]=='f' || line
[0]=='u') continue;
1235 if (line
[0]=='.') break;
1236 if (state
==0 && line
.size()!=1) {
1237 // old format detected, latch data
1240 if (state
==1 && line
[0]!='b' && line
[0]!='j') {
1241 // was old format but with 1 bit latch
1242 top
->setState(latches
, status
);
1256 top
->setState(latches
, line
);
1257 top
->setMemState(mem_latches
, line
);
1262 log("Simulating cycle %d.\n", cycle
);
1263 top
->setState(inputs
, line
);
1265 set_inports(clock
, State::S1
);
1266 set_inports(clockn
, State::S0
);
1268 top
->setState(inits
, line
);
1269 top
->setMemState(mem_inits
, line
);
1270 set_inports(clock
, State::S0
);
1271 set_inports(clockn
, State::S1
);
1274 register_output_step(10*cycle
);
1275 if (!multiclock
&& cycle
) {
1276 set_inports(clock
, State::S0
);
1277 set_inports(clockn
, State::S1
);
1279 register_output_step(10*cycle
+ 5);
1285 register_output_step(10*cycle
);
1286 write_output_files();
1289 std::vector
<std::string
> split(std::string text
, const char *delim
)
1291 std::vector
<std::string
> list
;
1292 char *p
= strdup(text
.c_str());
1293 char *t
= strtok(p
, delim
);
1296 t
= strtok(NULL
, delim
);
1302 std::string
signal_name(std::string
const & name
)
1304 size_t pos
= name
.find_first_of("@");
1305 if (pos
==std::string::npos
) {
1306 pos
= name
.find_first_of("#");
1307 if (pos
==std::string::npos
)
1308 log_error("Line does not contain proper signal name `%s`\n", name
.c_str());
1310 return name
.substr(0, pos
);
1313 void run_cosim_btor2_witness(Module
*topmod
)
1315 log_assert(top
== nullptr);
1316 if ((clock
.size()+clockn
.size())==0)
1317 log_error("Clock signal must be specified.\n");
1319 f
.open(sim_filename
.c_str());
1320 if (f
.fail() || GetSize(sim_filename
) == 0)
1321 log_error("Can not open file `%s`\n", sim_filename
.c_str());
1325 top
= new SimInstance(this, scope
, topmod
);
1329 std::vector
<std::string
> parts
;
1334 std::getline(f
, line
);
1335 if (line
.size()==0) continue;
1337 if (line
[0]=='#' || line
[0]=='@' || line
[0]=='.') {
1339 curr_cycle
= atoi(line
.c_str()+1);
1341 curr_cycle
= -1; // force detect change
1343 if (curr_cycle
!= prev_cycle
) {
1345 log("Simulating cycle %d.\n", cycle
);
1346 set_inports(clock
, State::S1
);
1347 set_inports(clockn
, State::S0
);
1349 register_output_step(10*cycle
+0);
1350 set_inports(clock
, State::S0
);
1351 set_inports(clockn
, State::S1
);
1353 register_output_step(10*cycle
+5);
1355 prev_cycle
= curr_cycle
;
1357 if (line
[0]=='.') break;
1368 if (line
[0]=='b' || line
[0]=='j')
1371 log_error("Line does not contain property.\n");
1373 default: // set state or inputs
1374 parts
= split(line
, " ");
1377 log_error("Invalid set state line content.\n");
1379 RTLIL::IdString escaped_s
= RTLIL::escape_id(signal_name(parts
[len
-1]));
1381 Wire
*w
= topmod
->wire(escaped_s
);
1383 Cell
*c
= topmod
->cell(escaped_s
);
1385 log_warning("Wire/cell %s not present in module %s\n",log_id(escaped_s
),log_id(topmod
));
1386 else if (c
->type
.in(ID($anyconst
), ID($anyseq
))) {
1387 SigSpec sig_y
= c
->getPort(ID::Y
);
1388 if ((int)parts
[1].size() != GetSize(sig_y
))
1389 log_error("Size of wire %s is different than provided data.\n", log_signal(sig_y
));
1390 top
->set_state(sig_y
, Const::from_string(parts
[1]));
1393 if ((int)parts
[1].size() != w
->width
)
1394 log_error("Size of wire %s is different than provided data.\n", log_signal(w
));
1395 top
->set_state(w
, Const::from_string(parts
[1]));
1398 Cell
*c
= topmod
->cell(escaped_s
);
1400 log_error("Cell %s not present in module %s\n",log_id(escaped_s
),log_id(topmod
));
1401 if (!c
->is_mem_cell())
1402 log_error("Cell %s is not memory cell in module %s\n",log_id(escaped_s
),log_id(topmod
));
1404 Const addr
= Const::from_string(parts
[1].substr(1,parts
[1].size()-2));
1405 Const data
= Const::from_string(parts
[2]);
1406 top
->set_memory_state(c
->parameters
.at(ID::MEMID
).decode_string(), addr
, data
);
1411 register_output_step(10*cycle
);
1412 write_output_files();
1415 std::string
define_signal(Wire
*wire
)
1417 std::stringstream f
;
1420 f
<< stringf("%s", RTLIL::unescape_id(wire
->name
).c_str());
1423 f
<< stringf("[%d:%d] %s", wire
->start_offset
, wire
->width
- 1 + wire
->start_offset
, RTLIL::unescape_id(wire
->name
).c_str());
1425 f
<< stringf("[%d:%d] %s", wire
->width
- 1 + wire
->start_offset
, wire
->start_offset
, RTLIL::unescape_id(wire
->name
).c_str());
1429 std::string
signal_list(std::map
<Wire
*,fstHandle
> &signals
)
1431 std::stringstream f
;
1432 for(auto item
=signals
.begin();item
!=signals
.end();item
++)
1433 f
<< stringf("%c%s", (item
==signals
.begin() ? ' ' : ','), RTLIL::unescape_id(item
->first
->name
).c_str());
1437 void generate_tb(Module
*topmod
, std::string tb_filename
, int numcycles
)
1439 fst
= new FstData(sim_filename
);
1442 log_error("Scope must be defined for co-simulation.\n");
1444 if ((clock
.size()+clockn
.size())==0)
1445 log_error("Clock signal must be specified.\n");
1447 std::vector
<fstHandle
> fst_clock
;
1448 std::map
<Wire
*,fstHandle
> clocks
;
1450 for (auto portname
: clock
)
1452 Wire
*w
= topmod
->wire(portname
);
1454 log_error("Can't find port %s on module %s.\n", log_id(portname
), log_id(top
->module
));
1456 log_error("Clock port %s on module %s is not input.\n", log_id(portname
), log_id(top
->module
));
1457 fstHandle id
= fst
->getHandle(scope
+ "." + RTLIL::unescape_id(portname
));
1459 log_error("Can't find port %s.%s in FST.\n", scope
.c_str(), log_id(portname
));
1460 fst_clock
.push_back(id
);
1463 for (auto portname
: clockn
)
1465 Wire
*w
= topmod
->wire(portname
);
1467 log_error("Can't find port %s on module %s.\n", log_id(portname
), log_id(top
->module
));
1469 log_error("Clock port %s on module %s is not input.\n", log_id(portname
), log_id(top
->module
));
1470 fstHandle id
= fst
->getHandle(scope
+ "." + RTLIL::unescape_id(portname
));
1472 log_error("Can't find port %s.%s in FST.\n", scope
.c_str(), log_id(portname
));
1473 fst_clock
.push_back(id
);
1477 SigMap
sigmap(topmod
);
1478 std::map
<Wire
*,fstHandle
> inputs
;
1479 std::map
<Wire
*,fstHandle
> outputs
;
1481 for (auto wire
: topmod
->wires()) {
1482 fstHandle id
= fst
->getHandle(scope
+ "." + RTLIL::unescape_id(wire
->name
));
1483 if (id
==0 && (wire
->port_input
|| wire
->port_output
))
1484 log_error("Unable to find required '%s' signal in file\n",(scope
+ "." + RTLIL::unescape_id(wire
->name
)).c_str());
1485 if (wire
->port_input
)
1486 if (clocks
.find(wire
)==clocks
.end())
1488 if (wire
->port_output
)
1492 uint64_t startCount
= 0;
1493 uint64_t stopCount
= 0;
1494 if (start_time
==0) {
1495 if (start_time
< fst
->getStartTime())
1496 log_warning("Start time is before simulation file start time\n");
1497 startCount
= fst
->getStartTime();
1498 } else if (start_time
==-1)
1499 startCount
= fst
->getEndTime();
1501 startCount
= start_time
/ fst
->getTimescale();
1502 if (startCount
> fst
->getEndTime()) {
1503 startCount
= fst
->getEndTime();
1504 log_warning("Start time is after simulation file end time\n");
1508 if (stop_time
< fst
->getStartTime())
1509 log_warning("Stop time is before simulation file start time\n");
1510 stopCount
= fst
->getStartTime();
1511 } else if (stop_time
==-1)
1512 stopCount
= fst
->getEndTime();
1514 stopCount
= stop_time
/ fst
->getTimescale();
1515 if (stopCount
> fst
->getEndTime()) {
1516 stopCount
= fst
->getEndTime();
1517 log_warning("Stop time is after simulation file end time\n");
1520 if (stopCount
<startCount
) {
1521 log_error("Stop time is before start time\n");
1525 log("Generate testbench data from %lu%s to %lu%s", (unsigned long)startCount
, fst
->getTimescaleString(), (unsigned long)stopCount
, fst
->getTimescaleString());
1527 log(" for %d clock cycle(s)",numcycles
);
1530 std::stringstream f
;
1531 f
<< stringf("`timescale 1%s/1%s\n", fst
->getTimescaleString(),fst
->getTimescaleString());
1532 f
<< stringf("module %s();\n",tb_filename
.c_str());
1535 int outputs_len
= 0;
1536 for(auto &item
: clocks
) {
1537 clk_len
+= item
.first
->width
;
1538 f
<< "\treg " << define_signal(item
.first
) << ";\n";
1540 for(auto &item
: inputs
) {
1541 inputs_len
+= item
.first
->width
;
1542 f
<< "\treg " << define_signal(item
.first
) << ";\n";
1544 for(auto &item
: outputs
) {
1545 outputs_len
+= item
.first
->width
;
1546 f
<< "\twire " << define_signal(item
.first
) << ";\n";
1548 int data_len
= clk_len
+ inputs_len
+ outputs_len
+ 32;
1550 f
<< stringf("\t%s uut(",RTLIL::unescape_id(topmod
->name
).c_str());
1551 for(auto item
=clocks
.begin();item
!=clocks
.end();item
++)
1552 f
<< stringf("%c.%s(%s)", (item
==clocks
.begin() ? ' ' : ','), RTLIL::unescape_id(item
->first
->name
).c_str(), RTLIL::unescape_id(item
->first
->name
).c_str());
1553 for(auto &item
: inputs
)
1554 f
<< stringf(",.%s(%s)", RTLIL::unescape_id(item
.first
->name
).c_str(), RTLIL::unescape_id(item
.first
->name
).c_str());
1555 for(auto &item
: outputs
)
1556 f
<< stringf(",.%s(%s)", RTLIL::unescape_id(item
.first
->name
).c_str(), RTLIL::unescape_id(item
.first
->name
).c_str());
1559 f
<< "\tinteger i;\n";
1560 uint64_t prev_time
= startCount
;
1561 log("Writing data to `%s`\n", (tb_filename
+".txt").c_str());
1562 std::ofstream
data_file(tb_filename
+".txt");
1563 std::stringstream initstate
;
1565 fst
->reconstructAllAtTimes(fst_clock
, startCount
, stopCount
, [&](uint64_t time
) {
1566 for(auto &item
: clocks
)
1567 data_file
<< stringf("%s",fst
->valueOf(item
.second
).c_str());
1568 for(auto &item
: inputs
)
1569 data_file
<< stringf("%s",fst
->valueOf(item
.second
).c_str());
1570 for(auto &item
: outputs
)
1571 data_file
<< stringf("%s",fst
->valueOf(item
.second
).c_str());
1572 data_file
<< stringf("%s\n",Const(time
-prev_time
).as_string().c_str());
1574 if (time
==startCount
) {
1576 for(auto var
: fst
->getVars()) {
1577 if (var
.is_reg
&& !Const::from_string(fst
->valueOf(var
.id
).c_str()).is_fully_undef()) {
1578 if (var
.scope
== scope
) {
1579 initstate
<< stringf("\t\tuut.%s = %d'b%s;\n", var
.name
.c_str(), var
.width
, fst
->valueOf(var
.id
).c_str());
1580 } else if (var
.scope
.find(scope
+".")==0) {
1581 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());
1589 // Limit to number of cycles if provided
1590 if (cycles_set
&& cycle
> numcycles
*2)
1591 throw fst_end_of_data_exception();
1592 if (time
==stopCount
)
1593 throw fst_end_of_data_exception();
1595 } catch(fst_end_of_data_exception
) {
1596 // end of data detected
1599 f
<< stringf("\treg [0:%d] data [0:%d];\n", data_len
-1, cycle
-1);
1600 f
<< "\tinitial begin;\n";
1601 f
<< stringf("\t\t$dumpfile(\"%s\");\n",tb_filename
.c_str());
1602 f
<< stringf("\t\t$dumpvars(0,%s);\n",tb_filename
.c_str());
1603 f
<< initstate
.str();
1604 f
<< stringf("\t\t$readmemb(\"%s.txt\", data);\n",tb_filename
.c_str());
1606 f
<< stringf("\t\t#(data[0][%d:%d]);\n", data_len
-32, data_len
-1);
1607 f
<< stringf("\t\t{%s } = data[0][%d:%d];\n", signal_list(clocks
).c_str(), 0, clk_len
-1);
1608 f
<< stringf("\t\t{%s } <= data[0][%d:%d];\n", signal_list(inputs
).c_str(), clk_len
, clk_len
+inputs_len
-1);
1610 f
<< stringf("\t\tfor (i = 1; i < %d; i++) begin\n",cycle
);
1612 f
<< stringf("\t\t\t#(data[i][%d:%d]);\n", data_len
-32, data_len
-1);
1613 f
<< stringf("\t\t\t{%s } = data[i][%d:%d];\n", signal_list(clocks
).c_str(), 0, clk_len
-1);
1614 f
<< stringf("\t\t\t{%s } <= data[i][%d:%d];\n", signal_list(inputs
).c_str(), clk_len
, clk_len
+inputs_len
-1);
1616 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);
1617 f
<< "\t\t\t\t$error(\"Signal difference detected\\n\");\n";
1622 f
<< "\t\t$finish;\n";
1626 log("Writing testbench to `%s`\n", (tb_filename
+".v").c_str());
1627 std::ofstream
tb_file(tb_filename
+".v");
1634 struct VCDWriter
: public OutputWriter
1636 VCDWriter(SimWorker
*worker
, std::string filename
) : OutputWriter(worker
) {
1637 vcdfile
.open(filename
.c_str());
1640 void write(std::map
<int, bool> &use_signal
) override
1642 if (!vcdfile
.is_open()) return;
1643 vcdfile
<< stringf("$version %s $end\n", worker
->date
? yosys_version_str
: "Yosys");
1646 std::time_t t
= std::time(nullptr);
1648 if (std::strftime(mbstr
, sizeof(mbstr
), "%c", std::localtime(&t
))) {
1649 vcdfile
<< stringf("$date ") << mbstr
<< stringf(" $end\n");
1653 if (!worker
->timescale
.empty())
1654 vcdfile
<< stringf("$timescale %s $end\n", worker
->timescale
.c_str());
1656 worker
->top
->write_output_header(
1657 [this](IdString name
) { vcdfile
<< stringf("$scope module %s $end\n", log_id(name
)); },
1658 [this]() { vcdfile
<< stringf("$upscope $end\n");},
1659 [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
)); }
1662 vcdfile
<< stringf("$enddefinitions $end\n");
1664 for(auto& d
: worker
->output_data
)
1666 vcdfile
<< stringf("#%d\n", d
.first
);
1667 for (auto &data
: d
.second
)
1669 if (!use_signal
.at(data
.first
)) continue;
1670 Const value
= data
.second
;
1672 for (int i
= GetSize(value
)-1; i
>= 0; i
--) {
1674 case State::S0
: vcdfile
<< "0"; break;
1675 case State::S1
: vcdfile
<< "1"; break;
1676 case State::Sx
: vcdfile
<< "x"; break;
1677 default: vcdfile
<< "z";
1680 vcdfile
<< stringf(" n%d\n", data
.first
);
1685 std::ofstream vcdfile
;
1688 struct FSTWriter
: public OutputWriter
1690 FSTWriter(SimWorker
*worker
, std::string filename
) : OutputWriter(worker
) {
1691 fstfile
= (struct fstContext
*)fstWriterCreate(filename
.c_str(),1);
1694 virtual ~FSTWriter()
1696 fstWriterClose(fstfile
);
1699 void write(std::map
<int, bool> &use_signal
) override
1701 if (!fstfile
) return;
1702 std::time_t t
= std::time(nullptr);
1703 fstWriterSetVersion(fstfile
, worker
->date
? yosys_version_str
: "Yosys");
1705 fstWriterSetDate(fstfile
, asctime(std::localtime(&t
)));
1707 fstWriterSetDate(fstfile
, "");
1708 if (!worker
->timescale
.empty())
1709 fstWriterSetTimescaleFromString(fstfile
, worker
->timescale
.c_str());
1711 fstWriterSetPackType(fstfile
, FST_WR_PT_FASTLZ
);
1712 fstWriterSetRepackOnClose(fstfile
, 1);
1714 worker
->top
->write_output_header(
1715 [this](IdString name
) { fstWriterSetScope(fstfile
, FST_ST_VCD_MODULE
, stringf("%s",log_id(name
)).c_str(), nullptr); },
1716 [this]() { fstWriterSetUpscope(fstfile
); },
1717 [this,use_signal
](Wire
*wire
, int id
, bool is_reg
) {
1718 if (!use_signal
.at(id
)) return;
1719 fstHandle fst_id
= fstWriterCreateVar(fstfile
, is_reg
? FST_VT_VCD_REG
: FST_VT_VCD_WIRE
, FST_VD_IMPLICIT
, GetSize(wire
),
1720 stringf("%s%s", wire
->name
[0] == '$' ? "\\" : "", log_id(wire
)).c_str(), 0);
1722 mapping
.emplace(id
, fst_id
);
1726 for(auto& d
: worker
->output_data
)
1728 fstWriterEmitTimeChange(fstfile
, d
.first
);
1729 for (auto &data
: d
.second
)
1731 if (!use_signal
.at(data
.first
)) continue;
1732 Const value
= data
.second
;
1733 std::stringstream ss
;
1734 for (int i
= GetSize(value
)-1; i
>= 0; i
--) {
1736 case State::S0
: ss
<< "0"; break;
1737 case State::S1
: ss
<< "1"; break;
1738 case State::Sx
: ss
<< "x"; break;
1742 fstWriterEmitValueChange(fstfile
, mapping
[data
.first
], ss
.str().c_str());
1747 struct fstContext
*fstfile
= nullptr;
1748 std::map
<int,fstHandle
> mapping
;
1751 struct AIWWriter
: public OutputWriter
1753 AIWWriter(SimWorker
*worker
, std::string filename
) : OutputWriter(worker
) {
1754 aiwfile
.open(filename
.c_str());
1757 virtual ~AIWWriter()
1759 aiwfile
<< '.' << '\n';
1762 void write(std::map
<int, bool> &) override
1764 if (!aiwfile
.is_open()) return;
1765 if (worker
->map_filename
.empty())
1766 log_cmd_error("For AIGER witness file map parameter is mandatory.\n");
1768 std::ifstream
mf(worker
->map_filename
);
1769 std::string type
, symbol
;
1770 int variable
, index
;
1772 log_cmd_error("Not able to read AIGER witness map file.\n");
1773 while (mf
>> type
>> variable
>> index
>> symbol
) {
1774 RTLIL::IdString escaped_s
= RTLIL::escape_id(symbol
);
1775 Wire
*w
= worker
->top
->module
->wire(escaped_s
);
1777 log_error("Wire %s not present in module %s\n",log_id(escaped_s
),log_id(worker
->top
->module
));
1778 if (index
< w
->start_offset
|| index
> w
->start_offset
+ w
->width
)
1779 log_error("Index %d for wire %s is out of range\n", index
, log_signal(w
));
1780 if (type
== "input") {
1781 aiw_inputs
[variable
] = SigBit(w
,index
-w
->start_offset
);
1782 } else if (type
== "init") {
1783 aiw_inits
[variable
] = SigBit(w
,index
-w
->start_offset
);
1784 } else if (type
== "latch") {
1785 aiw_latches
[variable
] = {SigBit(w
,index
-w
->start_offset
), false};
1786 } else if (type
== "invlatch") {
1787 aiw_latches
[variable
] = {SigBit(w
,index
-w
->start_offset
), true};
1791 worker
->top
->write_output_header(
1794 [this](Wire
*wire
, int id
, bool) { mapping
[wire
] = id
; }
1797 std::map
<int, Yosys::RTLIL::Const
> current
;
1799 for(auto& d
: worker
->output_data
)
1801 for (auto &data
: d
.second
)
1803 current
[data
.first
] = data
.second
;
1806 for (int i
= 0;; i
++)
1808 if (aiw_latches
.count(i
)) {
1809 SigBit bit
= aiw_latches
.at(i
).first
;
1810 auto v
= current
[mapping
[bit
.wire
]].bits
.at(bit
.offset
);
1812 aiwfile
<< (aiw_latches
.at(i
).second
? '0' : '1');
1814 aiwfile
<< (aiw_latches
.at(i
).second
? '1' : '0');
1823 for (int i
= 0;; i
++)
1825 if (aiw_inputs
.count(i
)) {
1826 SigBit bit
= aiw_inputs
.at(i
);
1827 auto v
= current
[mapping
[bit
.wire
]].bits
.at(bit
.offset
);
1834 if (aiw_inits
.count(i
)) {
1835 SigBit bit
= aiw_inits
.at(i
);
1836 auto v
= current
[mapping
[bit
.wire
]].bits
.at(bit
.offset
);
1849 std::ofstream aiwfile
;
1850 dict
<int, std::pair
<SigBit
, bool>> aiw_latches
;
1851 dict
<int, SigBit
> aiw_inputs
, aiw_inits
;
1852 std::map
<Wire
*,int> mapping
;
1855 struct SimPass
: public Pass
{
1856 SimPass() : Pass("sim", "simulate the circuit") { }
1857 void help() override
1859 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1861 log(" sim [options] [top-level]\n");
1863 log("This command simulates the circuit using the given top-level module.\n");
1865 log(" -vcd <filename>\n");
1866 log(" write the simulation results to the given VCD file\n");
1868 log(" -fst <filename>\n");
1869 log(" write the simulation results to the given FST file\n");
1871 log(" -aiw <filename>\n");
1872 log(" write the simulation results to an AIGER witness file\n");
1873 log(" (requires a *.aim file via -map)\n");
1876 log(" ignore constant x outputs in simulation file.\n");
1879 log(" include date and full version info in output.\n");
1881 log(" -clock <portname>\n");
1882 log(" name of top-level clock input\n");
1884 log(" -clockn <portname>\n");
1885 log(" name of top-level clock input (inverse polarity)\n");
1887 log(" -multiclock\n");
1888 log(" mark that witness file is multiclock.\n");
1890 log(" -reset <portname>\n");
1891 log(" name of top-level reset input (active high)\n");
1893 log(" -resetn <portname>\n");
1894 log(" name of top-level inverted reset input (active low)\n");
1896 log(" -rstlen <integer>\n");
1897 log(" number of cycles reset should stay active (default: 1)\n");
1900 log(" zero-initialize all uninitialized regs and memories\n");
1902 log(" -timescale <string>\n");
1903 log(" include the specified timescale declaration in the vcd\n");
1905 log(" -n <integer>\n");
1906 log(" number of clock cycles to simulate (default: 20)\n");
1909 log(" use all nets in VCD/FST operations, not just those with public names\n");
1912 log(" writeback mode: use final simulation state as new init state\n");
1915 log(" read simulation results file (file formats supported: FST, VCD, AIW and WIT)\n");
1916 log(" VCD support requires vcd2fst external tool to be present\n");
1918 log(" -map <filename>\n");
1919 log(" read file with port and latch symbols, needed for AIGER witness input\n");
1921 log(" -scope <name>\n");
1922 log(" scope of simulation top model\n");
1924 log(" -at <time>\n");
1925 log(" sets start and stop time\n");
1927 log(" -start <time>\n");
1928 log(" start co-simulation in arbitary time (default 0)\n");
1930 log(" -stop <time>\n");
1931 log(" stop co-simulation in arbitary time (default END)\n");
1934 log(" simulation with stimulus from FST (default)\n");
1937 log(" co-simulation expect exact match\n");
1939 log(" -sim-gold\n");
1940 log(" co-simulation, x in simulation can match any value in FST\n");
1942 log(" -sim-gate\n");
1943 log(" co-simulation, x in FST can match any value in simulation\n");
1946 log(" disable per-cycle/sample log message\n");
1949 log(" enable debug output\n");
1954 static std::string
file_base_name(std::string
const & path
)
1956 return path
.substr(path
.find_last_of("/\\") + 1);
1959 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) override
1963 bool start_set
= false, stop_set
= false, at_set
= false;
1965 log_header(design
, "Executing SIM pass (simulate the circuit).\n");
1968 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
1969 if (args
[argidx
] == "-vcd" && argidx
+1 < args
.size()) {
1970 std::string vcd_filename
= args
[++argidx
];
1971 rewrite_filename(vcd_filename
);
1972 worker
.outputfiles
.emplace_back(std::unique_ptr
<VCDWriter
>(new VCDWriter(&worker
, vcd_filename
.c_str())));
1975 if (args
[argidx
] == "-fst" && argidx
+1 < args
.size()) {
1976 std::string fst_filename
= args
[++argidx
];
1977 rewrite_filename(fst_filename
);
1978 worker
.outputfiles
.emplace_back(std::unique_ptr
<FSTWriter
>(new FSTWriter(&worker
, fst_filename
.c_str())));
1981 if (args
[argidx
] == "-aiw" && argidx
+1 < args
.size()) {
1982 std::string aiw_filename
= args
[++argidx
];
1983 rewrite_filename(aiw_filename
);
1984 worker
.outputfiles
.emplace_back(std::unique_ptr
<AIWWriter
>(new AIWWriter(&worker
, aiw_filename
.c_str())));
1987 if (args
[argidx
] == "-n" && argidx
+1 < args
.size()) {
1988 numcycles
= atoi(args
[++argidx
].c_str());
1989 worker
.cycles_set
= true;
1992 if (args
[argidx
] == "-rstlen" && argidx
+1 < args
.size()) {
1993 worker
.rstlen
= atoi(args
[++argidx
].c_str());
1996 if (args
[argidx
] == "-clock" && argidx
+1 < args
.size()) {
1997 worker
.clock
.insert(RTLIL::escape_id(args
[++argidx
]));
2000 if (args
[argidx
] == "-clockn" && argidx
+1 < args
.size()) {
2001 worker
.clockn
.insert(RTLIL::escape_id(args
[++argidx
]));
2004 if (args
[argidx
] == "-reset" && argidx
+1 < args
.size()) {
2005 worker
.reset
.insert(RTLIL::escape_id(args
[++argidx
]));
2008 if (args
[argidx
] == "-resetn" && argidx
+1 < args
.size()) {
2009 worker
.resetn
.insert(RTLIL::escape_id(args
[++argidx
]));
2012 if (args
[argidx
] == "-timescale" && argidx
+1 < args
.size()) {
2013 worker
.timescale
= args
[++argidx
];
2016 if (args
[argidx
] == "-a") {
2017 worker
.hide_internal
= false;
2020 if (args
[argidx
] == "-q") {
2021 worker
.verbose
= false;
2024 if (args
[argidx
] == "-d") {
2025 worker
.debug
= true;
2028 if (args
[argidx
] == "-w") {
2029 worker
.writeback
= true;
2032 if (args
[argidx
] == "-zinit") {
2033 worker
.zinit
= true;
2036 if (args
[argidx
] == "-r" && argidx
+1 < args
.size()) {
2037 std::string sim_filename
= args
[++argidx
];
2038 rewrite_filename(sim_filename
);
2039 worker
.sim_filename
= sim_filename
;
2042 if (args
[argidx
] == "-map" && argidx
+1 < args
.size()) {
2043 std::string map_filename
= args
[++argidx
];
2044 rewrite_filename(map_filename
);
2045 worker
.map_filename
= map_filename
;
2048 if (args
[argidx
] == "-scope" && argidx
+1 < args
.size()) {
2049 worker
.scope
= args
[++argidx
];
2052 if (args
[argidx
] == "-start" && argidx
+1 < args
.size()) {
2053 worker
.start_time
= stringToTime(args
[++argidx
]);
2057 if (args
[argidx
] == "-stop" && argidx
+1 < args
.size()) {
2058 worker
.stop_time
= stringToTime(args
[++argidx
]);
2062 if (args
[argidx
] == "-at" && argidx
+1 < args
.size()) {
2063 worker
.start_time
= stringToTime(args
[++argidx
]);
2064 worker
.stop_time
= worker
.start_time
;
2068 if (args
[argidx
] == "-sim") {
2069 worker
.sim_mode
= SimulationMode::sim
;
2072 if (args
[argidx
] == "-sim-cmp") {
2073 worker
.sim_mode
= SimulationMode::cmp
;
2076 if (args
[argidx
] == "-sim-gold") {
2077 worker
.sim_mode
= SimulationMode::gold
;
2080 if (args
[argidx
] == "-sim-gate") {
2081 worker
.sim_mode
= SimulationMode::gate
;
2084 if (args
[argidx
] == "-x") {
2085 worker
.ignore_x
= true;
2088 if (args
[argidx
] == "-date") {
2092 if (args
[argidx
] == "-multiclock") {
2093 worker
.multiclock
= true;
2098 extra_args(args
, argidx
, design
);
2099 if (at_set
&& (start_set
|| stop_set
|| worker
.cycles_set
))
2100 log_error("'at' option can only be defined separate of 'start','stop' and 'n'\n");
2101 if (stop_set
&& worker
.cycles_set
)
2102 log_error("'stop' and 'n' can only be used exclusively'\n");
2104 Module
*top_mod
= nullptr;
2106 if (design
->full_selection()) {
2107 top_mod
= design
->top_module();
2110 log_cmd_error("Design has no top module, use the 'hierarchy' command to specify one.\n");
2112 auto mods
= design
->selected_whole_modules();
2113 if (GetSize(mods
) != 1)
2114 log_cmd_error("Only one top module must be selected.\n");
2115 top_mod
= mods
.front();
2118 if (worker
.sim_filename
.empty())
2119 worker
.run(top_mod
, numcycles
);
2121 std::string filename_trim
= file_base_name(worker
.sim_filename
);
2122 if (filename_trim
.size() > 4 && ((filename_trim
.compare(filename_trim
.size()-4, std::string::npos
, ".fst") == 0) ||
2123 filename_trim
.compare(filename_trim
.size()-4, std::string::npos
, ".vcd") == 0)) {
2124 worker
.run_cosim_fst(top_mod
, numcycles
);
2125 } else if (filename_trim
.size() > 4 && filename_trim
.compare(filename_trim
.size()-4, std::string::npos
, ".aiw") == 0) {
2126 if (worker
.map_filename
.empty())
2127 log_cmd_error("For AIGER witness file map parameter is mandatory.\n");
2128 worker
.run_cosim_aiger_witness(top_mod
);
2129 } else if (filename_trim
.size() > 4 && filename_trim
.compare(filename_trim
.size()-4, std::string::npos
, ".wit") == 0) {
2130 worker
.run_cosim_btor2_witness(top_mod
);
2132 log_cmd_error("Unhandled extension for simulation input file `%s`.\n", worker
.sim_filename
.c_str());
2138 struct Fst2TbPass
: public Pass
{
2139 Fst2TbPass() : Pass("fst2tb", "generate testbench out of fst file") { }
2140 void help() override
2142 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
2144 log(" fst2tb [options] [top-level]\n");
2146 log("This command generates testbench for the circuit using the given top-level module\n");
2147 log("and simulus signal from FST file\n");
2149 log(" -tb <name>\n");
2150 log(" generated testbench name.\n");
2151 log(" files <name>.v and <name>.txt are created as result.\n");
2153 log(" -r <filename>\n");
2154 log(" read simulation FST file\n");
2156 log(" -clock <portname>\n");
2157 log(" name of top-level clock input\n");
2159 log(" -clockn <portname>\n");
2160 log(" name of top-level clock input (inverse polarity)\n");
2162 log(" -scope <name>\n");
2163 log(" scope of simulation top model\n");
2165 log(" -start <time>\n");
2166 log(" start co-simulation in arbitary time (default 0)\n");
2168 log(" -stop <time>\n");
2169 log(" stop co-simulation in arbitary time (default END)\n");
2171 log(" -n <integer>\n");
2172 log(" number of clock cycles to simulate (default: 20)\n");
2176 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) override
2180 bool stop_set
= false;
2181 std::string tb_filename
;
2183 log_header(design
, "Executing FST2FB pass.\n");
2186 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
2187 if (args
[argidx
] == "-clock" && argidx
+1 < args
.size()) {
2188 worker
.clock
.insert(RTLIL::escape_id(args
[++argidx
]));
2191 if (args
[argidx
] == "-clockn" && argidx
+1 < args
.size()) {
2192 worker
.clockn
.insert(RTLIL::escape_id(args
[++argidx
]));
2195 if (args
[argidx
] == "-r" && argidx
+1 < args
.size()) {
2196 std::string sim_filename
= args
[++argidx
];
2197 rewrite_filename(sim_filename
);
2198 worker
.sim_filename
= sim_filename
;
2201 if (args
[argidx
] == "-n" && argidx
+1 < args
.size()) {
2202 numcycles
= atoi(args
[++argidx
].c_str());
2203 worker
.cycles_set
= true;
2206 if (args
[argidx
] == "-scope" && argidx
+1 < args
.size()) {
2207 worker
.scope
= args
[++argidx
];
2210 if (args
[argidx
] == "-start" && argidx
+1 < args
.size()) {
2211 worker
.start_time
= stringToTime(args
[++argidx
]);
2214 if (args
[argidx
] == "-stop" && argidx
+1 < args
.size()) {
2215 worker
.stop_time
= stringToTime(args
[++argidx
]);
2219 if (args
[argidx
] == "-tb" && argidx
+1 < args
.size()) {
2220 tb_filename
= args
[++argidx
];
2225 extra_args(args
, argidx
, design
);
2226 if (stop_set
&& worker
.cycles_set
)
2227 log_error("'stop' and 'n' can only be used exclusively'\n");
2229 Module
*top_mod
= nullptr;
2231 if (design
->full_selection()) {
2232 top_mod
= design
->top_module();
2235 log_cmd_error("Design has no top module, use the 'hierarchy' command to specify one.\n");
2237 auto mods
= design
->selected_whole_modules();
2238 if (GetSize(mods
) != 1)
2239 log_cmd_error("Only one top module must be selected.\n");
2240 top_mod
= mods
.front();
2243 if (tb_filename
.empty())
2244 log_cmd_error("Testbench name must be defined.\n");
2246 if (worker
.sim_filename
.empty())
2247 log_cmd_error("Stimulus FST file must be defined.\n");
2249 worker
.generate_tb(top_mod
, tb_filename
, numcycles
);
2253 PRIVATE_NAMESPACE_END