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