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"
23 #include "kernel/mem.h"
28 PRIVATE_NAMESPACE_BEGIN
33 bool hide_internal
= true;
34 bool writeback
= false;
47 for (auto &bit
: v
.bits
)
59 dict
<Cell
*, SimInstance
*> children
;
62 dict
<SigBit
, State
> state_nets
;
63 dict
<SigBit
, pool
<Cell
*>> upd_cells
;
64 dict
<SigBit
, pool
<Wire
*>> upd_outports
;
66 pool
<SigBit
> dirty_bits
;
67 pool
<Cell
*> dirty_cells
;
68 pool
<IdString
> dirty_memories
;
69 pool
<SimInstance
*, hash_ptr_ops
> dirty_children
;
80 std::vector
<Const
> past_wr_clk
;
81 std::vector
<Const
> past_wr_en
;
82 std::vector
<Const
> past_wr_addr
;
83 std::vector
<Const
> past_wr_data
;
87 dict
<Cell
*, ff_state_t
> ff_database
;
88 dict
<IdString
, mem_state_t
> mem_database
;
89 pool
<Cell
*> formal_database
;
90 dict
<Cell
*, IdString
> mem_cells
;
92 std::vector
<Mem
> memories
;
94 dict
<Wire
*, pair
<int, Const
>> vcd_database
;
96 SimInstance(SimShared
*shared
, Module
*module
, Cell
*instance
= nullptr, SimInstance
*parent
= nullptr) :
97 shared(shared
), module(module
), instance(instance
), parent(parent
), sigmap(module
)
102 log_assert(parent
->children
.count(instance
) == 0);
103 parent
->children
[instance
] = this;
106 for (auto wire
: module
->wires())
108 SigSpec sig
= sigmap(wire
);
110 for (int i
= 0; i
< GetSize(sig
); i
++) {
111 if (state_nets
.count(sig
[i
]) == 0)
112 state_nets
[sig
[i
]] = State::Sx
;
113 if (wire
->port_output
) {
114 upd_outports
[sig
[i
]].insert(wire
);
115 dirty_bits
.insert(sig
[i
]);
119 if (wire
->attributes
.count(ID::init
)) {
120 Const initval
= wire
->attributes
.at(ID::init
);
121 for (int i
= 0; i
< GetSize(sig
) && i
< GetSize(initval
); i
++)
122 if (initval
[i
] == State::S0
|| initval
[i
] == State::S1
) {
123 state_nets
[sig
[i
]] = initval
[i
];
124 dirty_bits
.insert(sig
[i
]);
129 memories
= Mem::get_all_memories(module
);
130 for (auto &mem
: memories
) {
131 auto &mdb
= mem_database
[mem
.memid
];
133 for (auto &port
: mem
.wr_ports
) {
134 mdb
.past_wr_clk
.push_back(Const(State::Sx
));
135 mdb
.past_wr_en
.push_back(Const(State::Sx
, GetSize(port
.en
)));
136 mdb
.past_wr_addr
.push_back(Const(State::Sx
, GetSize(port
.addr
)));
137 mdb
.past_wr_data
.push_back(Const(State::Sx
, GetSize(port
.data
)));
139 mdb
.data
= mem
.get_init_data();
142 for (auto cell
: module
->cells())
144 Module
*mod
= module
->design
->module(cell
->type
);
146 if (mod
!= nullptr) {
147 dirty_children
.insert(new SimInstance(shared
, mod
, cell
, this));
150 for (auto &port
: cell
->connections()) {
151 if (cell
->input(port
.first
))
152 for (auto bit
: sigmap(port
.second
)) {
153 upd_cells
[bit
].insert(cell
);
154 // Make sure cell inputs connected to constants are updated in the first cycle
155 if (bit
.wire
== nullptr)
156 dirty_bits
.insert(bit
);
160 if (cell
->type
.in(ID($dff
))) {
162 ff
.past_clock
= State::Sx
;
163 ff
.past_d
= Const(State::Sx
, cell
->getParam(ID::WIDTH
).as_int());
164 ff_database
[cell
] = ff
;
167 if (cell
->type
.in(ID($mem
), ID($meminit
), ID($memwr
), ID($memrd
)))
169 mem_cells
[cell
] = cell
->parameters
.at(ID::MEMID
).decode_string();
171 if (cell
->type
.in(ID($
assert), ID($cover
), ID($assume
))) {
172 formal_database
.insert(cell
);
178 for (auto &it
: ff_database
)
180 Cell
*cell
= it
.first
;
181 ff_state_t
&ff
= it
.second
;
184 SigSpec qsig
= cell
->getPort(ID::Q
);
185 Const qdata
= get_state(qsig
);
187 set_state(qsig
, qdata
);
190 for (auto &it
: mem_database
) {
191 mem_state_t
&mem
= it
.second
;
192 for (auto &val
: 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_cells
.count(cell
))
266 dirty_memories
.insert(mem_cells
[cell
]);
270 if (children
.count(cell
))
272 auto child
= children
.at(cell
);
273 for (auto &conn
: cell
->connections())
274 if (cell
->input(conn
.first
)) {
275 Const value
= get_state(conn
.second
);
276 child
->set_state(child
->module
->wire(conn
.first
), value
);
278 dirty_children
.insert(child
);
282 if (yosys_celltypes
.cell_evaluable(cell
->type
))
284 RTLIL::SigSpec sig_a
, sig_b
, sig_c
, sig_d
, sig_s
, sig_y
;
285 bool has_a
, has_b
, has_c
, has_d
, has_s
, has_y
;
287 has_a
= cell
->hasPort(ID::A
);
288 has_b
= cell
->hasPort(ID::B
);
289 has_c
= cell
->hasPort(ID::C
);
290 has_d
= cell
->hasPort(ID::D
);
291 has_s
= cell
->hasPort(ID::S
);
292 has_y
= cell
->hasPort(ID::Y
);
294 if (has_a
) sig_a
= cell
->getPort(ID::A
);
295 if (has_b
) sig_b
= cell
->getPort(ID::B
);
296 if (has_c
) sig_c
= cell
->getPort(ID::C
);
297 if (has_d
) sig_d
= cell
->getPort(ID::D
);
298 if (has_s
) sig_s
= cell
->getPort(ID::S
);
299 if (has_y
) sig_y
= cell
->getPort(ID::Y
);
302 log("[%s] eval %s (%s)\n", hiername().c_str(), log_id(cell
), log_id(cell
->type
));
304 // Simple (A -> Y) and (A,B -> Y) cells
305 if (has_a
&& !has_c
&& !has_d
&& !has_s
&& has_y
) {
306 set_state(sig_y
, CellTypes::eval(cell
, get_state(sig_a
), get_state(sig_b
)));
310 // (A,B,C -> Y) cells
311 if (has_a
&& has_b
&& has_c
&& !has_d
&& !has_s
&& has_y
) {
312 set_state(sig_y
, CellTypes::eval(cell
, get_state(sig_a
), get_state(sig_b
), get_state(sig_c
)));
316 // (A,B,S -> Y) cells
317 if (has_a
&& has_b
&& !has_c
&& !has_d
&& has_s
&& has_y
) {
318 set_state(sig_y
, CellTypes::eval(cell
, get_state(sig_a
), get_state(sig_b
), get_state(sig_s
)));
322 log_warning("Unsupported evaluable cell type: %s (%s.%s)\n", log_id(cell
->type
), log_id(module
), log_id(cell
));
326 log_error("Unsupported cell type: %s (%s.%s)\n", log_id(cell
->type
), log_id(module
), log_id(cell
));
329 void update_memory(IdString id
) {
330 auto &mdb
= mem_database
[id
];
331 auto &mem
= *mdb
.mem
;
333 for (int port_idx
= 0; port_idx
< GetSize(mem
.rd_ports
); port_idx
++)
335 auto &port
= mem
.rd_ports
[port_idx
];
336 Const addr
= get_state(port
.addr
);
337 Const data
= Const(State::Sx
, mem
.width
);
340 log_error("Memory %s.%s has clocked read ports. Run 'memory' with -nordff.\n", log_id(module
), log_id(mem
.memid
));
342 if (addr
.is_fully_def()) {
343 int index
= addr
.as_int() - mem
.start_offset
;
344 if (index
>= 0 && index
< mem
.size
)
345 data
= mdb
.data
.extract(index
*mem
.width
, mem
.width
);
348 set_state(port
.data
, data
);
354 pool
<Cell
*> queue_cells
;
355 pool
<Wire
*> queue_outports
;
357 queue_cells
.swap(dirty_cells
);
361 for (auto bit
: dirty_bits
)
363 if (upd_cells
.count(bit
))
364 for (auto cell
: upd_cells
.at(bit
))
365 queue_cells
.insert(cell
);
367 if (upd_outports
.count(bit
) && parent
!= nullptr)
368 for (auto wire
: upd_outports
.at(bit
))
369 queue_outports
.insert(wire
);
374 if (!queue_cells
.empty())
376 for (auto cell
: queue_cells
)
383 for (auto &memid
: dirty_memories
)
384 update_memory(memid
);
385 dirty_memories
.clear();
387 for (auto wire
: queue_outports
)
388 if (instance
->hasPort(wire
->name
)) {
389 Const value
= get_state(wire
);
390 parent
->set_state(instance
->getPort(wire
->name
), value
);
393 queue_outports
.clear();
395 for (auto child
: dirty_children
)
398 dirty_children
.clear();
400 if (dirty_bits
.empty())
407 bool did_something
= false;
409 for (auto &it
: ff_database
)
411 Cell
*cell
= it
.first
;
412 ff_state_t
&ff
= it
.second
;
414 if (cell
->type
.in(ID($dff
)))
416 bool clkpol
= cell
->getParam(ID::CLK_POLARITY
).as_bool();
417 State current_clock
= get_state(cell
->getPort(ID::CLK
))[0];
419 if (clkpol
? (ff
.past_clock
== State::S1
|| current_clock
!= State::S1
) :
420 (ff
.past_clock
== State::S0
|| current_clock
!= State::S0
))
423 if (set_state(cell
->getPort(ID::Q
), ff
.past_d
))
424 did_something
= true;
428 for (auto &it
: mem_database
)
430 mem_state_t
&mdb
= it
.second
;
431 auto &mem
= *mdb
.mem
;
433 for (int port_idx
= 0; port_idx
< GetSize(mem
.wr_ports
); port_idx
++)
435 auto &port
= mem
.wr_ports
[port_idx
];
436 Const addr
, data
, enable
;
438 if (!port
.clk_enable
)
440 addr
= get_state(port
.addr
);
441 data
= get_state(port
.data
);
442 enable
= get_state(port
.en
);
446 if (port
.clk_polarity
?
447 (mdb
.past_wr_clk
[port_idx
] == State::S1
|| get_state(port
.clk
) != State::S1
) :
448 (mdb
.past_wr_clk
[port_idx
] == State::S0
|| get_state(port
.clk
) != State::S0
))
451 addr
= mdb
.past_wr_addr
[port_idx
];
452 data
= mdb
.past_wr_data
[port_idx
];
453 enable
= mdb
.past_wr_en
[port_idx
];
456 if (addr
.is_fully_def())
458 int index
= addr
.as_int() - mem
.start_offset
;
459 if (index
>= 0 && index
< mem
.size
)
460 for (int i
= 0; i
< mem
.width
; i
++)
461 if (enable
[i
] == State::S1
&& mdb
.data
.bits
.at(index
*mem
.width
+i
) != data
[i
]) {
462 mdb
.data
.bits
.at(index
*mem
.width
+i
) = data
[i
];
463 dirty_memories
.insert(mem
.memid
);
464 did_something
= true;
470 for (auto it
: children
)
471 if (it
.second
->update_ph2()) {
472 dirty_children
.insert(it
.second
);
473 did_something
= true;
476 return did_something
;
481 for (auto &it
: ff_database
)
483 Cell
*cell
= it
.first
;
484 ff_state_t
&ff
= it
.second
;
486 if (cell
->type
.in(ID($dff
))) {
487 ff
.past_clock
= get_state(cell
->getPort(ID::CLK
))[0];
488 ff
.past_d
= get_state(cell
->getPort(ID::D
));
492 for (auto &it
: mem_database
)
494 mem_state_t
&mem
= it
.second
;
496 for (int i
= 0; i
< GetSize(mem
.mem
->wr_ports
); i
++) {
497 auto &port
= mem
.mem
->wr_ports
[i
];
498 mem
.past_wr_clk
[i
] = get_state(port
.clk
);
499 mem
.past_wr_en
[i
] = get_state(port
.en
);
500 mem
.past_wr_addr
[i
] = get_state(port
.addr
);
501 mem
.past_wr_data
[i
] = get_state(port
.data
);
505 for (auto cell
: formal_database
)
507 string label
= log_id(cell
);
508 if (cell
->attributes
.count(ID::src
))
509 label
= cell
->attributes
.at(ID::src
).decode_string();
511 State a
= get_state(cell
->getPort(ID::A
))[0];
512 State en
= get_state(cell
->getPort(ID::EN
))[0];
514 if (cell
->type
== ID($cover
) && en
== State::S1
&& a
!= State::S1
)
515 log("Cover %s.%s (%s) reached.\n", hiername().c_str(), log_id(cell
), label
.c_str());
517 if (cell
->type
== ID($assume
) && en
== State::S1
&& a
!= State::S1
)
518 log("Assumption %s.%s (%s) failed.\n", hiername().c_str(), log_id(cell
), label
.c_str());
520 if (cell
->type
== ID($
assert) && en
== State::S1
&& a
!= State::S1
)
521 log_warning("Assert %s.%s (%s) failed.\n", hiername().c_str(), log_id(cell
), label
.c_str());
524 for (auto it
: children
)
525 it
.second
->update_ph3();
528 void writeback(pool
<Module
*> &wbmods
)
530 if (wbmods
.count(module
))
531 log_error("Instance %s of module %s is not unique: Writeback not possible. (Fix by running 'uniquify'.)\n", hiername().c_str(), log_id(module
));
533 wbmods
.insert(module
);
535 for (auto wire
: module
->wires())
536 wire
->attributes
.erase(ID::init
);
538 for (auto &it
: ff_database
)
540 Cell
*cell
= it
.first
;
541 SigSpec sig_q
= cell
->getPort(ID::Q
);
542 Const initval
= get_state(sig_q
);
544 for (int i
= 0; i
< GetSize(sig_q
); i
++)
546 Wire
*w
= sig_q
[i
].wire
;
548 if (w
->attributes
.count(ID::init
) == 0)
549 w
->attributes
[ID::init
] = Const(State::Sx
, GetSize(w
));
551 w
->attributes
[ID::init
][sig_q
[i
].offset
] = initval
[i
];
555 for (auto &it
: mem_database
)
557 mem_state_t
&mem
= it
.second
;
558 mem
.mem
->clear_inits();
560 minit
.addr
= mem
.mem
->start_offset
;
561 minit
.data
= mem
.data
;
562 mem
.mem
->inits
.push_back(minit
);
566 for (auto it
: children
)
567 it
.second
->writeback(wbmods
);
570 void write_vcd_header(std::ofstream
&f
, int &id
)
572 f
<< stringf("$scope module %s $end\n", log_id(name()));
574 for (auto wire
: module
->wires())
576 if (shared
->hide_internal
&& wire
->name
[0] == '$')
579 f
<< stringf("$var wire %d n%d %s%s $end\n", GetSize(wire
), id
, wire
->name
[0] == '$' ? "\\" : "", log_id(wire
));
580 vcd_database
[wire
] = make_pair(id
++, Const());
583 for (auto child
: children
)
584 child
.second
->write_vcd_header(f
, id
);
586 f
<< stringf("$upscope $end\n");
589 void write_vcd_step(std::ofstream
&f
)
591 for (auto &it
: vcd_database
)
593 Wire
*wire
= it
.first
;
594 Const value
= get_state(wire
);
595 int id
= it
.second
.first
;
597 if (it
.second
.second
== value
)
600 it
.second
.second
= value
;
603 for (int i
= GetSize(value
)-1; i
>= 0; i
--) {
605 case State::S0
: f
<< "0"; break;
606 case State::S1
: f
<< "1"; break;
607 case State::Sx
: f
<< "x"; break;
612 f
<< stringf(" n%d\n", id
);
615 for (auto child
: children
)
616 child
.second
->write_vcd_step(f
);
620 struct SimWorker
: SimShared
622 SimInstance
*top
= nullptr;
623 std::ofstream vcdfile
;
624 pool
<IdString
> clock
, clockn
, reset
, resetn
;
625 std::string timescale
;
632 void write_vcd_header()
634 if (!vcdfile
.is_open())
637 vcdfile
<< stringf("$version %s $end\n", yosys_version_str
);
639 std::time_t t
= std::time(nullptr);
641 if (std::strftime(mbstr
, sizeof(mbstr
), "%c", std::localtime(&t
))) {
642 vcdfile
<< stringf("$date ") << mbstr
<< stringf(" $end\n");
645 if (!timescale
.empty())
646 vcdfile
<< stringf("$timescale %s $end\n", timescale
.c_str());
649 top
->write_vcd_header(vcdfile
, id
);
651 vcdfile
<< stringf("$enddefinitions $end\n");
654 void write_vcd_step(int t
)
656 if (!vcdfile
.is_open())
659 vcdfile
<< stringf("#%d\n", t
);
660 top
->write_vcd_step(vcdfile
);
668 log("\n-- ph1 --\n");
673 log("\n-- ph2 --\n");
675 if (!top
->update_ph2())
680 log("\n-- ph3 --\n");
685 void set_inports(pool
<IdString
> ports
, State value
)
687 for (auto portname
: ports
)
689 Wire
*w
= top
->module
->wire(portname
);
692 log_error("Can't find port %s on module %s.\n", log_id(portname
), log_id(top
->module
));
694 top
->set_state(w
, value
);
698 void run(Module
*topmod
, int numcycles
)
700 log_assert(top
== nullptr);
701 top
= new SimInstance(this, topmod
);
704 log("\n===== 0 =====\n");
706 log("Simulating cycle 0.\n");
708 set_inports(reset
, State::S1
);
709 set_inports(resetn
, State::S0
);
711 set_inports(clock
, State::Sx
);
712 set_inports(clockn
, State::Sx
);
719 for (int cycle
= 0; cycle
< numcycles
; cycle
++)
722 log("\n===== %d =====\n", 10*cycle
+ 5);
724 set_inports(clock
, State::S0
);
725 set_inports(clockn
, State::S1
);
728 write_vcd_step(10*cycle
+ 5);
731 log("\n===== %d =====\n", 10*cycle
+ 10);
733 log("Simulating cycle %d.\n", cycle
+1);
735 set_inports(clock
, State::S1
);
736 set_inports(clockn
, State::S0
);
738 if (cycle
+1 == rstlen
) {
739 set_inports(reset
, State::S0
);
740 set_inports(resetn
, State::S1
);
744 write_vcd_step(10*cycle
+ 10);
747 write_vcd_step(10*numcycles
+ 2);
750 pool
<Module
*> wbmods
;
751 top
->writeback(wbmods
);
756 struct SimPass
: public Pass
{
757 SimPass() : Pass("sim", "simulate the circuit") { }
760 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
762 log(" sim [options] [top-level]\n");
764 log("This command simulates the circuit using the given top-level module.\n");
766 log(" -vcd <filename>\n");
767 log(" write the simulation results to the given VCD file\n");
769 log(" -clock <portname>\n");
770 log(" name of top-level clock input\n");
772 log(" -clockn <portname>\n");
773 log(" name of top-level clock input (inverse polarity)\n");
775 log(" -reset <portname>\n");
776 log(" name of top-level reset input (active high)\n");
778 log(" -resetn <portname>\n");
779 log(" name of top-level inverted reset input (active low)\n");
781 log(" -rstlen <integer>\n");
782 log(" number of cycles reset should stay active (default: 1)\n");
785 log(" zero-initialize all uninitialized regs and memories\n");
787 log(" -timescale <string>\n");
788 log(" include the specified timescale declaration in the vcd\n");
790 log(" -n <integer>\n");
791 log(" number of cycles to simulate (default: 20)\n");
794 log(" include all nets in VCD output, not just those with public names\n");
797 log(" writeback mode: use final simulation state as new init state\n");
800 log(" enable debug output\n");
803 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) override
808 log_header(design
, "Executing SIM pass (simulate the circuit).\n");
811 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
812 if (args
[argidx
] == "-vcd" && argidx
+1 < args
.size()) {
813 std::string vcd_filename
= args
[++argidx
];
814 rewrite_filename(vcd_filename
);
815 worker
.vcdfile
.open(vcd_filename
.c_str());
818 if (args
[argidx
] == "-n" && argidx
+1 < args
.size()) {
819 numcycles
= atoi(args
[++argidx
].c_str());
822 if (args
[argidx
] == "-rstlen" && argidx
+1 < args
.size()) {
823 worker
.rstlen
= atoi(args
[++argidx
].c_str());
826 if (args
[argidx
] == "-clock" && argidx
+1 < args
.size()) {
827 worker
.clock
.insert(RTLIL::escape_id(args
[++argidx
]));
830 if (args
[argidx
] == "-clockn" && argidx
+1 < args
.size()) {
831 worker
.clockn
.insert(RTLIL::escape_id(args
[++argidx
]));
834 if (args
[argidx
] == "-reset" && argidx
+1 < args
.size()) {
835 worker
.reset
.insert(RTLIL::escape_id(args
[++argidx
]));
838 if (args
[argidx
] == "-resetn" && argidx
+1 < args
.size()) {
839 worker
.resetn
.insert(RTLIL::escape_id(args
[++argidx
]));
842 if (args
[argidx
] == "-timescale" && argidx
+1 < args
.size()) {
843 worker
.timescale
= args
[++argidx
];
846 if (args
[argidx
] == "-a") {
847 worker
.hide_internal
= false;
850 if (args
[argidx
] == "-d") {
854 if (args
[argidx
] == "-w") {
855 worker
.writeback
= true;
858 if (args
[argidx
] == "-zinit") {
864 extra_args(args
, argidx
, design
);
866 Module
*top_mod
= nullptr;
868 if (design
->full_selection()) {
869 top_mod
= design
->top_module();
872 log_cmd_error("Design has no top module, use the 'hierarchy' command to specify one.\n");
874 auto mods
= design
->selected_whole_modules();
875 if (GetSize(mods
) != 1)
876 log_cmd_error("Only one top module must be selected.\n");
877 top_mod
= mods
.front();
880 worker
.run(top_mod
, numcycles
);
884 PRIVATE_NAMESPACE_END