2013-11-25 13:43:57 -06:00
|
|
|
/*
|
|
|
|
* yosys -- Yosys Open SYnthesis Suite
|
|
|
|
*
|
|
|
|
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
|
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "kernel/register.h"
|
|
|
|
#include "kernel/celltypes.h"
|
|
|
|
#include "kernel/log.h"
|
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
|
|
|
struct statdata_t
|
|
|
|
{
|
|
|
|
#define STAT_INT_MEMBERS X(num_wires) X(num_wire_bits) X(num_pub_wires) X(num_pub_wire_bits) \
|
|
|
|
X(num_memories) X(num_memory_bits) X(num_cells) X(num_processes)
|
|
|
|
|
|
|
|
#define X(_name) int _name;
|
|
|
|
STAT_INT_MEMBERS
|
|
|
|
#undef X
|
|
|
|
|
|
|
|
std::map<RTLIL::IdString, int> num_cells_by_type;
|
|
|
|
|
|
|
|
statdata_t operator+(const statdata_t &other) const
|
|
|
|
{
|
|
|
|
statdata_t sum = other;
|
|
|
|
#define X(_name) sum._name += _name;
|
|
|
|
STAT_INT_MEMBERS
|
|
|
|
#undef X
|
|
|
|
for (auto &it : num_cells_by_type)
|
|
|
|
sum.num_cells_by_type[it.first] += it.second;
|
|
|
|
return sum;
|
|
|
|
}
|
|
|
|
|
|
|
|
statdata_t operator*(int other) const
|
|
|
|
{
|
|
|
|
statdata_t sum = *this;
|
|
|
|
#define X(_name) sum._name *= other;
|
|
|
|
STAT_INT_MEMBERS
|
|
|
|
#undef X
|
|
|
|
for (auto &it : sum.num_cells_by_type)
|
|
|
|
it.second *= other;
|
|
|
|
return sum;
|
|
|
|
}
|
|
|
|
|
|
|
|
statdata_t()
|
|
|
|
{
|
|
|
|
#define X(_name) _name = 0;
|
|
|
|
STAT_INT_MEMBERS
|
|
|
|
#undef X
|
|
|
|
}
|
|
|
|
|
2014-08-22 10:20:28 -05:00
|
|
|
statdata_t(RTLIL::Design *design, RTLIL::Module *mod, bool width_mode)
|
2013-11-25 13:43:57 -06:00
|
|
|
{
|
|
|
|
#define X(_name) _name = 0;
|
|
|
|
STAT_INT_MEMBERS
|
|
|
|
#undef X
|
|
|
|
|
2014-07-26 18:49:51 -05:00
|
|
|
for (auto &it : mod->wires_)
|
2013-11-25 13:43:57 -06:00
|
|
|
{
|
|
|
|
if (!design->selected(mod, it.second))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (it.first[0] == '\\') {
|
|
|
|
num_pub_wires++;
|
|
|
|
num_pub_wire_bits += it.second->width;
|
|
|
|
}
|
|
|
|
|
|
|
|
num_wires++;
|
|
|
|
num_wire_bits += it.second->width;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto &it : mod->memories) {
|
|
|
|
if (!design->selected(mod, it.second))
|
|
|
|
continue;
|
|
|
|
num_memories++;
|
|
|
|
num_memory_bits += it.second->width * it.second->size;
|
|
|
|
}
|
|
|
|
|
2014-08-22 10:20:28 -05:00
|
|
|
for (auto &it : mod->cells_)
|
|
|
|
{
|
2013-11-25 13:43:57 -06:00
|
|
|
if (!design->selected(mod, it.second))
|
|
|
|
continue;
|
2014-08-22 10:20:28 -05:00
|
|
|
|
|
|
|
RTLIL::IdString cell_type = it.second->type;
|
|
|
|
|
|
|
|
if (width_mode)
|
|
|
|
{
|
2014-09-03 19:07:52 -05:00
|
|
|
if (cell_type.in("$not", "$pos", "$neg",
|
2014-08-22 10:20:28 -05:00
|
|
|
"$logic_not", "$logic_and", "$logic_or",
|
|
|
|
"$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool",
|
|
|
|
"$lut", "$and", "$or", "$xor", "$xnor",
|
|
|
|
"$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
|
|
|
|
"$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt",
|
|
|
|
"$add", "$sub", "$mul", "$div", "$mod", "$pow")) {
|
|
|
|
int width_a = it.second->hasPort("\\A") ? SIZE(it.second->getPort("\\A")) : 0;
|
|
|
|
int width_b = it.second->hasPort("\\B") ? SIZE(it.second->getPort("\\B")) : 0;
|
|
|
|
int width_y = it.second->hasPort("\\Y") ? SIZE(it.second->getPort("\\Y")) : 0;
|
|
|
|
cell_type = stringf("%s_%d", cell_type.c_str(), std::max<int>({width_a, width_b, width_y}));
|
|
|
|
}
|
|
|
|
else if (cell_type.in("$mux", "$pmux"))
|
|
|
|
cell_type = stringf("%s_%d", cell_type.c_str(), SIZE(it.second->getPort("\\Y")));
|
|
|
|
else if (cell_type.in("$sr", "$dff", "$dffsr", "$adff", "$dlatch", "$dlatchsr"))
|
|
|
|
cell_type = stringf("%s_%d", cell_type.c_str(), SIZE(it.second->getPort("\\Q")));
|
|
|
|
}
|
|
|
|
|
2013-11-25 13:43:57 -06:00
|
|
|
num_cells++;
|
2014-08-22 10:20:28 -05:00
|
|
|
num_cells_by_type[cell_type]++;
|
2013-11-25 13:43:57 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
for (auto &it : mod->processes) {
|
|
|
|
if (!design->selected(mod, it.second))
|
|
|
|
continue;
|
|
|
|
num_processes++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void log_data()
|
|
|
|
{
|
|
|
|
log(" Number of wires: %6d\n", num_wires);
|
|
|
|
log(" Number of wire bits: %6d\n", num_wire_bits);
|
|
|
|
log(" Number of public wires: %6d\n", num_pub_wires);
|
|
|
|
log(" Number of public wire bits: %6d\n", num_pub_wire_bits);
|
|
|
|
log(" Number of memories: %6d\n", num_memories);
|
|
|
|
log(" Number of memory bits: %6d\n", num_memory_bits);
|
|
|
|
log(" Number of processes: %6d\n", num_processes);
|
|
|
|
log(" Number of cells: %6d\n", num_cells);
|
|
|
|
for (auto &it : num_cells_by_type)
|
|
|
|
log(" %-26s %6d\n", RTLIL::id2cstr(it.first), it.second);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
statdata_t hierarchy_worker(std::map<RTLIL::IdString, statdata_t> &mod_stat, RTLIL::IdString mod, int level)
|
|
|
|
{
|
|
|
|
statdata_t mod_data = mod_stat.at(mod);
|
|
|
|
std::map<RTLIL::IdString, int> num_cells_by_type;
|
|
|
|
num_cells_by_type.swap(mod_data.num_cells_by_type);
|
|
|
|
|
|
|
|
for (auto &it : num_cells_by_type)
|
|
|
|
if (mod_stat.count(it.first) > 0) {
|
|
|
|
log(" %*s%-*s %6d\n", 2*level, "", 26-2*level, RTLIL::id2cstr(it.first), it.second);
|
|
|
|
mod_data = mod_data + hierarchy_worker(mod_stat, it.first, level+1) * it.second;
|
2013-11-25 14:08:34 -06:00
|
|
|
mod_data.num_cells -= it.second;
|
2013-11-25 13:43:57 -06:00
|
|
|
} else {
|
|
|
|
mod_data.num_cells_by_type[it.first] += it.second;
|
|
|
|
}
|
|
|
|
|
|
|
|
return mod_data;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct StatPass : public Pass {
|
|
|
|
StatPass() : Pass("stat", "print some statistics") { }
|
|
|
|
virtual void help()
|
|
|
|
{
|
|
|
|
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
|
|
|
log("\n");
|
|
|
|
log(" stat [options] [selection]\n");
|
|
|
|
log("\n");
|
|
|
|
log("Print some statistics (number of objects) on the selected portion of the\n");
|
|
|
|
log("design.\n");
|
|
|
|
log("\n");
|
|
|
|
log(" -top <module>\n");
|
|
|
|
log(" print design hierarchy with this module as top. if the design is fully\n");
|
|
|
|
log(" selected and a module has the 'top' attribute set, this module is used\n");
|
|
|
|
log(" default value for this option.\n");
|
|
|
|
log("\n");
|
2014-08-22 10:20:28 -05:00
|
|
|
log(" -width\n");
|
|
|
|
log(" annotate internal cell types with their word width.\n");
|
|
|
|
log(" e.g. $add_8 for an 8 bit wide $add cell.\n");
|
|
|
|
log("\n");
|
2013-11-25 13:43:57 -06:00
|
|
|
}
|
|
|
|
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
|
|
|
|
{
|
|
|
|
log_header("Printing statistics.\n");
|
|
|
|
|
2014-08-22 10:20:28 -05:00
|
|
|
bool width_mode = false;
|
2013-11-25 13:43:57 -06:00
|
|
|
RTLIL::Module *top_mod = NULL;
|
|
|
|
std::map<RTLIL::IdString, statdata_t> mod_stat;
|
|
|
|
|
|
|
|
size_t argidx;
|
|
|
|
for (argidx = 1; argidx < args.size(); argidx++)
|
|
|
|
{
|
2014-08-22 10:20:28 -05:00
|
|
|
if (args[argidx] == "-width") {
|
|
|
|
width_mode = true;
|
|
|
|
continue;
|
|
|
|
}
|
2013-11-25 13:43:57 -06:00
|
|
|
if (args[argidx] == "-top" && argidx+1 < args.size()) {
|
2014-07-27 03:18:00 -05:00
|
|
|
if (design->modules_.count(RTLIL::escape_id(args[argidx+1])) == 0)
|
2013-11-25 13:43:57 -06:00
|
|
|
log_cmd_error("Can't find module %s.\n", args[argidx+1].c_str());
|
2014-07-27 03:18:00 -05:00
|
|
|
top_mod = design->modules_.at(RTLIL::escape_id(args[++argidx]));
|
2013-11-25 13:43:57 -06:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
extra_args(args, argidx, design);
|
|
|
|
|
2014-07-27 03:18:00 -05:00
|
|
|
for (auto &it : design->modules_)
|
2013-11-25 13:43:57 -06:00
|
|
|
{
|
|
|
|
if (!design->selected_module(it.first))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!top_mod && design->full_selection())
|
|
|
|
if (it.second->get_bool_attribute("\\top"))
|
|
|
|
top_mod = it.second;
|
|
|
|
|
2014-08-22 10:20:28 -05:00
|
|
|
statdata_t data(design, it.second, width_mode);
|
2013-11-25 13:43:57 -06:00
|
|
|
mod_stat[it.first] = data;
|
|
|
|
|
|
|
|
log("\n");
|
|
|
|
log("=== %s%s ===\n", RTLIL::id2cstr(it.first), design->selected_whole_module(it.first) ? "" : " (partially selected)");
|
|
|
|
log("\n");
|
|
|
|
data.log_data();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (top_mod != NULL)
|
|
|
|
{
|
|
|
|
log("\n");
|
|
|
|
log("=== design hierarchy ===\n");
|
|
|
|
log("\n");
|
|
|
|
|
|
|
|
log(" %-28s %6d\n", RTLIL::id2cstr(top_mod->name), 1);
|
|
|
|
statdata_t data = hierarchy_worker(mod_stat, top_mod->name, 0);
|
|
|
|
|
|
|
|
log("\n");
|
|
|
|
data.log_data();
|
|
|
|
}
|
|
|
|
|
|
|
|
log("\n");
|
|
|
|
}
|
|
|
|
} StatPass;
|
|
|
|
|