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 addAdditionalInputs(std::map
<Wire
*,fstHandle
> &inputs
)
809 for (auto cell
: module
->cells())
811 if (cell
->type
.in(ID($anyseq
))) {
812 SigSpec sig_y
= cell
->getPort(ID::Y
);
813 if (sig_y
.is_wire()) {
814 Wire
*wire
= sig_y
.as_wire();
815 fstHandle id
= shared
->fst
->getHandle(scope
+ "." + RTLIL::unescape_id(wire
->name
));
817 log_error("Unable to find required '%s' signal in file\n",(scope
+ "." + RTLIL::unescape_id(wire
->name
)).c_str());
822 for (auto child
: children
)
823 child
.second
->addAdditionalInputs(inputs
);
826 void setState(dict
<int, std::pair
<SigBit
,bool>> bits
, std::string values
)
828 for(auto bit
: bits
) {
829 if (bit
.first
>= GetSize(values
))
830 log_error("Too few input data bits in file.\n");
831 switch(values
.at(bit
.first
)) {
832 case '0': set_state(bit
.second
.first
, bit
.second
.second
? State::S1
: State::S0
); break;
833 case '1': set_state(bit
.second
.first
, bit
.second
.second
? State::S0
: State::S1
); break;
834 default: set_state(bit
.second
.first
, State::Sx
); break;
839 void setMemState(dict
<int, std::pair
<std::string
,int>> bits
, std::string values
)
841 for(auto bit
: bits
) {
842 if (bit
.first
>= GetSize(values
))
843 log_error("Too few input data bits in file.\n");
844 switch(values
.at(bit
.first
)) {
845 case '0': set_memory_state_bit(bit
.second
.first
, bit
.second
.second
, State::S0
); break;
846 case '1': set_memory_state_bit(bit
.second
.first
, bit
.second
.second
, State::S1
); break;
847 default: set_memory_state_bit(bit
.second
.first
, bit
.second
.second
, State::Sx
); break;
855 for(auto &item
: fst_handles
) {
856 if (item
.second
==0) continue; // Ignore signals not found
857 Const fst_val
= Const::from_string(shared
->fst
->valueOf(item
.second
));
858 Const sim_val
= get_state(item
.first
);
859 if (sim_val
.size()!=fst_val
.size()) {
860 log_warning("Signal '%s.%s' size is different in gold and gate.\n", scope
.c_str(), log_id(item
.first
));
863 if (shared
->sim_mode
== SimulationMode::sim
) {
864 // No checks performed when using stimulus
865 } else if (shared
->sim_mode
== SimulationMode::gate
&& !fst_val
.is_fully_def()) { // FST data contains X
866 for(int i
=0;i
<fst_val
.size();i
++) {
867 if (fst_val
[i
]!=State::Sx
&& fst_val
[i
]!=sim_val
[i
]) {
868 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
));
873 } else if (shared
->sim_mode
== SimulationMode::gold
&& !sim_val
.is_fully_def()) { // sim data contains X
874 for(int i
=0;i
<sim_val
.size();i
++) {
875 if (sim_val
[i
]!=State::Sx
&& fst_val
[i
]!=sim_val
[i
]) {
876 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
));
882 if (fst_val
!=sim_val
) {
883 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
));
888 for (auto child
: children
)
889 retVal
|= child
.second
->checkSignals();
894 struct SimWorker
: SimShared
896 SimInstance
*top
= nullptr;
897 pool
<IdString
> clock
, clockn
, reset
, resetn
;
898 std::string timescale
;
899 std::string sim_filename
;
900 std::string map_filename
;
909 void register_signals()
912 top
->register_signals(id
);
915 void register_output_step(int t
)
917 std::map
<int,Const
> data
;
918 top
->register_output_step_values(&data
);
919 output_data
.emplace_back(t
, data
);
922 void write_output_files()
924 std::map
<int, bool> use_signal
;
925 bool first
= ignore_x
;
926 for(auto& d
: output_data
)
929 for (auto &data
: d
.second
)
930 use_signal
[data
.first
] = !data
.second
.is_fully_undef();
933 for (auto &data
: d
.second
)
934 use_signal
[data
.first
] = true;
936 if (!ignore_x
) break;
938 for(auto& writer
: outputfiles
)
939 writer
->write(use_signal
);
947 log("\n-- ph1 --\n");
952 log("\n-- ph2 --\n");
954 if (!top
->update_ph2())
959 log("\n-- ph3 --\n");
964 void set_inports(pool
<IdString
> ports
, State value
)
966 for (auto portname
: ports
)
968 Wire
*w
= top
->module
->wire(portname
);
971 log_error("Can't find port %s on module %s.\n", log_id(portname
), log_id(top
->module
));
973 top
->set_state(w
, value
);
977 void run(Module
*topmod
, int numcycles
)
979 log_assert(top
== nullptr);
980 top
= new SimInstance(this, scope
, topmod
);
984 log("\n===== 0 =====\n");
986 log("Simulating cycle 0.\n");
988 set_inports(reset
, State::S1
);
989 set_inports(resetn
, State::S0
);
991 set_inports(clock
, State::Sx
);
992 set_inports(clockn
, State::Sx
);
996 register_output_step(0);
998 for (int cycle
= 0; cycle
< numcycles
; cycle
++)
1001 log("\n===== %d =====\n", 10*cycle
+ 5);
1003 log("Simulating cycle %d.\n", (cycle
*2)+1);
1004 set_inports(clock
, State::S0
);
1005 set_inports(clockn
, State::S1
);
1008 register_output_step(10*cycle
+ 5);
1011 log("\n===== %d =====\n", 10*cycle
+ 10);
1013 log("Simulating cycle %d.\n", (cycle
*2)+2);
1015 set_inports(clock
, State::S1
);
1016 set_inports(clockn
, State::S0
);
1018 if (cycle
+1 == rstlen
) {
1019 set_inports(reset
, State::S0
);
1020 set_inports(resetn
, State::S1
);
1024 register_output_step(10*cycle
+ 10);
1027 register_output_step(10*numcycles
+ 2);
1029 write_output_files();
1032 pool
<Module
*> wbmods
;
1033 top
->writeback(wbmods
);
1037 void run_cosim_fst(Module
*topmod
, int numcycles
)
1039 log_assert(top
== nullptr);
1040 fst
= new FstData(sim_filename
);
1043 log_error("Scope must be defined for co-simulation.\n");
1045 top
= new SimInstance(this, scope
, topmod
);
1048 std::vector
<fstHandle
> fst_clock
;
1050 for (auto portname
: clock
)
1052 Wire
*w
= topmod
->wire(portname
);
1054 log_error("Can't find port %s on module %s.\n", log_id(portname
), log_id(top
->module
));
1056 log_error("Clock port %s on module %s is not input.\n", log_id(portname
), log_id(top
->module
));
1057 fstHandle id
= fst
->getHandle(scope
+ "." + RTLIL::unescape_id(portname
));
1059 log_error("Can't find port %s.%s in FST.\n", scope
.c_str(), log_id(portname
));
1060 fst_clock
.push_back(id
);
1062 for (auto portname
: clockn
)
1064 Wire
*w
= topmod
->wire(portname
);
1066 log_error("Can't find port %s on module %s.\n", log_id(portname
), log_id(top
->module
));
1068 log_error("Clock port %s on module %s is not input.\n", log_id(portname
), log_id(top
->module
));
1069 fstHandle id
= fst
->getHandle(scope
+ "." + RTLIL::unescape_id(portname
));
1071 log_error("Can't find port %s.%s in FST.\n", scope
.c_str(), log_id(portname
));
1072 fst_clock
.push_back(id
);
1075 SigMap
sigmap(topmod
);
1076 std::map
<Wire
*,fstHandle
> inputs
;
1078 for (auto wire
: topmod
->wires()) {
1079 if (wire
->port_input
) {
1080 fstHandle id
= fst
->getHandle(scope
+ "." + RTLIL::unescape_id(wire
->name
));
1082 log_error("Unable to find required '%s' signal in file\n",(scope
+ "." + RTLIL::unescape_id(wire
->name
)).c_str());
1087 top
->addAdditionalInputs(inputs
);
1089 uint64_t startCount
= 0;
1090 uint64_t stopCount
= 0;
1091 if (start_time
==0) {
1092 if (start_time
< fst
->getStartTime())
1093 log_warning("Start time is before simulation file start time\n");
1094 startCount
= fst
->getStartTime();
1095 } else if (start_time
==-1)
1096 startCount
= fst
->getEndTime();
1098 startCount
= start_time
/ fst
->getTimescale();
1099 if (startCount
> fst
->getEndTime()) {
1100 startCount
= fst
->getEndTime();
1101 log_warning("Start time is after simulation file end time\n");
1105 if (stop_time
< fst
->getStartTime())
1106 log_warning("Stop time is before simulation file start time\n");
1107 stopCount
= fst
->getStartTime();
1108 } else if (stop_time
==-1)
1109 stopCount
= fst
->getEndTime();
1111 stopCount
= stop_time
/ fst
->getTimescale();
1112 if (stopCount
> fst
->getEndTime()) {
1113 stopCount
= fst
->getEndTime();
1114 log_warning("Stop time is after simulation file end time\n");
1117 if (stopCount
<startCount
) {
1118 log_error("Stop time is before start time\n");
1121 bool initial
= true;
1123 log("Co-simulation from %lu%s to %lu%s", (unsigned long)startCount
, fst
->getTimescaleString(), (unsigned long)stopCount
, fst
->getTimescaleString());
1125 log(" for %d clock cycle(s)",numcycles
);
1127 bool all_samples
= fst_clock
.empty();
1130 fst
->reconstructAllAtTimes(fst_clock
, startCount
, stopCount
, [&](uint64_t time
) {
1132 log("Co-simulating %s %d [%lu%s].\n", (all_samples
? "sample" : "cycle"), cycle
, (unsigned long)time
, fst
->getTimescaleString());
1133 bool did_something
= false;
1134 for(auto &item
: inputs
) {
1135 std::string v
= fst
->valueOf(item
.second
);
1136 did_something
|= top
->set_state(item
.first
, Const::from_string(v
));
1140 did_something
|= top
->setInitState();
1145 register_output_step(time
);
1147 bool status
= top
->checkSignals();
1149 log_error("Signal difference\n");
1152 // Limit to number of cycles if provided
1153 if (cycles_set
&& cycle
> numcycles
*2)
1154 throw fst_end_of_data_exception();
1155 if (time
==stopCount
)
1156 throw fst_end_of_data_exception();
1158 } catch(fst_end_of_data_exception
) {
1159 // end of data detected
1162 write_output_files();
1165 pool
<Module
*> wbmods
;
1166 top
->writeback(wbmods
);
1171 std::string
cell_name(std::string
const & name
)
1173 size_t pos
= name
.find_last_of("[");
1174 if (pos
!=std::string::npos
)
1175 return name
.substr(0, pos
);
1179 int mem_cell_addr(std::string
const & name
)
1181 size_t pos
= name
.find_last_of("[");
1182 return atoi(name
.substr(pos
+1).c_str());
1185 void run_cosim_aiger_witness(Module
*topmod
)
1187 log_assert(top
== nullptr);
1188 if (!multiclock
&& (clock
.size()+clockn
.size())==0)
1189 log_error("Clock signal must be specified.\n");
1190 if (multiclock
&& (clock
.size()+clockn
.size())>0)
1191 log_error("For multiclock witness there should be no clock signal.\n");
1193 top
= new SimInstance(this, scope
, topmod
);
1196 std::ifstream
mf(map_filename
);
1197 std::string type
, symbol
;
1198 int variable
, index
;
1199 dict
<int, std::pair
<SigBit
,bool>> inputs
, inits
, latches
;
1200 dict
<int, std::pair
<std::string
,int>> mem_inits
, mem_latches
;
1202 log_cmd_error("Not able to read AIGER witness map file.\n");
1203 while (mf
>> type
>> variable
>> index
>> symbol
) {
1204 RTLIL::IdString escaped_s
= RTLIL::escape_id(symbol
);
1205 Wire
*w
= topmod
->wire(escaped_s
);
1207 escaped_s
= RTLIL::escape_id(cell_name(symbol
));
1208 Cell
*c
= topmod
->cell(escaped_s
);
1210 log_warning("Wire/cell %s not present in module %s\n",symbol
.c_str(),log_id(topmod
));
1212 if (c
->is_mem_cell()) {
1213 std::string memid
= c
->parameters
.at(ID::MEMID
).decode_string();
1214 auto &state
= top
->mem_database
[memid
];
1216 int offset
= (mem_cell_addr(symbol
) - state
.mem
->start_offset
) * state
.mem
->width
+ index
;
1218 mem_inits
[variable
] = { memid
, offset
};
1219 else if (type
== "latch")
1220 mem_latches
[variable
] = { memid
, offset
};
1222 log_error("Map file addressing cell %s as type %s\n", symbol
.c_str(), type
.c_str());
1224 log_error("Cell %s in map file is not memory cell\n", symbol
.c_str());
1227 if (index
< w
->start_offset
|| index
> w
->start_offset
+ w
->width
)
1228 log_error("Index %d for wire %s is out of range\n", index
, log_signal(w
));
1229 if (type
== "input") {
1230 inputs
[variable
] = {SigBit(w
,index
-w
->start_offset
), false};
1231 } else if (type
== "init") {
1232 inits
[variable
] = {SigBit(w
,index
-w
->start_offset
), false};
1233 } else if (type
== "latch") {
1234 latches
[variable
] = {SigBit(w
,index
-w
->start_offset
), false};
1235 } else if (type
== "invlatch") {
1236 latches
[variable
] = {SigBit(w
,index
-w
->start_offset
), true};
1242 f
.open(sim_filename
.c_str());
1243 if (f
.fail() || GetSize(sim_filename
) == 0)
1244 log_error("Can not open file `%s`\n", sim_filename
.c_str());
1253 std::getline(f
, line
);
1254 if (line
.size()==0 || line
[0]=='#' || line
[0]=='c' || line
[0]=='f' || line
[0]=='u') continue;
1255 if (line
[0]=='.') break;
1256 if (state
==0 && line
.size()!=1) {
1257 // old format detected, latch data
1260 if (state
==1 && line
[0]!='b' && line
[0]!='j') {
1261 // was old format but with 1 bit latch
1262 top
->setState(latches
, status
);
1276 top
->setState(latches
, line
);
1277 top
->setMemState(mem_latches
, line
);
1282 log("Simulating cycle %d.\n", cycle
);
1283 top
->setState(inputs
, line
);
1285 set_inports(clock
, State::S1
);
1286 set_inports(clockn
, State::S0
);
1288 top
->setState(inits
, line
);
1289 top
->setMemState(mem_inits
, line
);
1290 set_inports(clock
, State::S0
);
1291 set_inports(clockn
, State::S1
);
1294 register_output_step(10*cycle
);
1295 if (!multiclock
&& cycle
) {
1296 set_inports(clock
, State::S0
);
1297 set_inports(clockn
, State::S1
);
1299 register_output_step(10*cycle
+ 5);
1305 register_output_step(10*cycle
);
1306 write_output_files();
1309 std::vector
<std::string
> split(std::string text
, const char *delim
)
1311 std::vector
<std::string
> list
;
1312 char *p
= strdup(text
.c_str());
1313 char *t
= strtok(p
, delim
);
1316 t
= strtok(NULL
, delim
);
1322 std::string
signal_name(std::string
const & name
)
1324 size_t pos
= name
.find_first_of("@");
1325 if (pos
==std::string::npos
) {
1326 pos
= name
.find_first_of("#");
1327 if (pos
==std::string::npos
)
1328 log_error("Line does not contain proper signal name `%s`\n", name
.c_str());
1330 return name
.substr(0, pos
);
1333 void run_cosim_btor2_witness(Module
*topmod
)
1335 log_assert(top
== nullptr);
1336 if (!multiclock
&& (clock
.size()+clockn
.size())==0)
1337 log_error("Clock signal must be specified.\n");
1338 if (multiclock
&& (clock
.size()+clockn
.size())>0)
1339 log_error("For multiclock witness there should be no clock signal.\n");
1341 f
.open(sim_filename
.c_str());
1342 if (f
.fail() || GetSize(sim_filename
) == 0)
1343 log_error("Can not open file `%s`\n", sim_filename
.c_str());
1347 top
= new SimInstance(this, scope
, topmod
);
1351 std::vector
<std::string
> parts
;
1356 std::getline(f
, line
);
1357 if (line
.size()==0) continue;
1359 if (line
[0]=='#' || line
[0]=='@' || line
[0]=='.') {
1361 curr_cycle
= atoi(line
.c_str()+1);
1363 curr_cycle
= -1; // force detect change
1365 if (curr_cycle
!= prev_cycle
) {
1367 log("Simulating cycle %d.\n", cycle
);
1368 set_inports(clock
, State::S1
);
1369 set_inports(clockn
, State::S0
);
1371 register_output_step(10*cycle
+0);
1373 set_inports(clock
, State::S0
);
1374 set_inports(clockn
, State::S1
);
1376 register_output_step(10*cycle
+5);
1379 prev_cycle
= curr_cycle
;
1381 if (line
[0]=='.') break;
1392 if (line
[0]=='b' || line
[0]=='j')
1395 log_error("Line does not contain property.\n");
1397 default: // set state or inputs
1398 parts
= split(line
, " ");
1401 log_error("Invalid set state line content.\n");
1403 RTLIL::IdString escaped_s
= RTLIL::escape_id(signal_name(parts
[len
-1]));
1405 Wire
*w
= topmod
->wire(escaped_s
);
1407 Cell
*c
= topmod
->cell(escaped_s
);
1409 log_warning("Wire/cell %s not present in module %s\n",log_id(escaped_s
),log_id(topmod
));
1410 else if (c
->type
.in(ID($anyconst
), ID($anyseq
))) {
1411 SigSpec sig_y
= c
->getPort(ID::Y
);
1412 if ((int)parts
[1].size() != GetSize(sig_y
))
1413 log_error("Size of wire %s is different than provided data.\n", log_signal(sig_y
));
1414 top
->set_state(sig_y
, Const::from_string(parts
[1]));
1417 if ((int)parts
[1].size() != w
->width
)
1418 log_error("Size of wire %s is different than provided data.\n", log_signal(w
));
1419 top
->set_state(w
, Const::from_string(parts
[1]));
1422 Cell
*c
= topmod
->cell(escaped_s
);
1424 log_error("Cell %s not present in module %s\n",log_id(escaped_s
),log_id(topmod
));
1425 if (!c
->is_mem_cell())
1426 log_error("Cell %s is not memory cell in module %s\n",log_id(escaped_s
),log_id(topmod
));
1428 Const addr
= Const::from_string(parts
[1].substr(1,parts
[1].size()-2));
1429 Const data
= Const::from_string(parts
[2]);
1430 top
->set_memory_state(c
->parameters
.at(ID::MEMID
).decode_string(), addr
, data
);
1435 register_output_step(10*cycle
);
1436 write_output_files();
1439 std::string
define_signal(Wire
*wire
)
1441 std::stringstream f
;
1444 f
<< stringf("%s", RTLIL::unescape_id(wire
->name
).c_str());
1447 f
<< stringf("[%d:%d] %s", wire
->start_offset
, wire
->width
- 1 + wire
->start_offset
, RTLIL::unescape_id(wire
->name
).c_str());
1449 f
<< stringf("[%d:%d] %s", wire
->width
- 1 + wire
->start_offset
, wire
->start_offset
, RTLIL::unescape_id(wire
->name
).c_str());
1453 std::string
signal_list(std::map
<Wire
*,fstHandle
> &signals
)
1455 std::stringstream f
;
1456 for(auto item
=signals
.begin();item
!=signals
.end();item
++)
1457 f
<< stringf("%c%s", (item
==signals
.begin() ? ' ' : ','), RTLIL::unescape_id(item
->first
->name
).c_str());
1461 void generate_tb(Module
*topmod
, std::string tb_filename
, int numcycles
)
1463 fst
= new FstData(sim_filename
);
1466 log_error("Scope must be defined for co-simulation.\n");
1468 if ((clock
.size()+clockn
.size())==0)
1469 log_error("Clock signal must be specified.\n");
1471 std::vector
<fstHandle
> fst_clock
;
1472 std::map
<Wire
*,fstHandle
> clocks
;
1474 for (auto portname
: clock
)
1476 Wire
*w
= topmod
->wire(portname
);
1478 log_error("Can't find port %s on module %s.\n", log_id(portname
), log_id(top
->module
));
1480 log_error("Clock port %s on module %s is not input.\n", log_id(portname
), log_id(top
->module
));
1481 fstHandle id
= fst
->getHandle(scope
+ "." + RTLIL::unescape_id(portname
));
1483 log_error("Can't find port %s.%s in FST.\n", scope
.c_str(), log_id(portname
));
1484 fst_clock
.push_back(id
);
1487 for (auto portname
: clockn
)
1489 Wire
*w
= topmod
->wire(portname
);
1491 log_error("Can't find port %s on module %s.\n", log_id(portname
), log_id(top
->module
));
1493 log_error("Clock port %s on module %s is not input.\n", log_id(portname
), log_id(top
->module
));
1494 fstHandle id
= fst
->getHandle(scope
+ "." + RTLIL::unescape_id(portname
));
1496 log_error("Can't find port %s.%s in FST.\n", scope
.c_str(), log_id(portname
));
1497 fst_clock
.push_back(id
);
1501 SigMap
sigmap(topmod
);
1502 std::map
<Wire
*,fstHandle
> inputs
;
1503 std::map
<Wire
*,fstHandle
> outputs
;
1505 for (auto wire
: topmod
->wires()) {
1506 fstHandle id
= fst
->getHandle(scope
+ "." + RTLIL::unescape_id(wire
->name
));
1507 if (id
==0 && (wire
->port_input
|| wire
->port_output
))
1508 log_error("Unable to find required '%s' signal in file\n",(scope
+ "." + RTLIL::unescape_id(wire
->name
)).c_str());
1509 if (wire
->port_input
)
1510 if (clocks
.find(wire
)==clocks
.end())
1512 if (wire
->port_output
)
1516 uint64_t startCount
= 0;
1517 uint64_t stopCount
= 0;
1518 if (start_time
==0) {
1519 if (start_time
< fst
->getStartTime())
1520 log_warning("Start time is before simulation file start time\n");
1521 startCount
= fst
->getStartTime();
1522 } else if (start_time
==-1)
1523 startCount
= fst
->getEndTime();
1525 startCount
= start_time
/ fst
->getTimescale();
1526 if (startCount
> fst
->getEndTime()) {
1527 startCount
= fst
->getEndTime();
1528 log_warning("Start time is after simulation file end time\n");
1532 if (stop_time
< fst
->getStartTime())
1533 log_warning("Stop time is before simulation file start time\n");
1534 stopCount
= fst
->getStartTime();
1535 } else if (stop_time
==-1)
1536 stopCount
= fst
->getEndTime();
1538 stopCount
= stop_time
/ fst
->getTimescale();
1539 if (stopCount
> fst
->getEndTime()) {
1540 stopCount
= fst
->getEndTime();
1541 log_warning("Stop time is after simulation file end time\n");
1544 if (stopCount
<startCount
) {
1545 log_error("Stop time is before start time\n");
1549 log("Generate testbench data from %lu%s to %lu%s", (unsigned long)startCount
, fst
->getTimescaleString(), (unsigned long)stopCount
, fst
->getTimescaleString());
1551 log(" for %d clock cycle(s)",numcycles
);
1554 std::stringstream f
;
1555 f
<< stringf("`timescale 1%s/1%s\n", fst
->getTimescaleString(),fst
->getTimescaleString());
1556 f
<< stringf("module %s();\n",tb_filename
.c_str());
1559 int outputs_len
= 0;
1560 for(auto &item
: clocks
) {
1561 clk_len
+= item
.first
->width
;
1562 f
<< "\treg " << define_signal(item
.first
) << ";\n";
1564 for(auto &item
: inputs
) {
1565 inputs_len
+= item
.first
->width
;
1566 f
<< "\treg " << define_signal(item
.first
) << ";\n";
1568 for(auto &item
: outputs
) {
1569 outputs_len
+= item
.first
->width
;
1570 f
<< "\twire " << define_signal(item
.first
) << ";\n";
1572 int data_len
= clk_len
+ inputs_len
+ outputs_len
+ 32;
1574 f
<< stringf("\t%s uut(",RTLIL::unescape_id(topmod
->name
).c_str());
1575 for(auto item
=clocks
.begin();item
!=clocks
.end();item
++)
1576 f
<< stringf("%c.%s(%s)", (item
==clocks
.begin() ? ' ' : ','), RTLIL::unescape_id(item
->first
->name
).c_str(), RTLIL::unescape_id(item
->first
->name
).c_str());
1577 for(auto &item
: inputs
)
1578 f
<< stringf(",.%s(%s)", RTLIL::unescape_id(item
.first
->name
).c_str(), RTLIL::unescape_id(item
.first
->name
).c_str());
1579 for(auto &item
: outputs
)
1580 f
<< stringf(",.%s(%s)", RTLIL::unescape_id(item
.first
->name
).c_str(), RTLIL::unescape_id(item
.first
->name
).c_str());
1583 f
<< "\tinteger i;\n";
1584 uint64_t prev_time
= startCount
;
1585 log("Writing data to `%s`\n", (tb_filename
+".txt").c_str());
1586 std::ofstream
data_file(tb_filename
+".txt");
1587 std::stringstream initstate
;
1589 fst
->reconstructAllAtTimes(fst_clock
, startCount
, stopCount
, [&](uint64_t time
) {
1590 for(auto &item
: clocks
)
1591 data_file
<< stringf("%s",fst
->valueOf(item
.second
).c_str());
1592 for(auto &item
: inputs
)
1593 data_file
<< stringf("%s",fst
->valueOf(item
.second
).c_str());
1594 for(auto &item
: outputs
)
1595 data_file
<< stringf("%s",fst
->valueOf(item
.second
).c_str());
1596 data_file
<< stringf("%s\n",Const(time
-prev_time
).as_string().c_str());
1598 if (time
==startCount
) {
1600 for(auto var
: fst
->getVars()) {
1601 if (var
.is_reg
&& !Const::from_string(fst
->valueOf(var
.id
).c_str()).is_fully_undef()) {
1602 if (var
.scope
== scope
) {
1603 initstate
<< stringf("\t\tuut.%s = %d'b%s;\n", var
.name
.c_str(), var
.width
, fst
->valueOf(var
.id
).c_str());
1604 } else if (var
.scope
.find(scope
+".")==0) {
1605 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());
1613 // Limit to number of cycles if provided
1614 if (cycles_set
&& cycle
> numcycles
*2)
1615 throw fst_end_of_data_exception();
1616 if (time
==stopCount
)
1617 throw fst_end_of_data_exception();
1619 } catch(fst_end_of_data_exception
) {
1620 // end of data detected
1623 f
<< stringf("\treg [0:%d] data [0:%d];\n", data_len
-1, cycle
-1);
1624 f
<< "\tinitial begin;\n";
1625 f
<< stringf("\t\t$dumpfile(\"%s\");\n",tb_filename
.c_str());
1626 f
<< stringf("\t\t$dumpvars(0,%s);\n",tb_filename
.c_str());
1627 f
<< initstate
.str();
1628 f
<< stringf("\t\t$readmemb(\"%s.txt\", data);\n",tb_filename
.c_str());
1630 f
<< stringf("\t\t#(data[0][%d:%d]);\n", data_len
-32, data_len
-1);
1631 f
<< stringf("\t\t{%s } = data[0][%d:%d];\n", signal_list(clocks
).c_str(), 0, clk_len
-1);
1632 f
<< stringf("\t\t{%s } <= data[0][%d:%d];\n", signal_list(inputs
).c_str(), clk_len
, clk_len
+inputs_len
-1);
1634 f
<< stringf("\t\tfor (i = 1; i < %d; i++) begin\n",cycle
);
1636 f
<< stringf("\t\t\t#(data[i][%d:%d]);\n", data_len
-32, data_len
-1);
1637 f
<< stringf("\t\t\t{%s } = data[i][%d:%d];\n", signal_list(clocks
).c_str(), 0, clk_len
-1);
1638 f
<< stringf("\t\t\t{%s } <= data[i][%d:%d];\n", signal_list(inputs
).c_str(), clk_len
, clk_len
+inputs_len
-1);
1640 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);
1641 f
<< "\t\t\t\t$error(\"Signal difference detected\\n\");\n";
1646 f
<< "\t\t$finish;\n";
1650 log("Writing testbench to `%s`\n", (tb_filename
+".v").c_str());
1651 std::ofstream
tb_file(tb_filename
+".v");
1658 struct VCDWriter
: public OutputWriter
1660 VCDWriter(SimWorker
*worker
, std::string filename
) : OutputWriter(worker
) {
1661 vcdfile
.open(filename
.c_str());
1664 void write(std::map
<int, bool> &use_signal
) override
1666 if (!vcdfile
.is_open()) return;
1667 vcdfile
<< stringf("$version %s $end\n", worker
->date
? yosys_version_str
: "Yosys");
1670 std::time_t t
= std::time(nullptr);
1672 if (std::strftime(mbstr
, sizeof(mbstr
), "%c", std::localtime(&t
))) {
1673 vcdfile
<< stringf("$date ") << mbstr
<< stringf(" $end\n");
1677 if (!worker
->timescale
.empty())
1678 vcdfile
<< stringf("$timescale %s $end\n", worker
->timescale
.c_str());
1680 worker
->top
->write_output_header(
1681 [this](IdString name
) { vcdfile
<< stringf("$scope module %s $end\n", log_id(name
)); },
1682 [this]() { vcdfile
<< stringf("$upscope $end\n");},
1683 [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
)); }
1686 vcdfile
<< stringf("$enddefinitions $end\n");
1688 for(auto& d
: worker
->output_data
)
1690 vcdfile
<< stringf("#%d\n", d
.first
);
1691 for (auto &data
: d
.second
)
1693 if (!use_signal
.at(data
.first
)) continue;
1694 Const value
= data
.second
;
1696 for (int i
= GetSize(value
)-1; i
>= 0; i
--) {
1698 case State::S0
: vcdfile
<< "0"; break;
1699 case State::S1
: vcdfile
<< "1"; break;
1700 case State::Sx
: vcdfile
<< "x"; break;
1701 default: vcdfile
<< "z";
1704 vcdfile
<< stringf(" n%d\n", data
.first
);
1709 std::ofstream vcdfile
;
1712 struct FSTWriter
: public OutputWriter
1714 FSTWriter(SimWorker
*worker
, std::string filename
) : OutputWriter(worker
) {
1715 fstfile
= (struct fstContext
*)fstWriterCreate(filename
.c_str(),1);
1718 virtual ~FSTWriter()
1720 fstWriterClose(fstfile
);
1723 void write(std::map
<int, bool> &use_signal
) override
1725 if (!fstfile
) return;
1726 std::time_t t
= std::time(nullptr);
1727 fstWriterSetVersion(fstfile
, worker
->date
? yosys_version_str
: "Yosys");
1729 fstWriterSetDate(fstfile
, asctime(std::localtime(&t
)));
1731 fstWriterSetDate(fstfile
, "");
1732 if (!worker
->timescale
.empty())
1733 fstWriterSetTimescaleFromString(fstfile
, worker
->timescale
.c_str());
1735 fstWriterSetPackType(fstfile
, FST_WR_PT_FASTLZ
);
1736 fstWriterSetRepackOnClose(fstfile
, 1);
1738 worker
->top
->write_output_header(
1739 [this](IdString name
) { fstWriterSetScope(fstfile
, FST_ST_VCD_MODULE
, stringf("%s",log_id(name
)).c_str(), nullptr); },
1740 [this]() { fstWriterSetUpscope(fstfile
); },
1741 [this,use_signal
](Wire
*wire
, int id
, bool is_reg
) {
1742 if (!use_signal
.at(id
)) return;
1743 fstHandle fst_id
= fstWriterCreateVar(fstfile
, is_reg
? FST_VT_VCD_REG
: FST_VT_VCD_WIRE
, FST_VD_IMPLICIT
, GetSize(wire
),
1744 stringf("%s%s", wire
->name
[0] == '$' ? "\\" : "", log_id(wire
)).c_str(), 0);
1746 mapping
.emplace(id
, fst_id
);
1750 for(auto& d
: worker
->output_data
)
1752 fstWriterEmitTimeChange(fstfile
, d
.first
);
1753 for (auto &data
: d
.second
)
1755 if (!use_signal
.at(data
.first
)) continue;
1756 Const value
= data
.second
;
1757 std::stringstream ss
;
1758 for (int i
= GetSize(value
)-1; i
>= 0; i
--) {
1760 case State::S0
: ss
<< "0"; break;
1761 case State::S1
: ss
<< "1"; break;
1762 case State::Sx
: ss
<< "x"; break;
1766 fstWriterEmitValueChange(fstfile
, mapping
[data
.first
], ss
.str().c_str());
1771 struct fstContext
*fstfile
= nullptr;
1772 std::map
<int,fstHandle
> mapping
;
1775 struct AIWWriter
: public OutputWriter
1777 AIWWriter(SimWorker
*worker
, std::string filename
) : OutputWriter(worker
) {
1778 aiwfile
.open(filename
.c_str());
1781 virtual ~AIWWriter()
1783 aiwfile
<< '.' << '\n';
1786 void write(std::map
<int, bool> &) override
1788 if (!aiwfile
.is_open()) return;
1789 if (worker
->map_filename
.empty())
1790 log_cmd_error("For AIGER witness file map parameter is mandatory.\n");
1792 std::ifstream
mf(worker
->map_filename
);
1793 std::string type
, symbol
;
1794 int variable
, index
;
1796 log_cmd_error("Not able to read AIGER witness map file.\n");
1797 while (mf
>> type
>> variable
>> index
>> symbol
) {
1798 RTLIL::IdString escaped_s
= RTLIL::escape_id(symbol
);
1799 Wire
*w
= worker
->top
->module
->wire(escaped_s
);
1801 log_error("Wire %s not present in module %s\n",log_id(escaped_s
),log_id(worker
->top
->module
));
1802 if (index
< w
->start_offset
|| index
> w
->start_offset
+ w
->width
)
1803 log_error("Index %d for wire %s is out of range\n", index
, log_signal(w
));
1804 if (type
== "input") {
1805 aiw_inputs
[variable
] = SigBit(w
,index
-w
->start_offset
);
1806 if (worker
->clock
.count(escaped_s
)) {
1807 clocks
[variable
] = true;
1809 if (worker
->clockn
.count(escaped_s
)) {
1810 clocks
[variable
] = false;
1812 } else if (type
== "init") {
1813 aiw_inits
[variable
] = SigBit(w
,index
-w
->start_offset
);
1814 } else if (type
== "latch") {
1815 aiw_latches
[variable
] = {SigBit(w
,index
-w
->start_offset
), false};
1816 } else if (type
== "invlatch") {
1817 aiw_latches
[variable
] = {SigBit(w
,index
-w
->start_offset
), true};
1821 worker
->top
->write_output_header(
1824 [this](Wire
*wire
, int id
, bool) { mapping
[wire
] = id
; }
1827 std::map
<int, Yosys::RTLIL::Const
> current
;
1829 for (auto iter
= worker
->output_data
.begin(); iter
!= std::prev(worker
->output_data
.end()); ++iter
)
1832 for (auto &data
: d
.second
)
1834 current
[data
.first
] = data
.second
;
1837 for (int i
= 0;; i
++)
1839 if (aiw_latches
.count(i
)) {
1850 for (auto it
: clocks
)
1852 auto val
= it
.second
? State::S1
: State::S0
;
1853 SigBit bit
= aiw_inputs
.at(it
.first
);
1854 auto v
= current
[mapping
[bit
.wire
]].bits
.at(bit
.offset
);
1860 for (int i
= 0;; i
++)
1862 if (aiw_inputs
.count(i
)) {
1863 SigBit bit
= aiw_inputs
.at(i
);
1864 auto v
= current
[mapping
[bit
.wire
]].bits
.at(bit
.offset
);
1871 if (aiw_inits
.count(i
)) {
1872 SigBit bit
= aiw_inits
.at(i
);
1873 auto v
= current
[mapping
[bit
.wire
]].bits
.at(bit
.offset
);
1886 std::ofstream aiwfile
;
1887 dict
<int, std::pair
<SigBit
, bool>> aiw_latches
;
1888 dict
<int, SigBit
> aiw_inputs
, aiw_inits
;
1889 dict
<int, bool> clocks
;
1890 std::map
<Wire
*,int> mapping
;
1893 struct SimPass
: public Pass
{
1894 SimPass() : Pass("sim", "simulate the circuit") { }
1895 void help() override
1897 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1899 log(" sim [options] [top-level]\n");
1901 log("This command simulates the circuit using the given top-level module.\n");
1903 log(" -vcd <filename>\n");
1904 log(" write the simulation results to the given VCD file\n");
1906 log(" -fst <filename>\n");
1907 log(" write the simulation results to the given FST file\n");
1909 log(" -aiw <filename>\n");
1910 log(" write the simulation results to an AIGER witness file\n");
1911 log(" (requires a *.aim file via -map)\n");
1914 log(" ignore constant x outputs in simulation file.\n");
1917 log(" include date and full version info in output.\n");
1919 log(" -clock <portname>\n");
1920 log(" name of top-level clock input\n");
1922 log(" -clockn <portname>\n");
1923 log(" name of top-level clock input (inverse polarity)\n");
1925 log(" -multiclock\n");
1926 log(" mark that witness file is multiclock.\n");
1928 log(" -reset <portname>\n");
1929 log(" name of top-level reset input (active high)\n");
1931 log(" -resetn <portname>\n");
1932 log(" name of top-level inverted reset input (active low)\n");
1934 log(" -rstlen <integer>\n");
1935 log(" number of cycles reset should stay active (default: 1)\n");
1938 log(" zero-initialize all uninitialized regs and memories\n");
1940 log(" -timescale <string>\n");
1941 log(" include the specified timescale declaration in the vcd\n");
1943 log(" -n <integer>\n");
1944 log(" number of clock cycles to simulate (default: 20)\n");
1947 log(" use all nets in VCD/FST operations, not just those with public names\n");
1950 log(" writeback mode: use final simulation state as new init state\n");
1953 log(" read simulation results file (file formats supported: FST, VCD, AIW and WIT)\n");
1954 log(" VCD support requires vcd2fst external tool to be present\n");
1956 log(" -map <filename>\n");
1957 log(" read file with port and latch symbols, needed for AIGER witness input\n");
1959 log(" -scope <name>\n");
1960 log(" scope of simulation top model\n");
1962 log(" -at <time>\n");
1963 log(" sets start and stop time\n");
1965 log(" -start <time>\n");
1966 log(" start co-simulation in arbitary time (default 0)\n");
1968 log(" -stop <time>\n");
1969 log(" stop co-simulation in arbitary time (default END)\n");
1972 log(" simulation with stimulus from FST (default)\n");
1975 log(" co-simulation expect exact match\n");
1977 log(" -sim-gold\n");
1978 log(" co-simulation, x in simulation can match any value in FST\n");
1980 log(" -sim-gate\n");
1981 log(" co-simulation, x in FST can match any value in simulation\n");
1984 log(" disable per-cycle/sample log message\n");
1987 log(" enable debug output\n");
1992 static std::string
file_base_name(std::string
const & path
)
1994 return path
.substr(path
.find_last_of("/\\") + 1);
1997 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) override
2001 bool start_set
= false, stop_set
= false, at_set
= false;
2003 log_header(design
, "Executing SIM pass (simulate the circuit).\n");
2006 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
2007 if (args
[argidx
] == "-vcd" && argidx
+1 < args
.size()) {
2008 std::string vcd_filename
= args
[++argidx
];
2009 rewrite_filename(vcd_filename
);
2010 worker
.outputfiles
.emplace_back(std::unique_ptr
<VCDWriter
>(new VCDWriter(&worker
, vcd_filename
.c_str())));
2013 if (args
[argidx
] == "-fst" && argidx
+1 < args
.size()) {
2014 std::string fst_filename
= args
[++argidx
];
2015 rewrite_filename(fst_filename
);
2016 worker
.outputfiles
.emplace_back(std::unique_ptr
<FSTWriter
>(new FSTWriter(&worker
, fst_filename
.c_str())));
2019 if (args
[argidx
] == "-aiw" && argidx
+1 < args
.size()) {
2020 std::string aiw_filename
= args
[++argidx
];
2021 rewrite_filename(aiw_filename
);
2022 worker
.outputfiles
.emplace_back(std::unique_ptr
<AIWWriter
>(new AIWWriter(&worker
, aiw_filename
.c_str())));
2025 if (args
[argidx
] == "-n" && argidx
+1 < args
.size()) {
2026 numcycles
= atoi(args
[++argidx
].c_str());
2027 worker
.cycles_set
= true;
2030 if (args
[argidx
] == "-rstlen" && argidx
+1 < args
.size()) {
2031 worker
.rstlen
= atoi(args
[++argidx
].c_str());
2034 if (args
[argidx
] == "-clock" && argidx
+1 < args
.size()) {
2035 worker
.clock
.insert(RTLIL::escape_id(args
[++argidx
]));
2038 if (args
[argidx
] == "-clockn" && argidx
+1 < args
.size()) {
2039 worker
.clockn
.insert(RTLIL::escape_id(args
[++argidx
]));
2042 if (args
[argidx
] == "-reset" && argidx
+1 < args
.size()) {
2043 worker
.reset
.insert(RTLIL::escape_id(args
[++argidx
]));
2046 if (args
[argidx
] == "-resetn" && argidx
+1 < args
.size()) {
2047 worker
.resetn
.insert(RTLIL::escape_id(args
[++argidx
]));
2050 if (args
[argidx
] == "-timescale" && argidx
+1 < args
.size()) {
2051 worker
.timescale
= args
[++argidx
];
2054 if (args
[argidx
] == "-a") {
2055 worker
.hide_internal
= false;
2058 if (args
[argidx
] == "-q") {
2059 worker
.verbose
= false;
2062 if (args
[argidx
] == "-d") {
2063 worker
.debug
= true;
2066 if (args
[argidx
] == "-w") {
2067 worker
.writeback
= true;
2070 if (args
[argidx
] == "-zinit") {
2071 worker
.zinit
= true;
2074 if (args
[argidx
] == "-r" && argidx
+1 < args
.size()) {
2075 std::string sim_filename
= args
[++argidx
];
2076 rewrite_filename(sim_filename
);
2077 worker
.sim_filename
= sim_filename
;
2080 if (args
[argidx
] == "-map" && argidx
+1 < args
.size()) {
2081 std::string map_filename
= args
[++argidx
];
2082 rewrite_filename(map_filename
);
2083 worker
.map_filename
= map_filename
;
2086 if (args
[argidx
] == "-scope" && argidx
+1 < args
.size()) {
2087 worker
.scope
= args
[++argidx
];
2090 if (args
[argidx
] == "-start" && argidx
+1 < args
.size()) {
2091 worker
.start_time
= stringToTime(args
[++argidx
]);
2095 if (args
[argidx
] == "-stop" && argidx
+1 < args
.size()) {
2096 worker
.stop_time
= stringToTime(args
[++argidx
]);
2100 if (args
[argidx
] == "-at" && argidx
+1 < args
.size()) {
2101 worker
.start_time
= stringToTime(args
[++argidx
]);
2102 worker
.stop_time
= worker
.start_time
;
2106 if (args
[argidx
] == "-sim") {
2107 worker
.sim_mode
= SimulationMode::sim
;
2110 if (args
[argidx
] == "-sim-cmp") {
2111 worker
.sim_mode
= SimulationMode::cmp
;
2114 if (args
[argidx
] == "-sim-gold") {
2115 worker
.sim_mode
= SimulationMode::gold
;
2118 if (args
[argidx
] == "-sim-gate") {
2119 worker
.sim_mode
= SimulationMode::gate
;
2122 if (args
[argidx
] == "-x") {
2123 worker
.ignore_x
= true;
2126 if (args
[argidx
] == "-date") {
2130 if (args
[argidx
] == "-multiclock") {
2131 worker
.multiclock
= true;
2136 extra_args(args
, argidx
, design
);
2137 if (at_set
&& (start_set
|| stop_set
|| worker
.cycles_set
))
2138 log_error("'at' option can only be defined separate of 'start','stop' and 'n'\n");
2139 if (stop_set
&& worker
.cycles_set
)
2140 log_error("'stop' and 'n' can only be used exclusively'\n");
2142 Module
*top_mod
= nullptr;
2144 if (design
->full_selection()) {
2145 top_mod
= design
->top_module();
2148 log_cmd_error("Design has no top module, use the 'hierarchy' command to specify one.\n");
2150 auto mods
= design
->selected_whole_modules();
2151 if (GetSize(mods
) != 1)
2152 log_cmd_error("Only one top module must be selected.\n");
2153 top_mod
= mods
.front();
2156 if (worker
.sim_filename
.empty())
2157 worker
.run(top_mod
, numcycles
);
2159 std::string filename_trim
= file_base_name(worker
.sim_filename
);
2160 if (filename_trim
.size() > 4 && ((filename_trim
.compare(filename_trim
.size()-4, std::string::npos
, ".fst") == 0) ||
2161 filename_trim
.compare(filename_trim
.size()-4, std::string::npos
, ".vcd") == 0)) {
2162 worker
.run_cosim_fst(top_mod
, numcycles
);
2163 } else if (filename_trim
.size() > 4 && filename_trim
.compare(filename_trim
.size()-4, std::string::npos
, ".aiw") == 0) {
2164 if (worker
.map_filename
.empty())
2165 log_cmd_error("For AIGER witness file map parameter is mandatory.\n");
2166 worker
.run_cosim_aiger_witness(top_mod
);
2167 } else if (filename_trim
.size() > 4 && filename_trim
.compare(filename_trim
.size()-4, std::string::npos
, ".wit") == 0) {
2168 worker
.run_cosim_btor2_witness(top_mod
);
2170 log_cmd_error("Unhandled extension for simulation input file `%s`.\n", worker
.sim_filename
.c_str());
2176 struct Fst2TbPass
: public Pass
{
2177 Fst2TbPass() : Pass("fst2tb", "generate testbench out of fst file") { }
2178 void help() override
2180 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
2182 log(" fst2tb [options] [top-level]\n");
2184 log("This command generates testbench for the circuit using the given top-level module\n");
2185 log("and simulus signal from FST file\n");
2187 log(" -tb <name>\n");
2188 log(" generated testbench name.\n");
2189 log(" files <name>.v and <name>.txt are created as result.\n");
2191 log(" -r <filename>\n");
2192 log(" read simulation FST file\n");
2194 log(" -clock <portname>\n");
2195 log(" name of top-level clock input\n");
2197 log(" -clockn <portname>\n");
2198 log(" name of top-level clock input (inverse polarity)\n");
2200 log(" -scope <name>\n");
2201 log(" scope of simulation top model\n");
2203 log(" -start <time>\n");
2204 log(" start co-simulation in arbitary time (default 0)\n");
2206 log(" -stop <time>\n");
2207 log(" stop co-simulation in arbitary time (default END)\n");
2209 log(" -n <integer>\n");
2210 log(" number of clock cycles to simulate (default: 20)\n");
2214 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) override
2218 bool stop_set
= false;
2219 std::string tb_filename
;
2221 log_header(design
, "Executing FST2FB pass.\n");
2224 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
2225 if (args
[argidx
] == "-clock" && argidx
+1 < args
.size()) {
2226 worker
.clock
.insert(RTLIL::escape_id(args
[++argidx
]));
2229 if (args
[argidx
] == "-clockn" && argidx
+1 < args
.size()) {
2230 worker
.clockn
.insert(RTLIL::escape_id(args
[++argidx
]));
2233 if (args
[argidx
] == "-r" && argidx
+1 < args
.size()) {
2234 std::string sim_filename
= args
[++argidx
];
2235 rewrite_filename(sim_filename
);
2236 worker
.sim_filename
= sim_filename
;
2239 if (args
[argidx
] == "-n" && argidx
+1 < args
.size()) {
2240 numcycles
= atoi(args
[++argidx
].c_str());
2241 worker
.cycles_set
= true;
2244 if (args
[argidx
] == "-scope" && argidx
+1 < args
.size()) {
2245 worker
.scope
= args
[++argidx
];
2248 if (args
[argidx
] == "-start" && argidx
+1 < args
.size()) {
2249 worker
.start_time
= stringToTime(args
[++argidx
]);
2252 if (args
[argidx
] == "-stop" && argidx
+1 < args
.size()) {
2253 worker
.stop_time
= stringToTime(args
[++argidx
]);
2257 if (args
[argidx
] == "-tb" && argidx
+1 < args
.size()) {
2258 tb_filename
= args
[++argidx
];
2263 extra_args(args
, argidx
, design
);
2264 if (stop_set
&& worker
.cycles_set
)
2265 log_error("'stop' and 'n' can only be used exclusively'\n");
2267 Module
*top_mod
= nullptr;
2269 if (design
->full_selection()) {
2270 top_mod
= design
->top_module();
2273 log_cmd_error("Design has no top module, use the 'hierarchy' command to specify one.\n");
2275 auto mods
= design
->selected_whole_modules();
2276 if (GetSize(mods
) != 1)
2277 log_cmd_error("Only one top module must be selected.\n");
2278 top_mod
= mods
.front();
2281 if (tb_filename
.empty())
2282 log_cmd_error("Testbench name must be defined.\n");
2284 if (worker
.sim_filename
.empty())
2285 log_cmd_error("Stimulus FST file must be defined.\n");
2287 worker
.generate_tb(top_mod
, tb_filename
, numcycles
);
2291 PRIVATE_NAMESPACE_END