2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #include "kernel/yosys.h"
21 #include "kernel/sigtools.h"
22 #include "kernel/celltypes.h"
23 #include "kernel/utils.h"
26 PRIVATE_NAMESPACE_BEGIN
28 struct CheckPass
: public Pass
{
29 CheckPass() : Pass("check", "check for obvious problems in the design") { }
30 void help() YS_OVERRIDE
32 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
34 log(" check [options] [selection]\n");
36 log("This pass identifies the following problems in the current design:\n");
38 log(" - combinatorial loops\n");
40 log(" - two or more conflicting drivers for one wire\n");
42 log(" - used wires that do not have a driver\n");
47 log(" Also check for wires which have the 'init' attribute set.\n");
50 log(" Also check for wires that have the 'init' attribute set and are not\n");
51 log(" driven by an FF cell type.\n");
54 log(" Also check for internal cells that have not been mapped to cells of the\n");
55 log(" target architecture.\n");
57 log(" -allow-tbuf\n");
58 log(" Modify the -mapped behavior to still allow $_TBUF_ cells.\n");
61 log(" Produce a runtime error if any problems are found in the current design.\n");
64 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
70 bool allow_tbuf
= false;
71 bool assert_mode
= false;
74 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
75 if (args
[argidx
] == "-noinit") {
79 if (args
[argidx
] == "-initdrv") {
83 if (args
[argidx
] == "-mapped") {
87 if (args
[argidx
] == "-allow-tbuf") {
91 if (args
[argidx
] == "-assert") {
97 extra_args(args
, argidx
, design
);
99 log_header(design
, "Executing CHECK pass (checking for obvious problems).\n");
101 for (auto module
: design
->selected_whole_modules_warn())
103 if (module
->has_processes_warn())
106 log("checking module %s..\n", log_id(module
));
108 SigMap
sigmap(module
);
109 dict
<SigBit
, vector
<string
>> wire_drivers
;
110 dict
<SigBit
, int> wire_drivers_count
;
111 pool
<SigBit
> used_wires
;
112 TopoSort
<string
> topo
;
114 for (auto cell
: module
->cells())
116 if (mapped
&& cell
->type
.begins_with("$") && design
->module(cell
->type
) == nullptr) {
117 if (allow_tbuf
&& cell
->type
== ID($_TBUF_
)) goto cell_allowed
;
118 log_warning("Cell %s.%s is an unmapped internal cell of type %s.\n", log_id(module
), log_id(cell
), log_id(cell
->type
));
122 for (auto &conn
: cell
->connections()) {
123 SigSpec sig
= sigmap(conn
.second
);
124 bool logic_cell
= yosys_celltypes
.cell_evaluable(cell
->type
);
125 if (cell
->input(conn
.first
))
129 topo
.edge(stringf("wire %s", log_signal(bit
)),
130 stringf("cell %s (%s)", log_id(cell
), log_id(cell
->type
)));
131 used_wires
.insert(bit
);
133 if (cell
->output(conn
.first
))
134 for (int i
= 0; i
< GetSize(sig
); i
++) {
136 topo
.edge(stringf("cell %s (%s)", log_id(cell
), log_id(cell
->type
)),
137 stringf("wire %s", log_signal(sig
[i
])));
139 wire_drivers
[sig
[i
]].push_back(stringf("port %s[%d] of cell %s (%s)",
140 log_id(conn
.first
), i
, log_id(cell
), log_id(cell
->type
)));
142 if (!cell
->input(conn
.first
) && cell
->output(conn
.first
))
144 if (bit
.wire
) wire_drivers_count
[bit
]++;
148 pool
<SigBit
> init_bits
;
150 for (auto wire
: module
->wires()) {
151 if (wire
->port_input
) {
152 SigSpec sig
= sigmap(wire
);
153 for (int i
= 0; i
< GetSize(sig
); i
++)
154 wire_drivers
[sig
[i
]].push_back(stringf("module input %s[%d]", log_id(wire
), i
));
156 if (wire
->port_output
)
157 for (auto bit
: sigmap(wire
))
158 if (bit
.wire
) used_wires
.insert(bit
);
159 if (wire
->port_input
&& !wire
->port_output
)
160 for (auto bit
: sigmap(wire
))
161 if (bit
.wire
) wire_drivers_count
[bit
]++;
162 if (wire
->attributes
.count(ID::init
)) {
163 Const initval
= wire
->attributes
.at(ID::init
);
164 for (int i
= 0; i
< GetSize(initval
) && i
< GetSize(wire
); i
++)
165 if (initval
[i
] == State::S0
|| initval
[i
] == State::S1
)
166 init_bits
.insert(sigmap(SigBit(wire
, i
)));
168 log_warning("Wire %s.%s has an unprocessed 'init' attribute.\n", log_id(module
), log_id(wire
));
174 for (auto it
: wire_drivers
)
175 if (wire_drivers_count
[it
.first
] > 1) {
176 string message
= stringf("multiple conflicting drivers for %s.%s:\n", log_id(module
), log_signal(it
.first
));
177 for (auto str
: it
.second
)
178 message
+= stringf(" %s\n", str
.c_str());
179 log_warning("%s", message
.c_str());
183 for (auto bit
: used_wires
)
184 if (!wire_drivers
.count(bit
)) {
185 log_warning("Wire %s.%s is used but has no driver.\n", log_id(module
), log_signal(bit
));
190 for (auto &loop
: topo
.loops
) {
191 string message
= stringf("found logic loop in module %s:\n", log_id(module
));
192 for (auto &str
: loop
)
193 message
+= stringf(" %s\n", str
.c_str());
194 log_warning("%s", message
.c_str());
200 for (auto cell
: module
->cells())
202 if (RTLIL::builtin_ff_cell_types().count(cell
->type
) == 0)
205 for (auto bit
: sigmap(cell
->getPort(ID::Q
)))
206 init_bits
.erase(bit
);
209 SigSpec
init_sig(init_bits
);
210 init_sig
.sort_and_unify();
212 for (auto chunk
: init_sig
.chunks()) {
213 log_warning("Wire %s.%s has 'init' attribute and is not driven by an FF cell.\n", log_id(module
), log_signal(chunk
));
219 log("found and reported %d problems.\n", counter
);
221 if (assert_mode
&& counter
> 0)
222 log_error("Found %d problems in 'check -assert'.\n", counter
);
226 PRIVATE_NAMESPACE_END