Rearrange counters to me more realistic

Instead of counting gate types, convert to gate count estimates
and some other interesting statistics. Also handling the descent
into child scopes.
This commit is contained in:
Stephen Williams 2014-02-09 08:59:51 -08:00
parent f5041e6c09
commit 9f2b7d6553
4 changed files with 123 additions and 32 deletions

View File

@ -20,7 +20,7 @@
# include "sizer_priv.h"
void scan_logs_gates(ivl_scope_t scope, ivl_net_logic_t log, struct sizer_statistics&stats)
void scan_logs_gates(ivl_scope_t, ivl_net_logic_t log, struct sizer_statistics&stats)
{
unsigned wid = ivl_logic_width(log);
@ -35,11 +35,15 @@ void scan_logs(ivl_scope_t scope, struct sizer_statistics&stats)
case IVL_LO_AND:
case IVL_LO_OR:
case IVL_LO_XOR:
case IVL_LO_NAND:
case IVL_LO_NOR:
case IVL_LO_XNOR:
case IVL_LO_BUF:
case IVL_LO_NOT:
scan_logs_gates(scope, log, stats);
break;
default:
stats.log_unknown += 1;
stats.log_bytype[ivl_logic_type(log)] += 1;
break;
}
}

View File

@ -19,6 +19,12 @@
# include "sizer_priv.h"
using namespace std;
/*
* Count each bit of flip-flops. It is clear and obvious how these
* come out, so no need to make alternate counts as well.
*/
static void scan_lpms_ff(ivl_scope_t, ivl_lpm_t lpm, struct sizer_statistics&stats)
{
ivl_nexus_t out = ivl_lpm_q(lpm);
@ -27,6 +33,19 @@ static void scan_lpms_ff(ivl_scope_t, ivl_lpm_t lpm, struct sizer_statistics&sta
stats.flop_count += wid;
}
/*
* Count adders as 2m gates.
* Also keep a count of adders by width, just out of curiosity.
*/
static void scans_lpms_add(ivl_scope_t, ivl_lpm_t lpm, struct sizer_statistics&stats)
{
unsigned wid = ivl_lpm_width(lpm);
stats.adder_count[wid] += 1;
stats.gate_count += 2*wid;
}
void scan_lpms(ivl_scope_t scope, struct sizer_statistics&stats)
{
for (unsigned idx = 0 ; idx < ivl_scope_lpms(scope) ; idx += 1) {
@ -43,7 +62,7 @@ void scan_lpms(ivl_scope_t scope, struct sizer_statistics&stats)
break;
case IVL_LPM_ADD:
stats.adder_count += 1;
scans_lpms_add(scope, lpm, stats);
break;
// D-Type flip-flops.
@ -52,7 +71,7 @@ void scan_lpms(ivl_scope_t scope, struct sizer_statistics&stats)
break;
default:
stats.lpm_unknown += 1;
stats.lpm_bytype[ivl_lpm_type(lpm)] += 1;
break;
}
}

View File

@ -25,6 +25,8 @@
# include <cstring>
# include <cassert>
using namespace std;
/*
* This is a null target module. It does nothing.
*/
@ -53,8 +55,24 @@ int sizer_errors = 0;
FILE*sizer_out = 0;
static int process_scan_fun(ivl_process_t net, void*raw);
static void emit_sizer_root(ivl_design_t des, ivl_scope_t model);
static void emit_sizer_scope(ivl_design_t des, ivl_scope_t model, struct sizer_statistics&stats);
static void show_stats(struct sizer_statistics&stats);
/*
* This is called by the ivl core to get version information from the
* loadable code generator.
*/
const char* target_query(const char*key)
{
if (strcmp(key,"version") == 0)
return version_string;
return 0;
}
/*
* This is the main entry point from the IVL core.
*/
int target_design(ivl_design_t des)
{
const char*sizer_path = ivl_design_flag(des, "-o");
@ -65,11 +83,14 @@ int target_design(ivl_design_t des)
// Detect processes and dispatch them.
ivl_design_process(des, &process_scan_fun, 0);
// Locate the root scope for the design.
// Locate the root scopes for the design.
ivl_scope_t*roots;
unsigned nroots;
ivl_design_roots(des, &roots, &nroots);
// Process all the root scopes. It is possible that there are
// multiple root scopes, we will give isolated numbers for
// each and keep then separate.
for (unsigned idx = 0 ; idx < nroots ; idx += 1) {
if (ivl_scope_type(roots[idx]) != IVL_SCT_MODULE) {
fprintf(stderr, "SIZER: The root scope %s must be a module.\n", ivl_scope_basename(roots[idx]));
@ -77,21 +98,22 @@ int target_design(ivl_design_t des)
continue;
}
emit_sizer_root(des, roots[idx]);
struct sizer_statistics stats;
emit_sizer_scope(des, roots[idx], stats);
fprintf(sizer_out, "**** TOTALS\n");
show_stats(stats);
}
return sizer_errors;
}
const char* target_query(const char*key)
{
if (strcmp(key,"version") == 0)
return version_string;
return 0;
}
/*
* Processes are not collected into scopes, but we should not have any
* left anyhow. Give error messages for all the processes that we find
* to be remaining.
*/
static int process_scan_fun(ivl_process_t net, void* /*raw*/)
{
fprintf(stderr, "%s:%u: SIZER: Processes not synthesized for statistics.\n",
@ -100,20 +122,43 @@ static int process_scan_fun(ivl_process_t net, void* /*raw*/)
return 0;
}
static void emit_sizer_root(ivl_design_t des, ivl_scope_t model)
static void emit_sizer_scope(ivl_design_t des, ivl_scope_t scope, struct sizer_statistics&stats)
{
fprintf(sizer_out, "**** Root module: %s\n", ivl_scope_name(model));
fprintf(sizer_out, " Logic gates: %u (ivl_net_logic_t nodes))\n", ivl_scope_logs(model));
fprintf(sizer_out, " LPM nodes : %u (ivl_lpm_t nodes)\n", ivl_scope_lpms(model));
fprintf(sizer_out, "**** module/scope: %s\n", ivl_scope_name(scope));
struct sizer_statistics stats;
scan_logs(model, stats);
scan_lpms(model, stats);
scan_logs(scope, stats);
scan_lpms(scope, stats);
show_stats(stats);
for (size_t idx = 0 ; idx < ivl_scope_childs(scope) ; idx += 1) {
ivl_scope_t child = ivl_scope_child(scope,idx);
struct sizer_statistics child_stats;
emit_sizer_scope(des, child, child_stats);
stats += child_stats;
}
}
static void show_stats(struct sizer_statistics&stats)
{
fprintf(sizer_out, " Flip-Flops : %u\n", stats.flop_count);
fprintf(sizer_out, " Logic Gates : %u\n", stats.gate_count);
fprintf(sizer_out, " LPM Unknown : %u\n", stats.lpm_unknown);
fprintf(sizer_out, " Logic Unknown: %u\n", stats.log_unknown);
for (map<unsigned,unsigned>::const_iterator cur = stats.adder_count.begin()
; cur != stats.adder_count.end() ; ++ cur) {
fprintf(sizer_out, " ADDER[%u]: %u\n", cur->first, cur->second);
}
// These are diagnostic outputs for when more detail is needed.
for (map<ivl_lpm_type_t,unsigned>::const_iterator cur = stats.lpm_bytype.begin()
; cur != stats.lpm_bytype.end() ; ++ cur) {
fprintf(sizer_out, " LPM[%d]: %u unaccounted\n", cur->first, cur->second);
}
for (map<ivl_logic_t,unsigned>::const_iterator cur = stats.log_bytype.begin()
; cur != stats.log_bytype.end() ; ++ cur) {
fprintf(sizer_out, " LOG[%d]: %u unaccounted\n", cur->first, cur->second);
}
}
unsigned get_nexus_width(ivl_nexus_t nex)
@ -130,3 +175,25 @@ unsigned get_nexus_width(ivl_nexus_t nex)
sizer_errors += 1;
return 0;
}
struct sizer_statistics& sizer_statistics::operator += (const sizer_statistics&that)
{
flop_count += that.flop_count;
gate_count += that.gate_count;
for (map<unsigned,unsigned>::const_iterator cur = that.adder_count.begin()
; cur != that.adder_count.end() ; ++ cur)
adder_count[cur->first] += cur->second;
for (map<ivl_lpm_type_t,unsigned>::const_iterator cur = that.lpm_bytype.begin()
; cur != that.lpm_bytype.end() ; ++ cur)
lpm_bytype[cur->first] += cur->second;
for (map<ivl_logic_t,unsigned>::const_iterator cur = that.log_bytype.begin()
; cur != that.log_bytype.end() ; ++ cur)
log_bytype[cur->first] += cur->second;
return *this;
}

View File

@ -22,25 +22,26 @@
# include "config.h"
# include "ivl_target.h"
# include <map>
# include <cstdio>
struct sizer_statistics {
// These are the accumulated global statistics
unsigned flop_count;
unsigned gate_count;
unsigned adder_count;
unsigned lpm_unknown;
unsigned log_unknown;
// Count adders of various dimension
std::map<unsigned,unsigned> adder_count;
// Different kinds of nodes that we have not accounted for
std::map<ivl_lpm_type_t,unsigned> lpm_bytype;
std::map<ivl_logic_t,unsigned> log_bytype;
inline sizer_statistics()
{
flop_count = 0;
gate_count = 0;
adder_count = 0;
lpm_unknown = 0;
log_unknown = 0;
}
struct sizer_statistics& operator += (const struct sizer_statistics&that);
};
extern int sizer_errors;