2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #include "kernel/yosys.h"
21 #include "kernel/sigtools.h"
22 #include "kernel/celltypes.h"
25 PRIVATE_NAMESPACE_BEGIN
30 bool hide_internal
= true;
31 bool writeback
= false;
42 dict
<Cell
*, SimInstance
*> children
;
45 dict
<SigBit
, State
> state_nets
;
46 dict
<SigBit
, pool
<Cell
*>> upd_cells
;
47 dict
<SigBit
, pool
<Wire
*>> upd_outports
;
49 pool
<SigBit
> dirty_bits
;
50 pool
<SimInstance
*, hash_ptr_ops
> dirty_children
;
58 dict
<Cell
*, ff_state_t
> ff_database
;
60 dict
<Wire
*, pair
<int, Const
>> vcd_database
;
62 SimInstance(SimShared
*shared
, Module
*module
, Cell
*instance
= nullptr, SimInstance
*parent
= nullptr) :
63 shared(shared
), module(module
), instance(instance
), parent(parent
), sigmap(module
)
66 log_assert(parent
->children
.count(instance
) == 0);
67 parent
->children
[instance
] = this;
70 for (auto wire
: module
->wires())
72 SigSpec sig
= sigmap(wire
);
74 for (int i
= 0; i
< GetSize(sig
); i
++) {
75 if (state_nets
.count(sig
[i
]) == 0)
76 state_nets
[sig
[i
]] = State::Sx
;
77 if (wire
->port_output
) {
78 upd_outports
[sig
[i
]].insert(wire
);
79 dirty_bits
.insert(sig
[i
]);
83 if (wire
->attributes
.count("\\init")) {
84 Const initval
= wire
->attributes
.at("\\init");
85 for (int i
= 0; i
< GetSize(sig
) && i
< GetSize(initval
); i
++)
86 if (initval
[i
] == State::S0
|| initval
[i
] == State::S1
) {
87 state_nets
[sig
[i
]] = initval
[i
];
88 dirty_bits
.insert(sig
[i
]);
93 for (auto cell
: module
->cells())
95 Module
*mod
= module
->design
->module(cell
->type
);
98 dirty_children
.insert(new SimInstance(shared
, mod
, cell
, this));
101 for (auto &port
: cell
->connections()) {
102 if (cell
->input(port
.first
))
103 for (auto bit
: sigmap(port
.second
))
104 upd_cells
[bit
].insert(cell
);
107 if (cell
->type
.in("$dff")) {
109 ff
.past_clock
= State::Sx
;
110 ff
.past_d
= Const(State::Sx
, cell
->getParam("\\WIDTH").as_int());
111 ff_database
[cell
] = ff
;
118 for (auto child
: children
)
122 IdString
name() const
124 if (instance
!= nullptr)
125 return instance
->name
;
129 std::string
hiername() const
131 if (instance
!= nullptr)
132 return parent
->hiername() + "." + log_id(instance
->name
);
134 return log_id(module
->name
);
137 Const
get_state(SigSpec sig
)
141 for (auto bit
: sigmap(sig
))
142 if (bit
.wire
== nullptr)
143 value
.bits
.push_back(bit
.data
);
144 else if (state_nets
.count(bit
))
145 value
.bits
.push_back(state_nets
.at(bit
));
147 value
.bits
.push_back(State::Sz
);
150 log("[%s] get %s: %s\n", hiername().c_str(), log_signal(sig
), log_signal(value
));
154 bool set_state(SigSpec sig
, Const value
)
156 bool did_something
= false;
159 log_assert(GetSize(sig
) == GetSize(value
));
161 for (int i
= 0; i
< GetSize(sig
); i
++)
162 if (state_nets
.at(sig
[i
]) != value
[i
]) {
163 state_nets
.at(sig
[i
]) = value
[i
];
164 dirty_bits
.insert(sig
[i
]);
165 did_something
= true;
169 log("[%s] set %s: %s\n", hiername().c_str(), log_signal(sig
), log_signal(value
));
170 return did_something
;
173 void update_cell(Cell
*cell
)
175 if (ff_database
.count(cell
))
178 if (children
.count(cell
))
180 auto child
= children
.at(cell
);
181 for (auto &conn
: cell
->connections())
182 if (cell
->input(conn
.first
)) {
183 Const value
= get_state(conn
.second
);
184 child
->set_state(child
->module
->wire(conn
.first
), value
);
186 dirty_children
.insert(child
);
190 if (yosys_celltypes
.cell_evaluable(cell
->type
))
192 RTLIL::SigSpec sig_a
, sig_b
, sig_c
, sig_d
, sig_s
, sig_y
;
193 bool has_a
, has_b
, has_c
, has_d
, has_s
, has_y
;
195 has_a
= cell
->hasPort("\\A");
196 has_b
= cell
->hasPort("\\B");
197 has_c
= cell
->hasPort("\\C");
198 has_d
= cell
->hasPort("\\D");
199 has_s
= cell
->hasPort("\\S");
200 has_y
= cell
->hasPort("\\Y");
202 if (has_a
) sig_a
= cell
->getPort("\\A");
203 if (has_b
) sig_b
= cell
->getPort("\\B");
204 if (has_c
) sig_c
= cell
->getPort("\\C");
205 if (has_d
) sig_d
= cell
->getPort("\\D");
206 if (has_s
) sig_s
= cell
->getPort("\\S");
207 if (has_y
) sig_y
= cell
->getPort("\\Y");
210 log("[%s] eval %s (%s)\n", hiername().c_str(), log_id(cell
), log_id(cell
->type
));
212 // Simple (A -> Y) and (A,B -> Y) cells
213 if (has_a
&& !has_c
&& !has_d
&& !has_s
&& has_y
) {
214 set_state(sig_y
, CellTypes::eval(cell
, get_state(sig_a
), get_state(sig_b
)));
218 // (A,B,C -> Y) cells
219 if (has_a
&& has_b
&& has_c
&& !has_d
&& !has_s
&& has_y
) {
220 set_state(sig_y
, CellTypes::eval(cell
, get_state(sig_a
), get_state(sig_b
), get_state(sig_c
)));
224 // (A,B,S -> Y) cells
225 if (has_a
&& has_b
&& !has_c
&& !has_d
&& has_s
&& has_y
) {
226 set_state(sig_y
, CellTypes::eval(cell
, get_state(sig_a
), get_state(sig_b
), get_state(sig_s
)));
230 log_warning("Unsupported evaluable cell type: %s (%s.%s)\n", log_id(cell
->type
), log_id(module
), log_id(cell
));
236 log_warning("Unsupported cell type: %s (%s.%s)\n", log_id(cell
->type
), log_id(module
), log_id(cell
));
241 pool
<Cell
*> queue_cells
;
242 pool
<Wire
*> queue_outports
;
246 for (auto bit
: dirty_bits
)
248 if (upd_cells
.count(bit
))
249 for (auto cell
: upd_cells
.at(bit
))
250 queue_cells
.insert(cell
);
252 if (upd_outports
.count(bit
) && parent
!= nullptr)
253 for (auto wire
: upd_outports
.at(bit
))
254 queue_outports
.insert(wire
);
259 if (!queue_cells
.empty())
261 for (auto cell
: queue_cells
)
268 for (auto wire
: queue_outports
)
269 if (instance
->hasPort(wire
->name
)) {
270 Const value
= get_state(wire
);
271 parent
->set_state(instance
->getPort(wire
->name
), value
);
274 queue_outports
.clear();
276 for (auto child
: dirty_children
)
279 dirty_children
.clear();
281 if (dirty_bits
.empty())
288 bool did_something
= false;
290 for (auto &it
: ff_database
)
292 Cell
*cell
= it
.first
;
293 ff_state_t
&ff
= it
.second
;
295 if (cell
->type
.in("$dff"))
297 bool clkpol
= cell
->getParam("\\CLK_POLARITY").as_bool();
298 State current_clock
= get_state(cell
->getPort("\\CLK"))[0];
300 if (clkpol
? (ff
.past_clock
== State::S1
|| current_clock
!= State::S1
) :
301 (ff
.past_clock
== State::S0
|| current_clock
!= State::S0
))
304 if (set_state(cell
->getPort("\\Q"), ff
.past_d
))
305 did_something
= true;
309 for (auto it
: children
)
310 if (it
.second
->update_ph2()) {
311 dirty_children
.insert(it
.second
);
312 did_something
= true;
315 return did_something
;
320 for (auto &it
: ff_database
)
322 Cell
*cell
= it
.first
;
323 ff_state_t
&ff
= it
.second
;
325 if (cell
->type
.in("$dff")) {
326 ff
.past_clock
= get_state(cell
->getPort("\\CLK"))[0];
327 ff
.past_d
= get_state(cell
->getPort("\\D"));
331 for (auto it
: children
)
332 it
.second
->update_ph3();
335 void writeback(pool
<Module
*> &wbmods
)
337 if (wbmods
.count(module
))
338 log_error("Instance %s of module %s is not unique: Writeback not possible.\n", hiername().c_str(), log_id(module
));
340 wbmods
.insert(module
);
342 for (auto wire
: module
->wires())
343 wire
->attributes
.erase("\\init");
345 for (auto &it
: ff_database
)
347 Cell
*cell
= it
.first
;
348 SigSpec sig_q
= cell
->getPort("\\Q");
349 Const initval
= get_state(sig_q
);
351 for (int i
= 0; i
< GetSize(sig_q
); i
++)
353 Wire
*w
= sig_q
[i
].wire
;
355 if (w
->attributes
.count("\\init") == 0)
356 w
->attributes
["\\init"] = Const(State::Sx
, GetSize(w
));
358 w
->attributes
["\\init"][sig_q
[i
].offset
] = initval
[i
];
362 for (auto it
: children
)
363 it
.second
->writeback(wbmods
);
366 void write_vcd_header(std::ofstream
&f
, int &id
)
368 f
<< stringf("$scope module %s $end\n", log_id(name()));
370 for (auto wire
: module
->wires())
372 if (shared
->hide_internal
&& wire
->name
[0] == '$')
375 f
<< stringf("$var wire %d n%d %s%s $end\n", GetSize(wire
), id
, wire
->name
[0] == '$' ? "\\" : "", log_id(wire
));
376 vcd_database
[wire
] = make_pair(id
++, Const());
379 for (auto child
: children
)
380 child
.second
->write_vcd_header(f
, id
);
382 f
<< stringf("$upscope $end\n");
385 void write_vcd_step(std::ofstream
&f
)
387 for (auto &it
: vcd_database
)
389 Wire
*wire
= it
.first
;
390 Const value
= get_state(wire
);
391 int id
= it
.second
.first
;
393 if (it
.second
.second
== value
)
396 it
.second
.second
= value
;
399 for (int i
= GetSize(value
)-1; i
>= 0; i
--) {
401 case State::S0
: f
<< "0"; break;
402 case State::S1
: f
<< "1"; break;
403 case State::Sx
: f
<< "x"; break;
408 f
<< stringf(" n%d\n", id
);
411 for (auto child
: children
)
412 child
.second
->write_vcd_step(f
);
416 struct SimWorker
: SimShared
418 SimInstance
*top
= nullptr;
419 std::ofstream vcdfile
;
420 pool
<IdString
> clock
, clockn
, reset
, resetn
;
427 void write_vcd_header()
429 if (!vcdfile
.is_open())
433 top
->write_vcd_header(vcdfile
, id
);
435 vcdfile
<< stringf("$enddefinitions $end\n");
438 void write_vcd_step(int t
)
440 if (!vcdfile
.is_open())
443 vcdfile
<< stringf("#%d\n", t
);
444 top
->write_vcd_step(vcdfile
);
452 log("\n-- ph1 --\n");
457 log("\n-- ph2 --\n");
459 while (top
->update_ph2());
462 log("\n-- ph3 --\n");
467 void set_inports(pool
<IdString
> ports
, State value
)
469 for (auto portname
: ports
)
471 Wire
*w
= top
->module
->wire(portname
);
474 log_error("Can't find port %s on module %s.\n", log_id(portname
), log_id(top
->module
));
476 top
->set_state(w
, value
);
480 void run(Module
*topmod
, int numcycles
)
482 log_assert(top
== nullptr);
483 top
= new SimInstance(this, topmod
);
486 log("\n===== 0 =====\n");
488 set_inports(reset
, State::S1
);
489 set_inports(resetn
, State::S0
);
496 for (int cycle
= 0; cycle
< numcycles
; cycle
++)
499 log("\n===== %d =====\n", 10*cycle
+ 5);
501 set_inports(clock
, State::S0
);
502 set_inports(clockn
, State::S1
);
505 write_vcd_step(10*cycle
+ 5);
508 log("\n===== %d =====\n", 10*cycle
+ 10);
510 set_inports(clock
, State::S1
);
511 set_inports(clockn
, State::S0
);
514 set_inports(reset
, State::S0
);
515 set_inports(resetn
, State::S1
);
519 write_vcd_step(10*cycle
+ 10);
522 write_vcd_step(10*numcycles
+ 2);
525 pool
<Module
*> wbmods
;
526 top
->writeback(wbmods
);
531 struct SimPass
: public Pass
{
532 SimPass() : Pass("sim", "simulate the circuit") { }
535 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
537 log(" sim [options] [top-level]\n");
539 log("This command simulates the circuit using the given top-level module.\n");
541 log(" -vcd <filename>\n");
542 log(" write the simulation results to the given VCD file\n");
544 log(" -clock <portname>\n");
545 log(" name of top-level clock input\n");
547 log(" -clockn <portname>\n");
548 log(" name of top-level clock input (inverse polarity)\n");
550 log(" -reset <portname>\n");
551 log(" name of top-level reset input (active high)\n");
553 log(" -resetn <portname>\n");
554 log(" name of top-level inverted reset input (active low)\n");
556 log(" -n <integer>\n");
557 log(" number of cycles to simulate (default: 20)\n");
560 log(" include all nets in VCD output, nut just those with public names\n");
563 log(" writeback mode: use final simulation state as new init state\n");
566 log(" enable debug output\n");
569 virtual void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
)
574 log_header(design
, "Executing SIM pass (simulate the circuit).\n");
577 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
578 if (args
[argidx
] == "-vcd" && argidx
+1 < args
.size()) {
579 worker
.vcdfile
.open(args
[++argidx
].c_str());
582 if (args
[argidx
] == "-n" && argidx
+1 < args
.size()) {
583 numcycles
= atoi(args
[++argidx
].c_str());
586 if (args
[argidx
] == "-clock" && argidx
+1 < args
.size()) {
587 worker
.clock
.insert(RTLIL::escape_id(args
[++argidx
]));
590 if (args
[argidx
] == "-clockn" && argidx
+1 < args
.size()) {
591 worker
.clockn
.insert(RTLIL::escape_id(args
[++argidx
]));
594 if (args
[argidx
] == "-reset" && argidx
+1 < args
.size()) {
595 worker
.reset
.insert(RTLIL::escape_id(args
[++argidx
]));
598 if (args
[argidx
] == "-resetn" && argidx
+1 < args
.size()) {
599 worker
.resetn
.insert(RTLIL::escape_id(args
[++argidx
]));
602 if (args
[argidx
] == "-a") {
603 worker
.hide_internal
= false;
606 if (args
[argidx
] == "-d") {
610 if (args
[argidx
] == "-w") {
611 worker
.writeback
= true;
616 extra_args(args
, argidx
, design
);
618 Module
*top_mod
= nullptr;
620 if (design
->full_selection()) {
621 top_mod
= design
->top_module();
623 auto mods
= design
->selected_whole_modules();
624 if (GetSize(mods
) != 1)
625 log_cmd_error("Only one top module must be selected.\n");
626 top_mod
= mods
.front();
629 worker
.run(top_mod
, numcycles
);
633 PRIVATE_NAMESPACE_END