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/register.h"
21 #include "kernel/celltypes.h"
22 #include "passes/techmap/libparse.h"
24 #include "kernel/log.h"
27 PRIVATE_NAMESPACE_BEGIN
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)
34 #define STAT_NUMERIC_MEMBERS STAT_INT_MEMBERS X(area)
36 #define X(_name) int _name;
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
;
46 statdata_t
operator+(const statdata_t
&other
) const
48 statdata_t sum
= other
;
49 #define X(_name) sum._name += _name;
52 for (auto &it
: num_cells_by_type
)
53 sum
.num_cells_by_type
[it
.first
] += it
.second
;
57 statdata_t
operator*(int other
) const
59 statdata_t sum
= *this;
60 #define X(_name) sum._name *= other;
63 for (auto &it
: sum
.num_cells_by_type
)
70 #define X(_name) _name = 0;
75 statdata_t(RTLIL::Design
*design
, RTLIL::Module
*mod
, bool width_mode
, const dict
<IdString
, double> &cell_area
, string techname
)
79 #define X(_name) _name = 0;
83 for (auto &it
: mod
->wires_
)
85 if (!design
->selected(mod
, it
.second
))
88 if (it
.first
[0] == '\\') {
90 num_pub_wire_bits
+= it
.second
->width
;
94 num_wire_bits
+= it
.second
->width
;
97 for (auto &it
: mod
->memories
) {
98 if (!design
->selected(mod
, it
.second
))
101 num_memory_bits
+= it
.second
->width
* it
.second
->size
;
104 for (auto &it
: mod
->cells_
)
106 if (!design
->selected(mod
, it
.second
))
109 RTLIL::IdString cell_type
= it
.second
->type
;
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
}));
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")));
131 if (!cell_area
.empty()) {
132 if (cell_area
.count(cell_type
))
133 area
+= cell_area
.at(cell_type
);
135 unknown_cell_area
.insert(cell_type
);
139 num_cells_by_type
[cell_type
]++;
142 for (auto &it
: mod
->processes
) {
143 if (!design
->selected(mod
, it
.second
))
149 void log_data(RTLIL::IdString mod_name
, bool top_mod
)
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
)
161 log(" %-26s %6d\n", RTLIL::id2cstr(it
.first
), it
.second
);
163 if (!unknown_cell_area
.empty()) {
165 for (auto cell_type
: unknown_cell_area
)
166 log(" Area for cell type %s is unknown!\n", cell_type
.c_str());
171 log(" Chip area for %smodule '%s': %f\n", (top_mod
) ? "top " : "", mod_name
.c_str(), area
);
174 if (tech
== "xilinx")
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"];
188 int cnt
= std::min(lut5_cnt
, lut1_cnt
);
195 int cnt
= std::min(lut4_cnt
, lut1_cnt
);
200 int cnt
= std::min(lut4_cnt
, lut2_cnt
);
207 int cnt
= std::min(lut3_cnt
, lut1_cnt
);
212 int cnt
= std::min(lut3_cnt
, lut2_cnt
);
217 int cnt
= (lut3_cnt
+ 1) / 2;
221 lc_cnt
+= (lut2_cnt
+ lut1_cnt
+ 1) / 2;
224 log(" Estimated number of LCs: %10d\n", lc_cnt
);
229 statdata_t
hierarchy_worker(std::map
<RTLIL::IdString
, statdata_t
> &mod_stat
, RTLIL::IdString mod
, int level
)
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
);
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
;
241 mod_data
.num_cells_by_type
[it
.first
] += it
.second
;
247 void read_liberty_cellarea(dict
<IdString
, double> &cell_area
, string liberty_file
)
250 f
.open(liberty_file
.c_str());
251 yosys_input_files
.insert(liberty_file
);
253 log_cmd_error("Can't open liberty file `%s': %s\n", liberty_file
.c_str(), strerror(errno
));
254 LibertyParser
libparser(f
);
257 for (auto cell
: libparser
.ast
->children
)
259 if (cell
->id
!= "cell" || cell
->args
.size() != 1)
262 LibertyAst
*ar
= cell
->find("area");
263 if (ar
!= NULL
&& !ar
->value
.empty())
264 cell_area
["\\" + cell
->args
[0]] = atof(ar
->value
.c_str());
268 struct StatPass
: public Pass
{
269 StatPass() : Pass("stat", "print some statistics") { }
270 void help() YS_OVERRIDE
272 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
274 log(" stat [options] [selection]\n");
276 log("Print some statistics (number of objects) on the selected portion of the\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");
284 log(" -liberty <liberty_file>\n");
285 log(" use cell area information from the provided liberty file\n");
287 log(" -tech <technology>\n");
288 log(" print area estemate for the specified technology. Currently supported\n");
289 log(" values for <technology>: xilinx\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");
296 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
298 log_header(design
, "Printing statistics.\n");
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
;
307 for (argidx
= 1; argidx
< args
.size(); argidx
++)
309 if (args
[argidx
] == "-width") {
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
);
319 if (args
[argidx
] == "-tech" && argidx
+1 < args
.size()) {
320 techname
= args
[++argidx
];
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
]));
331 extra_args(args
, argidx
, design
);
333 if (techname
!= "" && techname
!= "xilinx")
334 log_cmd_error("Unsupported technology: '%s'\n", techname
.c_str());
336 for (auto mod
: design
->selected_modules())
338 if (!top_mod
&& design
->full_selection())
339 if (mod
->get_bool_attribute("\\top"))
342 statdata_t
data(design
, mod
, width_mode
, cell_area
, techname
);
343 mod_stat
[mod
->name
] = data
;
346 log("=== %s%s ===\n", RTLIL::id2cstr(mod
->name
), design
->selected_whole_module(mod
->name
) ? "" : " (partially selected)");
348 data
.log_data(mod
->name
, false);
351 if (top_mod
!= NULL
&& GetSize(mod_stat
) > 1)
354 log("=== design hierarchy ===\n");
357 log(" %-28s %6d\n", RTLIL::id2cstr(top_mod
->name
), 1);
358 statdata_t data
= hierarchy_worker(mod_stat
, top_mod
->name
, 0);
361 data
.log_data(top_mod
->name
, true);
368 PRIVATE_NAMESPACE_END