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");
44 log("When called with -noinit then this command also checks for wires which have\n");
45 log("the 'init' attribute set.\n");
47 log("When called with -initdrv then this command also checks for wires which have\n");
48 log("the 'init' attribute set and aren't driven by a FF cell type.\n");
50 log("When called with -assert then the command will produce an error if any\n");
51 log("problems are found in the current design.\n");
54 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
59 bool assert_mode
= false;
62 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
63 if (args
[argidx
] == "-noinit") {
67 if (args
[argidx
] == "-initdrv") {
71 if (args
[argidx
] == "-assert") {
77 extra_args(args
, argidx
, design
);
79 log_header(design
, "Executing CHECK pass (checking for obvious problems).\n");
81 pool
<IdString
> fftypes
;
82 fftypes
.insert("$sr");
83 fftypes
.insert("$ff");
84 fftypes
.insert("$dff");
85 fftypes
.insert("$dffe");
86 fftypes
.insert("$dffsr");
87 fftypes
.insert("$adff");
88 fftypes
.insert("$dlatch");
89 fftypes
.insert("$dlatchsr");
90 fftypes
.insert("$_DFFE_NN_");
91 fftypes
.insert("$_DFFE_NP_");
92 fftypes
.insert("$_DFFE_PN_");
93 fftypes
.insert("$_DFFE_PP_");
94 fftypes
.insert("$_DFFSR_NNN_");
95 fftypes
.insert("$_DFFSR_NNP_");
96 fftypes
.insert("$_DFFSR_NPN_");
97 fftypes
.insert("$_DFFSR_NPP_");
98 fftypes
.insert("$_DFFSR_PNN_");
99 fftypes
.insert("$_DFFSR_PNP_");
100 fftypes
.insert("$_DFFSR_PPN_");
101 fftypes
.insert("$_DFFSR_PPP_");
102 fftypes
.insert("$_DFF_NN0_");
103 fftypes
.insert("$_DFF_NN1_");
104 fftypes
.insert("$_DFF_NP0_");
105 fftypes
.insert("$_DFF_NP1_");
106 fftypes
.insert("$_DFF_N_");
107 fftypes
.insert("$_DFF_PN0_");
108 fftypes
.insert("$_DFF_PN1_");
109 fftypes
.insert("$_DFF_PP0_");
110 fftypes
.insert("$_DFF_PP1_");
111 fftypes
.insert("$_DFF_P_");
112 fftypes
.insert("$_DLATCHSR_NNN_");
113 fftypes
.insert("$_DLATCHSR_NNP_");
114 fftypes
.insert("$_DLATCHSR_NPN_");
115 fftypes
.insert("$_DLATCHSR_NPP_");
116 fftypes
.insert("$_DLATCHSR_PNN_");
117 fftypes
.insert("$_DLATCHSR_PNP_");
118 fftypes
.insert("$_DLATCHSR_PPN_");
119 fftypes
.insert("$_DLATCHSR_PPP_");
120 fftypes
.insert("$_DLATCH_N_");
121 fftypes
.insert("$_DLATCH_P_");
122 fftypes
.insert("$_FF_");
124 for (auto module
: design
->selected_whole_modules_warn())
126 if (module
->has_processes_warn())
129 log("checking module %s..\n", log_id(module
));
131 SigMap
sigmap(module
);
132 dict
<SigBit
, vector
<string
>> wire_drivers
;
133 dict
<SigBit
, int> wire_drivers_count
;
134 pool
<SigBit
> used_wires
;
135 TopoSort
<string
> topo
;
137 for (auto cell
: module
->cells())
138 for (auto &conn
: cell
->connections()) {
139 SigSpec sig
= sigmap(conn
.second
);
140 bool logic_cell
= yosys_celltypes
.cell_evaluable(cell
->type
);
141 if (cell
->input(conn
.first
))
145 topo
.edge(stringf("wire %s", log_signal(bit
)),
146 stringf("cell %s (%s)", log_id(cell
), log_id(cell
->type
)));
147 used_wires
.insert(bit
);
149 if (cell
->output(conn
.first
))
150 for (int i
= 0; i
< GetSize(sig
); i
++) {
152 topo
.edge(stringf("cell %s (%s)", log_id(cell
), log_id(cell
->type
)),
153 stringf("wire %s", log_signal(sig
[i
])));
155 wire_drivers
[sig
[i
]].push_back(stringf("port %s[%d] of cell %s (%s)",
156 log_id(conn
.first
), i
, log_id(cell
), log_id(cell
->type
)));
158 if (!cell
->input(conn
.first
) && cell
->output(conn
.first
))
160 if (bit
.wire
) wire_drivers_count
[bit
]++;
163 pool
<SigBit
> init_bits
;
165 for (auto wire
: module
->wires()) {
166 if (wire
->port_input
) {
167 SigSpec sig
= sigmap(wire
);
168 for (int i
= 0; i
< GetSize(sig
); i
++)
169 wire_drivers
[sig
[i
]].push_back(stringf("module input %s[%d]", log_id(wire
), i
));
171 if (wire
->port_output
)
172 for (auto bit
: sigmap(wire
))
173 if (bit
.wire
) used_wires
.insert(bit
);
174 if (wire
->port_input
&& !wire
->port_output
)
175 for (auto bit
: sigmap(wire
))
176 if (bit
.wire
) wire_drivers_count
[bit
]++;
177 if (wire
->attributes
.count("\\init")) {
178 Const initval
= wire
->attributes
.at("\\init");
179 for (int i
= 0; i
< GetSize(initval
) && i
< GetSize(wire
); i
++)
180 if (initval
[i
] == State::S0
|| initval
[i
] == State::S1
)
181 init_bits
.insert(sigmap(SigBit(wire
, i
)));
183 log_warning("Wire %s.%s has an unprocessed 'init' attribute.\n", log_id(module
), log_id(wire
));
189 for (auto it
: wire_drivers
)
190 if (wire_drivers_count
[it
.first
] > 1) {
191 string message
= stringf("multiple conflicting drivers for %s.%s:\n", log_id(module
), log_signal(it
.first
));
192 for (auto str
: it
.second
)
193 message
+= stringf(" %s\n", str
.c_str());
194 log_warning("%s", message
.c_str());
198 for (auto bit
: used_wires
)
199 if (!wire_drivers
.count(bit
)) {
200 log_warning("Wire %s.%s is used but has no driver.\n", log_id(module
), log_signal(bit
));
205 for (auto &loop
: topo
.loops
) {
206 string message
= stringf("found logic loop in module %s:\n", log_id(module
));
207 for (auto &str
: loop
)
208 message
+= stringf(" %s\n", str
.c_str());
209 log_warning("%s", message
.c_str());
215 for (auto cell
: module
->cells())
217 if (fftypes
.count(cell
->type
) == 0)
220 for (auto bit
: sigmap(cell
->getPort("\\Q")))
221 init_bits
.erase(bit
);
224 SigSpec
init_sig(init_bits
);
225 init_sig
.sort_and_unify();
227 for (auto chunk
: init_sig
.chunks()) {
228 log_warning("Wire %s.%s has 'init' attribute and is not driven by an FF cell.\n", log_id(module
), log_signal(chunk
));
234 log("found and reported %d problems.\n", counter
);
236 if (assert_mode
&& counter
> 0)
237 log_error("Found %d problems in 'check -assert'.\n", counter
);
241 PRIVATE_NAMESPACE_END