2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
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"
27 PRIVATE_NAMESPACE_BEGIN
32 bool hide_internal
= true;
33 bool writeback
= false;
46 for (auto &bit
: v
.bits
)
58 dict
<Cell
*, SimInstance
*> children
;
61 dict
<SigBit
, State
> state_nets
;
62 dict
<SigBit
, pool
<Cell
*>> upd_cells
;
63 dict
<SigBit
, pool
<Wire
*>> upd_outports
;
65 pool
<SigBit
> dirty_bits
;
66 pool
<Cell
*> dirty_cells
;
67 pool
<SimInstance
*, hash_ptr_ops
> dirty_children
;
84 dict
<Cell
*, ff_state_t
> ff_database
;
85 dict
<Cell
*, mem_state_t
> mem_database
;
86 pool
<Cell
*> formal_database
;
88 dict
<Wire
*, pair
<int, Const
>> vcd_database
;
90 SimInstance(SimShared
*shared
, Module
*module
, Cell
*instance
= nullptr, SimInstance
*parent
= nullptr) :
91 shared(shared
), module(module
), instance(instance
), parent(parent
), sigmap(module
)
96 log_assert(parent
->children
.count(instance
) == 0);
97 parent
->children
[instance
] = this;
100 for (auto wire
: module
->wires())
102 SigSpec sig
= sigmap(wire
);
104 for (int i
= 0; i
< GetSize(sig
); i
++) {
105 if (state_nets
.count(sig
[i
]) == 0)
106 state_nets
[sig
[i
]] = State::Sx
;
107 if (wire
->port_output
) {
108 upd_outports
[sig
[i
]].insert(wire
);
109 dirty_bits
.insert(sig
[i
]);
113 if (wire
->attributes
.count(ID::init
)) {
114 Const initval
= wire
->attributes
.at(ID::init
);
115 for (int i
= 0; i
< GetSize(sig
) && i
< GetSize(initval
); i
++)
116 if (initval
[i
] == State::S0
|| initval
[i
] == State::S1
) {
117 state_nets
[sig
[i
]] = initval
[i
];
118 dirty_bits
.insert(sig
[i
]);
123 for (auto cell
: module
->cells())
125 Module
*mod
= module
->design
->module(cell
->type
);
127 if (mod
!= nullptr) {
128 dirty_children
.insert(new SimInstance(shared
, mod
, cell
, this));
131 for (auto &port
: cell
->connections()) {
132 if (cell
->input(port
.first
))
133 for (auto bit
: sigmap(port
.second
)) {
134 upd_cells
[bit
].insert(cell
);
135 // Make sure cell inputs connected to constants are updated in the first cycle
136 if (bit
.wire
== nullptr)
137 dirty_bits
.insert(bit
);
141 if (cell
->type
.in(ID($dff
))) {
143 ff
.past_clock
= State::Sx
;
144 ff
.past_d
= Const(State::Sx
, cell
->getParam(ID::WIDTH
).as_int());
145 ff_database
[cell
] = ff
;
148 if (cell
->type
== ID($mem
))
152 mem
.past_wr_clk
= Const(State::Sx
, GetSize(cell
->getPort(ID::WR_CLK
)));
153 mem
.past_wr_en
= Const(State::Sx
, GetSize(cell
->getPort(ID::WR_EN
)));
154 mem
.past_wr_addr
= Const(State::Sx
, GetSize(cell
->getPort(ID::WR_ADDR
)));
155 mem
.past_wr_data
= Const(State::Sx
, GetSize(cell
->getPort(ID::WR_DATA
)));
157 mem
.data
= cell
->getParam(ID::INIT
);
158 int sz
= cell
->getParam(ID::SIZE
).as_int() * cell
->getParam(ID::WIDTH
).as_int();
160 if (GetSize(mem
.data
) > sz
)
161 mem
.data
.bits
.resize(sz
);
163 while (GetSize(mem
.data
) < sz
)
164 mem
.data
.bits
.push_back(State::Sx
);
166 mem_database
[cell
] = mem
;
168 if (cell
->type
.in(ID($memwr
),ID($memrd
)))
170 log_error("$memrd and $memwr cells have to be merged to stand-alone $mem cells (execute memory_collect pass)\n");
172 if (cell
->type
.in(ID($
assert), ID($cover
), ID($assume
))) {
173 formal_database
.insert(cell
);
179 for (auto &it
: ff_database
)
181 Cell
*cell
= it
.first
;
182 ff_state_t
&ff
= it
.second
;
185 SigSpec qsig
= cell
->getPort(ID::Q
);
186 Const qdata
= get_state(qsig
);
188 set_state(qsig
, qdata
);
191 for (auto &it
: mem_database
) {
192 mem_state_t
&mem
= it
.second
;
193 zinit(mem
.past_wr_en
);
201 for (auto child
: children
)
205 IdString
name() const
207 if (instance
!= nullptr)
208 return instance
->name
;
212 std::string
hiername() const
214 if (instance
!= nullptr)
215 return parent
->hiername() + "." + log_id(instance
->name
);
217 return log_id(module
->name
);
220 Const
get_state(SigSpec sig
)
224 for (auto bit
: sigmap(sig
))
225 if (bit
.wire
== nullptr)
226 value
.bits
.push_back(bit
.data
);
227 else if (state_nets
.count(bit
))
228 value
.bits
.push_back(state_nets
.at(bit
));
230 value
.bits
.push_back(State::Sz
);
233 log("[%s] get %s: %s\n", hiername().c_str(), log_signal(sig
), log_signal(value
));
237 bool set_state(SigSpec sig
, Const value
)
239 bool did_something
= false;
242 log_assert(GetSize(sig
) <= GetSize(value
));
244 for (int i
= 0; i
< GetSize(sig
); i
++)
245 if (state_nets
.at(sig
[i
]) != value
[i
]) {
246 state_nets
.at(sig
[i
]) = value
[i
];
247 dirty_bits
.insert(sig
[i
]);
248 did_something
= true;
252 log("[%s] set %s: %s\n", hiername().c_str(), log_signal(sig
), log_signal(value
));
253 return did_something
;
256 void update_cell(Cell
*cell
)
258 if (ff_database
.count(cell
))
261 if (formal_database
.count(cell
))
264 if (mem_database
.count(cell
))
266 mem_state_t
&mem
= mem_database
.at(cell
);
268 int num_rd_ports
= cell
->getParam(ID::RD_PORTS
).as_int();
270 int size
= cell
->getParam(ID::SIZE
).as_int();
271 int offset
= cell
->getParam(ID::OFFSET
).as_int();
272 int abits
= cell
->getParam(ID::ABITS
).as_int();
273 int width
= cell
->getParam(ID::WIDTH
).as_int();
275 if (cell
->getParam(ID::RD_CLK_ENABLE
).as_bool())
276 log_error("Memory %s.%s has clocked read ports. Run 'memory' with -nordff.\n", log_id(module
), log_id(cell
));
278 SigSpec rd_addr_sig
= cell
->getPort(ID::RD_ADDR
);
279 SigSpec rd_data_sig
= cell
->getPort(ID::RD_DATA
);
281 for (int port_idx
= 0; port_idx
< num_rd_ports
; port_idx
++)
283 Const addr
= get_state(rd_addr_sig
.extract(port_idx
*abits
, abits
));
284 Const data
= Const(State::Sx
, width
);
286 if (addr
.is_fully_def()) {
287 int index
= addr
.as_int() - offset
;
288 if (index
>= 0 && index
< size
)
289 data
= mem
.data
.extract(index
*width
, width
);
292 set_state(rd_data_sig
.extract(port_idx
*width
, width
), data
);
298 if (children
.count(cell
))
300 auto child
= children
.at(cell
);
301 for (auto &conn
: cell
->connections())
302 if (cell
->input(conn
.first
)) {
303 Const value
= get_state(conn
.second
);
304 child
->set_state(child
->module
->wire(conn
.first
), value
);
306 dirty_children
.insert(child
);
310 if (yosys_celltypes
.cell_evaluable(cell
->type
))
312 RTLIL::SigSpec sig_a
, sig_b
, sig_c
, sig_d
, sig_s
, sig_y
;
313 bool has_a
, has_b
, has_c
, has_d
, has_s
, has_y
;
315 has_a
= cell
->hasPort(ID::A
);
316 has_b
= cell
->hasPort(ID::B
);
317 has_c
= cell
->hasPort(ID::C
);
318 has_d
= cell
->hasPort(ID::D
);
319 has_s
= cell
->hasPort(ID::S
);
320 has_y
= cell
->hasPort(ID::Y
);
322 if (has_a
) sig_a
= cell
->getPort(ID::A
);
323 if (has_b
) sig_b
= cell
->getPort(ID::B
);
324 if (has_c
) sig_c
= cell
->getPort(ID::C
);
325 if (has_d
) sig_d
= cell
->getPort(ID::D
);
326 if (has_s
) sig_s
= cell
->getPort(ID::S
);
327 if (has_y
) sig_y
= cell
->getPort(ID::Y
);
330 log("[%s] eval %s (%s)\n", hiername().c_str(), log_id(cell
), log_id(cell
->type
));
332 // Simple (A -> Y) and (A,B -> Y) cells
333 if (has_a
&& !has_c
&& !has_d
&& !has_s
&& has_y
) {
334 set_state(sig_y
, CellTypes::eval(cell
, get_state(sig_a
), get_state(sig_b
)));
338 // (A,B,C -> Y) cells
339 if (has_a
&& has_b
&& has_c
&& !has_d
&& !has_s
&& has_y
) {
340 set_state(sig_y
, CellTypes::eval(cell
, get_state(sig_a
), get_state(sig_b
), get_state(sig_c
)));
344 // (A,B,S -> Y) cells
345 if (has_a
&& has_b
&& !has_c
&& !has_d
&& has_s
&& has_y
) {
346 set_state(sig_y
, CellTypes::eval(cell
, get_state(sig_a
), get_state(sig_b
), get_state(sig_s
)));
350 log_warning("Unsupported evaluable cell type: %s (%s.%s)\n", log_id(cell
->type
), log_id(module
), log_id(cell
));
354 log_error("Unsupported cell type: %s (%s.%s)\n", log_id(cell
->type
), log_id(module
), log_id(cell
));
359 pool
<Cell
*> queue_cells
;
360 pool
<Wire
*> queue_outports
;
362 queue_cells
.swap(dirty_cells
);
366 for (auto bit
: dirty_bits
)
368 if (upd_cells
.count(bit
))
369 for (auto cell
: upd_cells
.at(bit
))
370 queue_cells
.insert(cell
);
372 if (upd_outports
.count(bit
) && parent
!= nullptr)
373 for (auto wire
: upd_outports
.at(bit
))
374 queue_outports
.insert(wire
);
379 if (!queue_cells
.empty())
381 for (auto cell
: queue_cells
)
388 for (auto wire
: queue_outports
)
389 if (instance
->hasPort(wire
->name
)) {
390 Const value
= get_state(wire
);
391 parent
->set_state(instance
->getPort(wire
->name
), value
);
394 queue_outports
.clear();
396 for (auto child
: dirty_children
)
399 dirty_children
.clear();
401 if (dirty_bits
.empty())
408 bool did_something
= false;
410 for (auto &it
: ff_database
)
412 Cell
*cell
= it
.first
;
413 ff_state_t
&ff
= it
.second
;
415 if (cell
->type
.in(ID($dff
)))
417 bool clkpol
= cell
->getParam(ID::CLK_POLARITY
).as_bool();
418 State current_clock
= get_state(cell
->getPort(ID::CLK
))[0];
420 if (clkpol
? (ff
.past_clock
== State::S1
|| current_clock
!= State::S1
) :
421 (ff
.past_clock
== State::S0
|| current_clock
!= State::S0
))
424 if (set_state(cell
->getPort(ID::Q
), ff
.past_d
))
425 did_something
= true;
429 for (auto &it
: mem_database
)
431 Cell
*cell
= it
.first
;
432 mem_state_t
&mem
= it
.second
;
434 int num_wr_ports
= cell
->getParam(ID::WR_PORTS
).as_int();
436 int size
= cell
->getParam(ID::SIZE
).as_int();
437 int offset
= cell
->getParam(ID::OFFSET
).as_int();
438 int abits
= cell
->getParam(ID::ABITS
).as_int();
439 int width
= cell
->getParam(ID::WIDTH
).as_int();
441 Const wr_clk_enable
= cell
->getParam(ID::WR_CLK_ENABLE
);
442 Const wr_clk_polarity
= cell
->getParam(ID::WR_CLK_POLARITY
);
443 Const current_wr_clk
= get_state(cell
->getPort(ID::WR_CLK
));
445 for (int port_idx
= 0; port_idx
< num_wr_ports
; port_idx
++)
447 Const addr
, data
, enable
;
449 if (wr_clk_enable
[port_idx
] == State::S0
)
451 addr
= get_state(cell
->getPort(ID::WR_ADDR
).extract(port_idx
*abits
, abits
));
452 data
= get_state(cell
->getPort(ID::WR_DATA
).extract(port_idx
*width
, width
));
453 enable
= get_state(cell
->getPort(ID::WR_EN
).extract(port_idx
*width
, width
));
457 if (wr_clk_polarity
[port_idx
] == State::S1
?
458 (mem
.past_wr_clk
[port_idx
] == State::S1
|| current_wr_clk
[port_idx
] != State::S1
) :
459 (mem
.past_wr_clk
[port_idx
] == State::S0
|| current_wr_clk
[port_idx
] != State::S0
))
462 addr
= mem
.past_wr_addr
.extract(port_idx
*abits
, abits
);
463 data
= mem
.past_wr_data
.extract(port_idx
*width
, width
);
464 enable
= mem
.past_wr_en
.extract(port_idx
*width
, width
);
467 if (addr
.is_fully_def())
469 int index
= addr
.as_int() - offset
;
470 if (index
>= 0 && index
< size
)
471 for (int i
= 0; i
< width
; i
++)
472 if (enable
[i
] == State::S1
&& mem
.data
.bits
.at(index
*width
+i
) != data
[i
]) {
473 mem
.data
.bits
.at(index
*width
+i
) = data
[i
];
474 dirty_cells
.insert(cell
);
475 did_something
= true;
481 for (auto it
: children
)
482 if (it
.second
->update_ph2()) {
483 dirty_children
.insert(it
.second
);
484 did_something
= true;
487 return did_something
;
492 for (auto &it
: ff_database
)
494 Cell
*cell
= it
.first
;
495 ff_state_t
&ff
= it
.second
;
497 if (cell
->type
.in(ID($dff
))) {
498 ff
.past_clock
= get_state(cell
->getPort(ID::CLK
))[0];
499 ff
.past_d
= get_state(cell
->getPort(ID::D
));
503 for (auto &it
: mem_database
)
505 Cell
*cell
= it
.first
;
506 mem_state_t
&mem
= it
.second
;
508 mem
.past_wr_clk
= get_state(cell
->getPort(ID::WR_CLK
));
509 mem
.past_wr_en
= get_state(cell
->getPort(ID::WR_EN
));
510 mem
.past_wr_addr
= get_state(cell
->getPort(ID::WR_ADDR
));
511 mem
.past_wr_data
= get_state(cell
->getPort(ID::WR_DATA
));
514 for (auto cell
: formal_database
)
516 string label
= log_id(cell
);
517 if (cell
->attributes
.count(ID::src
))
518 label
= cell
->attributes
.at(ID::src
).decode_string();
520 State a
= get_state(cell
->getPort(ID::A
))[0];
521 State en
= get_state(cell
->getPort(ID::EN
))[0];
523 if (cell
->type
== ID($cover
) && en
== State::S1
&& a
!= State::S1
)
524 log("Cover %s.%s (%s) reached.\n", hiername().c_str(), log_id(cell
), label
.c_str());
526 if (cell
->type
== ID($assume
) && en
== State::S1
&& a
!= State::S1
)
527 log("Assumption %s.%s (%s) failed.\n", hiername().c_str(), log_id(cell
), label
.c_str());
529 if (cell
->type
== ID($
assert) && en
== State::S1
&& a
!= State::S1
)
530 log_warning("Assert %s.%s (%s) failed.\n", hiername().c_str(), log_id(cell
), label
.c_str());
533 for (auto it
: children
)
534 it
.second
->update_ph3();
537 void writeback(pool
<Module
*> &wbmods
)
539 if (wbmods
.count(module
))
540 log_error("Instance %s of module %s is not unique: Writeback not possible. (Fix by running 'uniquify'.)\n", hiername().c_str(), log_id(module
));
542 wbmods
.insert(module
);
544 for (auto wire
: module
->wires())
545 wire
->attributes
.erase(ID::init
);
547 for (auto &it
: ff_database
)
549 Cell
*cell
= it
.first
;
550 SigSpec sig_q
= cell
->getPort(ID::Q
);
551 Const initval
= get_state(sig_q
);
553 for (int i
= 0; i
< GetSize(sig_q
); i
++)
555 Wire
*w
= sig_q
[i
].wire
;
557 if (w
->attributes
.count(ID::init
) == 0)
558 w
->attributes
[ID::init
] = Const(State::Sx
, GetSize(w
));
560 w
->attributes
[ID::init
][sig_q
[i
].offset
] = initval
[i
];
564 for (auto &it
: mem_database
)
566 Cell
*cell
= it
.first
;
567 mem_state_t
&mem
= it
.second
;
568 Const initval
= mem
.data
;
570 while (GetSize(initval
) >= 2) {
571 if (initval
[GetSize(initval
)-1] != State::Sx
) break;
572 if (initval
[GetSize(initval
)-2] != State::Sx
) break;
573 initval
.bits
.pop_back();
576 cell
->setParam(ID::INIT
, initval
);
579 for (auto it
: children
)
580 it
.second
->writeback(wbmods
);
583 void write_vcd_header(std::ofstream
&f
, int &id
)
585 f
<< stringf("$scope module %s $end\n", log_id(name()));
587 for (auto wire
: module
->wires())
589 if (shared
->hide_internal
&& wire
->name
[0] == '$')
592 f
<< stringf("$var wire %d n%d %s%s $end\n", GetSize(wire
), id
, wire
->name
[0] == '$' ? "\\" : "", log_id(wire
));
593 vcd_database
[wire
] = make_pair(id
++, Const());
596 for (auto child
: children
)
597 child
.second
->write_vcd_header(f
, id
);
599 f
<< stringf("$upscope $end\n");
602 void write_vcd_step(std::ofstream
&f
)
604 for (auto &it
: vcd_database
)
606 Wire
*wire
= it
.first
;
607 Const value
= get_state(wire
);
608 int id
= it
.second
.first
;
610 if (it
.second
.second
== value
)
613 it
.second
.second
= value
;
616 for (int i
= GetSize(value
)-1; i
>= 0; i
--) {
618 case State::S0
: f
<< "0"; break;
619 case State::S1
: f
<< "1"; break;
620 case State::Sx
: f
<< "x"; break;
625 f
<< stringf(" n%d\n", id
);
628 for (auto child
: children
)
629 child
.second
->write_vcd_step(f
);
633 struct SimWorker
: SimShared
635 SimInstance
*top
= nullptr;
636 std::ofstream vcdfile
;
637 pool
<IdString
> clock
, clockn
, reset
, resetn
;
638 std::string timescale
;
645 void write_vcd_header()
647 if (!vcdfile
.is_open())
650 vcdfile
<< stringf("$version %s $end\n", yosys_version_str
);
652 std::time_t t
= std::time(nullptr);
654 if (std::strftime(mbstr
, sizeof(mbstr
), "%c", std::localtime(&t
))) {
655 vcdfile
<< stringf("$date ") << mbstr
<< stringf(" $end\n");
658 if (!timescale
.empty())
659 vcdfile
<< stringf("$timescale %s $end\n", timescale
.c_str());
662 top
->write_vcd_header(vcdfile
, id
);
664 vcdfile
<< stringf("$enddefinitions $end\n");
667 void write_vcd_step(int t
)
669 if (!vcdfile
.is_open())
672 vcdfile
<< stringf("#%d\n", t
);
673 top
->write_vcd_step(vcdfile
);
681 log("\n-- ph1 --\n");
686 log("\n-- ph2 --\n");
688 if (!top
->update_ph2())
693 log("\n-- ph3 --\n");
698 void set_inports(pool
<IdString
> ports
, State value
)
700 for (auto portname
: ports
)
702 Wire
*w
= top
->module
->wire(portname
);
705 log_error("Can't find port %s on module %s.\n", log_id(portname
), log_id(top
->module
));
707 top
->set_state(w
, value
);
711 void run(Module
*topmod
, int numcycles
)
713 log_assert(top
== nullptr);
714 top
= new SimInstance(this, topmod
);
717 log("\n===== 0 =====\n");
719 log("Simulating cycle 0.\n");
721 set_inports(reset
, State::S1
);
722 set_inports(resetn
, State::S0
);
724 set_inports(clock
, State::Sx
);
725 set_inports(clockn
, State::Sx
);
732 for (int cycle
= 0; cycle
< numcycles
; cycle
++)
735 log("\n===== %d =====\n", 10*cycle
+ 5);
737 set_inports(clock
, State::S0
);
738 set_inports(clockn
, State::S1
);
741 write_vcd_step(10*cycle
+ 5);
744 log("\n===== %d =====\n", 10*cycle
+ 10);
746 log("Simulating cycle %d.\n", cycle
+1);
748 set_inports(clock
, State::S1
);
749 set_inports(clockn
, State::S0
);
751 if (cycle
+1 == rstlen
) {
752 set_inports(reset
, State::S0
);
753 set_inports(resetn
, State::S1
);
757 write_vcd_step(10*cycle
+ 10);
760 write_vcd_step(10*numcycles
+ 2);
763 pool
<Module
*> wbmods
;
764 top
->writeback(wbmods
);
769 struct SimPass
: public Pass
{
770 SimPass() : Pass("sim", "simulate the circuit") { }
773 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
775 log(" sim [options] [top-level]\n");
777 log("This command simulates the circuit using the given top-level module.\n");
779 log(" -vcd <filename>\n");
780 log(" write the simulation results to the given VCD file\n");
782 log(" -clock <portname>\n");
783 log(" name of top-level clock input\n");
785 log(" -clockn <portname>\n");
786 log(" name of top-level clock input (inverse polarity)\n");
788 log(" -reset <portname>\n");
789 log(" name of top-level reset input (active high)\n");
791 log(" -resetn <portname>\n");
792 log(" name of top-level inverted reset input (active low)\n");
794 log(" -rstlen <integer>\n");
795 log(" number of cycles reset should stay active (default: 1)\n");
798 log(" zero-initialize all uninitialized regs and memories\n");
800 log(" -timescale <string>\n");
801 log(" include the specified timescale declaration in the vcd\n");
803 log(" -n <integer>\n");
804 log(" number of cycles to simulate (default: 20)\n");
807 log(" include all nets in VCD output, not just those with public names\n");
810 log(" writeback mode: use final simulation state as new init state\n");
813 log(" enable debug output\n");
816 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) override
821 log_header(design
, "Executing SIM pass (simulate the circuit).\n");
824 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
825 if (args
[argidx
] == "-vcd" && argidx
+1 < args
.size()) {
826 worker
.vcdfile
.open(args
[++argidx
].c_str());
829 if (args
[argidx
] == "-n" && argidx
+1 < args
.size()) {
830 numcycles
= atoi(args
[++argidx
].c_str());
833 if (args
[argidx
] == "-rstlen" && argidx
+1 < args
.size()) {
834 worker
.rstlen
= atoi(args
[++argidx
].c_str());
837 if (args
[argidx
] == "-clock" && argidx
+1 < args
.size()) {
838 worker
.clock
.insert(RTLIL::escape_id(args
[++argidx
]));
841 if (args
[argidx
] == "-clockn" && argidx
+1 < args
.size()) {
842 worker
.clockn
.insert(RTLIL::escape_id(args
[++argidx
]));
845 if (args
[argidx
] == "-reset" && argidx
+1 < args
.size()) {
846 worker
.reset
.insert(RTLIL::escape_id(args
[++argidx
]));
849 if (args
[argidx
] == "-resetn" && argidx
+1 < args
.size()) {
850 worker
.resetn
.insert(RTLIL::escape_id(args
[++argidx
]));
853 if (args
[argidx
] == "-timescale" && argidx
+1 < args
.size()) {
854 worker
.timescale
= args
[++argidx
];
857 if (args
[argidx
] == "-a") {
858 worker
.hide_internal
= false;
861 if (args
[argidx
] == "-d") {
865 if (args
[argidx
] == "-w") {
866 worker
.writeback
= true;
869 if (args
[argidx
] == "-zinit") {
875 extra_args(args
, argidx
, design
);
877 Module
*top_mod
= nullptr;
879 if (design
->full_selection()) {
880 top_mod
= design
->top_module();
883 log_cmd_error("Design has no top module, use the 'hierarchy' command to specify one.\n");
885 auto mods
= design
->selected_whole_modules();
886 if (GetSize(mods
) != 1)
887 log_cmd_error("Only one top module must be selected.\n");
888 top_mod
= mods
.front();
891 worker
.run(top_mod
, numcycles
);
895 PRIVATE_NAMESPACE_END