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/celltypes.h"
22 #include "passes/techmap/libparse.h"
23 #include "kernel/cost.h"
26 PRIVATE_NAMESPACE_BEGIN
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)
33 #define STAT_NUMERIC_MEMBERS STAT_INT_MEMBERS X(area)
35 #define X(_name) int _name;
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
;
45 statdata_t
operator+(const statdata_t
&other
) const
47 statdata_t sum
= other
;
48 #define X(_name) sum._name += _name;
51 for (auto &it
: num_cells_by_type
)
52 sum
.num_cells_by_type
[it
.first
] += it
.second
;
56 statdata_t
operator*(int other
) const
58 statdata_t sum
= *this;
59 #define X(_name) sum._name *= other;
62 for (auto &it
: sum
.num_cells_by_type
)
69 #define X(_name) _name = 0;
74 statdata_t(RTLIL::Design
*design
, RTLIL::Module
*mod
, bool width_mode
, const dict
<IdString
, double> &cell_area
, string techname
)
78 #define X(_name) _name = 0;
82 for (auto wire
: mod
->selected_wires())
84 if (wire
->name
[0] == '\\') {
86 num_pub_wire_bits
+= wire
->width
;
90 num_wire_bits
+= wire
->width
;
93 for (auto &it
: mod
->memories
) {
94 if (!design
->selected(mod
, it
.second
))
97 num_memory_bits
+= it
.second
->width
* it
.second
->size
;
100 for (auto cell
: mod
->selected_cells())
102 RTLIL::IdString cell_type
= cell
->type
;
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
}));
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
)));
124 if (!cell_area
.empty()) {
125 if (cell_area
.count(cell_type
))
126 area
+= cell_area
.at(cell_type
);
128 unknown_cell_area
.insert(cell_type
);
132 num_cells_by_type
[cell_type
]++;
135 for (auto &it
: mod
->processes
) {
136 if (!design
->selected(mod
, it
.second
))
142 void log_data(RTLIL::IdString mod_name
, bool top_mod
)
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
)
154 log(" %-26s %6d\n", log_id(it
.first
), it
.second
);
156 if (!unknown_cell_area
.empty()) {
158 for (auto cell_type
: unknown_cell_area
)
159 log(" Area for cell type %s is unknown!\n", cell_type
.c_str());
164 log(" Chip area for %smodule '%s': %f\n", (top_mod
) ? "top " : "", mod_name
.c_str(), area
);
167 if (tech
== "xilinx")
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
)];
181 int cnt
= std::min(lut5_cnt
, lut1_cnt
);
188 int cnt
= std::min(lut4_cnt
, lut1_cnt
);
193 int cnt
= std::min(lut4_cnt
, lut2_cnt
);
200 int cnt
= std::min(lut3_cnt
, lut1_cnt
);
205 int cnt
= std::min(lut3_cnt
, lut2_cnt
);
210 int cnt
= (lut3_cnt
+ 1) / 2;
214 lc_cnt
+= (lut2_cnt
+ lut1_cnt
+ 1) / 2;
217 log(" Estimated number of LCs: %10d\n", lc_cnt
);
223 bool tran_cnt_exact
= true;
224 auto &gate_costs
= CellCosts::cmos_gate_cost();
226 for (auto it
: num_cells_by_type
) {
227 auto ctype
= it
.first
;
228 auto cnum
= it
.second
;
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;
235 tran_cnt_exact
= false;
239 log(" Estimated number of transistors: %10d%s\n", tran_cnt
, tran_cnt_exact
? "" : "+");
244 statdata_t
hierarchy_worker(std::map
<RTLIL::IdString
, statdata_t
> &mod_stat
, RTLIL::IdString mod
, int level
)
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
);
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
;
256 mod_data
.num_cells_by_type
[it
.first
] += it
.second
;
262 void read_liberty_cellarea(dict
<IdString
, double> &cell_area
, string liberty_file
)
265 f
.open(liberty_file
.c_str());
266 yosys_input_files
.insert(liberty_file
);
268 log_cmd_error("Can't open liberty file `%s': %s\n", liberty_file
.c_str(), strerror(errno
));
269 LibertyParser
libparser(f
);
272 for (auto cell
: libparser
.ast
->children
)
274 if (cell
->id
!= "cell" || cell
->args
.size() != 1)
277 LibertyAst
*ar
= cell
->find("area");
278 if (ar
!= nullptr && !ar
->value
.empty())
279 cell_area
["\\" + cell
->args
[0]] = atof(ar
->value
.c_str());
283 struct StatPass
: public Pass
{
284 StatPass() : Pass("stat", "print some statistics") { }
285 void help() YS_OVERRIDE
287 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
289 log(" stat [options] [selection]\n");
291 log("Print some statistics (number of objects) on the selected portion of the\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");
299 log(" -liberty <liberty_file>\n");
300 log(" use cell area information from the provided liberty file\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");
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");
311 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
313 log_header(design
, "Printing statistics.\n");
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
;
322 for (argidx
= 1; argidx
< args
.size(); argidx
++)
324 if (args
[argidx
] == "-width") {
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
);
334 if (args
[argidx
] == "-tech" && argidx
+1 < args
.size()) {
335 techname
= args
[++argidx
];
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
]));
346 extra_args(args
, argidx
, design
);
348 if (techname
!= "" && techname
!= "xilinx" && techname
!= "cmos")
349 log_cmd_error("Unsupported technology: '%s'\n", techname
.c_str());
351 for (auto mod
: design
->selected_modules())
353 if (!top_mod
&& design
->full_selection())
354 if (mod
->get_bool_attribute(ID::top
))
357 statdata_t
data(design
, mod
, width_mode
, cell_area
, techname
);
358 mod_stat
[mod
->name
] = data
;
361 log("=== %s%s ===\n", log_id(mod
->name
), design
->selected_whole_module(mod
->name
) ? "" : " (partially selected)");
363 data
.log_data(mod
->name
, false);
366 if (top_mod
!= nullptr && GetSize(mod_stat
) > 1)
369 log("=== design hierarchy ===\n");
372 log(" %-28s %6d\n", log_id(top_mod
->name
), 1);
373 statdata_t data
= hierarchy_worker(mod_stat
, top_mod
->name
, 0);
376 data
.log_data(top_mod
->name
, true);
383 PRIVATE_NAMESPACE_END