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 bool hide_internal
= true;
72 bool writeback
= false;
75 FstData
*fst
= nullptr;
76 double start_time
= 0;
77 double stop_time
= -1;
78 SimulationMode sim_mode
= SimulationMode::sim
;
79 bool cycles_set
= false;
90 for (auto &bit
: v
.bits
)
103 dict
<Cell
*, SimInstance
*> children
;
106 dict
<SigBit
, State
> state_nets
;
107 dict
<SigBit
, pool
<Cell
*>> upd_cells
;
108 dict
<SigBit
, pool
<Wire
*>> upd_outports
;
110 pool
<SigBit
> dirty_bits
;
111 pool
<Cell
*> dirty_cells
;
112 pool
<IdString
> dirty_memories
;
113 pool
<SimInstance
*, hash_ptr_ops
> dirty_children
;
129 std::vector
<Const
> past_wr_clk
;
130 std::vector
<Const
> past_wr_en
;
131 std::vector
<Const
> past_wr_addr
;
132 std::vector
<Const
> past_wr_data
;
136 dict
<Cell
*, ff_state_t
> ff_database
;
137 dict
<IdString
, mem_state_t
> mem_database
;
138 pool
<Cell
*> formal_database
;
139 dict
<Cell
*, IdString
> mem_cells
;
141 std::vector
<Mem
> memories
;
143 dict
<Wire
*, pair
<int, Const
>> vcd_database
;
144 dict
<Wire
*, pair
<fstHandle
, Const
>> fst_database
;
145 dict
<Wire
*, fstHandle
> fst_handles
;
147 SimInstance(SimShared
*shared
, std::string scope
, Module
*module
, Cell
*instance
= nullptr, SimInstance
*parent
= nullptr) :
148 shared(shared
), scope(scope
), module(module
), instance(instance
), parent(parent
), sigmap(module
)
153 log_assert(parent
->children
.count(instance
) == 0);
154 parent
->children
[instance
] = this;
157 for (auto wire
: module
->wires())
159 SigSpec sig
= sigmap(wire
);
161 for (int i
= 0; i
< GetSize(sig
); i
++) {
162 if (state_nets
.count(sig
[i
]) == 0)
163 state_nets
[sig
[i
]] = State::Sx
;
164 if (wire
->port_output
) {
165 upd_outports
[sig
[i
]].insert(wire
);
166 dirty_bits
.insert(sig
[i
]);
170 if ((shared
->fst
) && !(shared
->hide_internal
&& wire
->name
[0] == '$')) {
171 fstHandle id
= shared
->fst
->getHandle(scope
+ "." + RTLIL::unescape_id(wire
->name
));
172 if (id
==0 && wire
->name
.isPublic())
173 log_warning("Unable to found wire %s in input file.\n", (scope
+ "." + RTLIL::unescape_id(wire
->name
)).c_str());
174 fst_handles
[wire
] = id
;
177 if (wire
->attributes
.count(ID::init
)) {
178 Const initval
= wire
->attributes
.at(ID::init
);
179 for (int i
= 0; i
< GetSize(sig
) && i
< GetSize(initval
); i
++)
180 if (initval
[i
] == State::S0
|| initval
[i
] == State::S1
) {
181 state_nets
[sig
[i
]] = initval
[i
];
182 dirty_bits
.insert(sig
[i
]);
187 memories
= Mem::get_all_memories(module
);
188 for (auto &mem
: memories
) {
189 auto &mdb
= mem_database
[mem
.memid
];
191 for (auto &port
: mem
.wr_ports
) {
192 mdb
.past_wr_clk
.push_back(Const(State::Sx
));
193 mdb
.past_wr_en
.push_back(Const(State::Sx
, GetSize(port
.en
)));
194 mdb
.past_wr_addr
.push_back(Const(State::Sx
, GetSize(port
.addr
)));
195 mdb
.past_wr_data
.push_back(Const(State::Sx
, GetSize(port
.data
)));
197 mdb
.data
= mem
.get_init_data();
200 for (auto cell
: module
->cells())
202 Module
*mod
= module
->design
->module(cell
->type
);
204 if (mod
!= nullptr) {
205 dirty_children
.insert(new SimInstance(shared
, scope
+ "." + RTLIL::unescape_id(cell
->name
), mod
, cell
, this));
208 for (auto &port
: cell
->connections()) {
209 if (cell
->input(port
.first
))
210 for (auto bit
: sigmap(port
.second
)) {
211 upd_cells
[bit
].insert(cell
);
212 // Make sure cell inputs connected to constants are updated in the first cycle
213 if (bit
.wire
== nullptr)
214 dirty_bits
.insert(bit
);
218 if (RTLIL::builtin_ff_cell_types().count(cell
->type
)) {
219 FfData
ff_data(nullptr, cell
);
221 ff
.past_d
= Const(State::Sx
, ff_data
.width
);
222 ff
.past_ad
= Const(State::Sx
, ff_data
.width
);
223 ff
.past_clk
= State::Sx
;
224 ff
.past_ce
= State::Sx
;
225 ff
.past_srst
= State::Sx
;
227 ff_database
[cell
] = ff
;
230 if (cell
->is_mem_cell())
232 mem_cells
[cell
] = cell
->parameters
.at(ID::MEMID
).decode_string();
234 if (cell
->type
.in(ID($
assert), ID($cover
), ID($assume
))) {
235 formal_database
.insert(cell
);
241 for (auto &it
: ff_database
)
243 ff_state_t
&ff
= it
.second
;
246 SigSpec qsig
= it
.second
.data
.sig_q
;
247 Const qdata
= get_state(qsig
);
249 set_state(qsig
, qdata
);
252 for (auto &it
: mem_database
) {
253 mem_state_t
&mem
= it
.second
;
254 for (auto &val
: mem
.past_wr_en
)
263 for (auto child
: children
)
267 IdString
name() const
269 if (instance
!= nullptr)
270 return instance
->name
;
274 std::string
hiername() const
276 if (instance
!= nullptr)
277 return parent
->hiername() + "." + log_id(instance
->name
);
279 return log_id(module
->name
);
282 Const
get_state(SigSpec sig
)
286 for (auto bit
: sigmap(sig
))
287 if (bit
.wire
== nullptr)
288 value
.bits
.push_back(bit
.data
);
289 else if (state_nets
.count(bit
))
290 value
.bits
.push_back(state_nets
.at(bit
));
292 value
.bits
.push_back(State::Sz
);
295 log("[%s] get %s: %s\n", hiername().c_str(), log_signal(sig
), log_signal(value
));
299 bool set_state(SigSpec sig
, Const value
)
301 bool did_something
= false;
304 log_assert(GetSize(sig
) <= GetSize(value
));
306 for (int i
= 0; i
< GetSize(sig
); i
++)
307 if (state_nets
.at(sig
[i
]) != value
[i
]) {
308 state_nets
.at(sig
[i
]) = value
[i
];
309 dirty_bits
.insert(sig
[i
]);
310 did_something
= true;
314 log("[%s] set %s: %s\n", hiername().c_str(), log_signal(sig
), log_signal(value
));
315 return did_something
;
318 void update_cell(Cell
*cell
)
320 if (ff_database
.count(cell
))
323 if (formal_database
.count(cell
))
326 if (mem_cells
.count(cell
))
328 dirty_memories
.insert(mem_cells
[cell
]);
332 if (children
.count(cell
))
334 auto child
= children
.at(cell
);
335 for (auto &conn
: cell
->connections())
336 if (cell
->input(conn
.first
) && GetSize(conn
.second
)) {
337 Const value
= get_state(conn
.second
);
338 child
->set_state(child
->module
->wire(conn
.first
), value
);
340 dirty_children
.insert(child
);
344 if (yosys_celltypes
.cell_evaluable(cell
->type
))
346 RTLIL::SigSpec sig_a
, sig_b
, sig_c
, sig_d
, sig_s
, sig_y
;
347 bool has_a
, has_b
, has_c
, has_d
, has_s
, has_y
;
349 has_a
= cell
->hasPort(ID::A
);
350 has_b
= cell
->hasPort(ID::B
);
351 has_c
= cell
->hasPort(ID::C
);
352 has_d
= cell
->hasPort(ID::D
);
353 has_s
= cell
->hasPort(ID::S
);
354 has_y
= cell
->hasPort(ID::Y
);
356 if (has_a
) sig_a
= cell
->getPort(ID::A
);
357 if (has_b
) sig_b
= cell
->getPort(ID::B
);
358 if (has_c
) sig_c
= cell
->getPort(ID::C
);
359 if (has_d
) sig_d
= cell
->getPort(ID::D
);
360 if (has_s
) sig_s
= cell
->getPort(ID::S
);
361 if (has_y
) sig_y
= cell
->getPort(ID::Y
);
364 log("[%s] eval %s (%s)\n", hiername().c_str(), log_id(cell
), log_id(cell
->type
));
366 // Simple (A -> Y) and (A,B -> Y) cells
367 if (has_a
&& !has_c
&& !has_d
&& !has_s
&& has_y
) {
368 set_state(sig_y
, CellTypes::eval(cell
, get_state(sig_a
), get_state(sig_b
)));
372 // (A,B,C -> Y) cells
373 if (has_a
&& has_b
&& has_c
&& !has_d
&& !has_s
&& has_y
) {
374 set_state(sig_y
, CellTypes::eval(cell
, get_state(sig_a
), get_state(sig_b
), get_state(sig_c
)));
379 if (has_a
&& !has_b
&& !has_c
&& !has_d
&& has_s
&& has_y
) {
380 set_state(sig_y
, CellTypes::eval(cell
, get_state(sig_a
), get_state(sig_s
)));
384 // (A,B,S -> Y) cells
385 if (has_a
&& has_b
&& !has_c
&& !has_d
&& has_s
&& has_y
) {
386 set_state(sig_y
, CellTypes::eval(cell
, get_state(sig_a
), get_state(sig_b
), get_state(sig_s
)));
390 log_warning("Unsupported evaluable cell type: %s (%s.%s)\n", log_id(cell
->type
), log_id(module
), log_id(cell
));
394 log_error("Unsupported cell type: %s (%s.%s)\n", log_id(cell
->type
), log_id(module
), log_id(cell
));
397 void update_memory(IdString id
) {
398 auto &mdb
= mem_database
[id
];
399 auto &mem
= *mdb
.mem
;
401 for (int port_idx
= 0; port_idx
< GetSize(mem
.rd_ports
); port_idx
++)
403 auto &port
= mem
.rd_ports
[port_idx
];
404 Const addr
= get_state(port
.addr
);
405 Const data
= Const(State::Sx
, mem
.width
<< port
.wide_log2
);
408 log_error("Memory %s.%s has clocked read ports. Run 'memory' with -nordff.\n", log_id(module
), log_id(mem
.memid
));
410 if (addr
.is_fully_def()) {
411 int index
= addr
.as_int() - mem
.start_offset
;
412 if (index
>= 0 && index
< mem
.size
)
413 data
= mdb
.data
.extract(index
*mem
.width
, mem
.width
<< port
.wide_log2
);
416 set_state(port
.data
, data
);
422 pool
<Cell
*> queue_cells
;
423 pool
<Wire
*> queue_outports
;
425 queue_cells
.swap(dirty_cells
);
429 for (auto bit
: dirty_bits
)
431 if (upd_cells
.count(bit
))
432 for (auto cell
: upd_cells
.at(bit
))
433 queue_cells
.insert(cell
);
435 if (upd_outports
.count(bit
) && parent
!= nullptr)
436 for (auto wire
: upd_outports
.at(bit
))
437 queue_outports
.insert(wire
);
442 if (!queue_cells
.empty())
444 for (auto cell
: queue_cells
)
451 for (auto &memid
: dirty_memories
)
452 update_memory(memid
);
453 dirty_memories
.clear();
455 for (auto wire
: queue_outports
)
456 if (instance
->hasPort(wire
->name
)) {
457 Const value
= get_state(wire
);
458 parent
->set_state(instance
->getPort(wire
->name
), value
);
461 queue_outports
.clear();
463 for (auto child
: dirty_children
)
466 dirty_children
.clear();
468 if (dirty_bits
.empty())
475 bool did_something
= false;
477 for (auto &it
: ff_database
)
479 ff_state_t
&ff
= it
.second
;
480 FfData
&ff_data
= ff
.data
;
482 Const current_q
= get_state(ff
.data
.sig_q
);
484 if (ff_data
.has_clk
) {
486 State current_clk
= get_state(ff_data
.sig_clk
)[0];
487 if (ff_data
.pol_clk
? (ff
.past_clk
== State::S0
&& current_clk
!= State::S0
) :
488 (ff
.past_clk
== State::S1
&& current_clk
!= State::S1
)) {
489 bool ce
= ff
.past_ce
== (ff_data
.pol_ce
? State::S1
: State::S0
);
490 // chip enable priority over reset
491 if (ff_data
.ce_over_srst
&& ff_data
.has_ce
&& !ce
) continue;
492 // set if no ce, or ce is enabled
493 if (!ff_data
.has_ce
|| (ff_data
.has_ce
&& ce
)) {
494 current_q
= ff
.past_d
;
496 // override if sync reset
497 if ((ff_data
.has_srst
) && (ff
.past_srst
== (ff_data
.pol_srst
? State::S1
: State::S0
))) {
498 current_q
= ff_data
.val_srst
;
503 if (ff_data
.has_aload
) {
504 State current_aload
= get_state(ff_data
.sig_aload
)[0];
505 if (current_aload
== (ff_data
.pol_aload
? State::S1
: State::S0
)) {
506 current_q
= ff_data
.has_clk
? ff
.past_ad
: get_state(ff
.data
.sig_ad
);
510 if (ff_data
.has_arst
) {
511 State current_arst
= get_state(ff_data
.sig_arst
)[0];
512 if (current_arst
== (ff_data
.pol_arst
? State::S1
: State::S0
)) {
513 current_q
= ff_data
.val_arst
;
517 if (ff
.data
.has_sr
) {
518 Const current_clr
= get_state(ff
.data
.sig_clr
);
519 Const current_set
= get_state(ff
.data
.sig_set
);
521 for(int i
=0;i
<ff
.past_d
.size();i
++) {
522 if (current_clr
[i
] == (ff_data
.pol_clr
? State::S1
: State::S0
)) {
523 current_q
[i
] = State::S0
;
525 else if (current_set
[i
] == (ff_data
.pol_set
? State::S1
: State::S0
)) {
526 current_q
[i
] = State::S1
;
530 if (ff_data
.has_gclk
) {
532 current_q
= ff
.past_d
;
534 if (set_state(ff_data
.sig_q
, current_q
))
535 did_something
= true;
538 for (auto &it
: mem_database
)
540 mem_state_t
&mdb
= it
.second
;
541 auto &mem
= *mdb
.mem
;
543 for (int port_idx
= 0; port_idx
< GetSize(mem
.wr_ports
); port_idx
++)
545 auto &port
= mem
.wr_ports
[port_idx
];
546 Const addr
, data
, enable
;
548 if (!port
.clk_enable
)
550 addr
= get_state(port
.addr
);
551 data
= get_state(port
.data
);
552 enable
= get_state(port
.en
);
556 if (port
.clk_polarity
?
557 (mdb
.past_wr_clk
[port_idx
] == State::S1
|| get_state(port
.clk
) != State::S1
) :
558 (mdb
.past_wr_clk
[port_idx
] == State::S0
|| get_state(port
.clk
) != State::S0
))
561 addr
= mdb
.past_wr_addr
[port_idx
];
562 data
= mdb
.past_wr_data
[port_idx
];
563 enable
= mdb
.past_wr_en
[port_idx
];
566 if (addr
.is_fully_def())
568 int index
= addr
.as_int() - mem
.start_offset
;
569 if (index
>= 0 && index
< mem
.size
)
570 for (int i
= 0; i
< (mem
.width
<< port
.wide_log2
); i
++)
571 if (enable
[i
] == State::S1
&& mdb
.data
.bits
.at(index
*mem
.width
+i
) != data
[i
]) {
572 mdb
.data
.bits
.at(index
*mem
.width
+i
) = data
[i
];
573 dirty_memories
.insert(mem
.memid
);
574 did_something
= true;
580 for (auto it
: children
)
581 if (it
.second
->update_ph2()) {
582 dirty_children
.insert(it
.second
);
583 did_something
= true;
586 return did_something
;
591 for (auto &it
: ff_database
)
593 ff_state_t
&ff
= it
.second
;
595 if (ff
.data
.has_aload
)
596 ff
.past_ad
= get_state(ff
.data
.sig_ad
);
598 if (ff
.data
.has_clk
|| ff
.data
.has_gclk
)
599 ff
.past_d
= get_state(ff
.data
.sig_d
);
602 ff
.past_clk
= get_state(ff
.data
.sig_clk
)[0];
605 ff
.past_ce
= get_state(ff
.data
.sig_ce
)[0];
607 if (ff
.data
.has_srst
)
608 ff
.past_srst
= get_state(ff
.data
.sig_srst
)[0];
611 for (auto &it
: mem_database
)
613 mem_state_t
&mem
= it
.second
;
615 for (int i
= 0; i
< GetSize(mem
.mem
->wr_ports
); i
++) {
616 auto &port
= mem
.mem
->wr_ports
[i
];
617 mem
.past_wr_clk
[i
] = get_state(port
.clk
);
618 mem
.past_wr_en
[i
] = get_state(port
.en
);
619 mem
.past_wr_addr
[i
] = get_state(port
.addr
);
620 mem
.past_wr_data
[i
] = get_state(port
.data
);
624 for (auto cell
: formal_database
)
626 string label
= log_id(cell
);
627 if (cell
->attributes
.count(ID::src
))
628 label
= cell
->attributes
.at(ID::src
).decode_string();
630 State a
= get_state(cell
->getPort(ID::A
))[0];
631 State en
= get_state(cell
->getPort(ID::EN
))[0];
633 if (cell
->type
== ID($cover
) && en
== State::S1
&& a
!= State::S1
)
634 log("Cover %s.%s (%s) reached.\n", hiername().c_str(), log_id(cell
), label
.c_str());
636 if (cell
->type
== ID($assume
) && en
== State::S1
&& a
!= State::S1
)
637 log("Assumption %s.%s (%s) failed.\n", hiername().c_str(), log_id(cell
), label
.c_str());
639 if (cell
->type
== ID($
assert) && en
== State::S1
&& a
!= State::S1
)
640 log_warning("Assert %s.%s (%s) failed.\n", hiername().c_str(), log_id(cell
), label
.c_str());
643 for (auto it
: children
)
644 it
.second
->update_ph3();
647 void writeback(pool
<Module
*> &wbmods
)
649 if (wbmods
.count(module
))
650 log_error("Instance %s of module %s is not unique: Writeback not possible. (Fix by running 'uniquify'.)\n", hiername().c_str(), log_id(module
));
652 wbmods
.insert(module
);
654 for (auto wire
: module
->wires())
655 wire
->attributes
.erase(ID::init
);
657 for (auto &it
: ff_database
)
659 SigSpec sig_q
= it
.second
.data
.sig_q
;
660 Const initval
= get_state(sig_q
);
662 for (int i
= 0; i
< GetSize(sig_q
); i
++)
664 Wire
*w
= sig_q
[i
].wire
;
666 if (w
->attributes
.count(ID::init
) == 0)
667 w
->attributes
[ID::init
] = Const(State::Sx
, GetSize(w
));
669 w
->attributes
[ID::init
][sig_q
[i
].offset
] = initval
[i
];
673 for (auto &it
: mem_database
)
675 mem_state_t
&mem
= it
.second
;
676 mem
.mem
->clear_inits();
678 minit
.addr
= mem
.mem
->start_offset
;
679 minit
.data
= mem
.data
;
680 minit
.en
= Const(State::S1
, mem
.mem
->width
);
681 mem
.mem
->inits
.push_back(minit
);
685 for (auto it
: children
)
686 it
.second
->writeback(wbmods
);
689 void write_vcd_header(std::ofstream
&f
, int &id
)
691 f
<< stringf("$scope module %s $end\n", log_id(name()));
693 for (auto wire
: module
->wires())
695 if (shared
->hide_internal
&& wire
->name
[0] == '$')
698 f
<< stringf("$var wire %d n%d %s%s $end\n", GetSize(wire
), id
, wire
->name
[0] == '$' ? "\\" : "", log_id(wire
));
699 vcd_database
[wire
] = make_pair(id
++, Const());
702 for (auto child
: children
)
703 child
.second
->write_vcd_header(f
, id
);
705 f
<< stringf("$upscope $end\n");
708 void write_vcd_step(std::ofstream
&f
)
710 for (auto &it
: vcd_database
)
712 Wire
*wire
= it
.first
;
713 Const value
= get_state(wire
);
714 int id
= it
.second
.first
;
716 if (it
.second
.second
== value
)
719 it
.second
.second
= value
;
722 for (int i
= GetSize(value
)-1; i
>= 0; i
--) {
724 case State::S0
: f
<< "0"; break;
725 case State::S1
: f
<< "1"; break;
726 case State::Sx
: f
<< "x"; break;
731 f
<< stringf(" n%d\n", id
);
734 for (auto child
: children
)
735 child
.second
->write_vcd_step(f
);
738 void write_fst_header(struct fstContext
*f
)
740 fstWriterSetScope(f
, FST_ST_VCD_MODULE
, stringf("%s",log_id(name())).c_str(), nullptr);
741 for (auto wire
: module
->wires())
743 if (shared
->hide_internal
&& wire
->name
[0] == '$')
746 fstHandle id
= fstWriterCreateVar(f
, FST_VT_VCD_WIRE
, FST_VD_IMPLICIT
, GetSize(wire
),
747 stringf("%s%s", wire
->name
[0] == '$' ? "\\" : "", log_id(wire
)).c_str(), 0);
748 fst_database
[wire
] = make_pair(id
, Const());
751 for (auto child
: children
)
752 child
.second
->write_fst_header(f
);
754 fstWriterSetUpscope(f
);
757 void write_fst_step(struct fstContext
*f
)
759 for (auto &it
: fst_database
)
761 Wire
*wire
= it
.first
;
762 Const value
= get_state(wire
);
763 fstHandle id
= it
.second
.first
;
765 if (it
.second
.second
== value
)
768 it
.second
.second
= value
;
769 std::stringstream ss
;
770 for (int i
= GetSize(value
)-1; i
>= 0; i
--) {
772 case State::S0
: ss
<< "0"; break;
773 case State::S1
: ss
<< "1"; break;
774 case State::Sx
: ss
<< "x"; break;
778 fstWriterEmitValueChange(f
, id
, ss
.str().c_str());
781 for (auto child
: children
)
782 child
.second
->write_fst_step(f
);
787 for (auto &it
: ff_database
)
789 SigSpec qsig
= it
.second
.data
.sig_q
;
790 if (qsig
.is_wire()) {
791 IdString name
= qsig
.as_wire()->name
;
792 fstHandle id
= shared
->fst
->getHandle(scope
+ "." + RTLIL::unescape_id(name
));
793 if (id
==0 && name
.isPublic())
794 log_warning("Unable to found wire %s in input file.\n", (scope
+ "." + RTLIL::unescape_id(name
)).c_str());
796 Const fst_val
= Const::from_string(shared
->fst
->valueOf(id
));
797 set_state(qsig
, fst_val
);
801 for (auto child
: children
)
802 child
.second
->setInitState();
808 for(auto &item
: fst_handles
) {
809 if (item
.second
==0) continue; // Ignore signals not found
810 Const fst_val
= Const::from_string(shared
->fst
->valueOf(item
.second
));
811 Const sim_val
= get_state(item
.first
);
812 if (sim_val
.size()!=fst_val
.size())
813 log_error("Signal '%s' size is different in gold and gate.\n", log_id(item
.first
));
814 if (shared
->sim_mode
== SimulationMode::sim
) {
815 // No checks performed when using stimulus
816 } else if (shared
->sim_mode
== SimulationMode::gate
&& !fst_val
.is_fully_def()) { // FST data contains X
817 for(int i
=0;i
<fst_val
.size();i
++) {
818 if (fst_val
[i
]!=State::Sx
&& fst_val
[i
]!=sim_val
[i
]) {
819 log_warning("Signal '%s' in file %s in simulation %s\n", log_id(item
.first
), log_signal(fst_val
), log_signal(sim_val
));
824 } else if (shared
->sim_mode
== SimulationMode::gold
&& !sim_val
.is_fully_def()) { // sim data contains X
825 for(int i
=0;i
<sim_val
.size();i
++) {
826 if (sim_val
[i
]!=State::Sx
&& fst_val
[i
]!=sim_val
[i
]) {
827 log_warning("Signal '%s' in file %s in simulation %s\n", log_id(item
.first
), log_signal(fst_val
), log_signal(sim_val
));
833 if (fst_val
!=sim_val
) {
834 log_warning("Signal '%s' in file %s in simulation '%s'\n", log_id(item
.first
), log_signal(fst_val
), log_signal(sim_val
));
839 for (auto child
: children
)
840 retVal
|= child
.second
->checkSignals();
845 struct SimWorker
: SimShared
847 SimInstance
*top
= nullptr;
848 std::ofstream vcdfile
;
849 struct fstContext
*fstfile
= nullptr;
850 pool
<IdString
> clock
, clockn
, reset
, resetn
;
851 std::string timescale
;
852 std::string sim_filename
;
860 void write_vcd_header()
862 vcdfile
<< stringf("$version %s $end\n", yosys_version_str
);
864 std::time_t t
= std::time(nullptr);
866 if (std::strftime(mbstr
, sizeof(mbstr
), "%c", std::localtime(&t
))) {
867 vcdfile
<< stringf("$date ") << mbstr
<< stringf(" $end\n");
870 if (!timescale
.empty())
871 vcdfile
<< stringf("$timescale %s $end\n", timescale
.c_str());
874 top
->write_vcd_header(vcdfile
, id
);
876 vcdfile
<< stringf("$enddefinitions $end\n");
879 void write_vcd_step(int t
)
881 vcdfile
<< stringf("#%d\n", t
);
882 top
->write_vcd_step(vcdfile
);
885 void write_fst_header()
887 std::time_t t
= std::time(nullptr);
888 fstWriterSetDate(fstfile
, asctime(std::localtime(&t
)));
889 fstWriterSetVersion(fstfile
, yosys_version_str
);
890 if (!timescale
.empty())
891 fstWriterSetTimescaleFromString(fstfile
, timescale
.c_str());
893 fstWriterSetPackType(fstfile
, FST_WR_PT_FASTLZ
);
894 fstWriterSetRepackOnClose(fstfile
, 1);
896 top
->write_fst_header(fstfile
);
899 void write_fst_step(int t
)
901 fstWriterEmitTimeChange(fstfile
, t
);
903 top
->write_fst_step(fstfile
);
906 void write_output_header()
908 if (vcdfile
.is_open())
914 void write_output_step(int t
)
916 if (vcdfile
.is_open())
922 void write_output_end()
925 fstWriterClose(fstfile
);
933 log("\n-- ph1 --\n");
938 log("\n-- ph2 --\n");
940 if (!top
->update_ph2())
945 log("\n-- ph3 --\n");
950 void set_inports(pool
<IdString
> ports
, State value
)
952 for (auto portname
: ports
)
954 Wire
*w
= top
->module
->wire(portname
);
957 log_error("Can't find port %s on module %s.\n", log_id(portname
), log_id(top
->module
));
959 top
->set_state(w
, value
);
963 void run(Module
*topmod
, int numcycles
)
965 log_assert(top
== nullptr);
966 top
= new SimInstance(this, scope
, topmod
);
969 log("\n===== 0 =====\n");
971 log("Simulating cycle 0.\n");
973 set_inports(reset
, State::S1
);
974 set_inports(resetn
, State::S0
);
976 set_inports(clock
, State::Sx
);
977 set_inports(clockn
, State::Sx
);
981 write_output_header();
982 write_output_step(0);
984 for (int cycle
= 0; cycle
< numcycles
; cycle
++)
987 log("\n===== %d =====\n", 10*cycle
+ 5);
989 log("Simulating cycle %d.\n", (cycle
*2)+1);
990 set_inports(clock
, State::S0
);
991 set_inports(clockn
, State::S1
);
994 write_output_step(10*cycle
+ 5);
997 log("\n===== %d =====\n", 10*cycle
+ 10);
999 log("Simulating cycle %d.\n", (cycle
*2)+2);
1001 set_inports(clock
, State::S1
);
1002 set_inports(clockn
, State::S0
);
1004 if (cycle
+1 == rstlen
) {
1005 set_inports(reset
, State::S0
);
1006 set_inports(resetn
, State::S1
);
1010 write_output_step(10*cycle
+ 10);
1013 write_output_step(10*numcycles
+ 2);
1018 pool
<Module
*> wbmods
;
1019 top
->writeback(wbmods
);
1023 void run_cosim(Module
*topmod
, int numcycles
)
1025 log_assert(top
== nullptr);
1026 fst
= new FstData(sim_filename
);
1029 log_error("Scope must be defined for co-simulation.\n");
1031 top
= new SimInstance(this, scope
, topmod
);
1033 std::vector
<fstHandle
> fst_clock
;
1035 for (auto portname
: clock
)
1037 Wire
*w
= topmod
->wire(portname
);
1039 log_error("Can't find port %s on module %s.\n", log_id(portname
), log_id(top
->module
));
1041 log_error("Clock port %s on module %s is not input.\n", log_id(portname
), log_id(top
->module
));
1042 fstHandle id
= fst
->getHandle(scope
+ "." + RTLIL::unescape_id(portname
));
1044 log_error("Can't find port %s.%s in FST.\n", scope
.c_str(), log_id(portname
));
1045 fst_clock
.push_back(id
);
1047 for (auto portname
: clockn
)
1049 Wire
*w
= topmod
->wire(portname
);
1051 log_error("Can't find port %s on module %s.\n", log_id(portname
), log_id(top
->module
));
1053 log_error("Clock port %s on module %s is not input.\n", log_id(portname
), log_id(top
->module
));
1054 fstHandle id
= fst
->getHandle(scope
+ "." + RTLIL::unescape_id(portname
));
1056 log_error("Can't find port %s.%s in FST.\n", scope
.c_str(), log_id(portname
));
1057 fst_clock
.push_back(id
);
1060 SigMap
sigmap(topmod
);
1061 std::map
<Wire
*,fstHandle
> inputs
;
1063 for (auto wire
: topmod
->wires()) {
1064 if (wire
->port_input
) {
1065 fstHandle id
= fst
->getHandle(scope
+ "." + RTLIL::unescape_id(wire
->name
));
1067 log_error("Unable to find required '%s' signal in file\n",(scope
+ "." + RTLIL::unescape_id(wire
->name
)).c_str());
1072 uint64_t startCount
= 0;
1073 uint64_t stopCount
= 0;
1074 if (start_time
==0) {
1075 if (start_time
< fst
->getStartTime())
1076 log_warning("Start time is before simulation file start time\n");
1077 startCount
= fst
->getStartTime();
1078 } else if (start_time
==-1)
1079 startCount
= fst
->getEndTime();
1081 startCount
= start_time
/ fst
->getTimescale();
1082 if (startCount
> fst
->getEndTime()) {
1083 startCount
= fst
->getEndTime();
1084 log_warning("Start time is after simulation file end time\n");
1088 if (stop_time
< fst
->getStartTime())
1089 log_warning("Stop time is before simulation file start time\n");
1090 stopCount
= fst
->getStartTime();
1091 } else if (stop_time
==-1)
1092 stopCount
= fst
->getEndTime();
1094 stopCount
= stop_time
/ fst
->getTimescale();
1095 if (stopCount
> fst
->getEndTime()) {
1096 stopCount
= fst
->getEndTime();
1097 log_warning("Stop time is after simulation file end time\n");
1100 if (stopCount
<startCount
) {
1101 log_error("Stop time is before start time\n");
1104 bool initial
= true;
1106 log("Co-simulation from %lu%s to %lu%s", (unsigned long)startCount
, fst
->getTimescaleString(), (unsigned long)stopCount
, fst
->getTimescaleString());
1108 log(" for %d clock cycle(s)",numcycles
);
1110 bool all_samples
= fst_clock
.empty();
1113 fst
->reconstructAllAtTimes(fst_clock
, startCount
, stopCount
, [&](uint64_t time
) {
1114 log("Co-simulating %s %d [%lu%s].\n", (all_samples
? "sample" : "cycle"), cycle
, (unsigned long)time
, fst
->getTimescaleString());
1115 for(auto &item
: inputs
) {
1116 std::string v
= fst
->valueOf(item
.second
);
1117 top
->set_state(item
.first
, Const::from_string(v
));
1121 top
->setInitState();
1122 write_output_header();
1126 write_output_step(5*cycle
);
1128 bool status
= top
->checkSignals();
1130 log_error("Signal difference\n");
1133 // Limit to number of cycles if provided
1134 if (cycles_set
&& cycle
> numcycles
*2)
1135 throw fst_end_of_data_exception();
1136 if (time
==stopCount
)
1137 throw fst_end_of_data_exception();
1139 } catch(fst_end_of_data_exception
) {
1140 // end of data detected
1142 write_output_step(5*(cycle
-1)+2);
1146 pool
<Module
*> wbmods
;
1147 top
->writeback(wbmods
);
1152 struct SimPass
: public Pass
{
1153 SimPass() : Pass("sim", "simulate the circuit") { }
1154 void help() override
1156 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1158 log(" sim [options] [top-level]\n");
1160 log("This command simulates the circuit using the given top-level module.\n");
1162 log(" -vcd <filename>\n");
1163 log(" write the simulation results to the given VCD file\n");
1165 log(" -fst <filename>\n");
1166 log(" write the simulation results to the given FST file\n");
1168 log(" -clock <portname>\n");
1169 log(" name of top-level clock input\n");
1171 log(" -clockn <portname>\n");
1172 log(" name of top-level clock input (inverse polarity)\n");
1174 log(" -reset <portname>\n");
1175 log(" name of top-level reset input (active high)\n");
1177 log(" -resetn <portname>\n");
1178 log(" name of top-level inverted reset input (active low)\n");
1180 log(" -rstlen <integer>\n");
1181 log(" number of cycles reset should stay active (default: 1)\n");
1184 log(" zero-initialize all uninitialized regs and memories\n");
1186 log(" -timescale <string>\n");
1187 log(" include the specified timescale declaration in the vcd\n");
1189 log(" -n <integer>\n");
1190 log(" number of clock cycles to simulate (default: 20)\n");
1193 log(" use all nets in VCD/FST operations, not just those with public names\n");
1196 log(" writeback mode: use final simulation state as new init state\n");
1199 log(" read simulation results file (file formats supported: FST)\n");
1202 log(" scope of simulation top model\n");
1204 log(" -at <time>\n");
1205 log(" sets start and stop time\n");
1207 log(" -start <time>\n");
1208 log(" start co-simulation in arbitary time (default 0)\n");
1210 log(" -stop <time>\n");
1211 log(" stop co-simulation in arbitary time (default END)\n");
1214 log(" simulation with stimulus from FST (default)\n");
1217 log(" co-simulation expect exact match\n");
1219 log(" -sim-gold\n");
1220 log(" co-simulation, x in simulation can match any value in FST\n");
1222 log(" -sim-gate\n");
1223 log(" co-simulation, x in FST can match any value in simulation\n");
1226 log(" enable debug output\n");
1229 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) override
1233 bool start_set
= false, stop_set
= false, at_set
= false;
1235 log_header(design
, "Executing SIM pass (simulate the circuit).\n");
1238 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
1239 if (args
[argidx
] == "-vcd" && argidx
+1 < args
.size()) {
1240 std::string vcd_filename
= args
[++argidx
];
1241 rewrite_filename(vcd_filename
);
1242 worker
.vcdfile
.open(vcd_filename
.c_str());
1245 if (args
[argidx
] == "-fst" && argidx
+1 < args
.size()) {
1246 std::string fst_filename
= args
[++argidx
];
1247 rewrite_filename(fst_filename
);
1248 worker
.fstfile
= (struct fstContext
*)fstWriterCreate(fst_filename
.c_str(),1);
1251 if (args
[argidx
] == "-n" && argidx
+1 < args
.size()) {
1252 numcycles
= atoi(args
[++argidx
].c_str());
1253 worker
.cycles_set
= true;
1256 if (args
[argidx
] == "-rstlen" && argidx
+1 < args
.size()) {
1257 worker
.rstlen
= atoi(args
[++argidx
].c_str());
1260 if (args
[argidx
] == "-clock" && argidx
+1 < args
.size()) {
1261 worker
.clock
.insert(RTLIL::escape_id(args
[++argidx
]));
1264 if (args
[argidx
] == "-clockn" && argidx
+1 < args
.size()) {
1265 worker
.clockn
.insert(RTLIL::escape_id(args
[++argidx
]));
1268 if (args
[argidx
] == "-reset" && argidx
+1 < args
.size()) {
1269 worker
.reset
.insert(RTLIL::escape_id(args
[++argidx
]));
1272 if (args
[argidx
] == "-resetn" && argidx
+1 < args
.size()) {
1273 worker
.resetn
.insert(RTLIL::escape_id(args
[++argidx
]));
1276 if (args
[argidx
] == "-timescale" && argidx
+1 < args
.size()) {
1277 worker
.timescale
= args
[++argidx
];
1280 if (args
[argidx
] == "-a") {
1281 worker
.hide_internal
= false;
1284 if (args
[argidx
] == "-d") {
1285 worker
.debug
= true;
1288 if (args
[argidx
] == "-w") {
1289 worker
.writeback
= true;
1292 if (args
[argidx
] == "-zinit") {
1293 worker
.zinit
= true;
1296 if (args
[argidx
] == "-r" && argidx
+1 < args
.size()) {
1297 std::string sim_filename
= args
[++argidx
];
1298 rewrite_filename(sim_filename
);
1299 worker
.sim_filename
= sim_filename
;
1302 if (args
[argidx
] == "-scope" && argidx
+1 < args
.size()) {
1303 worker
.scope
= args
[++argidx
];
1306 if (args
[argidx
] == "-start" && argidx
+1 < args
.size()) {
1307 worker
.start_time
= stringToTime(args
[++argidx
]);
1311 if (args
[argidx
] == "-stop" && argidx
+1 < args
.size()) {
1312 worker
.stop_time
= stringToTime(args
[++argidx
]);
1316 if (args
[argidx
] == "-at" && argidx
+1 < args
.size()) {
1317 worker
.start_time
= stringToTime(args
[++argidx
]);
1318 worker
.stop_time
= worker
.start_time
;
1322 if (args
[argidx
] == "-sim") {
1323 worker
.sim_mode
= SimulationMode::sim
;
1326 if (args
[argidx
] == "-sim-cmp") {
1327 worker
.sim_mode
= SimulationMode::cmp
;
1330 if (args
[argidx
] == "-sim-gold") {
1331 worker
.sim_mode
= SimulationMode::gold
;
1334 if (args
[argidx
] == "-sim-gate") {
1335 worker
.sim_mode
= SimulationMode::gate
;
1340 extra_args(args
, argidx
, design
);
1341 if (at_set
&& (start_set
|| stop_set
|| worker
.cycles_set
))
1342 log_error("'at' option can only be defined separate of 'start','stop' and 'n'\n");
1343 if (stop_set
&& worker
.cycles_set
)
1344 log_error("'stop' and 'n' can only be used exclusively'\n");
1346 Module
*top_mod
= nullptr;
1348 if (design
->full_selection()) {
1349 top_mod
= design
->top_module();
1352 log_cmd_error("Design has no top module, use the 'hierarchy' command to specify one.\n");
1354 auto mods
= design
->selected_whole_modules();
1355 if (GetSize(mods
) != 1)
1356 log_cmd_error("Only one top module must be selected.\n");
1357 top_mod
= mods
.front();
1360 if (worker
.sim_filename
.empty())
1361 worker
.run(top_mod
, numcycles
);
1363 worker
.run_cosim(top_mod
, numcycles
);
1367 PRIVATE_NAMESPACE_END