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
;
160 dict
<IdString
, dict
<int,fstHandle
>> fst_memories
;
162 SimInstance(SimShared
*shared
, std::string scope
, Module
*module
, Cell
*instance
= nullptr, SimInstance
*parent
= nullptr) :
163 shared(shared
), scope(scope
), module(module
), instance(instance
), parent(parent
), sigmap(module
)
168 log_assert(parent
->children
.count(instance
) == 0);
169 parent
->children
[instance
] = this;
172 for (auto wire
: module
->wires())
174 SigSpec sig
= sigmap(wire
);
176 for (int i
= 0; i
< GetSize(sig
); i
++) {
177 if (state_nets
.count(sig
[i
]) == 0)
178 state_nets
[sig
[i
]] = State::Sx
;
179 if (wire
->port_output
) {
180 upd_outports
[sig
[i
]].insert(wire
);
181 dirty_bits
.insert(sig
[i
]);
185 if ((shared
->fst
) && !(shared
->hide_internal
&& wire
->name
[0] == '$')) {
186 fstHandle id
= shared
->fst
->getHandle(scope
+ "." + RTLIL::unescape_id(wire
->name
));
187 if (id
==0 && wire
->name
.isPublic())
188 log_warning("Unable to find wire %s in input file.\n", (scope
+ "." + RTLIL::unescape_id(wire
->name
)).c_str());
189 fst_handles
[wire
] = id
;
192 if (wire
->attributes
.count(ID::init
)) {
193 Const initval
= wire
->attributes
.at(ID::init
);
194 for (int i
= 0; i
< GetSize(sig
) && i
< GetSize(initval
); i
++)
195 if (initval
[i
] == State::S0
|| initval
[i
] == State::S1
) {
196 state_nets
[sig
[i
]] = initval
[i
];
197 dirty_bits
.insert(sig
[i
]);
202 memories
= Mem::get_all_memories(module
);
203 for (auto &mem
: memories
) {
204 auto &mdb
= mem_database
[mem
.memid
];
206 for (auto &port
: mem
.wr_ports
) {
207 mdb
.past_wr_clk
.push_back(Const(State::Sx
));
208 mdb
.past_wr_en
.push_back(Const(State::Sx
, GetSize(port
.en
)));
209 mdb
.past_wr_addr
.push_back(Const(State::Sx
, GetSize(port
.addr
)));
210 mdb
.past_wr_data
.push_back(Const(State::Sx
, GetSize(port
.data
)));
212 mdb
.data
= mem
.get_init_data();
215 for (auto cell
: module
->cells())
217 Module
*mod
= module
->design
->module(cell
->type
);
219 if (mod
!= nullptr) {
220 dirty_children
.insert(new SimInstance(shared
, scope
+ "." + RTLIL::unescape_id(cell
->name
), mod
, cell
, this));
223 for (auto &port
: cell
->connections()) {
224 if (cell
->input(port
.first
))
225 for (auto bit
: sigmap(port
.second
)) {
226 upd_cells
[bit
].insert(cell
);
227 // Make sure cell inputs connected to constants are updated in the first cycle
228 if (bit
.wire
== nullptr)
229 dirty_bits
.insert(bit
);
233 if (RTLIL::builtin_ff_cell_types().count(cell
->type
)) {
234 FfData
ff_data(nullptr, cell
);
236 ff
.past_d
= Const(State::Sx
, ff_data
.width
);
237 ff
.past_ad
= Const(State::Sx
, ff_data
.width
);
238 ff
.past_clk
= State::Sx
;
239 ff
.past_ce
= State::Sx
;
240 ff
.past_srst
= State::Sx
;
242 ff_database
[cell
] = ff
;
245 if (cell
->is_mem_cell())
247 std::string name
= cell
->parameters
.at(ID::MEMID
).decode_string();
248 mem_cells
[cell
] = name
;
250 fst_memories
[name
] = shared
->fst
->getMemoryHandles(scope
+ "." + RTLIL::unescape_id(name
));
252 if (cell
->type
.in(ID($
assert), ID($cover
), ID($assume
))) {
253 formal_database
.insert(cell
);
259 for (auto &it
: ff_database
)
261 ff_state_t
&ff
= it
.second
;
265 SigSpec qsig
= it
.second
.data
.sig_q
;
266 Const qdata
= get_state(qsig
);
268 set_state(qsig
, qdata
);
271 for (auto &it
: mem_database
) {
272 mem_state_t
&mem
= it
.second
;
273 for (auto &val
: mem
.past_wr_en
)
282 for (auto child
: children
)
286 IdString
name() const
288 if (instance
!= nullptr)
289 return instance
->name
;
293 std::string
hiername() const
295 if (instance
!= nullptr)
296 return parent
->hiername() + "." + log_id(instance
->name
);
298 return log_id(module
->name
);
301 Const
get_state(SigSpec sig
)
305 for (auto bit
: sigmap(sig
))
306 if (bit
.wire
== nullptr)
307 value
.bits
.push_back(bit
.data
);
308 else if (state_nets
.count(bit
))
309 value
.bits
.push_back(state_nets
.at(bit
));
311 value
.bits
.push_back(State::Sz
);
314 log("[%s] get %s: %s\n", hiername().c_str(), log_signal(sig
), log_signal(value
));
318 bool set_state(SigSpec sig
, Const value
)
320 bool did_something
= false;
323 log_assert(GetSize(sig
) <= GetSize(value
));
325 for (int i
= 0; i
< GetSize(sig
); i
++)
326 if (state_nets
.at(sig
[i
]) != value
[i
]) {
327 state_nets
.at(sig
[i
]) = value
[i
];
328 dirty_bits
.insert(sig
[i
]);
329 did_something
= true;
333 log("[%s] set %s: %s\n", hiername().c_str(), log_signal(sig
), log_signal(value
));
334 return did_something
;
337 void set_memory_state(IdString memid
, Const addr
, Const data
)
339 auto &state
= mem_database
[memid
];
341 int offset
= (addr
.as_int() - state
.mem
->start_offset
) * state
.mem
->width
;
342 for (int i
= 0; i
< GetSize(data
); i
++)
343 if (0 <= i
+offset
&& i
+offset
< state
.mem
->size
* state
.mem
->width
)
344 state
.data
.bits
[i
+offset
] = data
.bits
[i
];
347 void set_memory_state_bit(IdString memid
, int offset
, State data
)
349 auto &state
= mem_database
[memid
];
350 if (offset
>= state
.mem
->size
* state
.mem
->width
)
351 log_error("Addressing out of bounds bit %d/%d of memory %s\n", offset
, state
.mem
->size
* state
.mem
->width
, log_id(memid
));
352 state
.data
.bits
[offset
] = data
;
355 void update_cell(Cell
*cell
)
357 if (ff_database
.count(cell
))
360 if (formal_database
.count(cell
))
363 if (mem_cells
.count(cell
))
365 dirty_memories
.insert(mem_cells
[cell
]);
369 if (children
.count(cell
))
371 auto child
= children
.at(cell
);
372 for (auto &conn
: cell
->connections())
373 if (cell
->input(conn
.first
) && GetSize(conn
.second
)) {
374 Const value
= get_state(conn
.second
);
375 child
->set_state(child
->module
->wire(conn
.first
), value
);
377 dirty_children
.insert(child
);
381 if (yosys_celltypes
.cell_evaluable(cell
->type
))
383 RTLIL::SigSpec sig_a
, sig_b
, sig_c
, sig_d
, sig_s
, sig_y
;
384 bool has_a
, has_b
, has_c
, has_d
, has_s
, has_y
;
386 has_a
= cell
->hasPort(ID::A
);
387 has_b
= cell
->hasPort(ID::B
);
388 has_c
= cell
->hasPort(ID::C
);
389 has_d
= cell
->hasPort(ID::D
);
390 has_s
= cell
->hasPort(ID::S
);
391 has_y
= cell
->hasPort(ID::Y
);
393 if (has_a
) sig_a
= cell
->getPort(ID::A
);
394 if (has_b
) sig_b
= cell
->getPort(ID::B
);
395 if (has_c
) sig_c
= cell
->getPort(ID::C
);
396 if (has_d
) sig_d
= cell
->getPort(ID::D
);
397 if (has_s
) sig_s
= cell
->getPort(ID::S
);
398 if (has_y
) sig_y
= cell
->getPort(ID::Y
);
401 log("[%s] eval %s (%s)\n", hiername().c_str(), log_id(cell
), log_id(cell
->type
));
403 // Simple (A -> Y) and (A,B -> Y) cells
404 if (has_a
&& !has_c
&& !has_d
&& !has_s
&& has_y
) {
405 set_state(sig_y
, CellTypes::eval(cell
, get_state(sig_a
), get_state(sig_b
)));
409 // (A,B,C -> Y) cells
410 if (has_a
&& has_b
&& has_c
&& !has_d
&& !has_s
&& has_y
) {
411 set_state(sig_y
, CellTypes::eval(cell
, get_state(sig_a
), get_state(sig_b
), get_state(sig_c
)));
416 if (has_a
&& !has_b
&& !has_c
&& !has_d
&& has_s
&& has_y
) {
417 set_state(sig_y
, CellTypes::eval(cell
, get_state(sig_a
), get_state(sig_s
)));
421 // (A,B,S -> Y) cells
422 if (has_a
&& has_b
&& !has_c
&& !has_d
&& has_s
&& has_y
) {
423 set_state(sig_y
, CellTypes::eval(cell
, get_state(sig_a
), get_state(sig_b
), get_state(sig_s
)));
427 log_warning("Unsupported evaluable cell type: %s (%s.%s)\n", log_id(cell
->type
), log_id(module
), log_id(cell
));
431 log_error("Unsupported cell type: %s (%s.%s)\n", log_id(cell
->type
), log_id(module
), log_id(cell
));
434 void update_memory(IdString id
) {
435 auto &mdb
= mem_database
[id
];
436 auto &mem
= *mdb
.mem
;
438 for (int port_idx
= 0; port_idx
< GetSize(mem
.rd_ports
); port_idx
++)
440 auto &port
= mem
.rd_ports
[port_idx
];
441 Const addr
= get_state(port
.addr
);
442 Const data
= Const(State::Sx
, mem
.width
<< port
.wide_log2
);
445 log_error("Memory %s.%s has clocked read ports. Run 'memory' with -nordff.\n", log_id(module
), log_id(mem
.memid
));
447 if (addr
.is_fully_def()) {
448 int index
= addr
.as_int() - mem
.start_offset
;
449 if (index
>= 0 && index
< mem
.size
)
450 data
= mdb
.data
.extract(index
*mem
.width
, mem
.width
<< port
.wide_log2
);
453 set_state(port
.data
, data
);
459 pool
<Cell
*> queue_cells
;
460 pool
<Wire
*> queue_outports
;
462 queue_cells
.swap(dirty_cells
);
466 for (auto bit
: dirty_bits
)
468 if (upd_cells
.count(bit
))
469 for (auto cell
: upd_cells
.at(bit
))
470 queue_cells
.insert(cell
);
472 if (upd_outports
.count(bit
) && parent
!= nullptr)
473 for (auto wire
: upd_outports
.at(bit
))
474 queue_outports
.insert(wire
);
479 if (!queue_cells
.empty())
481 for (auto cell
: queue_cells
)
488 for (auto &memid
: dirty_memories
)
489 update_memory(memid
);
490 dirty_memories
.clear();
492 for (auto wire
: queue_outports
)
493 if (instance
->hasPort(wire
->name
)) {
494 Const value
= get_state(wire
);
495 parent
->set_state(instance
->getPort(wire
->name
), value
);
498 queue_outports
.clear();
500 for (auto child
: dirty_children
)
503 dirty_children
.clear();
505 if (dirty_bits
.empty())
512 bool did_something
= false;
514 for (auto &it
: ff_database
)
516 ff_state_t
&ff
= it
.second
;
517 FfData
&ff_data
= ff
.data
;
519 Const current_q
= get_state(ff
.data
.sig_q
);
521 if (ff_data
.has_clk
) {
523 State current_clk
= get_state(ff_data
.sig_clk
)[0];
524 if (ff_data
.pol_clk
? (ff
.past_clk
== State::S0
&& current_clk
!= State::S0
) :
525 (ff
.past_clk
== State::S1
&& current_clk
!= State::S1
)) {
526 bool ce
= ff
.past_ce
== (ff_data
.pol_ce
? State::S1
: State::S0
);
527 // set if no ce, or ce is enabled
528 if (!ff_data
.has_ce
|| (ff_data
.has_ce
&& ce
)) {
529 current_q
= ff
.past_d
;
531 // override if sync reset
532 if ((ff_data
.has_srst
) && (ff
.past_srst
== (ff_data
.pol_srst
? State::S1
: State::S0
)) &&
533 ((!ff_data
.ce_over_srst
) || (ff_data
.ce_over_srst
&& ce
))) {
534 current_q
= ff_data
.val_srst
;
539 if (ff_data
.has_aload
) {
540 State current_aload
= get_state(ff_data
.sig_aload
)[0];
541 if (current_aload
== (ff_data
.pol_aload
? State::S1
: State::S0
)) {
542 current_q
= ff_data
.has_clk
? ff
.past_ad
: get_state(ff
.data
.sig_ad
);
546 if (ff_data
.has_arst
) {
547 State current_arst
= get_state(ff_data
.sig_arst
)[0];
548 if (current_arst
== (ff_data
.pol_arst
? State::S1
: State::S0
)) {
549 current_q
= ff_data
.val_arst
;
553 if (ff
.data
.has_sr
) {
554 Const current_clr
= get_state(ff
.data
.sig_clr
);
555 Const current_set
= get_state(ff
.data
.sig_set
);
557 for(int i
=0;i
<ff
.past_d
.size();i
++) {
558 if (current_clr
[i
] == (ff_data
.pol_clr
? State::S1
: State::S0
)) {
559 current_q
[i
] = State::S0
;
561 else if (current_set
[i
] == (ff_data
.pol_set
? State::S1
: State::S0
)) {
562 current_q
[i
] = State::S1
;
566 if (ff_data
.has_gclk
) {
568 current_q
= ff
.past_d
;
570 if (set_state(ff_data
.sig_q
, current_q
))
571 did_something
= true;
574 for (auto &it
: mem_database
)
576 mem_state_t
&mdb
= it
.second
;
577 auto &mem
= *mdb
.mem
;
579 for (int port_idx
= 0; port_idx
< GetSize(mem
.wr_ports
); port_idx
++)
581 auto &port
= mem
.wr_ports
[port_idx
];
582 Const addr
, data
, enable
;
584 if (!port
.clk_enable
)
586 addr
= get_state(port
.addr
);
587 data
= get_state(port
.data
);
588 enable
= get_state(port
.en
);
592 if (port
.clk_polarity
?
593 (mdb
.past_wr_clk
[port_idx
] == State::S1
|| get_state(port
.clk
) != State::S1
) :
594 (mdb
.past_wr_clk
[port_idx
] == State::S0
|| get_state(port
.clk
) != State::S0
))
597 addr
= mdb
.past_wr_addr
[port_idx
];
598 data
= mdb
.past_wr_data
[port_idx
];
599 enable
= mdb
.past_wr_en
[port_idx
];
602 if (addr
.is_fully_def())
604 int index
= addr
.as_int() - mem
.start_offset
;
605 if (index
>= 0 && index
< mem
.size
)
606 for (int i
= 0; i
< (mem
.width
<< port
.wide_log2
); i
++)
607 if (enable
[i
] == State::S1
&& mdb
.data
.bits
.at(index
*mem
.width
+i
) != data
[i
]) {
608 mdb
.data
.bits
.at(index
*mem
.width
+i
) = data
[i
];
609 dirty_memories
.insert(mem
.memid
);
610 did_something
= true;
616 for (auto it
: children
)
617 if (it
.second
->update_ph2()) {
618 dirty_children
.insert(it
.second
);
619 did_something
= true;
622 return did_something
;
627 for (auto &it
: ff_database
)
629 ff_state_t
&ff
= it
.second
;
631 if (ff
.data
.has_aload
)
632 ff
.past_ad
= get_state(ff
.data
.sig_ad
);
634 if (ff
.data
.has_clk
|| ff
.data
.has_gclk
)
635 ff
.past_d
= get_state(ff
.data
.sig_d
);
638 ff
.past_clk
= get_state(ff
.data
.sig_clk
)[0];
641 ff
.past_ce
= get_state(ff
.data
.sig_ce
)[0];
643 if (ff
.data
.has_srst
)
644 ff
.past_srst
= get_state(ff
.data
.sig_srst
)[0];
647 for (auto &it
: mem_database
)
649 mem_state_t
&mem
= it
.second
;
651 for (int i
= 0; i
< GetSize(mem
.mem
->wr_ports
); i
++) {
652 auto &port
= mem
.mem
->wr_ports
[i
];
653 mem
.past_wr_clk
[i
] = get_state(port
.clk
);
654 mem
.past_wr_en
[i
] = get_state(port
.en
);
655 mem
.past_wr_addr
[i
] = get_state(port
.addr
);
656 mem
.past_wr_data
[i
] = get_state(port
.data
);
660 for (auto cell
: formal_database
)
662 string label
= log_id(cell
);
663 if (cell
->attributes
.count(ID::src
))
664 label
= cell
->attributes
.at(ID::src
).decode_string();
666 State a
= get_state(cell
->getPort(ID::A
))[0];
667 State en
= get_state(cell
->getPort(ID::EN
))[0];
669 if (cell
->type
== ID($cover
) && en
== State::S1
&& a
!= State::S1
)
670 log("Cover %s.%s (%s) reached.\n", hiername().c_str(), log_id(cell
), label
.c_str());
672 if (cell
->type
== ID($assume
) && en
== State::S1
&& a
!= State::S1
)
673 log("Assumption %s.%s (%s) failed.\n", hiername().c_str(), log_id(cell
), label
.c_str());
675 if (cell
->type
== ID($
assert) && en
== State::S1
&& a
!= State::S1
)
676 log_warning("Assert %s.%s (%s) failed.\n", hiername().c_str(), log_id(cell
), label
.c_str());
679 for (auto it
: children
)
680 it
.second
->update_ph3();
683 void writeback(pool
<Module
*> &wbmods
)
685 if (wbmods
.count(module
))
686 log_error("Instance %s of module %s is not unique: Writeback not possible. (Fix by running 'uniquify'.)\n", hiername().c_str(), log_id(module
));
688 wbmods
.insert(module
);
690 for (auto wire
: module
->wires())
691 wire
->attributes
.erase(ID::init
);
693 for (auto &it
: ff_database
)
695 SigSpec sig_q
= it
.second
.data
.sig_q
;
696 Const initval
= get_state(sig_q
);
698 for (int i
= 0; i
< GetSize(sig_q
); i
++)
700 Wire
*w
= sig_q
[i
].wire
;
702 if (w
->attributes
.count(ID::init
) == 0)
703 w
->attributes
[ID::init
] = Const(State::Sx
, GetSize(w
));
705 w
->attributes
[ID::init
][sig_q
[i
].offset
] = initval
[i
];
709 for (auto &it
: mem_database
)
711 mem_state_t
&mem
= it
.second
;
712 mem
.mem
->clear_inits();
714 minit
.addr
= mem
.mem
->start_offset
;
715 minit
.data
= mem
.data
;
716 minit
.en
= Const(State::S1
, mem
.mem
->width
);
717 mem
.mem
->inits
.push_back(minit
);
721 for (auto it
: children
)
722 it
.second
->writeback(wbmods
);
725 void register_signals(int &id
)
727 for (auto wire
: module
->wires())
729 if (shared
->hide_internal
&& wire
->name
[0] == '$')
732 signal_database
[wire
] = make_pair(id
, Const());
736 for (auto child
: children
)
737 child
.second
->register_signals(id
);
740 void write_output_header(std::function
<void(IdString
)> enter_scope
, std::function
<void()> exit_scope
, std::function
<void(Wire
*, int, bool)> register_signal
)
744 dict
<Wire
*,bool> registers
;
745 for (auto cell
: module
->cells())
747 if (RTLIL::builtin_ff_cell_types().count(cell
->type
)) {
748 FfData
ff_data(nullptr, cell
);
749 SigSpec q
= sigmap(ff_data
.sig_q
);
750 if (q
.is_wire() && signal_database
.count(q
.as_wire()) != 0) {
751 registers
[q
.as_wire()] = true;
756 for (auto signal
: signal_database
)
758 register_signal(signal
.first
, signal
.second
.first
, registers
.count(signal
.first
)!=0);
761 for (auto child
: children
)
762 child
.second
->write_output_header(enter_scope
, exit_scope
, register_signal
);
767 void register_output_step_values(std::map
<int,Const
> *data
)
769 for (auto &it
: signal_database
)
771 Wire
*wire
= it
.first
;
772 Const value
= get_state(wire
);
773 int id
= it
.second
.first
;
775 if (it
.second
.second
== value
)
778 it
.second
.second
= value
;
779 data
->emplace(id
, value
);
782 for (auto child
: children
)
783 child
.second
->register_output_step_values(data
);
788 bool did_something
= false;
789 for(auto &item
: fst_handles
) {
790 if (item
.second
==0) continue; // Ignore signals not found
791 std::string v
= shared
->fst
->valueOf(item
.second
);
792 did_something
|= set_state(item
.first
, Const::from_string(v
));
794 for (auto &it
: ff_database
)
796 ff_state_t
&ff
= it
.second
;
797 SigSpec dsig
= it
.second
.data
.sig_d
;
798 Const value
= get_state(dsig
);
799 if (dsig
.is_wire()) {
801 if (ff
.data
.has_aload
)
803 did_something
|= true;
806 for (auto cell
: module
->cells())
808 if (cell
->is_mem_cell()) {
809 std::string memid
= cell
->parameters
.at(ID::MEMID
).decode_string();
810 for (auto &data
: fst_memories
[memid
])
812 std::string v
= shared
->fst
->valueOf(data
.second
);
813 set_memory_state(memid
, Const(data
.first
), Const::from_string(v
));
818 for (auto child
: children
)
819 did_something
|= child
.second
->setInitState();
820 return did_something
;
823 void addAdditionalInputs(std::map
<Wire
*,fstHandle
> &inputs
)
825 for (auto cell
: module
->cells())
827 if (cell
->type
.in(ID($anyseq
))) {
828 SigSpec sig_y
= sigmap(cell
->getPort(ID::Y
));
829 if (sig_y
.is_wire()) {
831 for(auto &item
: fst_handles
) {
832 if (item
.second
==0) continue; // Ignore signals not found
833 if (sig_y
== sigmap(item
.first
)) {
834 inputs
[sig_y
.as_wire()] = item
.second
;
840 log_error("Unable to find required '%s' signal in file\n",(scope
+ "." + RTLIL::unescape_id(sig_y
.as_wire()->name
)).c_str());
844 for (auto child
: children
)
845 child
.second
->addAdditionalInputs(inputs
);
848 void setState(dict
<int, std::pair
<SigBit
,bool>> bits
, std::string values
)
850 for(auto bit
: bits
) {
851 if (bit
.first
>= GetSize(values
))
852 log_error("Too few input data bits in file.\n");
853 switch(values
.at(bit
.first
)) {
854 case '0': set_state(bit
.second
.first
, bit
.second
.second
? State::S1
: State::S0
); break;
855 case '1': set_state(bit
.second
.first
, bit
.second
.second
? State::S0
: State::S1
); break;
856 default: set_state(bit
.second
.first
, State::Sx
); break;
861 void setMemState(dict
<int, std::pair
<std::string
,int>> bits
, std::string values
)
863 for(auto bit
: bits
) {
864 if (bit
.first
>= GetSize(values
))
865 log_error("Too few input data bits in file.\n");
866 switch(values
.at(bit
.first
)) {
867 case '0': set_memory_state_bit(bit
.second
.first
, bit
.second
.second
, State::S0
); break;
868 case '1': set_memory_state_bit(bit
.second
.first
, bit
.second
.second
, State::S1
); break;
869 default: set_memory_state_bit(bit
.second
.first
, bit
.second
.second
, State::Sx
); break;
877 for(auto &item
: fst_handles
) {
878 if (item
.second
==0) continue; // Ignore signals not found
879 Const fst_val
= Const::from_string(shared
->fst
->valueOf(item
.second
));
880 Const sim_val
= get_state(item
.first
);
881 if (sim_val
.size()!=fst_val
.size()) {
882 log_warning("Signal '%s.%s' size is different in gold and gate.\n", scope
.c_str(), log_id(item
.first
));
885 if (shared
->sim_mode
== SimulationMode::sim
) {
886 // No checks performed when using stimulus
887 } else if (shared
->sim_mode
== SimulationMode::gate
&& !fst_val
.is_fully_def()) { // FST data contains X
888 for(int i
=0;i
<fst_val
.size();i
++) {
889 if (fst_val
[i
]!=State::Sx
&& fst_val
[i
]!=sim_val
[i
]) {
890 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
));
895 } else if (shared
->sim_mode
== SimulationMode::gold
&& !sim_val
.is_fully_def()) { // sim data contains X
896 for(int i
=0;i
<sim_val
.size();i
++) {
897 if (sim_val
[i
]!=State::Sx
&& fst_val
[i
]!=sim_val
[i
]) {
898 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
));
904 if (fst_val
!=sim_val
) {
905 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
));
910 for (auto child
: children
)
911 retVal
|= child
.second
->checkSignals();
916 struct SimWorker
: SimShared
918 SimInstance
*top
= nullptr;
919 pool
<IdString
> clock
, clockn
, reset
, resetn
;
920 std::string timescale
;
921 std::string sim_filename
;
922 std::string map_filename
;
931 void register_signals()
934 top
->register_signals(id
);
937 void register_output_step(int t
)
939 std::map
<int,Const
> data
;
940 top
->register_output_step_values(&data
);
941 output_data
.emplace_back(t
, data
);
944 void write_output_files()
946 std::map
<int, bool> use_signal
;
947 bool first
= ignore_x
;
948 for(auto& d
: output_data
)
951 for (auto &data
: d
.second
)
952 use_signal
[data
.first
] = !data
.second
.is_fully_undef();
955 for (auto &data
: d
.second
)
956 use_signal
[data
.first
] = true;
958 if (!ignore_x
) break;
960 for(auto& writer
: outputfiles
)
961 writer
->write(use_signal
);
969 log("\n-- ph1 --\n");
974 log("\n-- ph2 --\n");
976 if (!top
->update_ph2())
981 log("\n-- ph3 --\n");
986 void set_inports(pool
<IdString
> ports
, State value
)
988 for (auto portname
: ports
)
990 Wire
*w
= top
->module
->wire(portname
);
993 log_error("Can't find port %s on module %s.\n", log_id(portname
), log_id(top
->module
));
995 top
->set_state(w
, value
);
999 void run(Module
*topmod
, int numcycles
)
1001 log_assert(top
== nullptr);
1002 top
= new SimInstance(this, scope
, topmod
);
1006 log("\n===== 0 =====\n");
1008 log("Simulating cycle 0.\n");
1010 set_inports(reset
, State::S1
);
1011 set_inports(resetn
, State::S0
);
1013 set_inports(clock
, State::Sx
);
1014 set_inports(clockn
, State::Sx
);
1018 register_output_step(0);
1020 for (int cycle
= 0; cycle
< numcycles
; cycle
++)
1023 log("\n===== %d =====\n", 10*cycle
+ 5);
1025 log("Simulating cycle %d.\n", (cycle
*2)+1);
1026 set_inports(clock
, State::S0
);
1027 set_inports(clockn
, State::S1
);
1030 register_output_step(10*cycle
+ 5);
1033 log("\n===== %d =====\n", 10*cycle
+ 10);
1035 log("Simulating cycle %d.\n", (cycle
*2)+2);
1037 set_inports(clock
, State::S1
);
1038 set_inports(clockn
, State::S0
);
1040 if (cycle
+1 == rstlen
) {
1041 set_inports(reset
, State::S0
);
1042 set_inports(resetn
, State::S1
);
1046 register_output_step(10*cycle
+ 10);
1049 register_output_step(10*numcycles
+ 2);
1051 write_output_files();
1054 pool
<Module
*> wbmods
;
1055 top
->writeback(wbmods
);
1059 void run_cosim_fst(Module
*topmod
, int numcycles
)
1061 log_assert(top
== nullptr);
1062 fst
= new FstData(sim_filename
);
1065 log_error("Scope must be defined for co-simulation.\n");
1067 top
= new SimInstance(this, scope
, topmod
);
1070 std::vector
<fstHandle
> fst_clock
;
1072 for (auto portname
: clock
)
1074 Wire
*w
= topmod
->wire(portname
);
1076 log_error("Can't find port %s on module %s.\n", log_id(portname
), log_id(top
->module
));
1078 log_error("Clock port %s on module %s is not input.\n", log_id(portname
), log_id(top
->module
));
1079 fstHandle id
= fst
->getHandle(scope
+ "." + RTLIL::unescape_id(portname
));
1081 log_error("Can't find port %s.%s in FST.\n", scope
.c_str(), log_id(portname
));
1082 fst_clock
.push_back(id
);
1084 for (auto portname
: clockn
)
1086 Wire
*w
= topmod
->wire(portname
);
1088 log_error("Can't find port %s on module %s.\n", log_id(portname
), log_id(top
->module
));
1090 log_error("Clock port %s on module %s is not input.\n", log_id(portname
), log_id(top
->module
));
1091 fstHandle id
= fst
->getHandle(scope
+ "." + RTLIL::unescape_id(portname
));
1093 log_error("Can't find port %s.%s in FST.\n", scope
.c_str(), log_id(portname
));
1094 fst_clock
.push_back(id
);
1097 SigMap
sigmap(topmod
);
1098 std::map
<Wire
*,fstHandle
> inputs
;
1100 for (auto wire
: topmod
->wires()) {
1101 if (wire
->port_input
) {
1102 fstHandle id
= fst
->getHandle(scope
+ "." + RTLIL::unescape_id(wire
->name
));
1104 log_error("Unable to find required '%s' signal in file\n",(scope
+ "." + RTLIL::unescape_id(wire
->name
)).c_str());
1109 top
->addAdditionalInputs(inputs
);
1111 uint64_t startCount
= 0;
1112 uint64_t stopCount
= 0;
1113 if (start_time
==0) {
1114 if (start_time
< fst
->getStartTime())
1115 log_warning("Start time is before simulation file start time\n");
1116 startCount
= fst
->getStartTime();
1117 } else if (start_time
==-1)
1118 startCount
= fst
->getEndTime();
1120 startCount
= start_time
/ fst
->getTimescale();
1121 if (startCount
> fst
->getEndTime()) {
1122 startCount
= fst
->getEndTime();
1123 log_warning("Start time is after simulation file end time\n");
1127 if (stop_time
< fst
->getStartTime())
1128 log_warning("Stop time is before simulation file start time\n");
1129 stopCount
= fst
->getStartTime();
1130 } else if (stop_time
==-1)
1131 stopCount
= fst
->getEndTime();
1133 stopCount
= stop_time
/ fst
->getTimescale();
1134 if (stopCount
> fst
->getEndTime()) {
1135 stopCount
= fst
->getEndTime();
1136 log_warning("Stop time is after simulation file end time\n");
1139 if (stopCount
<startCount
) {
1140 log_error("Stop time is before start time\n");
1143 bool initial
= true;
1145 log("Co-simulation from %lu%s to %lu%s", (unsigned long)startCount
, fst
->getTimescaleString(), (unsigned long)stopCount
, fst
->getTimescaleString());
1147 log(" for %d clock cycle(s)",numcycles
);
1149 bool all_samples
= fst_clock
.empty();
1152 fst
->reconstructAllAtTimes(fst_clock
, startCount
, stopCount
, [&](uint64_t time
) {
1154 log("Co-simulating %s %d [%lu%s].\n", (all_samples
? "sample" : "cycle"), cycle
, (unsigned long)time
, fst
->getTimescaleString());
1155 bool did_something
= false;
1156 for(auto &item
: inputs
) {
1157 std::string v
= fst
->valueOf(item
.second
);
1158 did_something
|= top
->set_state(item
.first
, Const::from_string(v
));
1162 did_something
|= top
->setInitState();
1167 register_output_step(time
);
1169 bool status
= top
->checkSignals();
1171 log_error("Signal difference\n");
1174 // Limit to number of cycles if provided
1175 if (cycles_set
&& cycle
> numcycles
*2)
1176 throw fst_end_of_data_exception();
1177 if (time
==stopCount
)
1178 throw fst_end_of_data_exception();
1180 } catch(fst_end_of_data_exception
) {
1181 // end of data detected
1184 write_output_files();
1187 pool
<Module
*> wbmods
;
1188 top
->writeback(wbmods
);
1193 std::string
cell_name(std::string
const & name
)
1195 size_t pos
= name
.find_last_of("[");
1196 if (pos
!=std::string::npos
)
1197 return name
.substr(0, pos
);
1201 int mem_cell_addr(std::string
const & name
)
1203 size_t pos
= name
.find_last_of("[");
1204 return atoi(name
.substr(pos
+1).c_str());
1207 void run_cosim_aiger_witness(Module
*topmod
)
1209 log_assert(top
== nullptr);
1210 if (!multiclock
&& (clock
.size()+clockn
.size())==0)
1211 log_error("Clock signal must be specified.\n");
1212 if (multiclock
&& (clock
.size()+clockn
.size())>0)
1213 log_error("For multiclock witness there should be no clock signal.\n");
1215 top
= new SimInstance(this, scope
, topmod
);
1218 std::ifstream
mf(map_filename
);
1219 std::string type
, symbol
;
1220 int variable
, index
;
1221 dict
<int, std::pair
<SigBit
,bool>> inputs
, inits
, latches
;
1222 dict
<int, std::pair
<std::string
,int>> mem_inits
, mem_latches
;
1224 log_cmd_error("Not able to read AIGER witness map file.\n");
1225 while (mf
>> type
>> variable
>> index
>> symbol
) {
1226 RTLIL::IdString escaped_s
= RTLIL::escape_id(symbol
);
1227 Wire
*w
= topmod
->wire(escaped_s
);
1229 escaped_s
= RTLIL::escape_id(cell_name(symbol
));
1230 Cell
*c
= topmod
->cell(escaped_s
);
1232 log_warning("Wire/cell %s not present in module %s\n",symbol
.c_str(),log_id(topmod
));
1234 if (c
->is_mem_cell()) {
1235 std::string memid
= c
->parameters
.at(ID::MEMID
).decode_string();
1236 auto &state
= top
->mem_database
[memid
];
1238 int offset
= (mem_cell_addr(symbol
) - state
.mem
->start_offset
) * state
.mem
->width
+ index
;
1240 mem_inits
[variable
] = { memid
, offset
};
1241 else if (type
== "latch")
1242 mem_latches
[variable
] = { memid
, offset
};
1244 log_error("Map file addressing cell %s as type %s\n", symbol
.c_str(), type
.c_str());
1246 log_error("Cell %s in map file is not memory cell\n", symbol
.c_str());
1249 if (index
< w
->start_offset
|| index
> w
->start_offset
+ w
->width
)
1250 log_error("Index %d for wire %s is out of range\n", index
, log_signal(w
));
1251 if (type
== "input") {
1252 inputs
[variable
] = {SigBit(w
,index
-w
->start_offset
), false};
1253 } else if (type
== "init") {
1254 inits
[variable
] = {SigBit(w
,index
-w
->start_offset
), false};
1255 } else if (type
== "latch") {
1256 latches
[variable
] = {SigBit(w
,index
-w
->start_offset
), false};
1257 } else if (type
== "invlatch") {
1258 latches
[variable
] = {SigBit(w
,index
-w
->start_offset
), true};
1264 f
.open(sim_filename
.c_str());
1265 if (f
.fail() || GetSize(sim_filename
) == 0)
1266 log_error("Can not open file `%s`\n", sim_filename
.c_str());
1275 std::getline(f
, line
);
1276 if (line
.size()==0 || line
[0]=='#' || line
[0]=='c' || line
[0]=='f' || line
[0]=='u') continue;
1277 if (line
[0]=='.') break;
1278 if (state
==0 && line
.size()!=1) {
1279 // old format detected, latch data
1282 if (state
==1 && line
[0]!='b' && line
[0]!='j') {
1283 // was old format but with 1 bit latch
1284 top
->setState(latches
, status
);
1298 top
->setState(latches
, line
);
1299 top
->setMemState(mem_latches
, line
);
1304 log("Simulating cycle %d.\n", cycle
);
1305 top
->setState(inputs
, line
);
1307 set_inports(clock
, State::S1
);
1308 set_inports(clockn
, State::S0
);
1310 top
->setState(inits
, line
);
1311 top
->setMemState(mem_inits
, line
);
1312 set_inports(clock
, State::S0
);
1313 set_inports(clockn
, State::S1
);
1316 register_output_step(10*cycle
);
1317 if (!multiclock
&& cycle
) {
1318 set_inports(clock
, State::S0
);
1319 set_inports(clockn
, State::S1
);
1321 register_output_step(10*cycle
+ 5);
1327 register_output_step(10*cycle
);
1328 write_output_files();
1331 std::vector
<std::string
> split(std::string text
, const char *delim
)
1333 std::vector
<std::string
> list
;
1334 char *p
= strdup(text
.c_str());
1335 char *t
= strtok(p
, delim
);
1338 t
= strtok(NULL
, delim
);
1344 std::string
signal_name(std::string
const & name
)
1346 size_t pos
= name
.find_first_of("@");
1347 if (pos
==std::string::npos
) {
1348 pos
= name
.find_first_of("#");
1349 if (pos
==std::string::npos
)
1350 log_error("Line does not contain proper signal name `%s`\n", name
.c_str());
1352 return name
.substr(0, pos
);
1355 void run_cosim_btor2_witness(Module
*topmod
)
1357 log_assert(top
== nullptr);
1358 if (!multiclock
&& (clock
.size()+clockn
.size())==0)
1359 log_error("Clock signal must be specified.\n");
1360 if (multiclock
&& (clock
.size()+clockn
.size())>0)
1361 log_error("For multiclock witness there should be no clock signal.\n");
1363 f
.open(sim_filename
.c_str());
1364 if (f
.fail() || GetSize(sim_filename
) == 0)
1365 log_error("Can not open file `%s`\n", sim_filename
.c_str());
1369 top
= new SimInstance(this, scope
, topmod
);
1373 std::vector
<std::string
> parts
;
1378 std::getline(f
, line
);
1379 if (line
.size()==0) continue;
1381 if (line
[0]=='#' || line
[0]=='@' || line
[0]=='.') {
1383 curr_cycle
= atoi(line
.c_str()+1);
1385 curr_cycle
= -1; // force detect change
1387 if (curr_cycle
!= prev_cycle
) {
1389 log("Simulating cycle %d.\n", cycle
);
1390 set_inports(clock
, State::S1
);
1391 set_inports(clockn
, State::S0
);
1393 register_output_step(10*cycle
+0);
1395 set_inports(clock
, State::S0
);
1396 set_inports(clockn
, State::S1
);
1398 register_output_step(10*cycle
+5);
1401 prev_cycle
= curr_cycle
;
1403 if (line
[0]=='.') break;
1414 if (line
[0]=='b' || line
[0]=='j')
1417 log_error("Line does not contain property.\n");
1419 default: // set state or inputs
1420 parts
= split(line
, " ");
1423 log_error("Invalid set state line content.\n");
1425 RTLIL::IdString escaped_s
= RTLIL::escape_id(signal_name(parts
[len
-1]));
1427 Wire
*w
= topmod
->wire(escaped_s
);
1429 Cell
*c
= topmod
->cell(escaped_s
);
1431 log_warning("Wire/cell %s not present in module %s\n",log_id(escaped_s
),log_id(topmod
));
1432 else if (c
->type
.in(ID($anyconst
), ID($anyseq
))) {
1433 SigSpec sig_y
= c
->getPort(ID::Y
);
1434 if ((int)parts
[1].size() != GetSize(sig_y
))
1435 log_error("Size of wire %s is different than provided data.\n", log_signal(sig_y
));
1436 top
->set_state(sig_y
, Const::from_string(parts
[1]));
1439 if ((int)parts
[1].size() != w
->width
)
1440 log_error("Size of wire %s is different than provided data.\n", log_signal(w
));
1441 top
->set_state(w
, Const::from_string(parts
[1]));
1444 Cell
*c
= topmod
->cell(escaped_s
);
1446 log_error("Cell %s not present in module %s\n",log_id(escaped_s
),log_id(topmod
));
1447 if (!c
->is_mem_cell())
1448 log_error("Cell %s is not memory cell in module %s\n",log_id(escaped_s
),log_id(topmod
));
1450 Const addr
= Const::from_string(parts
[1].substr(1,parts
[1].size()-2));
1451 Const data
= Const::from_string(parts
[2]);
1452 top
->set_memory_state(c
->parameters
.at(ID::MEMID
).decode_string(), addr
, data
);
1457 register_output_step(10*cycle
);
1458 write_output_files();
1461 std::string
define_signal(Wire
*wire
)
1463 std::stringstream f
;
1466 f
<< stringf("%s", RTLIL::unescape_id(wire
->name
).c_str());
1469 f
<< stringf("[%d:%d] %s", wire
->start_offset
, wire
->width
- 1 + wire
->start_offset
, RTLIL::unescape_id(wire
->name
).c_str());
1471 f
<< stringf("[%d:%d] %s", wire
->width
- 1 + wire
->start_offset
, wire
->start_offset
, RTLIL::unescape_id(wire
->name
).c_str());
1475 std::string
signal_list(std::map
<Wire
*,fstHandle
> &signals
)
1477 std::stringstream f
;
1478 for(auto item
=signals
.begin();item
!=signals
.end();item
++)
1479 f
<< stringf("%c%s", (item
==signals
.begin() ? ' ' : ','), RTLIL::unescape_id(item
->first
->name
).c_str());
1483 void generate_tb(Module
*topmod
, std::string tb_filename
, int numcycles
)
1485 fst
= new FstData(sim_filename
);
1488 log_error("Scope must be defined for co-simulation.\n");
1490 if ((clock
.size()+clockn
.size())==0)
1491 log_error("Clock signal must be specified.\n");
1493 std::vector
<fstHandle
> fst_clock
;
1494 std::map
<Wire
*,fstHandle
> clocks
;
1496 for (auto portname
: clock
)
1498 Wire
*w
= topmod
->wire(portname
);
1500 log_error("Can't find port %s on module %s.\n", log_id(portname
), log_id(top
->module
));
1502 log_error("Clock port %s on module %s is not input.\n", log_id(portname
), log_id(top
->module
));
1503 fstHandle id
= fst
->getHandle(scope
+ "." + RTLIL::unescape_id(portname
));
1505 log_error("Can't find port %s.%s in FST.\n", scope
.c_str(), log_id(portname
));
1506 fst_clock
.push_back(id
);
1509 for (auto portname
: clockn
)
1511 Wire
*w
= topmod
->wire(portname
);
1513 log_error("Can't find port %s on module %s.\n", log_id(portname
), log_id(top
->module
));
1515 log_error("Clock port %s on module %s is not input.\n", log_id(portname
), log_id(top
->module
));
1516 fstHandle id
= fst
->getHandle(scope
+ "." + RTLIL::unescape_id(portname
));
1518 log_error("Can't find port %s.%s in FST.\n", scope
.c_str(), log_id(portname
));
1519 fst_clock
.push_back(id
);
1523 SigMap
sigmap(topmod
);
1524 std::map
<Wire
*,fstHandle
> inputs
;
1525 std::map
<Wire
*,fstHandle
> outputs
;
1527 for (auto wire
: topmod
->wires()) {
1528 fstHandle id
= fst
->getHandle(scope
+ "." + RTLIL::unescape_id(wire
->name
));
1529 if (id
==0 && (wire
->port_input
|| wire
->port_output
))
1530 log_error("Unable to find required '%s' signal in file\n",(scope
+ "." + RTLIL::unescape_id(wire
->name
)).c_str());
1531 if (wire
->port_input
)
1532 if (clocks
.find(wire
)==clocks
.end())
1534 if (wire
->port_output
)
1538 uint64_t startCount
= 0;
1539 uint64_t stopCount
= 0;
1540 if (start_time
==0) {
1541 if (start_time
< fst
->getStartTime())
1542 log_warning("Start time is before simulation file start time\n");
1543 startCount
= fst
->getStartTime();
1544 } else if (start_time
==-1)
1545 startCount
= fst
->getEndTime();
1547 startCount
= start_time
/ fst
->getTimescale();
1548 if (startCount
> fst
->getEndTime()) {
1549 startCount
= fst
->getEndTime();
1550 log_warning("Start time is after simulation file end time\n");
1554 if (stop_time
< fst
->getStartTime())
1555 log_warning("Stop time is before simulation file start time\n");
1556 stopCount
= fst
->getStartTime();
1557 } else if (stop_time
==-1)
1558 stopCount
= fst
->getEndTime();
1560 stopCount
= stop_time
/ fst
->getTimescale();
1561 if (stopCount
> fst
->getEndTime()) {
1562 stopCount
= fst
->getEndTime();
1563 log_warning("Stop time is after simulation file end time\n");
1566 if (stopCount
<startCount
) {
1567 log_error("Stop time is before start time\n");
1571 log("Generate testbench data from %lu%s to %lu%s", (unsigned long)startCount
, fst
->getTimescaleString(), (unsigned long)stopCount
, fst
->getTimescaleString());
1573 log(" for %d clock cycle(s)",numcycles
);
1576 std::stringstream f
;
1577 f
<< stringf("`timescale 1%s/1%s\n", fst
->getTimescaleString(),fst
->getTimescaleString());
1578 f
<< stringf("module %s();\n",tb_filename
.c_str());
1581 int outputs_len
= 0;
1582 for(auto &item
: clocks
) {
1583 clk_len
+= item
.first
->width
;
1584 f
<< "\treg " << define_signal(item
.first
) << ";\n";
1586 for(auto &item
: inputs
) {
1587 inputs_len
+= item
.first
->width
;
1588 f
<< "\treg " << define_signal(item
.first
) << ";\n";
1590 for(auto &item
: outputs
) {
1591 outputs_len
+= item
.first
->width
;
1592 f
<< "\twire " << define_signal(item
.first
) << ";\n";
1594 int data_len
= clk_len
+ inputs_len
+ outputs_len
+ 32;
1596 f
<< stringf("\t%s uut(",RTLIL::unescape_id(topmod
->name
).c_str());
1597 for(auto item
=clocks
.begin();item
!=clocks
.end();item
++)
1598 f
<< stringf("%c.%s(%s)", (item
==clocks
.begin() ? ' ' : ','), RTLIL::unescape_id(item
->first
->name
).c_str(), RTLIL::unescape_id(item
->first
->name
).c_str());
1599 for(auto &item
: inputs
)
1600 f
<< stringf(",.%s(%s)", RTLIL::unescape_id(item
.first
->name
).c_str(), RTLIL::unescape_id(item
.first
->name
).c_str());
1601 for(auto &item
: outputs
)
1602 f
<< stringf(",.%s(%s)", RTLIL::unescape_id(item
.first
->name
).c_str(), RTLIL::unescape_id(item
.first
->name
).c_str());
1605 f
<< "\tinteger i;\n";
1606 uint64_t prev_time
= startCount
;
1607 log("Writing data to `%s`\n", (tb_filename
+".txt").c_str());
1608 std::ofstream
data_file(tb_filename
+".txt");
1609 std::stringstream initstate
;
1611 fst
->reconstructAllAtTimes(fst_clock
, startCount
, stopCount
, [&](uint64_t time
) {
1612 for(auto &item
: clocks
)
1613 data_file
<< stringf("%s",fst
->valueOf(item
.second
).c_str());
1614 for(auto &item
: inputs
)
1615 data_file
<< stringf("%s",fst
->valueOf(item
.second
).c_str());
1616 for(auto &item
: outputs
)
1617 data_file
<< stringf("%s",fst
->valueOf(item
.second
).c_str());
1618 data_file
<< stringf("%s\n",Const(time
-prev_time
).as_string().c_str());
1620 if (time
==startCount
) {
1622 for(auto var
: fst
->getVars()) {
1623 if (var
.is_reg
&& !Const::from_string(fst
->valueOf(var
.id
).c_str()).is_fully_undef()) {
1624 if (var
.scope
== scope
) {
1625 initstate
<< stringf("\t\tuut.%s = %d'b%s;\n", var
.name
.c_str(), var
.width
, fst
->valueOf(var
.id
).c_str());
1626 } else if (var
.scope
.find(scope
+".")==0) {
1627 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());
1635 // Limit to number of cycles if provided
1636 if (cycles_set
&& cycle
> numcycles
*2)
1637 throw fst_end_of_data_exception();
1638 if (time
==stopCount
)
1639 throw fst_end_of_data_exception();
1641 } catch(fst_end_of_data_exception
) {
1642 // end of data detected
1645 f
<< stringf("\treg [0:%d] data [0:%d];\n", data_len
-1, cycle
-1);
1646 f
<< "\tinitial begin;\n";
1647 f
<< stringf("\t\t$dumpfile(\"%s\");\n",tb_filename
.c_str());
1648 f
<< stringf("\t\t$dumpvars(0,%s);\n",tb_filename
.c_str());
1649 f
<< initstate
.str();
1650 f
<< stringf("\t\t$readmemb(\"%s.txt\", data);\n",tb_filename
.c_str());
1652 f
<< stringf("\t\t#(data[0][%d:%d]);\n", data_len
-32, data_len
-1);
1653 f
<< stringf("\t\t{%s } = data[0][%d:%d];\n", signal_list(clocks
).c_str(), 0, clk_len
-1);
1654 f
<< stringf("\t\t{%s } <= data[0][%d:%d];\n", signal_list(inputs
).c_str(), clk_len
, clk_len
+inputs_len
-1);
1656 f
<< stringf("\t\tfor (i = 1; i < %d; i++) begin\n",cycle
);
1658 f
<< stringf("\t\t\t#(data[i][%d:%d]);\n", data_len
-32, data_len
-1);
1659 f
<< stringf("\t\t\t{%s } = data[i][%d:%d];\n", signal_list(clocks
).c_str(), 0, clk_len
-1);
1660 f
<< stringf("\t\t\t{%s } <= data[i][%d:%d];\n", signal_list(inputs
).c_str(), clk_len
, clk_len
+inputs_len
-1);
1662 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);
1663 f
<< "\t\t\t\t$error(\"Signal difference detected\\n\");\n";
1668 f
<< "\t\t$finish;\n";
1672 log("Writing testbench to `%s`\n", (tb_filename
+".v").c_str());
1673 std::ofstream
tb_file(tb_filename
+".v");
1680 struct VCDWriter
: public OutputWriter
1682 VCDWriter(SimWorker
*worker
, std::string filename
) : OutputWriter(worker
) {
1683 vcdfile
.open(filename
.c_str());
1686 void write(std::map
<int, bool> &use_signal
) override
1688 if (!vcdfile
.is_open()) return;
1689 vcdfile
<< stringf("$version %s $end\n", worker
->date
? yosys_version_str
: "Yosys");
1692 std::time_t t
= std::time(nullptr);
1694 if (std::strftime(mbstr
, sizeof(mbstr
), "%c", std::localtime(&t
))) {
1695 vcdfile
<< stringf("$date ") << mbstr
<< stringf(" $end\n");
1699 if (!worker
->timescale
.empty())
1700 vcdfile
<< stringf("$timescale %s $end\n", worker
->timescale
.c_str());
1702 worker
->top
->write_output_header(
1703 [this](IdString name
) { vcdfile
<< stringf("$scope module %s $end\n", log_id(name
)); },
1704 [this]() { vcdfile
<< stringf("$upscope $end\n");},
1705 [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
)); }
1708 vcdfile
<< stringf("$enddefinitions $end\n");
1710 for(auto& d
: worker
->output_data
)
1712 vcdfile
<< stringf("#%d\n", d
.first
);
1713 for (auto &data
: d
.second
)
1715 if (!use_signal
.at(data
.first
)) continue;
1716 Const value
= data
.second
;
1718 for (int i
= GetSize(value
)-1; i
>= 0; i
--) {
1720 case State::S0
: vcdfile
<< "0"; break;
1721 case State::S1
: vcdfile
<< "1"; break;
1722 case State::Sx
: vcdfile
<< "x"; break;
1723 default: vcdfile
<< "z";
1726 vcdfile
<< stringf(" n%d\n", data
.first
);
1731 std::ofstream vcdfile
;
1734 struct FSTWriter
: public OutputWriter
1736 FSTWriter(SimWorker
*worker
, std::string filename
) : OutputWriter(worker
) {
1737 fstfile
= (struct fstContext
*)fstWriterCreate(filename
.c_str(),1);
1740 virtual ~FSTWriter()
1742 fstWriterClose(fstfile
);
1745 void write(std::map
<int, bool> &use_signal
) override
1747 if (!fstfile
) return;
1748 std::time_t t
= std::time(nullptr);
1749 fstWriterSetVersion(fstfile
, worker
->date
? yosys_version_str
: "Yosys");
1751 fstWriterSetDate(fstfile
, asctime(std::localtime(&t
)));
1753 fstWriterSetDate(fstfile
, "");
1754 if (!worker
->timescale
.empty())
1755 fstWriterSetTimescaleFromString(fstfile
, worker
->timescale
.c_str());
1757 fstWriterSetPackType(fstfile
, FST_WR_PT_FASTLZ
);
1758 fstWriterSetRepackOnClose(fstfile
, 1);
1760 worker
->top
->write_output_header(
1761 [this](IdString name
) { fstWriterSetScope(fstfile
, FST_ST_VCD_MODULE
, stringf("%s",log_id(name
)).c_str(), nullptr); },
1762 [this]() { fstWriterSetUpscope(fstfile
); },
1763 [this,use_signal
](Wire
*wire
, int id
, bool is_reg
) {
1764 if (!use_signal
.at(id
)) return;
1765 fstHandle fst_id
= fstWriterCreateVar(fstfile
, is_reg
? FST_VT_VCD_REG
: FST_VT_VCD_WIRE
, FST_VD_IMPLICIT
, GetSize(wire
),
1766 stringf("%s%s", wire
->name
[0] == '$' ? "\\" : "", log_id(wire
)).c_str(), 0);
1768 mapping
.emplace(id
, fst_id
);
1772 for(auto& d
: worker
->output_data
)
1774 fstWriterEmitTimeChange(fstfile
, d
.first
);
1775 for (auto &data
: d
.second
)
1777 if (!use_signal
.at(data
.first
)) continue;
1778 Const value
= data
.second
;
1779 std::stringstream ss
;
1780 for (int i
= GetSize(value
)-1; i
>= 0; i
--) {
1782 case State::S0
: ss
<< "0"; break;
1783 case State::S1
: ss
<< "1"; break;
1784 case State::Sx
: ss
<< "x"; break;
1788 fstWriterEmitValueChange(fstfile
, mapping
[data
.first
], ss
.str().c_str());
1793 struct fstContext
*fstfile
= nullptr;
1794 std::map
<int,fstHandle
> mapping
;
1797 struct AIWWriter
: public OutputWriter
1799 AIWWriter(SimWorker
*worker
, std::string filename
) : OutputWriter(worker
) {
1800 aiwfile
.open(filename
.c_str());
1803 virtual ~AIWWriter()
1805 aiwfile
<< '.' << '\n';
1808 void write(std::map
<int, bool> &) override
1810 if (!aiwfile
.is_open()) return;
1811 if (worker
->map_filename
.empty())
1812 log_cmd_error("For AIGER witness file map parameter is mandatory.\n");
1814 std::ifstream
mf(worker
->map_filename
);
1815 std::string type
, symbol
;
1816 int variable
, index
;
1819 log_cmd_error("Not able to read AIGER witness map file.\n");
1820 while (mf
>> type
>> variable
>> index
>> symbol
) {
1821 RTLIL::IdString escaped_s
= RTLIL::escape_id(symbol
);
1822 Wire
*w
= worker
->top
->module
->wire(escaped_s
);
1824 log_error("Wire %s not present in module %s\n",log_id(escaped_s
),log_id(worker
->top
->module
));
1825 if (index
< w
->start_offset
|| index
> w
->start_offset
+ w
->width
)
1826 log_error("Index %d for wire %s is out of range\n", index
, log_signal(w
));
1827 if (type
== "input") {
1828 aiw_inputs
[variable
] = SigBit(w
,index
-w
->start_offset
);
1829 if (worker
->clock
.count(escaped_s
)) {
1830 clocks
[variable
] = true;
1832 if (worker
->clockn
.count(escaped_s
)) {
1833 clocks
[variable
] = false;
1835 max_input
= max(max_input
,variable
);
1836 } else if (type
== "init") {
1837 aiw_inits
[variable
] = SigBit(w
,index
-w
->start_offset
);
1838 max_input
= max(max_input
,variable
);
1839 } else if (type
== "latch") {
1840 aiw_latches
[variable
] = {SigBit(w
,index
-w
->start_offset
), false};
1841 } else if (type
== "invlatch") {
1842 aiw_latches
[variable
] = {SigBit(w
,index
-w
->start_offset
), true};
1846 worker
->top
->write_output_header(
1849 [this](Wire
*wire
, int id
, bool) { mapping
[wire
] = id
; }
1852 std::map
<int, Yosys::RTLIL::Const
> current
;
1854 for (auto iter
= worker
->output_data
.begin(); iter
!= std::prev(worker
->output_data
.end()); ++iter
)
1857 for (auto &data
: d
.second
)
1859 current
[data
.first
] = data
.second
;
1862 for (int i
= 0;; i
++)
1864 if (aiw_latches
.count(i
)) {
1875 for (auto it
: clocks
)
1877 auto val
= it
.second
? State::S1
: State::S0
;
1878 SigBit bit
= aiw_inputs
.at(it
.first
);
1879 auto v
= current
[mapping
[bit
.wire
]].bits
.at(bit
.offset
);
1885 for (int i
= 0; i
<= max_input
; i
++)
1887 if (aiw_inputs
.count(i
)) {
1888 SigBit bit
= aiw_inputs
.at(i
);
1889 auto v
= current
[mapping
[bit
.wire
]].bits
.at(bit
.offset
);
1896 if (aiw_inits
.count(i
)) {
1897 SigBit bit
= aiw_inits
.at(i
);
1898 auto v
= current
[mapping
[bit
.wire
]].bits
.at(bit
.offset
);
1911 std::ofstream aiwfile
;
1912 dict
<int, std::pair
<SigBit
, bool>> aiw_latches
;
1913 dict
<int, SigBit
> aiw_inputs
, aiw_inits
;
1914 dict
<int, bool> clocks
;
1915 std::map
<Wire
*,int> mapping
;
1918 struct SimPass
: public Pass
{
1919 SimPass() : Pass("sim", "simulate the circuit") { }
1920 void help() override
1922 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1924 log(" sim [options] [top-level]\n");
1926 log("This command simulates the circuit using the given top-level module.\n");
1928 log(" -vcd <filename>\n");
1929 log(" write the simulation results to the given VCD file\n");
1931 log(" -fst <filename>\n");
1932 log(" write the simulation results to the given FST file\n");
1934 log(" -aiw <filename>\n");
1935 log(" write the simulation results to an AIGER witness file\n");
1936 log(" (requires a *.aim file via -map)\n");
1939 log(" ignore constant x outputs in simulation file.\n");
1942 log(" include date and full version info in output.\n");
1944 log(" -clock <portname>\n");
1945 log(" name of top-level clock input\n");
1947 log(" -clockn <portname>\n");
1948 log(" name of top-level clock input (inverse polarity)\n");
1950 log(" -multiclock\n");
1951 log(" mark that witness file is multiclock.\n");
1953 log(" -reset <portname>\n");
1954 log(" name of top-level reset input (active high)\n");
1956 log(" -resetn <portname>\n");
1957 log(" name of top-level inverted reset input (active low)\n");
1959 log(" -rstlen <integer>\n");
1960 log(" number of cycles reset should stay active (default: 1)\n");
1963 log(" zero-initialize all uninitialized regs and memories\n");
1965 log(" -timescale <string>\n");
1966 log(" include the specified timescale declaration in the vcd\n");
1968 log(" -n <integer>\n");
1969 log(" number of clock cycles to simulate (default: 20)\n");
1972 log(" use all nets in VCD/FST operations, not just those with public names\n");
1975 log(" writeback mode: use final simulation state as new init state\n");
1978 log(" read simulation results file (file formats supported: FST, VCD, AIW and WIT)\n");
1979 log(" VCD support requires vcd2fst external tool to be present\n");
1981 log(" -map <filename>\n");
1982 log(" read file with port and latch symbols, needed for AIGER witness input\n");
1984 log(" -scope <name>\n");
1985 log(" scope of simulation top model\n");
1987 log(" -at <time>\n");
1988 log(" sets start and stop time\n");
1990 log(" -start <time>\n");
1991 log(" start co-simulation in arbitary time (default 0)\n");
1993 log(" -stop <time>\n");
1994 log(" stop co-simulation in arbitary time (default END)\n");
1997 log(" simulation with stimulus from FST (default)\n");
2000 log(" co-simulation expect exact match\n");
2002 log(" -sim-gold\n");
2003 log(" co-simulation, x in simulation can match any value in FST\n");
2005 log(" -sim-gate\n");
2006 log(" co-simulation, x in FST can match any value in simulation\n");
2009 log(" disable per-cycle/sample log message\n");
2012 log(" enable debug output\n");
2017 static std::string
file_base_name(std::string
const & path
)
2019 return path
.substr(path
.find_last_of("/\\") + 1);
2022 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) override
2026 bool start_set
= false, stop_set
= false, at_set
= false;
2028 log_header(design
, "Executing SIM pass (simulate the circuit).\n");
2031 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
2032 if (args
[argidx
] == "-vcd" && argidx
+1 < args
.size()) {
2033 std::string vcd_filename
= args
[++argidx
];
2034 rewrite_filename(vcd_filename
);
2035 worker
.outputfiles
.emplace_back(std::unique_ptr
<VCDWriter
>(new VCDWriter(&worker
, vcd_filename
.c_str())));
2038 if (args
[argidx
] == "-fst" && argidx
+1 < args
.size()) {
2039 std::string fst_filename
= args
[++argidx
];
2040 rewrite_filename(fst_filename
);
2041 worker
.outputfiles
.emplace_back(std::unique_ptr
<FSTWriter
>(new FSTWriter(&worker
, fst_filename
.c_str())));
2044 if (args
[argidx
] == "-aiw" && argidx
+1 < args
.size()) {
2045 std::string aiw_filename
= args
[++argidx
];
2046 rewrite_filename(aiw_filename
);
2047 worker
.outputfiles
.emplace_back(std::unique_ptr
<AIWWriter
>(new AIWWriter(&worker
, aiw_filename
.c_str())));
2050 if (args
[argidx
] == "-n" && argidx
+1 < args
.size()) {
2051 numcycles
= atoi(args
[++argidx
].c_str());
2052 worker
.cycles_set
= true;
2055 if (args
[argidx
] == "-rstlen" && argidx
+1 < args
.size()) {
2056 worker
.rstlen
= atoi(args
[++argidx
].c_str());
2059 if (args
[argidx
] == "-clock" && argidx
+1 < args
.size()) {
2060 worker
.clock
.insert(RTLIL::escape_id(args
[++argidx
]));
2063 if (args
[argidx
] == "-clockn" && argidx
+1 < args
.size()) {
2064 worker
.clockn
.insert(RTLIL::escape_id(args
[++argidx
]));
2067 if (args
[argidx
] == "-reset" && argidx
+1 < args
.size()) {
2068 worker
.reset
.insert(RTLIL::escape_id(args
[++argidx
]));
2071 if (args
[argidx
] == "-resetn" && argidx
+1 < args
.size()) {
2072 worker
.resetn
.insert(RTLIL::escape_id(args
[++argidx
]));
2075 if (args
[argidx
] == "-timescale" && argidx
+1 < args
.size()) {
2076 worker
.timescale
= args
[++argidx
];
2079 if (args
[argidx
] == "-a") {
2080 worker
.hide_internal
= false;
2083 if (args
[argidx
] == "-q") {
2084 worker
.verbose
= false;
2087 if (args
[argidx
] == "-d") {
2088 worker
.debug
= true;
2091 if (args
[argidx
] == "-w") {
2092 worker
.writeback
= true;
2095 if (args
[argidx
] == "-zinit") {
2096 worker
.zinit
= true;
2099 if (args
[argidx
] == "-r" && argidx
+1 < args
.size()) {
2100 std::string sim_filename
= args
[++argidx
];
2101 rewrite_filename(sim_filename
);
2102 worker
.sim_filename
= sim_filename
;
2105 if (args
[argidx
] == "-map" && argidx
+1 < args
.size()) {
2106 std::string map_filename
= args
[++argidx
];
2107 rewrite_filename(map_filename
);
2108 worker
.map_filename
= map_filename
;
2111 if (args
[argidx
] == "-scope" && argidx
+1 < args
.size()) {
2112 worker
.scope
= args
[++argidx
];
2115 if (args
[argidx
] == "-start" && argidx
+1 < args
.size()) {
2116 worker
.start_time
= stringToTime(args
[++argidx
]);
2120 if (args
[argidx
] == "-stop" && argidx
+1 < args
.size()) {
2121 worker
.stop_time
= stringToTime(args
[++argidx
]);
2125 if (args
[argidx
] == "-at" && argidx
+1 < args
.size()) {
2126 worker
.start_time
= stringToTime(args
[++argidx
]);
2127 worker
.stop_time
= worker
.start_time
;
2131 if (args
[argidx
] == "-sim") {
2132 worker
.sim_mode
= SimulationMode::sim
;
2135 if (args
[argidx
] == "-sim-cmp") {
2136 worker
.sim_mode
= SimulationMode::cmp
;
2139 if (args
[argidx
] == "-sim-gold") {
2140 worker
.sim_mode
= SimulationMode::gold
;
2143 if (args
[argidx
] == "-sim-gate") {
2144 worker
.sim_mode
= SimulationMode::gate
;
2147 if (args
[argidx
] == "-x") {
2148 worker
.ignore_x
= true;
2151 if (args
[argidx
] == "-date") {
2155 if (args
[argidx
] == "-multiclock") {
2156 worker
.multiclock
= true;
2161 extra_args(args
, argidx
, design
);
2162 if (at_set
&& (start_set
|| stop_set
|| worker
.cycles_set
))
2163 log_error("'at' option can only be defined separate of 'start','stop' and 'n'\n");
2164 if (stop_set
&& worker
.cycles_set
)
2165 log_error("'stop' and 'n' can only be used exclusively'\n");
2167 Module
*top_mod
= nullptr;
2169 if (design
->full_selection()) {
2170 top_mod
= design
->top_module();
2173 log_cmd_error("Design has no top module, use the 'hierarchy' command to specify one.\n");
2175 auto mods
= design
->selected_whole_modules();
2176 if (GetSize(mods
) != 1)
2177 log_cmd_error("Only one top module must be selected.\n");
2178 top_mod
= mods
.front();
2181 if (worker
.sim_filename
.empty())
2182 worker
.run(top_mod
, numcycles
);
2184 std::string filename_trim
= file_base_name(worker
.sim_filename
);
2185 if (filename_trim
.size() > 4 && ((filename_trim
.compare(filename_trim
.size()-4, std::string::npos
, ".fst") == 0) ||
2186 filename_trim
.compare(filename_trim
.size()-4, std::string::npos
, ".vcd") == 0)) {
2187 worker
.run_cosim_fst(top_mod
, numcycles
);
2188 } else if (filename_trim
.size() > 4 && filename_trim
.compare(filename_trim
.size()-4, std::string::npos
, ".aiw") == 0) {
2189 if (worker
.map_filename
.empty())
2190 log_cmd_error("For AIGER witness file map parameter is mandatory.\n");
2191 worker
.run_cosim_aiger_witness(top_mod
);
2192 } else if (filename_trim
.size() > 4 && filename_trim
.compare(filename_trim
.size()-4, std::string::npos
, ".wit") == 0) {
2193 worker
.run_cosim_btor2_witness(top_mod
);
2195 log_cmd_error("Unhandled extension for simulation input file `%s`.\n", worker
.sim_filename
.c_str());
2201 struct Fst2TbPass
: public Pass
{
2202 Fst2TbPass() : Pass("fst2tb", "generate testbench out of fst file") { }
2203 void help() override
2205 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
2207 log(" fst2tb [options] [top-level]\n");
2209 log("This command generates testbench for the circuit using the given top-level module\n");
2210 log("and simulus signal from FST file\n");
2212 log(" -tb <name>\n");
2213 log(" generated testbench name.\n");
2214 log(" files <name>.v and <name>.txt are created as result.\n");
2216 log(" -r <filename>\n");
2217 log(" read simulation FST file\n");
2219 log(" -clock <portname>\n");
2220 log(" name of top-level clock input\n");
2222 log(" -clockn <portname>\n");
2223 log(" name of top-level clock input (inverse polarity)\n");
2225 log(" -scope <name>\n");
2226 log(" scope of simulation top model\n");
2228 log(" -start <time>\n");
2229 log(" start co-simulation in arbitary time (default 0)\n");
2231 log(" -stop <time>\n");
2232 log(" stop co-simulation in arbitary time (default END)\n");
2234 log(" -n <integer>\n");
2235 log(" number of clock cycles to simulate (default: 20)\n");
2239 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) override
2243 bool stop_set
= false;
2244 std::string tb_filename
;
2246 log_header(design
, "Executing FST2FB pass.\n");
2249 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
2250 if (args
[argidx
] == "-clock" && argidx
+1 < args
.size()) {
2251 worker
.clock
.insert(RTLIL::escape_id(args
[++argidx
]));
2254 if (args
[argidx
] == "-clockn" && argidx
+1 < args
.size()) {
2255 worker
.clockn
.insert(RTLIL::escape_id(args
[++argidx
]));
2258 if (args
[argidx
] == "-r" && argidx
+1 < args
.size()) {
2259 std::string sim_filename
= args
[++argidx
];
2260 rewrite_filename(sim_filename
);
2261 worker
.sim_filename
= sim_filename
;
2264 if (args
[argidx
] == "-n" && argidx
+1 < args
.size()) {
2265 numcycles
= atoi(args
[++argidx
].c_str());
2266 worker
.cycles_set
= true;
2269 if (args
[argidx
] == "-scope" && argidx
+1 < args
.size()) {
2270 worker
.scope
= args
[++argidx
];
2273 if (args
[argidx
] == "-start" && argidx
+1 < args
.size()) {
2274 worker
.start_time
= stringToTime(args
[++argidx
]);
2277 if (args
[argidx
] == "-stop" && argidx
+1 < args
.size()) {
2278 worker
.stop_time
= stringToTime(args
[++argidx
]);
2282 if (args
[argidx
] == "-tb" && argidx
+1 < args
.size()) {
2283 tb_filename
= args
[++argidx
];
2288 extra_args(args
, argidx
, design
);
2289 if (stop_set
&& worker
.cycles_set
)
2290 log_error("'stop' and 'n' can only be used exclusively'\n");
2292 Module
*top_mod
= nullptr;
2294 if (design
->full_selection()) {
2295 top_mod
= design
->top_module();
2298 log_cmd_error("Design has no top module, use the 'hierarchy' command to specify one.\n");
2300 auto mods
= design
->selected_whole_modules();
2301 if (GetSize(mods
) != 1)
2302 log_cmd_error("Only one top module must be selected.\n");
2303 top_mod
= mods
.front();
2306 if (tb_filename
.empty())
2307 log_cmd_error("Testbench name must be defined.\n");
2309 if (worker
.sim_filename
.empty())
2310 log_cmd_error("Stimulus FST file must be defined.\n");
2312 worker
.generate_tb(top_mod
, tb_filename
, numcycles
);
2316 PRIVATE_NAMESPACE_END