Merge pull request #1050 from YosysHQ/clifford/wandwor
[yosys.git] / passes / cmds / check.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5 *
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.
9 *
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.
17 *
18 */
19
20 #include "kernel/yosys.h"
21 #include "kernel/sigtools.h"
22 #include "kernel/celltypes.h"
23 #include "kernel/utils.h"
24
25 USING_YOSYS_NAMESPACE
26 PRIVATE_NAMESPACE_BEGIN
27
28 struct CheckPass : public Pass {
29 CheckPass() : Pass("check", "check for obvious problems in the design") { }
30 void help() YS_OVERRIDE
31 {
32 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
33 log("\n");
34 log(" check [options] [selection]\n");
35 log("\n");
36 log("This pass identifies the following problems in the current design:\n");
37 log("\n");
38 log(" - combinatorial loops\n");
39 log("\n");
40 log(" - two or more conflicting drivers for one wire\n");
41 log("\n");
42 log(" - used wires that do not have a driver\n");
43 log("\n");
44 log("When called with -noinit then this command also checks for wires which have\n");
45 log("the 'init' attribute set.\n");
46 log("\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");
49 log("\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");
52 log("\n");
53 }
54 void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
55 {
56 int counter = 0;
57 bool noinit = false;
58 bool initdrv = false;
59 bool assert_mode = false;
60
61 size_t argidx;
62 for (argidx = 1; argidx < args.size(); argidx++) {
63 if (args[argidx] == "-noinit") {
64 noinit = true;
65 continue;
66 }
67 if (args[argidx] == "-initdrv") {
68 initdrv = true;
69 continue;
70 }
71 if (args[argidx] == "-assert") {
72 assert_mode = true;
73 continue;
74 }
75 break;
76 }
77 extra_args(args, argidx, design);
78
79 log_header(design, "Executing CHECK pass (checking for obvious problems).\n");
80
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_");
123
124 for (auto module : design->selected_whole_modules_warn())
125 {
126 if (module->has_processes_warn())
127 continue;
128
129 log("checking module %s..\n", log_id(module));
130
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;
136
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))
142 for (auto bit : sig)
143 if (bit.wire) {
144 if (logic_cell)
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);
148 }
149 if (cell->output(conn.first))
150 for (int i = 0; i < GetSize(sig); i++) {
151 if (logic_cell)
152 topo.edge(stringf("cell %s (%s)", log_id(cell), log_id(cell->type)),
153 stringf("wire %s", log_signal(sig[i])));
154 if (sig[i].wire)
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)));
157 }
158 if (!cell->input(conn.first) && cell->output(conn.first))
159 for (auto bit : sig)
160 if (bit.wire) wire_drivers_count[bit]++;
161 }
162
163 pool<SigBit> init_bits;
164
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));
170 }
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)));
182 if (noinit) {
183 log_warning("Wire %s.%s has an unprocessed 'init' attribute.\n", log_id(module), log_id(wire));
184 counter++;
185 }
186 }
187 }
188
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());
195 counter++;
196 }
197
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));
201 counter++;
202 }
203
204 topo.sort();
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());
210 counter++;
211 }
212
213 if (initdrv)
214 {
215 for (auto cell : module->cells())
216 {
217 if (fftypes.count(cell->type) == 0)
218 continue;
219
220 for (auto bit : sigmap(cell->getPort("\\Q")))
221 init_bits.erase(bit);
222 }
223
224 SigSpec init_sig(init_bits);
225 init_sig.sort_and_unify();
226
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));
229 counter++;
230 }
231 }
232 }
233
234 log("found and reported %d problems.\n", counter);
235
236 if (assert_mode && counter > 0)
237 log_error("Found %d problems in 'check -assert'.\n", counter);
238 }
239 } CheckPass;
240
241 PRIVATE_NAMESPACE_END