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"
29 PRIVATE_NAMESPACE_BEGIN
31 enum class SimulationMode
{
37 static const std::map
<std::string
, int> g_units
=
39 { "", -9 }, // default is ns
50 static double stringToTime(std::string str
)
52 if (str
=="END") return -1;
55 long value
= strtol(str
.c_str(), &endptr
, 10);
57 if (g_units
.find(endptr
)==g_units
.end())
58 log_error("Cannot parse '%s', bad unit '%s'\n", str
.c_str(), endptr
);
61 log_error("Time value '%s' must be positive\n", str
.c_str());
63 return value
* pow(10.0, g_units
.at(endptr
));
69 bool hide_internal
= true;
70 bool writeback
= false;
73 FstData
*fst
= nullptr;
74 double start_time
= 0;
75 double stop_time
= -1;
76 SimulationMode sim_mode
= SimulationMode::cmp
;
77 bool cycles_set
= false;
88 for (auto &bit
: v
.bits
)
101 dict
<Cell
*, SimInstance
*> children
;
104 dict
<SigBit
, State
> state_nets
;
105 dict
<SigBit
, pool
<Cell
*>> upd_cells
;
106 dict
<SigBit
, pool
<Wire
*>> upd_outports
;
108 pool
<SigBit
> dirty_bits
;
109 pool
<Cell
*> dirty_cells
;
110 pool
<IdString
> dirty_memories
;
111 pool
<SimInstance
*, hash_ptr_ops
> dirty_children
;
122 std::vector
<Const
> past_wr_clk
;
123 std::vector
<Const
> past_wr_en
;
124 std::vector
<Const
> past_wr_addr
;
125 std::vector
<Const
> past_wr_data
;
129 dict
<Cell
*, ff_state_t
> ff_database
;
130 dict
<IdString
, mem_state_t
> mem_database
;
131 pool
<Cell
*> formal_database
;
132 dict
<Cell
*, IdString
> mem_cells
;
134 std::vector
<Mem
> memories
;
136 dict
<Wire
*, pair
<int, Const
>> vcd_database
;
137 dict
<Wire
*, pair
<fstHandle
, Const
>> fst_database
;
138 dict
<Wire
*, fstHandle
> fst_handles
;
140 SimInstance(SimShared
*shared
, std::string scope
, Module
*module
, Cell
*instance
= nullptr, SimInstance
*parent
= nullptr) :
141 shared(shared
), scope(scope
), module(module
), instance(instance
), parent(parent
), sigmap(module
)
146 log_assert(parent
->children
.count(instance
) == 0);
147 parent
->children
[instance
] = this;
150 for (auto wire
: module
->wires())
152 SigSpec sig
= sigmap(wire
);
154 for (int i
= 0; i
< GetSize(sig
); i
++) {
155 if (state_nets
.count(sig
[i
]) == 0)
156 state_nets
[sig
[i
]] = State::Sx
;
157 if (wire
->port_output
) {
158 upd_outports
[sig
[i
]].insert(wire
);
159 dirty_bits
.insert(sig
[i
]);
164 fstHandle id
= shared
->fst
->getHandle(scope
+ "." + RTLIL::unescape_id(wire
->name
));
165 if (id
==0 && wire
->name
.isPublic())
166 log_warning("Unable to found wire %s in input file.\n", (scope
+ "." + RTLIL::unescape_id(wire
->name
)).c_str());
167 fst_handles
[wire
] = id
;
170 if (wire
->attributes
.count(ID::init
)) {
171 Const initval
= wire
->attributes
.at(ID::init
);
172 for (int i
= 0; i
< GetSize(sig
) && i
< GetSize(initval
); i
++)
173 if (initval
[i
] == State::S0
|| initval
[i
] == State::S1
) {
174 state_nets
[sig
[i
]] = initval
[i
];
175 dirty_bits
.insert(sig
[i
]);
180 memories
= Mem::get_all_memories(module
);
181 for (auto &mem
: memories
) {
182 auto &mdb
= mem_database
[mem
.memid
];
184 for (auto &port
: mem
.wr_ports
) {
185 mdb
.past_wr_clk
.push_back(Const(State::Sx
));
186 mdb
.past_wr_en
.push_back(Const(State::Sx
, GetSize(port
.en
)));
187 mdb
.past_wr_addr
.push_back(Const(State::Sx
, GetSize(port
.addr
)));
188 mdb
.past_wr_data
.push_back(Const(State::Sx
, GetSize(port
.data
)));
190 mdb
.data
= mem
.get_init_data();
193 for (auto cell
: module
->cells())
195 Module
*mod
= module
->design
->module(cell
->type
);
197 if (mod
!= nullptr) {
198 dirty_children
.insert(new SimInstance(shared
, scope
+ "." + RTLIL::unescape_id(cell
->name
), mod
, cell
, this));
201 for (auto &port
: cell
->connections()) {
202 if (cell
->input(port
.first
))
203 for (auto bit
: sigmap(port
.second
)) {
204 upd_cells
[bit
].insert(cell
);
205 // Make sure cell inputs connected to constants are updated in the first cycle
206 if (bit
.wire
== nullptr)
207 dirty_bits
.insert(bit
);
211 if (cell
->type
.in(ID($dff
))) {
213 ff
.past_clock
= State::Sx
;
214 ff
.past_d
= Const(State::Sx
, cell
->getParam(ID::WIDTH
).as_int());
215 ff_database
[cell
] = ff
;
218 if (cell
->is_mem_cell())
220 mem_cells
[cell
] = cell
->parameters
.at(ID::MEMID
).decode_string();
222 if (cell
->type
.in(ID($
assert), ID($cover
), ID($assume
))) {
223 formal_database
.insert(cell
);
229 for (auto &it
: ff_database
)
231 Cell
*cell
= it
.first
;
232 ff_state_t
&ff
= it
.second
;
235 SigSpec qsig
= cell
->getPort(ID::Q
);
236 Const qdata
= get_state(qsig
);
238 set_state(qsig
, qdata
);
241 for (auto &it
: mem_database
) {
242 mem_state_t
&mem
= it
.second
;
243 for (auto &val
: mem
.past_wr_en
)
252 for (auto child
: children
)
256 IdString
name() const
258 if (instance
!= nullptr)
259 return instance
->name
;
263 std::string
hiername() const
265 if (instance
!= nullptr)
266 return parent
->hiername() + "." + log_id(instance
->name
);
268 return log_id(module
->name
);
271 Const
get_state(SigSpec sig
)
275 for (auto bit
: sigmap(sig
))
276 if (bit
.wire
== nullptr)
277 value
.bits
.push_back(bit
.data
);
278 else if (state_nets
.count(bit
))
279 value
.bits
.push_back(state_nets
.at(bit
));
281 value
.bits
.push_back(State::Sz
);
284 log("[%s] get %s: %s\n", hiername().c_str(), log_signal(sig
), log_signal(value
));
288 bool set_state(SigSpec sig
, Const value
)
290 bool did_something
= false;
293 log_assert(GetSize(sig
) <= GetSize(value
));
295 for (int i
= 0; i
< GetSize(sig
); i
++)
296 if (state_nets
.at(sig
[i
]) != value
[i
]) {
297 state_nets
.at(sig
[i
]) = value
[i
];
298 dirty_bits
.insert(sig
[i
]);
299 did_something
= true;
303 log("[%s] set %s: %s\n", hiername().c_str(), log_signal(sig
), log_signal(value
));
304 return did_something
;
307 void update_cell(Cell
*cell
)
309 if (ff_database
.count(cell
))
312 if (formal_database
.count(cell
))
315 if (mem_cells
.count(cell
))
317 dirty_memories
.insert(mem_cells
[cell
]);
321 if (children
.count(cell
))
323 auto child
= children
.at(cell
);
324 for (auto &conn
: cell
->connections())
325 if (cell
->input(conn
.first
) && GetSize(conn
.second
)) {
326 Const value
= get_state(conn
.second
);
327 child
->set_state(child
->module
->wire(conn
.first
), value
);
329 dirty_children
.insert(child
);
333 if (yosys_celltypes
.cell_evaluable(cell
->type
))
335 RTLIL::SigSpec sig_a
, sig_b
, sig_c
, sig_d
, sig_s
, sig_y
;
336 bool has_a
, has_b
, has_c
, has_d
, has_s
, has_y
;
338 has_a
= cell
->hasPort(ID::A
);
339 has_b
= cell
->hasPort(ID::B
);
340 has_c
= cell
->hasPort(ID::C
);
341 has_d
= cell
->hasPort(ID::D
);
342 has_s
= cell
->hasPort(ID::S
);
343 has_y
= cell
->hasPort(ID::Y
);
345 if (has_a
) sig_a
= cell
->getPort(ID::A
);
346 if (has_b
) sig_b
= cell
->getPort(ID::B
);
347 if (has_c
) sig_c
= cell
->getPort(ID::C
);
348 if (has_d
) sig_d
= cell
->getPort(ID::D
);
349 if (has_s
) sig_s
= cell
->getPort(ID::S
);
350 if (has_y
) sig_y
= cell
->getPort(ID::Y
);
353 log("[%s] eval %s (%s)\n", hiername().c_str(), log_id(cell
), log_id(cell
->type
));
355 // Simple (A -> Y) and (A,B -> Y) cells
356 if (has_a
&& !has_c
&& !has_d
&& !has_s
&& has_y
) {
357 set_state(sig_y
, CellTypes::eval(cell
, get_state(sig_a
), get_state(sig_b
)));
361 // (A,B,C -> Y) cells
362 if (has_a
&& has_b
&& has_c
&& !has_d
&& !has_s
&& has_y
) {
363 set_state(sig_y
, CellTypes::eval(cell
, get_state(sig_a
), get_state(sig_b
), get_state(sig_c
)));
367 // (A,B,S -> Y) cells
368 if (has_a
&& has_b
&& !has_c
&& !has_d
&& has_s
&& has_y
) {
369 set_state(sig_y
, CellTypes::eval(cell
, get_state(sig_a
), get_state(sig_b
), get_state(sig_s
)));
373 log_warning("Unsupported evaluable cell type: %s (%s.%s)\n", log_id(cell
->type
), log_id(module
), log_id(cell
));
377 log_error("Unsupported cell type: %s (%s.%s)\n", log_id(cell
->type
), log_id(module
), log_id(cell
));
380 void update_memory(IdString id
) {
381 auto &mdb
= mem_database
[id
];
382 auto &mem
= *mdb
.mem
;
384 for (int port_idx
= 0; port_idx
< GetSize(mem
.rd_ports
); port_idx
++)
386 auto &port
= mem
.rd_ports
[port_idx
];
387 Const addr
= get_state(port
.addr
);
388 Const data
= Const(State::Sx
, mem
.width
<< port
.wide_log2
);
391 log_error("Memory %s.%s has clocked read ports. Run 'memory' with -nordff.\n", log_id(module
), log_id(mem
.memid
));
393 if (addr
.is_fully_def()) {
394 int index
= addr
.as_int() - mem
.start_offset
;
395 if (index
>= 0 && index
< mem
.size
)
396 data
= mdb
.data
.extract(index
*mem
.width
, mem
.width
<< port
.wide_log2
);
399 set_state(port
.data
, data
);
405 pool
<Cell
*> queue_cells
;
406 pool
<Wire
*> queue_outports
;
408 queue_cells
.swap(dirty_cells
);
412 for (auto bit
: dirty_bits
)
414 if (upd_cells
.count(bit
))
415 for (auto cell
: upd_cells
.at(bit
))
416 queue_cells
.insert(cell
);
418 if (upd_outports
.count(bit
) && parent
!= nullptr)
419 for (auto wire
: upd_outports
.at(bit
))
420 queue_outports
.insert(wire
);
425 if (!queue_cells
.empty())
427 for (auto cell
: queue_cells
)
434 for (auto &memid
: dirty_memories
)
435 update_memory(memid
);
436 dirty_memories
.clear();
438 for (auto wire
: queue_outports
)
439 if (instance
->hasPort(wire
->name
)) {
440 Const value
= get_state(wire
);
441 parent
->set_state(instance
->getPort(wire
->name
), value
);
444 queue_outports
.clear();
446 for (auto child
: dirty_children
)
449 dirty_children
.clear();
451 if (dirty_bits
.empty())
458 bool did_something
= false;
460 for (auto &it
: ff_database
)
462 Cell
*cell
= it
.first
;
463 ff_state_t
&ff
= it
.second
;
465 if (cell
->type
.in(ID($dff
)))
467 bool clkpol
= cell
->getParam(ID::CLK_POLARITY
).as_bool();
468 State current_clock
= get_state(cell
->getPort(ID::CLK
))[0];
470 if (clkpol
? (ff
.past_clock
== State::S1
|| current_clock
!= State::S1
) :
471 (ff
.past_clock
== State::S0
|| current_clock
!= State::S0
))
474 if (set_state(cell
->getPort(ID::Q
), ff
.past_d
))
475 did_something
= true;
479 for (auto &it
: mem_database
)
481 mem_state_t
&mdb
= it
.second
;
482 auto &mem
= *mdb
.mem
;
484 for (int port_idx
= 0; port_idx
< GetSize(mem
.wr_ports
); port_idx
++)
486 auto &port
= mem
.wr_ports
[port_idx
];
487 Const addr
, data
, enable
;
489 if (!port
.clk_enable
)
491 addr
= get_state(port
.addr
);
492 data
= get_state(port
.data
);
493 enable
= get_state(port
.en
);
497 if (port
.clk_polarity
?
498 (mdb
.past_wr_clk
[port_idx
] == State::S1
|| get_state(port
.clk
) != State::S1
) :
499 (mdb
.past_wr_clk
[port_idx
] == State::S0
|| get_state(port
.clk
) != State::S0
))
502 addr
= mdb
.past_wr_addr
[port_idx
];
503 data
= mdb
.past_wr_data
[port_idx
];
504 enable
= mdb
.past_wr_en
[port_idx
];
507 if (addr
.is_fully_def())
509 int index
= addr
.as_int() - mem
.start_offset
;
510 if (index
>= 0 && index
< mem
.size
)
511 for (int i
= 0; i
< (mem
.width
<< port
.wide_log2
); i
++)
512 if (enable
[i
] == State::S1
&& mdb
.data
.bits
.at(index
*mem
.width
+i
) != data
[i
]) {
513 mdb
.data
.bits
.at(index
*mem
.width
+i
) = data
[i
];
514 dirty_memories
.insert(mem
.memid
);
515 did_something
= true;
521 for (auto it
: children
)
522 if (it
.second
->update_ph2()) {
523 dirty_children
.insert(it
.second
);
524 did_something
= true;
527 return did_something
;
532 for (auto &it
: ff_database
)
534 Cell
*cell
= it
.first
;
535 ff_state_t
&ff
= it
.second
;
537 if (cell
->type
.in(ID($dff
))) {
538 ff
.past_clock
= get_state(cell
->getPort(ID::CLK
))[0];
539 ff
.past_d
= get_state(cell
->getPort(ID::D
));
543 for (auto &it
: mem_database
)
545 mem_state_t
&mem
= it
.second
;
547 for (int i
= 0; i
< GetSize(mem
.mem
->wr_ports
); i
++) {
548 auto &port
= mem
.mem
->wr_ports
[i
];
549 mem
.past_wr_clk
[i
] = get_state(port
.clk
);
550 mem
.past_wr_en
[i
] = get_state(port
.en
);
551 mem
.past_wr_addr
[i
] = get_state(port
.addr
);
552 mem
.past_wr_data
[i
] = get_state(port
.data
);
556 for (auto cell
: formal_database
)
558 string label
= log_id(cell
);
559 if (cell
->attributes
.count(ID::src
))
560 label
= cell
->attributes
.at(ID::src
).decode_string();
562 State a
= get_state(cell
->getPort(ID::A
))[0];
563 State en
= get_state(cell
->getPort(ID::EN
))[0];
565 if (cell
->type
== ID($cover
) && en
== State::S1
&& a
!= State::S1
)
566 log("Cover %s.%s (%s) reached.\n", hiername().c_str(), log_id(cell
), label
.c_str());
568 if (cell
->type
== ID($assume
) && en
== State::S1
&& a
!= State::S1
)
569 log("Assumption %s.%s (%s) failed.\n", hiername().c_str(), log_id(cell
), label
.c_str());
571 if (cell
->type
== ID($
assert) && en
== State::S1
&& a
!= State::S1
)
572 log_warning("Assert %s.%s (%s) failed.\n", hiername().c_str(), log_id(cell
), label
.c_str());
575 for (auto it
: children
)
576 it
.second
->update_ph3();
579 void writeback(pool
<Module
*> &wbmods
)
581 if (wbmods
.count(module
))
582 log_error("Instance %s of module %s is not unique: Writeback not possible. (Fix by running 'uniquify'.)\n", hiername().c_str(), log_id(module
));
584 wbmods
.insert(module
);
586 for (auto wire
: module
->wires())
587 wire
->attributes
.erase(ID::init
);
589 for (auto &it
: ff_database
)
591 Cell
*cell
= it
.first
;
592 SigSpec sig_q
= cell
->getPort(ID::Q
);
593 Const initval
= get_state(sig_q
);
595 for (int i
= 0; i
< GetSize(sig_q
); i
++)
597 Wire
*w
= sig_q
[i
].wire
;
599 if (w
->attributes
.count(ID::init
) == 0)
600 w
->attributes
[ID::init
] = Const(State::Sx
, GetSize(w
));
602 w
->attributes
[ID::init
][sig_q
[i
].offset
] = initval
[i
];
606 for (auto &it
: mem_database
)
608 mem_state_t
&mem
= it
.second
;
609 mem
.mem
->clear_inits();
611 minit
.addr
= mem
.mem
->start_offset
;
612 minit
.data
= mem
.data
;
613 minit
.en
= Const(State::S1
, mem
.mem
->width
);
614 mem
.mem
->inits
.push_back(minit
);
618 for (auto it
: children
)
619 it
.second
->writeback(wbmods
);
622 void write_vcd_header(std::ofstream
&f
, int &id
)
624 f
<< stringf("$scope module %s $end\n", log_id(name()));
626 for (auto wire
: module
->wires())
628 if (shared
->hide_internal
&& wire
->name
[0] == '$')
631 f
<< stringf("$var wire %d n%d %s%s $end\n", GetSize(wire
), id
, wire
->name
[0] == '$' ? "\\" : "", log_id(wire
));
632 vcd_database
[wire
] = make_pair(id
++, Const());
635 for (auto child
: children
)
636 child
.second
->write_vcd_header(f
, id
);
638 f
<< stringf("$upscope $end\n");
641 void write_vcd_step(std::ofstream
&f
)
643 for (auto &it
: vcd_database
)
645 Wire
*wire
= it
.first
;
646 Const value
= get_state(wire
);
647 int id
= it
.second
.first
;
649 if (it
.second
.second
== value
)
652 it
.second
.second
= value
;
655 for (int i
= GetSize(value
)-1; i
>= 0; i
--) {
657 case State::S0
: f
<< "0"; break;
658 case State::S1
: f
<< "1"; break;
659 case State::Sx
: f
<< "x"; break;
664 f
<< stringf(" n%d\n", id
);
667 for (auto child
: children
)
668 child
.second
->write_vcd_step(f
);
671 void write_fst_header(struct fstContext
*f
)
673 fstWriterSetScope(f
, FST_ST_VCD_MODULE
, stringf("%s",log_id(name())).c_str(), nullptr);
674 for (auto wire
: module
->wires())
676 if (shared
->hide_internal
&& wire
->name
[0] == '$')
679 fstHandle id
= fstWriterCreateVar(f
, FST_VT_VCD_WIRE
, FST_VD_IMPLICIT
, GetSize(wire
),
680 stringf("%s%s", wire
->name
[0] == '$' ? "\\" : "", log_id(wire
)).c_str(), 0);
681 fst_database
[wire
] = make_pair(id
, Const());
684 for (auto child
: children
)
685 child
.second
->write_fst_header(f
);
687 fstWriterSetUpscope(f
);
690 void write_fst_step(struct fstContext
*f
)
692 for (auto &it
: fst_database
)
694 Wire
*wire
= it
.first
;
695 Const value
= get_state(wire
);
696 fstHandle id
= it
.second
.first
;
698 if (it
.second
.second
== value
)
701 it
.second
.second
= value
;
702 std::stringstream ss
;
703 for (int i
= GetSize(value
)-1; i
>= 0; i
--) {
705 case State::S0
: ss
<< "0"; break;
706 case State::S1
: ss
<< "1"; break;
707 case State::Sx
: ss
<< "x"; break;
711 fstWriterEmitValueChange(f
, id
, ss
.str().c_str());
714 for (auto child
: children
)
715 child
.second
->write_fst_step(f
);
718 void setInitState(uint64_t time
)
720 for (auto &it
: ff_database
)
722 Cell
*cell
= it
.first
;
724 SigSpec qsig
= cell
->getPort(ID::Q
);
725 if (qsig
.is_wire()) {
726 IdString name
= qsig
.as_wire()->name
;
727 fstHandle id
= shared
->fst
->getHandle(scope
+ "." + RTLIL::unescape_id(name
));
728 if (id
==0 && name
.isPublic())
729 log_warning("Unable to found wire %s in input file.\n", (scope
+ "." + RTLIL::unescape_id(name
)).c_str());
731 Const fst_val
= Const::from_string(shared
->fst
->valueAt(id
, time
));
732 set_state(qsig
, fst_val
);
736 for (auto child
: children
)
737 child
.second
->setInitState(time
);
740 bool checkSignals(uint64_t time
)
743 for(auto &item
: fst_handles
) {
744 if (item
.second
==0) continue; // Ignore signals not found
745 Const fst_val
= Const::from_string(shared
->fst
->valueAt(item
.second
, time
));
746 Const sim_val
= get_state(item
.first
);
747 if (shared
->sim_mode
== SimulationMode::gate
&& !fst_val
.is_fully_def()) { // FST data contains X
748 // TODO: check bit by bit
749 } else if (shared
->sim_mode
== SimulationMode::gold
&& !sim_val
.is_fully_def()) { // sim data contains X
750 // TODO: check bit by bit
752 if (fst_val
!=sim_val
) {
754 log("signal: %s fst: %s sim: %s\n", log_id(item
.first
), log_signal(fst_val
), log_signal(sim_val
));
757 //log("signal: %s fst: %s sim: %s\n", log_id(item.first), log_signal(fst_val), log_signal(sim_val));
759 for (auto child
: children
)
760 retVal
|= child
.second
->checkSignals(time
);
765 struct SimWorker
: SimShared
767 SimInstance
*top
= nullptr;
768 std::ofstream vcdfile
;
769 struct fstContext
*fstfile
= nullptr;
770 pool
<IdString
> clock
, clockn
, reset
, resetn
;
771 std::string timescale
;
772 std::string sim_filename
;
780 void write_vcd_header()
782 vcdfile
<< stringf("$version %s $end\n", yosys_version_str
);
784 std::time_t t
= std::time(nullptr);
786 if (std::strftime(mbstr
, sizeof(mbstr
), "%c", std::localtime(&t
))) {
787 vcdfile
<< stringf("$date ") << mbstr
<< stringf(" $end\n");
790 if (!timescale
.empty())
791 vcdfile
<< stringf("$timescale %s $end\n", timescale
.c_str());
794 top
->write_vcd_header(vcdfile
, id
);
796 vcdfile
<< stringf("$enddefinitions $end\n");
799 void write_vcd_step(int t
)
801 vcdfile
<< stringf("#%d\n", t
);
802 top
->write_vcd_step(vcdfile
);
805 void write_fst_header()
807 std::time_t t
= std::time(nullptr);
808 fstWriterSetDate(fstfile
, asctime(std::localtime(&t
)));
809 fstWriterSetVersion(fstfile
, yosys_version_str
);
810 if (!timescale
.empty())
811 fstWriterSetTimescaleFromString(fstfile
, timescale
.c_str());
813 fstWriterSetPackType(fstfile
, FST_WR_PT_FASTLZ
);
814 fstWriterSetRepackOnClose(fstfile
, 1);
816 top
->write_fst_header(fstfile
);
819 void write_fst_step(int t
)
821 fstWriterEmitTimeChange(fstfile
, t
);
823 top
->write_fst_step(fstfile
);
826 void write_output_header()
828 if (vcdfile
.is_open())
834 void write_output_step(int t
)
836 if (vcdfile
.is_open())
842 void write_output_end()
845 fstWriterClose(fstfile
);
853 log("\n-- ph1 --\n");
858 log("\n-- ph2 --\n");
860 if (!top
->update_ph2())
865 log("\n-- ph3 --\n");
870 void set_inports(pool
<IdString
> ports
, State value
)
872 for (auto portname
: ports
)
874 Wire
*w
= top
->module
->wire(portname
);
877 log_error("Can't find port %s on module %s.\n", log_id(portname
), log_id(top
->module
));
879 top
->set_state(w
, value
);
883 void run(Module
*topmod
, int numcycles
)
885 log_assert(top
== nullptr);
886 top
= new SimInstance(this, scope
, topmod
);
889 log("\n===== 0 =====\n");
891 log("Simulating cycle 0.\n");
893 set_inports(reset
, State::S1
);
894 set_inports(resetn
, State::S0
);
896 set_inports(clock
, State::Sx
);
897 set_inports(clockn
, State::Sx
);
901 write_output_header();
902 write_output_step(0);
904 for (int cycle
= 0; cycle
< numcycles
; cycle
++)
907 log("\n===== %d =====\n", 10*cycle
+ 5);
909 set_inports(clock
, State::S0
);
910 set_inports(clockn
, State::S1
);
913 write_output_step(10*cycle
+ 5);
916 log("\n===== %d =====\n", 10*cycle
+ 10);
918 log("Simulating cycle %d.\n", cycle
+1);
920 set_inports(clock
, State::S1
);
921 set_inports(clockn
, State::S0
);
923 if (cycle
+1 == rstlen
) {
924 set_inports(reset
, State::S0
);
925 set_inports(resetn
, State::S1
);
929 write_output_step(10*cycle
+ 10);
932 write_output_step(10*numcycles
+ 2);
937 pool
<Module
*> wbmods
;
938 top
->writeback(wbmods
);
942 void run_cosim(Module
*topmod
, int numcycles
)
944 log_assert(top
== nullptr);
945 fst
= new FstData(sim_filename
);
947 top
= new SimInstance(this, scope
, topmod
);
949 std::vector
<fstHandle
> fst_clock
;
951 for (auto portname
: clock
)
953 Wire
*w
= topmod
->wire(portname
);
955 log_error("Can't find port %s on module %s.\n", log_id(portname
), log_id(top
->module
));
957 log_error("Clock port %s on module %s is not input.\n", log_id(portname
), log_id(top
->module
));
958 fstHandle id
= fst
->getHandle(scope
+ "." + RTLIL::unescape_id(portname
));
960 log_error("Can't find port %s.%s in FST.\n", scope
.c_str(), log_id(portname
));
961 fst_clock
.push_back(id
);
963 for (auto portname
: clockn
)
965 Wire
*w
= topmod
->wire(portname
);
967 log_error("Can't find port %s on module %s.\n", log_id(portname
), log_id(top
->module
));
969 log_error("Clock port %s on module %s is not input.\n", log_id(portname
), log_id(top
->module
));
970 fstHandle id
= fst
->getHandle(scope
+ "." + RTLIL::unescape_id(portname
));
972 log_error("Can't find port %s.%s in FST.\n", scope
.c_str(), log_id(portname
));
973 fst_clock
.push_back(id
);
975 if (fst_clock
.size()==0)
976 log_error("No clock signals defined for input file\n");
978 SigMap
sigmap(topmod
);
979 std::map
<Wire
*,fstHandle
> inputs
;
981 for (auto wire
: topmod
->wires()) {
982 if (wire
->port_input
) {
983 fstHandle id
= fst
->getHandle(scope
+ "." + RTLIL::unescape_id(wire
->name
));
988 uint64_t startCount
= 0;
989 uint64_t stopCount
= 0;
991 if (start_time
< fst
->getStartTime())
992 log_warning("Start time is before simulation file start time\n");
993 startCount
= fst
->getStartTime();
994 } else if (start_time
==-1)
995 startCount
= fst
->getEndTime();
997 startCount
= start_time
/ fst
->getTimescale();
998 if (startCount
> fst
->getEndTime()) {
999 startCount
= fst
->getEndTime();
1000 log_warning("Start time is after simulation file end time\n");
1004 if (stop_time
< fst
->getStartTime())
1005 log_warning("Stop time is before simulation file start time\n");
1006 stopCount
= fst
->getStartTime();
1007 } else if (stop_time
==-1)
1008 stopCount
= fst
->getEndTime();
1010 stopCount
= stop_time
/ fst
->getTimescale();
1011 if (stopCount
> fst
->getEndTime()) {
1012 stopCount
= fst
->getEndTime();
1013 log_warning("Stop time is after simulation file end time\n");
1016 if (stopCount
<startCount
) {
1017 log_error("Stop time is before start time\n");
1019 auto edges
= fst
->getAllEdges(fst_clock
, startCount
, stopCount
);
1020 if (cycles_set
&& ((size_t)(numcycles
*2) < edges
.size()))
1021 edges
.erase(edges
.begin() + (numcycles
*2), edges
.end());
1023 if ((startCount
== stopCount
) && writeback
) {
1024 log("Update initial state with values from %zu\n",startCount
);
1026 edges
.push_back(startCount
);
1027 fst
->reconstructAllAtTimes(edges
);
1028 top
->setInitState(startCount
);
1029 pool
<Module
*> wbmods
;
1030 top
->writeback(wbmods
);
1033 log_error("No clock edges found in given time range\n");
1034 fst
->reconstructAllAtTimes(edges
);
1035 bool initial
= false;
1036 for(auto &time
: edges
) {
1037 for(auto &item
: inputs
) {
1038 std::string v
= fst
->valueAt(item
.second
, time
);
1039 top
->set_state(item
.first
, Const::from_string(v
));
1042 top
->setInitState(time
);
1047 bool status
= top
->checkSignals(time
);
1049 log_error("Signal difference at %zu\n", time
);
1055 struct SimPass
: public Pass
{
1056 SimPass() : Pass("sim", "simulate the circuit") { }
1057 void help() override
1059 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1061 log(" sim [options] [top-level]\n");
1063 log("This command simulates the circuit using the given top-level module.\n");
1065 log(" -vcd <filename>\n");
1066 log(" write the simulation results to the given VCD file\n");
1068 log(" -fst <filename>\n");
1069 log(" write the simulation results to the given FST file\n");
1071 log(" -clock <portname>\n");
1072 log(" name of top-level clock input\n");
1074 log(" -clockn <portname>\n");
1075 log(" name of top-level clock input (inverse polarity)\n");
1077 log(" -reset <portname>\n");
1078 log(" name of top-level reset input (active high)\n");
1080 log(" -resetn <portname>\n");
1081 log(" name of top-level inverted reset input (active low)\n");
1083 log(" -rstlen <integer>\n");
1084 log(" number of cycles reset should stay active (default: 1)\n");
1087 log(" zero-initialize all uninitialized regs and memories\n");
1089 log(" -timescale <string>\n");
1090 log(" include the specified timescale declaration in the vcd\n");
1092 log(" -n <integer>\n");
1093 log(" number of cycles to simulate (default: 20)\n");
1096 log(" include all nets in VCD output, not just those with public names\n");
1099 log(" writeback mode: use final simulation state as new init state\n");
1102 log(" read simulation results file (file formats supported: FST)\n");
1105 log(" scope of simulation top model\n");
1107 log(" -start <time>\n");
1108 log(" start co-simulation in arbitary time (default 0)\n");
1110 log(" -stop <time>\n");
1111 log(" stop co-simulation in arbitary time (default END)\n");
1114 log(" co-simulation expect exact match (default)\n");
1116 log(" -sim-gold\n");
1117 log(" co-simulation, x in simulation can match any value in FST\n");
1119 log(" -sim-gate\n");
1120 log(" co-simulation, x in FST can match any value in simulation\n");
1123 log(" enable debug output\n");
1126 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) override
1131 log_header(design
, "Executing SIM pass (simulate the circuit).\n");
1134 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
1135 if (args
[argidx
] == "-vcd" && argidx
+1 < args
.size()) {
1136 std::string vcd_filename
= args
[++argidx
];
1137 rewrite_filename(vcd_filename
);
1138 worker
.vcdfile
.open(vcd_filename
.c_str());
1141 if (args
[argidx
] == "-fst" && argidx
+1 < args
.size()) {
1142 std::string fst_filename
= args
[++argidx
];
1143 rewrite_filename(fst_filename
);
1144 worker
.fstfile
= (struct fstContext
*)fstWriterCreate(fst_filename
.c_str(),1);
1147 if (args
[argidx
] == "-n" && argidx
+1 < args
.size()) {
1148 numcycles
= atoi(args
[++argidx
].c_str());
1149 worker
.cycles_set
= true;
1152 if (args
[argidx
] == "-rstlen" && argidx
+1 < args
.size()) {
1153 worker
.rstlen
= atoi(args
[++argidx
].c_str());
1156 if (args
[argidx
] == "-clock" && argidx
+1 < args
.size()) {
1157 worker
.clock
.insert(RTLIL::escape_id(args
[++argidx
]));
1160 if (args
[argidx
] == "-clockn" && argidx
+1 < args
.size()) {
1161 worker
.clockn
.insert(RTLIL::escape_id(args
[++argidx
]));
1164 if (args
[argidx
] == "-reset" && argidx
+1 < args
.size()) {
1165 worker
.reset
.insert(RTLIL::escape_id(args
[++argidx
]));
1168 if (args
[argidx
] == "-resetn" && argidx
+1 < args
.size()) {
1169 worker
.resetn
.insert(RTLIL::escape_id(args
[++argidx
]));
1172 if (args
[argidx
] == "-timescale" && argidx
+1 < args
.size()) {
1173 worker
.timescale
= args
[++argidx
];
1176 if (args
[argidx
] == "-a") {
1177 worker
.hide_internal
= false;
1180 if (args
[argidx
] == "-d") {
1181 worker
.debug
= true;
1184 if (args
[argidx
] == "-w") {
1185 worker
.writeback
= true;
1188 if (args
[argidx
] == "-zinit") {
1189 worker
.zinit
= true;
1192 if (args
[argidx
] == "-r" && argidx
+1 < args
.size()) {
1193 std::string sim_filename
= args
[++argidx
];
1194 rewrite_filename(sim_filename
);
1195 worker
.sim_filename
= sim_filename
;
1198 if (args
[argidx
] == "-scope" && argidx
+1 < args
.size()) {
1199 worker
.scope
= args
[++argidx
];
1202 if (args
[argidx
] == "-start" && argidx
+1 < args
.size()) {
1203 worker
.start_time
= stringToTime(args
[++argidx
]);
1206 if (args
[argidx
] == "-stop" && argidx
+1 < args
.size()) {
1207 worker
.stop_time
= stringToTime(args
[++argidx
]);
1210 if (args
[argidx
] == "-sim-cmp") {
1211 worker
.sim_mode
= SimulationMode::cmp
;
1214 if (args
[argidx
] == "-sim-gold") {
1215 worker
.sim_mode
= SimulationMode::gold
;
1218 if (args
[argidx
] == "-sim-gate") {
1219 worker
.sim_mode
= SimulationMode::gate
;
1224 extra_args(args
, argidx
, design
);
1226 Module
*top_mod
= nullptr;
1228 if (design
->full_selection()) {
1229 top_mod
= design
->top_module();
1232 log_cmd_error("Design has no top module, use the 'hierarchy' command to specify one.\n");
1234 auto mods
= design
->selected_whole_modules();
1235 if (GetSize(mods
) != 1)
1236 log_cmd_error("Only one top module must be selected.\n");
1237 top_mod
= mods
.front();
1240 if (worker
.sim_filename
.empty())
1241 worker
.run(top_mod
, numcycles
);
1243 worker
.run_cosim(top_mod
, numcycles
);
1247 PRIVATE_NAMESPACE_END