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 &item
: fst_handles
) {
786 if (item
.second
==0) continue; // Ignore signals not found
787 std::string v
= shared
->fst
->valueOf(item
.second
);
788 did_something
|= set_state(item
.first
, Const::from_string(v
));
790 for (auto &it
: ff_database
)
792 ff_state_t
&ff
= it
.second
;
793 SigSpec dsig
= it
.second
.data
.sig_d
;
794 Const value
= get_state(dsig
);
795 if (dsig
.is_wire()) {
797 if (ff
.data
.has_aload
)
799 did_something
|= true;
802 for (auto child
: children
)
803 did_something
|= child
.second
->setInitState();
804 return did_something
;
807 void setState(dict
<int, std::pair
<SigBit
,bool>> bits
, std::string values
)
809 for(auto bit
: bits
) {
810 if (bit
.first
>= GetSize(values
))
811 log_error("Too few input data bits in file.\n");
812 switch(values
.at(bit
.first
)) {
813 case '0': set_state(bit
.second
.first
, bit
.second
.second
? State::S1
: State::S0
); break;
814 case '1': set_state(bit
.second
.first
, bit
.second
.second
? State::S0
: State::S1
); break;
815 default: set_state(bit
.second
.first
, State::Sx
); break;
820 void setMemState(dict
<int, std::pair
<std::string
,int>> bits
, std::string values
)
822 for(auto bit
: bits
) {
823 if (bit
.first
>= GetSize(values
))
824 log_error("Too few input data bits in file.\n");
825 switch(values
.at(bit
.first
)) {
826 case '0': set_memory_state_bit(bit
.second
.first
, bit
.second
.second
, State::S0
); break;
827 case '1': set_memory_state_bit(bit
.second
.first
, bit
.second
.second
, State::S1
); break;
828 default: set_memory_state_bit(bit
.second
.first
, bit
.second
.second
, State::Sx
); break;
836 for(auto &item
: fst_handles
) {
837 if (item
.second
==0) continue; // Ignore signals not found
838 Const fst_val
= Const::from_string(shared
->fst
->valueOf(item
.second
));
839 Const sim_val
= get_state(item
.first
);
840 if (sim_val
.size()!=fst_val
.size()) {
841 log_warning("Signal '%s.%s' size is different in gold and gate.\n", scope
.c_str(), log_id(item
.first
));
844 if (shared
->sim_mode
== SimulationMode::sim
) {
845 // No checks performed when using stimulus
846 } else if (shared
->sim_mode
== SimulationMode::gate
&& !fst_val
.is_fully_def()) { // FST data contains X
847 for(int i
=0;i
<fst_val
.size();i
++) {
848 if (fst_val
[i
]!=State::Sx
&& fst_val
[i
]!=sim_val
[i
]) {
849 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
));
854 } else if (shared
->sim_mode
== SimulationMode::gold
&& !sim_val
.is_fully_def()) { // sim data contains X
855 for(int i
=0;i
<sim_val
.size();i
++) {
856 if (sim_val
[i
]!=State::Sx
&& fst_val
[i
]!=sim_val
[i
]) {
857 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
));
863 if (fst_val
!=sim_val
) {
864 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
));
869 for (auto child
: children
)
870 retVal
|= child
.second
->checkSignals();
875 struct SimWorker
: SimShared
877 SimInstance
*top
= nullptr;
878 pool
<IdString
> clock
, clockn
, reset
, resetn
;
879 std::string timescale
;
880 std::string sim_filename
;
881 std::string map_filename
;
890 void register_signals()
893 top
->register_signals(id
);
896 void register_output_step(int t
)
898 std::map
<int,Const
> data
;
899 top
->register_output_step_values(&data
);
900 output_data
.emplace_back(t
, data
);
903 void write_output_files()
905 std::map
<int, bool> use_signal
;
906 bool first
= ignore_x
;
907 for(auto& d
: output_data
)
910 for (auto &data
: d
.second
)
911 use_signal
[data
.first
] = !data
.second
.is_fully_undef();
914 for (auto &data
: d
.second
)
915 use_signal
[data
.first
] = true;
917 if (!ignore_x
) break;
919 for(auto& writer
: outputfiles
)
920 writer
->write(use_signal
);
928 log("\n-- ph1 --\n");
933 log("\n-- ph2 --\n");
935 if (!top
->update_ph2())
940 log("\n-- ph3 --\n");
945 void set_inports(pool
<IdString
> ports
, State value
)
947 for (auto portname
: ports
)
949 Wire
*w
= top
->module
->wire(portname
);
952 log_error("Can't find port %s on module %s.\n", log_id(portname
), log_id(top
->module
));
954 top
->set_state(w
, value
);
958 void run(Module
*topmod
, int numcycles
)
960 log_assert(top
== nullptr);
961 top
= new SimInstance(this, scope
, topmod
);
965 log("\n===== 0 =====\n");
967 log("Simulating cycle 0.\n");
969 set_inports(reset
, State::S1
);
970 set_inports(resetn
, State::S0
);
972 set_inports(clock
, State::Sx
);
973 set_inports(clockn
, State::Sx
);
977 register_output_step(0);
979 for (int cycle
= 0; cycle
< numcycles
; cycle
++)
982 log("\n===== %d =====\n", 10*cycle
+ 5);
984 log("Simulating cycle %d.\n", (cycle
*2)+1);
985 set_inports(clock
, State::S0
);
986 set_inports(clockn
, State::S1
);
989 register_output_step(10*cycle
+ 5);
992 log("\n===== %d =====\n", 10*cycle
+ 10);
994 log("Simulating cycle %d.\n", (cycle
*2)+2);
996 set_inports(clock
, State::S1
);
997 set_inports(clockn
, State::S0
);
999 if (cycle
+1 == rstlen
) {
1000 set_inports(reset
, State::S0
);
1001 set_inports(resetn
, State::S1
);
1005 register_output_step(10*cycle
+ 10);
1008 register_output_step(10*numcycles
+ 2);
1010 write_output_files();
1013 pool
<Module
*> wbmods
;
1014 top
->writeback(wbmods
);
1018 void run_cosim_fst(Module
*topmod
, int numcycles
)
1020 log_assert(top
== nullptr);
1021 fst
= new FstData(sim_filename
);
1024 log_error("Scope must be defined for co-simulation.\n");
1026 top
= new SimInstance(this, scope
, topmod
);
1029 std::vector
<fstHandle
> fst_clock
;
1031 for (auto portname
: clock
)
1033 Wire
*w
= topmod
->wire(portname
);
1035 log_error("Can't find port %s on module %s.\n", log_id(portname
), log_id(top
->module
));
1037 log_error("Clock port %s on module %s is not input.\n", log_id(portname
), log_id(top
->module
));
1038 fstHandle id
= fst
->getHandle(scope
+ "." + RTLIL::unescape_id(portname
));
1040 log_error("Can't find port %s.%s in FST.\n", scope
.c_str(), log_id(portname
));
1041 fst_clock
.push_back(id
);
1043 for (auto portname
: clockn
)
1045 Wire
*w
= topmod
->wire(portname
);
1047 log_error("Can't find port %s on module %s.\n", log_id(portname
), log_id(top
->module
));
1049 log_error("Clock port %s on module %s is not input.\n", log_id(portname
), log_id(top
->module
));
1050 fstHandle id
= fst
->getHandle(scope
+ "." + RTLIL::unescape_id(portname
));
1052 log_error("Can't find port %s.%s in FST.\n", scope
.c_str(), log_id(portname
));
1053 fst_clock
.push_back(id
);
1056 SigMap
sigmap(topmod
);
1057 std::map
<Wire
*,fstHandle
> inputs
;
1059 for (auto wire
: topmod
->wires()) {
1060 if (wire
->port_input
) {
1061 fstHandle id
= fst
->getHandle(scope
+ "." + RTLIL::unescape_id(wire
->name
));
1063 log_error("Unable to find required '%s' signal in file\n",(scope
+ "." + RTLIL::unescape_id(wire
->name
)).c_str());
1068 uint64_t startCount
= 0;
1069 uint64_t stopCount
= 0;
1070 if (start_time
==0) {
1071 if (start_time
< fst
->getStartTime())
1072 log_warning("Start time is before simulation file start time\n");
1073 startCount
= fst
->getStartTime();
1074 } else if (start_time
==-1)
1075 startCount
= fst
->getEndTime();
1077 startCount
= start_time
/ fst
->getTimescale();
1078 if (startCount
> fst
->getEndTime()) {
1079 startCount
= fst
->getEndTime();
1080 log_warning("Start time is after simulation file end time\n");
1084 if (stop_time
< fst
->getStartTime())
1085 log_warning("Stop time is before simulation file start time\n");
1086 stopCount
= fst
->getStartTime();
1087 } else if (stop_time
==-1)
1088 stopCount
= fst
->getEndTime();
1090 stopCount
= stop_time
/ fst
->getTimescale();
1091 if (stopCount
> fst
->getEndTime()) {
1092 stopCount
= fst
->getEndTime();
1093 log_warning("Stop time is after simulation file end time\n");
1096 if (stopCount
<startCount
) {
1097 log_error("Stop time is before start time\n");
1100 bool initial
= true;
1102 log("Co-simulation from %lu%s to %lu%s", (unsigned long)startCount
, fst
->getTimescaleString(), (unsigned long)stopCount
, fst
->getTimescaleString());
1104 log(" for %d clock cycle(s)",numcycles
);
1106 bool all_samples
= fst_clock
.empty();
1109 fst
->reconstructAllAtTimes(fst_clock
, startCount
, stopCount
, [&](uint64_t time
) {
1111 log("Co-simulating %s %d [%lu%s].\n", (all_samples
? "sample" : "cycle"), cycle
, (unsigned long)time
, fst
->getTimescaleString());
1112 bool did_something
= false;
1113 for(auto &item
: inputs
) {
1114 std::string v
= fst
->valueOf(item
.second
);
1115 did_something
|= top
->set_state(item
.first
, Const::from_string(v
));
1119 did_something
|= top
->setInitState();
1124 register_output_step(time
);
1126 bool status
= top
->checkSignals();
1128 log_error("Signal difference\n");
1131 // Limit to number of cycles if provided
1132 if (cycles_set
&& cycle
> numcycles
*2)
1133 throw fst_end_of_data_exception();
1134 if (time
==stopCount
)
1135 throw fst_end_of_data_exception();
1137 } catch(fst_end_of_data_exception
) {
1138 // end of data detected
1141 write_output_files();
1144 pool
<Module
*> wbmods
;
1145 top
->writeback(wbmods
);
1150 std::string
cell_name(std::string
const & name
)
1152 size_t pos
= name
.find_last_of("[");
1153 if (pos
!=std::string::npos
)
1154 return name
.substr(0, pos
);
1158 int mem_cell_addr(std::string
const & name
)
1160 size_t pos
= name
.find_last_of("[");
1161 return atoi(name
.substr(pos
+1).c_str());
1164 void run_cosim_aiger_witness(Module
*topmod
)
1166 log_assert(top
== nullptr);
1167 if (!multiclock
&& (clock
.size()+clockn
.size())==0)
1168 log_error("Clock signal must be specified.\n");
1169 if (multiclock
&& (clock
.size()+clockn
.size())>0)
1170 log_error("For multiclock witness there should be no clock signal.\n");
1172 top
= new SimInstance(this, scope
, topmod
);
1175 std::ifstream
mf(map_filename
);
1176 std::string type
, symbol
;
1177 int variable
, index
;
1178 dict
<int, std::pair
<SigBit
,bool>> inputs
, inits
, latches
;
1179 dict
<int, std::pair
<std::string
,int>> mem_inits
, mem_latches
;
1181 log_cmd_error("Not able to read AIGER witness map file.\n");
1182 while (mf
>> type
>> variable
>> index
>> symbol
) {
1183 RTLIL::IdString escaped_s
= RTLIL::escape_id(symbol
);
1184 Wire
*w
= topmod
->wire(escaped_s
);
1186 escaped_s
= RTLIL::escape_id(cell_name(symbol
));
1187 Cell
*c
= topmod
->cell(escaped_s
);
1189 log_warning("Wire/cell %s not present in module %s\n",symbol
.c_str(),log_id(topmod
));
1191 if (c
->is_mem_cell()) {
1192 std::string memid
= c
->parameters
.at(ID::MEMID
).decode_string();
1193 auto &state
= top
->mem_database
[memid
];
1195 int offset
= (mem_cell_addr(symbol
) - state
.mem
->start_offset
) * state
.mem
->width
+ index
;
1197 mem_inits
[variable
] = { memid
, offset
};
1198 else if (type
== "latch")
1199 mem_latches
[variable
] = { memid
, offset
};
1201 log_error("Map file addressing cell %s as type %s\n", symbol
.c_str(), type
.c_str());
1203 log_error("Cell %s in map file is not memory cell\n", symbol
.c_str());
1206 if (index
< w
->start_offset
|| index
> w
->start_offset
+ w
->width
)
1207 log_error("Index %d for wire %s is out of range\n", index
, log_signal(w
));
1208 if (type
== "input") {
1209 inputs
[variable
] = {SigBit(w
,index
-w
->start_offset
), false};
1210 } else if (type
== "init") {
1211 inits
[variable
] = {SigBit(w
,index
-w
->start_offset
), false};
1212 } else if (type
== "latch") {
1213 latches
[variable
] = {SigBit(w
,index
-w
->start_offset
), false};
1214 } else if (type
== "invlatch") {
1215 latches
[variable
] = {SigBit(w
,index
-w
->start_offset
), true};
1221 f
.open(sim_filename
.c_str());
1222 if (f
.fail() || GetSize(sim_filename
) == 0)
1223 log_error("Can not open file `%s`\n", sim_filename
.c_str());
1232 std::getline(f
, line
);
1233 if (line
.size()==0 || line
[0]=='#' || line
[0]=='c' || line
[0]=='f' || line
[0]=='u') continue;
1234 if (line
[0]=='.') break;
1235 if (state
==0 && line
.size()!=1) {
1236 // old format detected, latch data
1239 if (state
==1 && line
[0]!='b' && line
[0]!='j') {
1240 // was old format but with 1 bit latch
1241 top
->setState(latches
, status
);
1255 top
->setState(latches
, line
);
1256 top
->setMemState(mem_latches
, line
);
1261 log("Simulating cycle %d.\n", cycle
);
1262 top
->setState(inputs
, line
);
1264 set_inports(clock
, State::S1
);
1265 set_inports(clockn
, State::S0
);
1267 top
->setState(inits
, line
);
1268 top
->setMemState(mem_inits
, line
);
1269 set_inports(clock
, State::S0
);
1270 set_inports(clockn
, State::S1
);
1273 register_output_step(10*cycle
);
1274 if (!multiclock
&& cycle
) {
1275 set_inports(clock
, State::S0
);
1276 set_inports(clockn
, State::S1
);
1278 register_output_step(10*cycle
+ 5);
1284 register_output_step(10*cycle
);
1285 write_output_files();
1288 std::vector
<std::string
> split(std::string text
, const char *delim
)
1290 std::vector
<std::string
> list
;
1291 char *p
= strdup(text
.c_str());
1292 char *t
= strtok(p
, delim
);
1295 t
= strtok(NULL
, delim
);
1301 std::string
signal_name(std::string
const & name
)
1303 size_t pos
= name
.find_first_of("@");
1304 if (pos
==std::string::npos
) {
1305 pos
= name
.find_first_of("#");
1306 if (pos
==std::string::npos
)
1307 log_error("Line does not contain proper signal name `%s`\n", name
.c_str());
1309 return name
.substr(0, pos
);
1312 void run_cosim_btor2_witness(Module
*topmod
)
1314 log_assert(top
== nullptr);
1315 if (!multiclock
&& (clock
.size()+clockn
.size())==0)
1316 log_error("Clock signal must be specified.\n");
1317 if (multiclock
&& (clock
.size()+clockn
.size())>0)
1318 log_error("For multiclock witness there should be no clock signal.\n");
1320 f
.open(sim_filename
.c_str());
1321 if (f
.fail() || GetSize(sim_filename
) == 0)
1322 log_error("Can not open file `%s`\n", sim_filename
.c_str());
1326 top
= new SimInstance(this, scope
, topmod
);
1330 std::vector
<std::string
> parts
;
1335 std::getline(f
, line
);
1336 if (line
.size()==0) continue;
1338 if (line
[0]=='#' || line
[0]=='@' || line
[0]=='.') {
1340 curr_cycle
= atoi(line
.c_str()+1);
1342 curr_cycle
= -1; // force detect change
1344 if (curr_cycle
!= prev_cycle
) {
1346 log("Simulating cycle %d.\n", cycle
);
1347 set_inports(clock
, State::S1
);
1348 set_inports(clockn
, State::S0
);
1350 register_output_step(10*cycle
+0);
1352 set_inports(clock
, State::S0
);
1353 set_inports(clockn
, State::S1
);
1355 register_output_step(10*cycle
+5);
1358 prev_cycle
= curr_cycle
;
1360 if (line
[0]=='.') break;
1371 if (line
[0]=='b' || line
[0]=='j')
1374 log_error("Line does not contain property.\n");
1376 default: // set state or inputs
1377 parts
= split(line
, " ");
1380 log_error("Invalid set state line content.\n");
1382 RTLIL::IdString escaped_s
= RTLIL::escape_id(signal_name(parts
[len
-1]));
1384 Wire
*w
= topmod
->wire(escaped_s
);
1386 Cell
*c
= topmod
->cell(escaped_s
);
1388 log_warning("Wire/cell %s not present in module %s\n",log_id(escaped_s
),log_id(topmod
));
1389 else if (c
->type
.in(ID($anyconst
), ID($anyseq
))) {
1390 SigSpec sig_y
= c
->getPort(ID::Y
);
1391 if ((int)parts
[1].size() != GetSize(sig_y
))
1392 log_error("Size of wire %s is different than provided data.\n", log_signal(sig_y
));
1393 top
->set_state(sig_y
, Const::from_string(parts
[1]));
1396 if ((int)parts
[1].size() != w
->width
)
1397 log_error("Size of wire %s is different than provided data.\n", log_signal(w
));
1398 top
->set_state(w
, Const::from_string(parts
[1]));
1401 Cell
*c
= topmod
->cell(escaped_s
);
1403 log_error("Cell %s not present in module %s\n",log_id(escaped_s
),log_id(topmod
));
1404 if (!c
->is_mem_cell())
1405 log_error("Cell %s is not memory cell in module %s\n",log_id(escaped_s
),log_id(topmod
));
1407 Const addr
= Const::from_string(parts
[1].substr(1,parts
[1].size()-2));
1408 Const data
= Const::from_string(parts
[2]);
1409 top
->set_memory_state(c
->parameters
.at(ID::MEMID
).decode_string(), addr
, data
);
1414 register_output_step(10*cycle
);
1415 write_output_files();
1418 std::string
define_signal(Wire
*wire
)
1420 std::stringstream f
;
1423 f
<< stringf("%s", RTLIL::unescape_id(wire
->name
).c_str());
1426 f
<< stringf("[%d:%d] %s", wire
->start_offset
, wire
->width
- 1 + wire
->start_offset
, RTLIL::unescape_id(wire
->name
).c_str());
1428 f
<< stringf("[%d:%d] %s", wire
->width
- 1 + wire
->start_offset
, wire
->start_offset
, RTLIL::unescape_id(wire
->name
).c_str());
1432 std::string
signal_list(std::map
<Wire
*,fstHandle
> &signals
)
1434 std::stringstream f
;
1435 for(auto item
=signals
.begin();item
!=signals
.end();item
++)
1436 f
<< stringf("%c%s", (item
==signals
.begin() ? ' ' : ','), RTLIL::unescape_id(item
->first
->name
).c_str());
1440 void generate_tb(Module
*topmod
, std::string tb_filename
, int numcycles
)
1442 fst
= new FstData(sim_filename
);
1445 log_error("Scope must be defined for co-simulation.\n");
1447 if ((clock
.size()+clockn
.size())==0)
1448 log_error("Clock signal must be specified.\n");
1450 std::vector
<fstHandle
> fst_clock
;
1451 std::map
<Wire
*,fstHandle
> clocks
;
1453 for (auto portname
: clock
)
1455 Wire
*w
= topmod
->wire(portname
);
1457 log_error("Can't find port %s on module %s.\n", log_id(portname
), log_id(top
->module
));
1459 log_error("Clock port %s on module %s is not input.\n", log_id(portname
), log_id(top
->module
));
1460 fstHandle id
= fst
->getHandle(scope
+ "." + RTLIL::unescape_id(portname
));
1462 log_error("Can't find port %s.%s in FST.\n", scope
.c_str(), log_id(portname
));
1463 fst_clock
.push_back(id
);
1466 for (auto portname
: clockn
)
1468 Wire
*w
= topmod
->wire(portname
);
1470 log_error("Can't find port %s on module %s.\n", log_id(portname
), log_id(top
->module
));
1472 log_error("Clock port %s on module %s is not input.\n", log_id(portname
), log_id(top
->module
));
1473 fstHandle id
= fst
->getHandle(scope
+ "." + RTLIL::unescape_id(portname
));
1475 log_error("Can't find port %s.%s in FST.\n", scope
.c_str(), log_id(portname
));
1476 fst_clock
.push_back(id
);
1480 SigMap
sigmap(topmod
);
1481 std::map
<Wire
*,fstHandle
> inputs
;
1482 std::map
<Wire
*,fstHandle
> outputs
;
1484 for (auto wire
: topmod
->wires()) {
1485 fstHandle id
= fst
->getHandle(scope
+ "." + RTLIL::unescape_id(wire
->name
));
1486 if (id
==0 && (wire
->port_input
|| wire
->port_output
))
1487 log_error("Unable to find required '%s' signal in file\n",(scope
+ "." + RTLIL::unescape_id(wire
->name
)).c_str());
1488 if (wire
->port_input
)
1489 if (clocks
.find(wire
)==clocks
.end())
1491 if (wire
->port_output
)
1495 uint64_t startCount
= 0;
1496 uint64_t stopCount
= 0;
1497 if (start_time
==0) {
1498 if (start_time
< fst
->getStartTime())
1499 log_warning("Start time is before simulation file start time\n");
1500 startCount
= fst
->getStartTime();
1501 } else if (start_time
==-1)
1502 startCount
= fst
->getEndTime();
1504 startCount
= start_time
/ fst
->getTimescale();
1505 if (startCount
> fst
->getEndTime()) {
1506 startCount
= fst
->getEndTime();
1507 log_warning("Start time is after simulation file end time\n");
1511 if (stop_time
< fst
->getStartTime())
1512 log_warning("Stop time is before simulation file start time\n");
1513 stopCount
= fst
->getStartTime();
1514 } else if (stop_time
==-1)
1515 stopCount
= fst
->getEndTime();
1517 stopCount
= stop_time
/ fst
->getTimescale();
1518 if (stopCount
> fst
->getEndTime()) {
1519 stopCount
= fst
->getEndTime();
1520 log_warning("Stop time is after simulation file end time\n");
1523 if (stopCount
<startCount
) {
1524 log_error("Stop time is before start time\n");
1528 log("Generate testbench data from %lu%s to %lu%s", (unsigned long)startCount
, fst
->getTimescaleString(), (unsigned long)stopCount
, fst
->getTimescaleString());
1530 log(" for %d clock cycle(s)",numcycles
);
1533 std::stringstream f
;
1534 f
<< stringf("`timescale 1%s/1%s\n", fst
->getTimescaleString(),fst
->getTimescaleString());
1535 f
<< stringf("module %s();\n",tb_filename
.c_str());
1538 int outputs_len
= 0;
1539 for(auto &item
: clocks
) {
1540 clk_len
+= item
.first
->width
;
1541 f
<< "\treg " << define_signal(item
.first
) << ";\n";
1543 for(auto &item
: inputs
) {
1544 inputs_len
+= item
.first
->width
;
1545 f
<< "\treg " << define_signal(item
.first
) << ";\n";
1547 for(auto &item
: outputs
) {
1548 outputs_len
+= item
.first
->width
;
1549 f
<< "\twire " << define_signal(item
.first
) << ";\n";
1551 int data_len
= clk_len
+ inputs_len
+ outputs_len
+ 32;
1553 f
<< stringf("\t%s uut(",RTLIL::unescape_id(topmod
->name
).c_str());
1554 for(auto item
=clocks
.begin();item
!=clocks
.end();item
++)
1555 f
<< stringf("%c.%s(%s)", (item
==clocks
.begin() ? ' ' : ','), RTLIL::unescape_id(item
->first
->name
).c_str(), RTLIL::unescape_id(item
->first
->name
).c_str());
1556 for(auto &item
: inputs
)
1557 f
<< stringf(",.%s(%s)", RTLIL::unescape_id(item
.first
->name
).c_str(), RTLIL::unescape_id(item
.first
->name
).c_str());
1558 for(auto &item
: outputs
)
1559 f
<< stringf(",.%s(%s)", RTLIL::unescape_id(item
.first
->name
).c_str(), RTLIL::unescape_id(item
.first
->name
).c_str());
1562 f
<< "\tinteger i;\n";
1563 uint64_t prev_time
= startCount
;
1564 log("Writing data to `%s`\n", (tb_filename
+".txt").c_str());
1565 std::ofstream
data_file(tb_filename
+".txt");
1566 std::stringstream initstate
;
1568 fst
->reconstructAllAtTimes(fst_clock
, startCount
, stopCount
, [&](uint64_t time
) {
1569 for(auto &item
: clocks
)
1570 data_file
<< stringf("%s",fst
->valueOf(item
.second
).c_str());
1571 for(auto &item
: inputs
)
1572 data_file
<< stringf("%s",fst
->valueOf(item
.second
).c_str());
1573 for(auto &item
: outputs
)
1574 data_file
<< stringf("%s",fst
->valueOf(item
.second
).c_str());
1575 data_file
<< stringf("%s\n",Const(time
-prev_time
).as_string().c_str());
1577 if (time
==startCount
) {
1579 for(auto var
: fst
->getVars()) {
1580 if (var
.is_reg
&& !Const::from_string(fst
->valueOf(var
.id
).c_str()).is_fully_undef()) {
1581 if (var
.scope
== scope
) {
1582 initstate
<< stringf("\t\tuut.%s = %d'b%s;\n", var
.name
.c_str(), var
.width
, fst
->valueOf(var
.id
).c_str());
1583 } else if (var
.scope
.find(scope
+".")==0) {
1584 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());
1592 // Limit to number of cycles if provided
1593 if (cycles_set
&& cycle
> numcycles
*2)
1594 throw fst_end_of_data_exception();
1595 if (time
==stopCount
)
1596 throw fst_end_of_data_exception();
1598 } catch(fst_end_of_data_exception
) {
1599 // end of data detected
1602 f
<< stringf("\treg [0:%d] data [0:%d];\n", data_len
-1, cycle
-1);
1603 f
<< "\tinitial begin;\n";
1604 f
<< stringf("\t\t$dumpfile(\"%s\");\n",tb_filename
.c_str());
1605 f
<< stringf("\t\t$dumpvars(0,%s);\n",tb_filename
.c_str());
1606 f
<< initstate
.str();
1607 f
<< stringf("\t\t$readmemb(\"%s.txt\", data);\n",tb_filename
.c_str());
1609 f
<< stringf("\t\t#(data[0][%d:%d]);\n", data_len
-32, data_len
-1);
1610 f
<< stringf("\t\t{%s } = data[0][%d:%d];\n", signal_list(clocks
).c_str(), 0, clk_len
-1);
1611 f
<< stringf("\t\t{%s } <= data[0][%d:%d];\n", signal_list(inputs
).c_str(), clk_len
, clk_len
+inputs_len
-1);
1613 f
<< stringf("\t\tfor (i = 1; i < %d; i++) begin\n",cycle
);
1615 f
<< stringf("\t\t\t#(data[i][%d:%d]);\n", data_len
-32, data_len
-1);
1616 f
<< stringf("\t\t\t{%s } = data[i][%d:%d];\n", signal_list(clocks
).c_str(), 0, clk_len
-1);
1617 f
<< stringf("\t\t\t{%s } <= data[i][%d:%d];\n", signal_list(inputs
).c_str(), clk_len
, clk_len
+inputs_len
-1);
1619 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);
1620 f
<< "\t\t\t\t$error(\"Signal difference detected\\n\");\n";
1625 f
<< "\t\t$finish;\n";
1629 log("Writing testbench to `%s`\n", (tb_filename
+".v").c_str());
1630 std::ofstream
tb_file(tb_filename
+".v");
1637 struct VCDWriter
: public OutputWriter
1639 VCDWriter(SimWorker
*worker
, std::string filename
) : OutputWriter(worker
) {
1640 vcdfile
.open(filename
.c_str());
1643 void write(std::map
<int, bool> &use_signal
) override
1645 if (!vcdfile
.is_open()) return;
1646 vcdfile
<< stringf("$version %s $end\n", worker
->date
? yosys_version_str
: "Yosys");
1649 std::time_t t
= std::time(nullptr);
1651 if (std::strftime(mbstr
, sizeof(mbstr
), "%c", std::localtime(&t
))) {
1652 vcdfile
<< stringf("$date ") << mbstr
<< stringf(" $end\n");
1656 if (!worker
->timescale
.empty())
1657 vcdfile
<< stringf("$timescale %s $end\n", worker
->timescale
.c_str());
1659 worker
->top
->write_output_header(
1660 [this](IdString name
) { vcdfile
<< stringf("$scope module %s $end\n", log_id(name
)); },
1661 [this]() { vcdfile
<< stringf("$upscope $end\n");},
1662 [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
)); }
1665 vcdfile
<< stringf("$enddefinitions $end\n");
1667 for(auto& d
: worker
->output_data
)
1669 vcdfile
<< stringf("#%d\n", d
.first
);
1670 for (auto &data
: d
.second
)
1672 if (!use_signal
.at(data
.first
)) continue;
1673 Const value
= data
.second
;
1675 for (int i
= GetSize(value
)-1; i
>= 0; i
--) {
1677 case State::S0
: vcdfile
<< "0"; break;
1678 case State::S1
: vcdfile
<< "1"; break;
1679 case State::Sx
: vcdfile
<< "x"; break;
1680 default: vcdfile
<< "z";
1683 vcdfile
<< stringf(" n%d\n", data
.first
);
1688 std::ofstream vcdfile
;
1691 struct FSTWriter
: public OutputWriter
1693 FSTWriter(SimWorker
*worker
, std::string filename
) : OutputWriter(worker
) {
1694 fstfile
= (struct fstContext
*)fstWriterCreate(filename
.c_str(),1);
1697 virtual ~FSTWriter()
1699 fstWriterClose(fstfile
);
1702 void write(std::map
<int, bool> &use_signal
) override
1704 if (!fstfile
) return;
1705 std::time_t t
= std::time(nullptr);
1706 fstWriterSetVersion(fstfile
, worker
->date
? yosys_version_str
: "Yosys");
1708 fstWriterSetDate(fstfile
, asctime(std::localtime(&t
)));
1710 fstWriterSetDate(fstfile
, "");
1711 if (!worker
->timescale
.empty())
1712 fstWriterSetTimescaleFromString(fstfile
, worker
->timescale
.c_str());
1714 fstWriterSetPackType(fstfile
, FST_WR_PT_FASTLZ
);
1715 fstWriterSetRepackOnClose(fstfile
, 1);
1717 worker
->top
->write_output_header(
1718 [this](IdString name
) { fstWriterSetScope(fstfile
, FST_ST_VCD_MODULE
, stringf("%s",log_id(name
)).c_str(), nullptr); },
1719 [this]() { fstWriterSetUpscope(fstfile
); },
1720 [this,use_signal
](Wire
*wire
, int id
, bool is_reg
) {
1721 if (!use_signal
.at(id
)) return;
1722 fstHandle fst_id
= fstWriterCreateVar(fstfile
, is_reg
? FST_VT_VCD_REG
: FST_VT_VCD_WIRE
, FST_VD_IMPLICIT
, GetSize(wire
),
1723 stringf("%s%s", wire
->name
[0] == '$' ? "\\" : "", log_id(wire
)).c_str(), 0);
1725 mapping
.emplace(id
, fst_id
);
1729 for(auto& d
: worker
->output_data
)
1731 fstWriterEmitTimeChange(fstfile
, d
.first
);
1732 for (auto &data
: d
.second
)
1734 if (!use_signal
.at(data
.first
)) continue;
1735 Const value
= data
.second
;
1736 std::stringstream ss
;
1737 for (int i
= GetSize(value
)-1; i
>= 0; i
--) {
1739 case State::S0
: ss
<< "0"; break;
1740 case State::S1
: ss
<< "1"; break;
1741 case State::Sx
: ss
<< "x"; break;
1745 fstWriterEmitValueChange(fstfile
, mapping
[data
.first
], ss
.str().c_str());
1750 struct fstContext
*fstfile
= nullptr;
1751 std::map
<int,fstHandle
> mapping
;
1754 struct AIWWriter
: public OutputWriter
1756 AIWWriter(SimWorker
*worker
, std::string filename
) : OutputWriter(worker
) {
1757 aiwfile
.open(filename
.c_str());
1760 virtual ~AIWWriter()
1762 aiwfile
<< '.' << '\n';
1765 void write(std::map
<int, bool> &) override
1767 if (!aiwfile
.is_open()) return;
1768 if (worker
->map_filename
.empty())
1769 log_cmd_error("For AIGER witness file map parameter is mandatory.\n");
1771 std::ifstream
mf(worker
->map_filename
);
1772 std::string type
, symbol
;
1773 int variable
, index
;
1775 log_cmd_error("Not able to read AIGER witness map file.\n");
1776 while (mf
>> type
>> variable
>> index
>> symbol
) {
1777 RTLIL::IdString escaped_s
= RTLIL::escape_id(symbol
);
1778 Wire
*w
= worker
->top
->module
->wire(escaped_s
);
1780 log_error("Wire %s not present in module %s\n",log_id(escaped_s
),log_id(worker
->top
->module
));
1781 if (index
< w
->start_offset
|| index
> w
->start_offset
+ w
->width
)
1782 log_error("Index %d for wire %s is out of range\n", index
, log_signal(w
));
1783 if (type
== "input") {
1784 aiw_inputs
[variable
] = SigBit(w
,index
-w
->start_offset
);
1785 if (worker
->clock
.count(escaped_s
)) {
1786 clocks
[variable
] = true;
1788 if (worker
->clockn
.count(escaped_s
)) {
1789 clocks
[variable
] = false;
1791 } else if (type
== "init") {
1792 aiw_inits
[variable
] = SigBit(w
,index
-w
->start_offset
);
1793 } else if (type
== "latch") {
1794 aiw_latches
[variable
] = {SigBit(w
,index
-w
->start_offset
), false};
1795 } else if (type
== "invlatch") {
1796 aiw_latches
[variable
] = {SigBit(w
,index
-w
->start_offset
), true};
1800 worker
->top
->write_output_header(
1803 [this](Wire
*wire
, int id
, bool) { mapping
[wire
] = id
; }
1806 std::map
<int, Yosys::RTLIL::Const
> current
;
1808 for(auto& d
: worker
->output_data
)
1810 for (auto &data
: d
.second
)
1812 current
[data
.first
] = data
.second
;
1815 for (int i
= 0;; i
++)
1817 if (aiw_latches
.count(i
)) {
1818 SigBit bit
= aiw_latches
.at(i
).first
;
1819 auto v
= current
[mapping
[bit
.wire
]].bits
.at(bit
.offset
);
1821 aiwfile
<< (aiw_latches
.at(i
).second
? '0' : '1');
1823 aiwfile
<< (aiw_latches
.at(i
).second
? '1' : '0');
1833 for (auto it
: clocks
)
1835 auto val
= it
.second
? State::S1
: State::S0
;
1836 SigBit bit
= aiw_inputs
.at(it
.first
);
1837 auto v
= current
[mapping
[bit
.wire
]].bits
.at(bit
.offset
);
1843 for (int i
= 0;; i
++)
1845 if (aiw_inputs
.count(i
)) {
1846 SigBit bit
= aiw_inputs
.at(i
);
1847 auto v
= current
[mapping
[bit
.wire
]].bits
.at(bit
.offset
);
1854 if (aiw_inits
.count(i
)) {
1855 SigBit bit
= aiw_inits
.at(i
);
1856 auto v
= current
[mapping
[bit
.wire
]].bits
.at(bit
.offset
);
1869 std::ofstream aiwfile
;
1870 dict
<int, std::pair
<SigBit
, bool>> aiw_latches
;
1871 dict
<int, SigBit
> aiw_inputs
, aiw_inits
;
1872 dict
<int, bool> clocks
;
1873 std::map
<Wire
*,int> mapping
;
1876 struct SimPass
: public Pass
{
1877 SimPass() : Pass("sim", "simulate the circuit") { }
1878 void help() override
1880 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1882 log(" sim [options] [top-level]\n");
1884 log("This command simulates the circuit using the given top-level module.\n");
1886 log(" -vcd <filename>\n");
1887 log(" write the simulation results to the given VCD file\n");
1889 log(" -fst <filename>\n");
1890 log(" write the simulation results to the given FST file\n");
1892 log(" -aiw <filename>\n");
1893 log(" write the simulation results to an AIGER witness file\n");
1894 log(" (requires a *.aim file via -map)\n");
1897 log(" ignore constant x outputs in simulation file.\n");
1900 log(" include date and full version info in output.\n");
1902 log(" -clock <portname>\n");
1903 log(" name of top-level clock input\n");
1905 log(" -clockn <portname>\n");
1906 log(" name of top-level clock input (inverse polarity)\n");
1908 log(" -multiclock\n");
1909 log(" mark that witness file is multiclock.\n");
1911 log(" -reset <portname>\n");
1912 log(" name of top-level reset input (active high)\n");
1914 log(" -resetn <portname>\n");
1915 log(" name of top-level inverted reset input (active low)\n");
1917 log(" -rstlen <integer>\n");
1918 log(" number of cycles reset should stay active (default: 1)\n");
1921 log(" zero-initialize all uninitialized regs and memories\n");
1923 log(" -timescale <string>\n");
1924 log(" include the specified timescale declaration in the vcd\n");
1926 log(" -n <integer>\n");
1927 log(" number of clock cycles to simulate (default: 20)\n");
1930 log(" use all nets in VCD/FST operations, not just those with public names\n");
1933 log(" writeback mode: use final simulation state as new init state\n");
1936 log(" read simulation results file (file formats supported: FST, VCD, AIW and WIT)\n");
1937 log(" VCD support requires vcd2fst external tool to be present\n");
1939 log(" -map <filename>\n");
1940 log(" read file with port and latch symbols, needed for AIGER witness input\n");
1942 log(" -scope <name>\n");
1943 log(" scope of simulation top model\n");
1945 log(" -at <time>\n");
1946 log(" sets start and stop time\n");
1948 log(" -start <time>\n");
1949 log(" start co-simulation in arbitary time (default 0)\n");
1951 log(" -stop <time>\n");
1952 log(" stop co-simulation in arbitary time (default END)\n");
1955 log(" simulation with stimulus from FST (default)\n");
1958 log(" co-simulation expect exact match\n");
1960 log(" -sim-gold\n");
1961 log(" co-simulation, x in simulation can match any value in FST\n");
1963 log(" -sim-gate\n");
1964 log(" co-simulation, x in FST can match any value in simulation\n");
1967 log(" disable per-cycle/sample log message\n");
1970 log(" enable debug output\n");
1975 static std::string
file_base_name(std::string
const & path
)
1977 return path
.substr(path
.find_last_of("/\\") + 1);
1980 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) override
1984 bool start_set
= false, stop_set
= false, at_set
= false;
1986 log_header(design
, "Executing SIM pass (simulate the circuit).\n");
1989 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
1990 if (args
[argidx
] == "-vcd" && argidx
+1 < args
.size()) {
1991 std::string vcd_filename
= args
[++argidx
];
1992 rewrite_filename(vcd_filename
);
1993 worker
.outputfiles
.emplace_back(std::unique_ptr
<VCDWriter
>(new VCDWriter(&worker
, vcd_filename
.c_str())));
1996 if (args
[argidx
] == "-fst" && argidx
+1 < args
.size()) {
1997 std::string fst_filename
= args
[++argidx
];
1998 rewrite_filename(fst_filename
);
1999 worker
.outputfiles
.emplace_back(std::unique_ptr
<FSTWriter
>(new FSTWriter(&worker
, fst_filename
.c_str())));
2002 if (args
[argidx
] == "-aiw" && argidx
+1 < args
.size()) {
2003 std::string aiw_filename
= args
[++argidx
];
2004 rewrite_filename(aiw_filename
);
2005 worker
.outputfiles
.emplace_back(std::unique_ptr
<AIWWriter
>(new AIWWriter(&worker
, aiw_filename
.c_str())));
2008 if (args
[argidx
] == "-n" && argidx
+1 < args
.size()) {
2009 numcycles
= atoi(args
[++argidx
].c_str());
2010 worker
.cycles_set
= true;
2013 if (args
[argidx
] == "-rstlen" && argidx
+1 < args
.size()) {
2014 worker
.rstlen
= atoi(args
[++argidx
].c_str());
2017 if (args
[argidx
] == "-clock" && argidx
+1 < args
.size()) {
2018 worker
.clock
.insert(RTLIL::escape_id(args
[++argidx
]));
2021 if (args
[argidx
] == "-clockn" && argidx
+1 < args
.size()) {
2022 worker
.clockn
.insert(RTLIL::escape_id(args
[++argidx
]));
2025 if (args
[argidx
] == "-reset" && argidx
+1 < args
.size()) {
2026 worker
.reset
.insert(RTLIL::escape_id(args
[++argidx
]));
2029 if (args
[argidx
] == "-resetn" && argidx
+1 < args
.size()) {
2030 worker
.resetn
.insert(RTLIL::escape_id(args
[++argidx
]));
2033 if (args
[argidx
] == "-timescale" && argidx
+1 < args
.size()) {
2034 worker
.timescale
= args
[++argidx
];
2037 if (args
[argidx
] == "-a") {
2038 worker
.hide_internal
= false;
2041 if (args
[argidx
] == "-q") {
2042 worker
.verbose
= false;
2045 if (args
[argidx
] == "-d") {
2046 worker
.debug
= true;
2049 if (args
[argidx
] == "-w") {
2050 worker
.writeback
= true;
2053 if (args
[argidx
] == "-zinit") {
2054 worker
.zinit
= true;
2057 if (args
[argidx
] == "-r" && argidx
+1 < args
.size()) {
2058 std::string sim_filename
= args
[++argidx
];
2059 rewrite_filename(sim_filename
);
2060 worker
.sim_filename
= sim_filename
;
2063 if (args
[argidx
] == "-map" && argidx
+1 < args
.size()) {
2064 std::string map_filename
= args
[++argidx
];
2065 rewrite_filename(map_filename
);
2066 worker
.map_filename
= map_filename
;
2069 if (args
[argidx
] == "-scope" && argidx
+1 < args
.size()) {
2070 worker
.scope
= args
[++argidx
];
2073 if (args
[argidx
] == "-start" && argidx
+1 < args
.size()) {
2074 worker
.start_time
= stringToTime(args
[++argidx
]);
2078 if (args
[argidx
] == "-stop" && argidx
+1 < args
.size()) {
2079 worker
.stop_time
= stringToTime(args
[++argidx
]);
2083 if (args
[argidx
] == "-at" && argidx
+1 < args
.size()) {
2084 worker
.start_time
= stringToTime(args
[++argidx
]);
2085 worker
.stop_time
= worker
.start_time
;
2089 if (args
[argidx
] == "-sim") {
2090 worker
.sim_mode
= SimulationMode::sim
;
2093 if (args
[argidx
] == "-sim-cmp") {
2094 worker
.sim_mode
= SimulationMode::cmp
;
2097 if (args
[argidx
] == "-sim-gold") {
2098 worker
.sim_mode
= SimulationMode::gold
;
2101 if (args
[argidx
] == "-sim-gate") {
2102 worker
.sim_mode
= SimulationMode::gate
;
2105 if (args
[argidx
] == "-x") {
2106 worker
.ignore_x
= true;
2109 if (args
[argidx
] == "-date") {
2113 if (args
[argidx
] == "-multiclock") {
2114 worker
.multiclock
= true;
2119 extra_args(args
, argidx
, design
);
2120 if (at_set
&& (start_set
|| stop_set
|| worker
.cycles_set
))
2121 log_error("'at' option can only be defined separate of 'start','stop' and 'n'\n");
2122 if (stop_set
&& worker
.cycles_set
)
2123 log_error("'stop' and 'n' can only be used exclusively'\n");
2125 Module
*top_mod
= nullptr;
2127 if (design
->full_selection()) {
2128 top_mod
= design
->top_module();
2131 log_cmd_error("Design has no top module, use the 'hierarchy' command to specify one.\n");
2133 auto mods
= design
->selected_whole_modules();
2134 if (GetSize(mods
) != 1)
2135 log_cmd_error("Only one top module must be selected.\n");
2136 top_mod
= mods
.front();
2139 if (worker
.sim_filename
.empty())
2140 worker
.run(top_mod
, numcycles
);
2142 std::string filename_trim
= file_base_name(worker
.sim_filename
);
2143 if (filename_trim
.size() > 4 && ((filename_trim
.compare(filename_trim
.size()-4, std::string::npos
, ".fst") == 0) ||
2144 filename_trim
.compare(filename_trim
.size()-4, std::string::npos
, ".vcd") == 0)) {
2145 worker
.run_cosim_fst(top_mod
, numcycles
);
2146 } else if (filename_trim
.size() > 4 && filename_trim
.compare(filename_trim
.size()-4, std::string::npos
, ".aiw") == 0) {
2147 if (worker
.map_filename
.empty())
2148 log_cmd_error("For AIGER witness file map parameter is mandatory.\n");
2149 worker
.run_cosim_aiger_witness(top_mod
);
2150 } else if (filename_trim
.size() > 4 && filename_trim
.compare(filename_trim
.size()-4, std::string::npos
, ".wit") == 0) {
2151 worker
.run_cosim_btor2_witness(top_mod
);
2153 log_cmd_error("Unhandled extension for simulation input file `%s`.\n", worker
.sim_filename
.c_str());
2159 struct Fst2TbPass
: public Pass
{
2160 Fst2TbPass() : Pass("fst2tb", "generate testbench out of fst file") { }
2161 void help() override
2163 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
2165 log(" fst2tb [options] [top-level]\n");
2167 log("This command generates testbench for the circuit using the given top-level module\n");
2168 log("and simulus signal from FST file\n");
2170 log(" -tb <name>\n");
2171 log(" generated testbench name.\n");
2172 log(" files <name>.v and <name>.txt are created as result.\n");
2174 log(" -r <filename>\n");
2175 log(" read simulation FST file\n");
2177 log(" -clock <portname>\n");
2178 log(" name of top-level clock input\n");
2180 log(" -clockn <portname>\n");
2181 log(" name of top-level clock input (inverse polarity)\n");
2183 log(" -scope <name>\n");
2184 log(" scope of simulation top model\n");
2186 log(" -start <time>\n");
2187 log(" start co-simulation in arbitary time (default 0)\n");
2189 log(" -stop <time>\n");
2190 log(" stop co-simulation in arbitary time (default END)\n");
2192 log(" -n <integer>\n");
2193 log(" number of clock cycles to simulate (default: 20)\n");
2197 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) override
2201 bool stop_set
= false;
2202 std::string tb_filename
;
2204 log_header(design
, "Executing FST2FB pass.\n");
2207 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
2208 if (args
[argidx
] == "-clock" && argidx
+1 < args
.size()) {
2209 worker
.clock
.insert(RTLIL::escape_id(args
[++argidx
]));
2212 if (args
[argidx
] == "-clockn" && argidx
+1 < args
.size()) {
2213 worker
.clockn
.insert(RTLIL::escape_id(args
[++argidx
]));
2216 if (args
[argidx
] == "-r" && argidx
+1 < args
.size()) {
2217 std::string sim_filename
= args
[++argidx
];
2218 rewrite_filename(sim_filename
);
2219 worker
.sim_filename
= sim_filename
;
2222 if (args
[argidx
] == "-n" && argidx
+1 < args
.size()) {
2223 numcycles
= atoi(args
[++argidx
].c_str());
2224 worker
.cycles_set
= true;
2227 if (args
[argidx
] == "-scope" && argidx
+1 < args
.size()) {
2228 worker
.scope
= args
[++argidx
];
2231 if (args
[argidx
] == "-start" && argidx
+1 < args
.size()) {
2232 worker
.start_time
= stringToTime(args
[++argidx
]);
2235 if (args
[argidx
] == "-stop" && argidx
+1 < args
.size()) {
2236 worker
.stop_time
= stringToTime(args
[++argidx
]);
2240 if (args
[argidx
] == "-tb" && argidx
+1 < args
.size()) {
2241 tb_filename
= args
[++argidx
];
2246 extra_args(args
, argidx
, design
);
2247 if (stop_set
&& worker
.cycles_set
)
2248 log_error("'stop' and 'n' can only be used exclusively'\n");
2250 Module
*top_mod
= nullptr;
2252 if (design
->full_selection()) {
2253 top_mod
= design
->top_module();
2256 log_cmd_error("Design has no top module, use the 'hierarchy' command to specify one.\n");
2258 auto mods
= design
->selected_whole_modules();
2259 if (GetSize(mods
) != 1)
2260 log_cmd_error("Only one top module must be selected.\n");
2261 top_mod
= mods
.front();
2264 if (tb_filename
.empty())
2265 log_cmd_error("Testbench name must be defined.\n");
2267 if (worker
.sim_filename
.empty())
2268 log_cmd_error("Stimulus FST file must be defined.\n");
2270 worker
.generate_tb(top_mod
, tb_filename
, numcycles
);
2274 PRIVATE_NAMESPACE_END