If d_bit already in sigbit_chain_next, create extra wire
[yosys.git] / passes / cmds / stat.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/register.h"
21 #include "kernel/celltypes.h"
22 #include "passes/techmap/libparse.h"
23
24 #include "kernel/log.h"
25
26 USING_YOSYS_NAMESPACE
27 PRIVATE_NAMESPACE_BEGIN
28
29 struct statdata_t
30 {
31 #define STAT_INT_MEMBERS X(num_wires) X(num_wire_bits) X(num_pub_wires) X(num_pub_wire_bits) \
32 X(num_memories) X(num_memory_bits) X(num_cells) X(num_processes)
33
34 #define STAT_NUMERIC_MEMBERS STAT_INT_MEMBERS X(area)
35
36 #define X(_name) int _name;
37 STAT_INT_MEMBERS
38 #undef X
39 double area;
40 string tech;
41
42 std::map<RTLIL::IdString, int> techinfo;
43 std::map<RTLIL::IdString, int, RTLIL::sort_by_id_str> num_cells_by_type;
44 std::set<RTLIL::IdString> unknown_cell_area;
45
46 statdata_t operator+(const statdata_t &other) const
47 {
48 statdata_t sum = other;
49 #define X(_name) sum._name += _name;
50 STAT_NUMERIC_MEMBERS
51 #undef X
52 for (auto &it : num_cells_by_type)
53 sum.num_cells_by_type[it.first] += it.second;
54 return sum;
55 }
56
57 statdata_t operator*(int other) const
58 {
59 statdata_t sum = *this;
60 #define X(_name) sum._name *= other;
61 STAT_NUMERIC_MEMBERS
62 #undef X
63 for (auto &it : sum.num_cells_by_type)
64 it.second *= other;
65 return sum;
66 }
67
68 statdata_t()
69 {
70 #define X(_name) _name = 0;
71 STAT_NUMERIC_MEMBERS
72 #undef X
73 }
74
75 statdata_t(RTLIL::Design *design, RTLIL::Module *mod, bool width_mode, const dict<IdString, double> &cell_area, string techname)
76 {
77 tech = techname;
78
79 #define X(_name) _name = 0;
80 STAT_NUMERIC_MEMBERS
81 #undef X
82
83 for (auto &it : mod->wires_)
84 {
85 if (!design->selected(mod, it.second))
86 continue;
87
88 if (it.first[0] == '\\') {
89 num_pub_wires++;
90 num_pub_wire_bits += it.second->width;
91 }
92
93 num_wires++;
94 num_wire_bits += it.second->width;
95 }
96
97 for (auto &it : mod->memories) {
98 if (!design->selected(mod, it.second))
99 continue;
100 num_memories++;
101 num_memory_bits += it.second->width * it.second->size;
102 }
103
104 for (auto &it : mod->cells_)
105 {
106 if (!design->selected(mod, it.second))
107 continue;
108
109 RTLIL::IdString cell_type = it.second->type;
110
111 if (width_mode)
112 {
113 if (cell_type.in("$not", "$pos", "$neg",
114 "$logic_not", "$logic_and", "$logic_or",
115 "$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool",
116 "$lut", "$and", "$or", "$xor", "$xnor",
117 "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
118 "$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt",
119 "$add", "$sub", "$mul", "$div", "$mod", "$pow", "$alu")) {
120 int width_a = it.second->hasPort("\\A") ? GetSize(it.second->getPort("\\A")) : 0;
121 int width_b = it.second->hasPort("\\B") ? GetSize(it.second->getPort("\\B")) : 0;
122 int width_y = it.second->hasPort("\\Y") ? GetSize(it.second->getPort("\\Y")) : 0;
123 cell_type = stringf("%s_%d", cell_type.c_str(), max<int>({width_a, width_b, width_y}));
124 }
125 else if (cell_type.in("$mux", "$pmux"))
126 cell_type = stringf("%s_%d", cell_type.c_str(), GetSize(it.second->getPort("\\Y")));
127 else if (cell_type.in("$sr", "$dff", "$dffsr", "$adff", "$dlatch", "$dlatchsr"))
128 cell_type = stringf("%s_%d", cell_type.c_str(), GetSize(it.second->getPort("\\Q")));
129 }
130
131 if (!cell_area.empty()) {
132 if (cell_area.count(cell_type))
133 area += cell_area.at(cell_type);
134 else
135 unknown_cell_area.insert(cell_type);
136 }
137
138 num_cells++;
139 num_cells_by_type[cell_type]++;
140 }
141
142 for (auto &it : mod->processes) {
143 if (!design->selected(mod, it.second))
144 continue;
145 num_processes++;
146 }
147 }
148
149 void log_data(RTLIL::IdString mod_name, bool top_mod)
150 {
151 log(" Number of wires: %6d\n", num_wires);
152 log(" Number of wire bits: %6d\n", num_wire_bits);
153 log(" Number of public wires: %6d\n", num_pub_wires);
154 log(" Number of public wire bits: %6d\n", num_pub_wire_bits);
155 log(" Number of memories: %6d\n", num_memories);
156 log(" Number of memory bits: %6d\n", num_memory_bits);
157 log(" Number of processes: %6d\n", num_processes);
158 log(" Number of cells: %6d\n", num_cells);
159 for (auto &it : num_cells_by_type)
160 if (it.second)
161 log(" %-26s %6d\n", RTLIL::id2cstr(it.first), it.second);
162
163 if (!unknown_cell_area.empty()) {
164 log("\n");
165 for (auto cell_type : unknown_cell_area)
166 log(" Area for cell type %s is unknown!\n", cell_type.c_str());
167 }
168
169 if (area != 0) {
170 log("\n");
171 log(" Chip area for %smodule '%s': %f\n", (top_mod) ? "top " : "", mod_name.c_str(), area);
172 }
173
174 if (tech == "xilinx")
175 {
176 int lut6_cnt = num_cells_by_type["\\LUT6"];
177 int lut5_cnt = num_cells_by_type["\\LUT5"];
178 int lut4_cnt = num_cells_by_type["\\LUT4"];
179 int lut3_cnt = num_cells_by_type["\\LUT3"];
180 int lut2_cnt = num_cells_by_type["\\LUT2"];
181 int lut1_cnt = num_cells_by_type["\\LUT1"];
182 int lc_cnt = 0;
183
184 lc_cnt += lut6_cnt;
185
186 lc_cnt += lut5_cnt;
187 if (lut1_cnt) {
188 int cnt = std::min(lut5_cnt, lut1_cnt);
189 lut5_cnt -= cnt;
190 lut1_cnt -= cnt;
191 }
192
193 lc_cnt += lut4_cnt;
194 if (lut1_cnt) {
195 int cnt = std::min(lut4_cnt, lut1_cnt);
196 lut4_cnt -= cnt;
197 lut1_cnt -= cnt;
198 }
199 if (lut2_cnt) {
200 int cnt = std::min(lut4_cnt, lut2_cnt);
201 lut4_cnt -= cnt;
202 lut2_cnt -= cnt;
203 }
204
205 lc_cnt += lut3_cnt;
206 if (lut1_cnt) {
207 int cnt = std::min(lut3_cnt, lut1_cnt);
208 lut3_cnt -= cnt;
209 lut1_cnt -= cnt;
210 }
211 if (lut2_cnt) {
212 int cnt = std::min(lut3_cnt, lut2_cnt);
213 lut3_cnt -= cnt;
214 lut2_cnt -= cnt;
215 }
216 if (lut3_cnt) {
217 int cnt = (lut3_cnt + 1) / 2;
218 lut3_cnt -= cnt;
219 }
220
221 lc_cnt += (lut2_cnt + lut1_cnt + 1) / 2;
222
223 log("\n");
224 log(" Estimated number of LCs: %10d\n", lc_cnt);
225 }
226 }
227 };
228
229 statdata_t hierarchy_worker(std::map<RTLIL::IdString, statdata_t> &mod_stat, RTLIL::IdString mod, int level)
230 {
231 statdata_t mod_data = mod_stat.at(mod);
232 std::map<RTLIL::IdString, int, RTLIL::sort_by_id_str> num_cells_by_type;
233 num_cells_by_type.swap(mod_data.num_cells_by_type);
234
235 for (auto &it : num_cells_by_type)
236 if (mod_stat.count(it.first) > 0) {
237 log(" %*s%-*s %6d\n", 2*level, "", 26-2*level, RTLIL::id2cstr(it.first), it.second);
238 mod_data = mod_data + hierarchy_worker(mod_stat, it.first, level+1) * it.second;
239 mod_data.num_cells -= it.second;
240 } else {
241 mod_data.num_cells_by_type[it.first] += it.second;
242 }
243
244 return mod_data;
245 }
246
247 void read_liberty_cellarea(dict<IdString, double> &cell_area, string liberty_file)
248 {
249 std::ifstream f;
250 f.open(liberty_file.c_str());
251 yosys_input_files.insert(liberty_file);
252 if (f.fail())
253 log_cmd_error("Can't open liberty file `%s': %s\n", liberty_file.c_str(), strerror(errno));
254 LibertyParser libparser(f);
255 f.close();
256
257 for (auto cell : libparser.ast->children)
258 {
259 if (cell->id != "cell" || cell->args.size() != 1)
260 continue;
261
262 LibertyAst *ar = cell->find("area");
263 if (ar != NULL && !ar->value.empty())
264 cell_area["\\" + cell->args[0]] = atof(ar->value.c_str());
265 }
266 }
267
268 struct StatPass : public Pass {
269 StatPass() : Pass("stat", "print some statistics") { }
270 void help() YS_OVERRIDE
271 {
272 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
273 log("\n");
274 log(" stat [options] [selection]\n");
275 log("\n");
276 log("Print some statistics (number of objects) on the selected portion of the\n");
277 log("design.\n");
278 log("\n");
279 log(" -top <module>\n");
280 log(" print design hierarchy with this module as top. if the design is fully\n");
281 log(" selected and a module has the 'top' attribute set, this module is used\n");
282 log(" default value for this option.\n");
283 log("\n");
284 log(" -liberty <liberty_file>\n");
285 log(" use cell area information from the provided liberty file\n");
286 log("\n");
287 log(" -tech <technology>\n");
288 log(" print area estemate for the specified technology. Corrently supported\n");
289 log(" calues for <technology>: xilinx\n");
290 log("\n");
291 log(" -width\n");
292 log(" annotate internal cell types with their word width.\n");
293 log(" e.g. $add_8 for an 8 bit wide $add cell.\n");
294 log("\n");
295 }
296 void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
297 {
298 log_header(design, "Printing statistics.\n");
299
300 bool width_mode = false;
301 RTLIL::Module *top_mod = NULL;
302 std::map<RTLIL::IdString, statdata_t> mod_stat;
303 dict<IdString, double> cell_area;
304 string techname;
305
306 size_t argidx;
307 for (argidx = 1; argidx < args.size(); argidx++)
308 {
309 if (args[argidx] == "-width") {
310 width_mode = true;
311 continue;
312 }
313 if (args[argidx] == "-liberty" && argidx+1 < args.size()) {
314 string liberty_file = args[++argidx];
315 rewrite_filename(liberty_file);
316 read_liberty_cellarea(cell_area, liberty_file);
317 continue;
318 }
319 if (args[argidx] == "-tech" && argidx+1 < args.size()) {
320 techname = args[++argidx];
321 continue;
322 }
323 if (args[argidx] == "-top" && argidx+1 < args.size()) {
324 if (design->modules_.count(RTLIL::escape_id(args[argidx+1])) == 0)
325 log_cmd_error("Can't find module %s.\n", args[argidx+1].c_str());
326 top_mod = design->modules_.at(RTLIL::escape_id(args[++argidx]));
327 continue;
328 }
329 break;
330 }
331 extra_args(args, argidx, design);
332
333 if (techname != "" && techname != "xilinx")
334 log_cmd_error("Unsupported technology: '%s'\n", techname.c_str());
335
336 for (auto mod : design->selected_modules())
337 {
338 if (!top_mod && design->full_selection())
339 if (mod->get_bool_attribute("\\top"))
340 top_mod = mod;
341
342 statdata_t data(design, mod, width_mode, cell_area, techname);
343 mod_stat[mod->name] = data;
344
345 log("\n");
346 log("=== %s%s ===\n", RTLIL::id2cstr(mod->name), design->selected_whole_module(mod->name) ? "" : " (partially selected)");
347 log("\n");
348 data.log_data(mod->name, false);
349 }
350
351 if (top_mod != NULL && GetSize(mod_stat) > 1)
352 {
353 log("\n");
354 log("=== design hierarchy ===\n");
355 log("\n");
356
357 log(" %-28s %6d\n", RTLIL::id2cstr(top_mod->name), 1);
358 statdata_t data = hierarchy_worker(mod_stat, top_mod->name, 0);
359
360 log("\n");
361 data.log_data(top_mod->name, true);
362 }
363
364 log("\n");
365 }
366 } StatPass;
367
368 PRIVATE_NAMESPACE_END