629 lines
28 KiB
C++
629 lines
28 KiB
C++
#include <cstring>
|
|
#include <cstdlib>
|
|
#include <vector>
|
|
|
|
#include "echo_arch.h"
|
|
#include "arch_types.h"
|
|
#include "vtr_list.h"
|
|
#include "vtr_util.h"
|
|
#include "vtr_memory.h"
|
|
#include "vtr_assert.h"
|
|
|
|
using vtr::t_linked_vptr;
|
|
|
|
void PrintArchInfo(FILE* Echo, const t_arch* arch);
|
|
static void PrintPb_types_rec(FILE* Echo, const t_pb_type* pb_type, int level);
|
|
static void PrintPb_types_recPower(FILE* Echo,
|
|
const t_pb_type* pb_type,
|
|
const char* tabs);
|
|
|
|
/* Output the data from architecture data so user can verify it
|
|
* was interpretted correctly. */
|
|
void EchoArch(const char* EchoFile,
|
|
const std::vector<t_physical_tile_type>& PhysicalTileTypes,
|
|
const std::vector<t_logical_block_type>& LogicalBlockTypes,
|
|
const t_arch* arch) {
|
|
int i, j;
|
|
FILE* Echo;
|
|
t_model* cur_model;
|
|
t_model_ports* model_port;
|
|
t_linked_vptr* cur_vptr;
|
|
|
|
Echo = vtr::fopen(EchoFile, "w");
|
|
cur_model = nullptr;
|
|
|
|
//Print all layout device switch/segment list info first
|
|
PrintArchInfo(Echo, arch);
|
|
|
|
//Models
|
|
fprintf(Echo, "*************************************************\n");
|
|
for (j = 0; j < 2; j++) {
|
|
if (j == 0) {
|
|
fprintf(Echo, "Printing user models \n");
|
|
cur_model = arch->models;
|
|
} else if (j == 1) {
|
|
fprintf(Echo, "Printing library models \n");
|
|
cur_model = arch->model_library;
|
|
}
|
|
while (cur_model) {
|
|
fprintf(Echo, "Model: \"%s\"\n", cur_model->name);
|
|
model_port = cur_model->inputs;
|
|
while (model_port) {
|
|
fprintf(Echo, "\tInput Ports: \"%s\" \"%d\" min_size=\"%d\"\n",
|
|
model_port->name, model_port->size,
|
|
model_port->min_size);
|
|
model_port = model_port->next;
|
|
}
|
|
model_port = cur_model->outputs;
|
|
while (model_port) {
|
|
fprintf(Echo, "\tOutput Ports: \"%s\" \"%d\" min_size=\"%d\"\n",
|
|
model_port->name, model_port->size,
|
|
model_port->min_size);
|
|
model_port = model_port->next;
|
|
}
|
|
cur_vptr = cur_model->pb_types;
|
|
i = 0;
|
|
while (cur_vptr != nullptr) {
|
|
fprintf(Echo, "\tpb_type %d: \"%s\"\n", i,
|
|
((t_pb_type*)cur_vptr->data_vptr)->name);
|
|
cur_vptr = cur_vptr->next;
|
|
i++;
|
|
}
|
|
|
|
cur_model = cur_model->next;
|
|
}
|
|
}
|
|
fprintf(Echo, "*************************************************\n\n");
|
|
fprintf(Echo, "*************************************************\n");
|
|
for (auto& Type : PhysicalTileTypes) {
|
|
fprintf(Echo, "Type: \"%s\"\n", Type.name);
|
|
fprintf(Echo, "\tcapacity: %d\n", Type.capacity);
|
|
fprintf(Echo, "\twidth: %d\n", Type.width);
|
|
fprintf(Echo, "\theight: %d\n", Type.height);
|
|
for (const t_fc_specification& fc_spec : Type.fc_specs) {
|
|
fprintf(Echo, "fc_value_type: ");
|
|
if (fc_spec.fc_value_type == e_fc_value_type::ABSOLUTE) {
|
|
fprintf(Echo, "ABSOLUTE");
|
|
} else if (fc_spec.fc_value_type == e_fc_value_type::FRACTIONAL) {
|
|
fprintf(Echo, "FRACTIONAL");
|
|
} else {
|
|
VTR_ASSERT(false);
|
|
}
|
|
fprintf(Echo, " fc_value: %f", fc_spec.fc_value);
|
|
fprintf(Echo, " segment: %s", arch->Segments[fc_spec.seg_index].name.c_str());
|
|
fprintf(Echo, " pins:");
|
|
for (int pin : fc_spec.pins) {
|
|
fprintf(Echo, " %d", pin);
|
|
}
|
|
fprintf(Echo, "\n");
|
|
}
|
|
fprintf(Echo, "\tnum_drivers: %d\n", Type.num_drivers);
|
|
fprintf(Echo, "\tnum_receivers: %d\n", Type.num_receivers);
|
|
|
|
int index = Type.index;
|
|
fprintf(Echo, "\tindex: %d\n", index);
|
|
|
|
for (auto LogicalBlock : Type.equivalent_sites) {
|
|
fprintf(Echo, "\nEquivalent Site: %s\n", LogicalBlock->name);
|
|
}
|
|
fprintf(Echo, "\n");
|
|
}
|
|
|
|
fprintf(Echo, "*************************************************\n\n");
|
|
fprintf(Echo, "*************************************************\n");
|
|
|
|
for (auto& LogicalBlock : LogicalBlockTypes) {
|
|
if (LogicalBlock.pb_type) {
|
|
PrintPb_types_rec(Echo, LogicalBlock.pb_type, 2);
|
|
}
|
|
fprintf(Echo, "\n");
|
|
}
|
|
|
|
fclose(Echo);
|
|
}
|
|
|
|
//Added May 2013 Daniel Chen, help dump arch info after loading from XML
|
|
void PrintArchInfo(FILE* Echo, const t_arch* arch) {
|
|
int i, j;
|
|
|
|
fprintf(Echo, "Printing architecture... \n\n");
|
|
//Layout
|
|
fprintf(Echo, "*************************************************\n");
|
|
for (const auto& grid_layout : arch->grid_layouts) {
|
|
if (grid_layout.grid_type == GridDefType::AUTO) {
|
|
fprintf(Echo, "Layout: '%s' Type: auto Aspect_Ratio: %f\n", grid_layout.name.c_str(), grid_layout.aspect_ratio);
|
|
} else {
|
|
VTR_ASSERT(grid_layout.grid_type == GridDefType::FIXED);
|
|
fprintf(Echo, "Layout: '%s' Type: fixed Width: %d Height %d\n", grid_layout.name.c_str(), grid_layout.width, grid_layout.height);
|
|
}
|
|
}
|
|
fprintf(Echo, "*************************************************\n\n");
|
|
//Device
|
|
fprintf(Echo, "*************************************************\n");
|
|
fprintf(Echo, "Device Info:\n");
|
|
|
|
fprintf(Echo,
|
|
"\tSizing: R_minW_nmos %e R_minW_pmos %e\n",
|
|
arch->R_minW_nmos, arch->R_minW_pmos);
|
|
|
|
fprintf(Echo, "\tArea: grid_logic_tile_area %e\n",
|
|
arch->grid_logic_tile_area);
|
|
|
|
fprintf(Echo, "\tChannel Width Distribution:\n");
|
|
|
|
switch (arch->Chans.chan_x_dist.type) {
|
|
case (UNIFORM):
|
|
fprintf(Echo, "\t\tx: type uniform peak %e\n",
|
|
arch->Chans.chan_x_dist.peak);
|
|
break;
|
|
case (GAUSSIAN):
|
|
fprintf(Echo,
|
|
"\t\tx: type gaussian peak %e \
|
|
width %e Xpeak %e dc %e\n",
|
|
arch->Chans.chan_x_dist.peak, arch->Chans.chan_x_dist.width,
|
|
arch->Chans.chan_x_dist.xpeak, arch->Chans.chan_x_dist.dc);
|
|
break;
|
|
case (PULSE):
|
|
fprintf(Echo,
|
|
"\t\tx: type pulse peak %e \
|
|
width %e Xpeak %e dc %e\n",
|
|
arch->Chans.chan_x_dist.peak, arch->Chans.chan_x_dist.width,
|
|
arch->Chans.chan_x_dist.xpeak, arch->Chans.chan_x_dist.dc);
|
|
break;
|
|
case (DELTA):
|
|
fprintf(Echo,
|
|
"\t\tx: distr dleta peak %e \
|
|
Xpeak %e dc %e\n",
|
|
arch->Chans.chan_x_dist.peak, arch->Chans.chan_x_dist.xpeak,
|
|
arch->Chans.chan_x_dist.dc);
|
|
break;
|
|
default:
|
|
fprintf(Echo, "\t\tInvalid Distribution!\n");
|
|
break;
|
|
}
|
|
|
|
switch (arch->Chans.chan_y_dist.type) {
|
|
case (UNIFORM):
|
|
fprintf(Echo, "\t\ty: type uniform peak %e\n",
|
|
arch->Chans.chan_y_dist.peak);
|
|
break;
|
|
case (GAUSSIAN):
|
|
fprintf(Echo,
|
|
"\t\ty: type gaussian peak %e \
|
|
width %e Xpeak %e dc %e\n",
|
|
arch->Chans.chan_y_dist.peak, arch->Chans.chan_y_dist.width,
|
|
arch->Chans.chan_y_dist.xpeak, arch->Chans.chan_y_dist.dc);
|
|
break;
|
|
case (PULSE):
|
|
fprintf(Echo,
|
|
"\t\ty: type pulse peak %e \
|
|
width %e Xpeak %e dc %e\n",
|
|
arch->Chans.chan_y_dist.peak, arch->Chans.chan_y_dist.width,
|
|
arch->Chans.chan_y_dist.xpeak, arch->Chans.chan_y_dist.dc);
|
|
break;
|
|
case (DELTA):
|
|
fprintf(Echo,
|
|
"\t\ty: distr dleta peak %e \
|
|
Xpeak %e dc %e\n",
|
|
arch->Chans.chan_y_dist.peak, arch->Chans.chan_y_dist.xpeak,
|
|
arch->Chans.chan_y_dist.dc);
|
|
break;
|
|
default:
|
|
fprintf(Echo, "\t\tInvalid Distribution!\n");
|
|
break;
|
|
}
|
|
|
|
switch (arch->SBType) {
|
|
case (WILTON):
|
|
fprintf(Echo, "\tSwitch Block: type wilton fs %d\n", arch->Fs);
|
|
break;
|
|
case (UNIVERSAL):
|
|
fprintf(Echo, "\tSwitch Block: type universal fs %d\n", arch->Fs);
|
|
break;
|
|
case (SUBSET):
|
|
fprintf(Echo, "\tSwitch Block: type subset fs %d\n", arch->Fs);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
fprintf(Echo, "\tInput Connect Block Switch Name: %s\n", arch->ipin_cblock_switch_name.c_str());
|
|
|
|
fprintf(Echo, "*************************************************\n\n");
|
|
//Switch list
|
|
fprintf(Echo, "*************************************************\n");
|
|
fprintf(Echo, "Switch List:\n");
|
|
|
|
//13 is hard coded because format of %e is always 1.123456e+12
|
|
//It always consists of 10 alphanumeric digits, a decimal
|
|
//and a sign
|
|
for (i = 0; i < arch->num_switches; i++) {
|
|
if (arch->Switches[i].type() == SwitchType::MUX) {
|
|
fprintf(Echo, "\tSwitch[%d]: name %s type mux\n", i + 1, arch->Switches[i].name);
|
|
} else if (arch->Switches[i].type() == SwitchType::TRISTATE) {
|
|
fprintf(Echo, "\tSwitch[%d]: name %s type tristate\n", i + 1, arch->Switches[i].name);
|
|
} else if (arch->Switches[i].type() == SwitchType::SHORT) {
|
|
fprintf(Echo, "\tSwitch[%d]: name %s type short\n", i + 1, arch->Switches[i].name);
|
|
} else if (arch->Switches[i].type() == SwitchType::BUFFER) {
|
|
fprintf(Echo, "\tSwitch[%d]: name %s type buffer\n", i + 1, arch->Switches[i].name);
|
|
} else {
|
|
VTR_ASSERT(arch->Switches[i].type() == SwitchType::PASS_GATE);
|
|
fprintf(Echo, "\tSwitch[%d]: name %s type pass_gate\n", i + 1, arch->Switches[i].name);
|
|
}
|
|
fprintf(Echo, "\t\t\t\tR %e Cin %e Cout %e\n", arch->Switches[i].R,
|
|
arch->Switches[i].Cin, arch->Switches[i].Cout);
|
|
fprintf(Echo, "\t\t\t\t#Tdel values %d buf_size %e mux_trans_size %e\n",
|
|
(int)arch->Switches[i].Tdel_map_.size(), arch->Switches[i].buf_size,
|
|
arch->Switches[i].mux_trans_size);
|
|
if (arch->Switches[i].power_buffer_type == POWER_BUFFER_TYPE_AUTO) {
|
|
fprintf(Echo, "\t\t\t\tpower_buffer_size auto\n");
|
|
} else {
|
|
fprintf(Echo, "\t\t\t\tpower_buffer_size %e\n",
|
|
arch->Switches[i].power_buffer_size);
|
|
}
|
|
}
|
|
|
|
fprintf(Echo, "*************************************************\n\n");
|
|
//Segment List
|
|
fprintf(Echo, "*************************************************\n");
|
|
fprintf(Echo, "Segment List:\n");
|
|
for (i = 0; i < (int)(arch->Segments).size(); i++) {
|
|
const struct t_segment_inf& seg = arch->Segments[i];
|
|
fprintf(Echo,
|
|
"\tSegment[%d]: frequency %d length %d R_metal %e C_metal %e\n",
|
|
i + 1, seg.frequency, seg.length,
|
|
seg.Rmetal, seg.Cmetal);
|
|
|
|
if (seg.directionality == UNI_DIRECTIONAL) {
|
|
//wire_switch == arch_opin_switch
|
|
fprintf(Echo, "\t\t\t\ttype unidir mux_name %s\n",
|
|
arch->Switches[seg.arch_wire_switch].name);
|
|
} else { //Should be bidir
|
|
fprintf(Echo, "\t\t\t\ttype bidir wire_switch %s arch_opin_switch %s\n",
|
|
arch->Switches[seg.arch_wire_switch].name,
|
|
arch->Switches[seg.arch_opin_switch].name);
|
|
}
|
|
|
|
fprintf(Echo, "\t\t\t\tcb ");
|
|
for (j = 0; j < (int)seg.cb.size(); j++) {
|
|
if (seg.cb[j]) {
|
|
fprintf(Echo, "1 ");
|
|
} else {
|
|
fprintf(Echo, "0 ");
|
|
}
|
|
}
|
|
fprintf(Echo, "\n");
|
|
|
|
fprintf(Echo, "\t\t\t\tsb ");
|
|
for (j = 0; j < (int)seg.sb.size(); j++) {
|
|
if (seg.sb[j]) {
|
|
fprintf(Echo, "1 ");
|
|
} else {
|
|
fprintf(Echo, "0 ");
|
|
}
|
|
}
|
|
fprintf(Echo, "\n");
|
|
}
|
|
fprintf(Echo, "*************************************************\n\n");
|
|
//Direct List
|
|
fprintf(Echo, "*************************************************\n");
|
|
fprintf(Echo, "Direct List:\n");
|
|
for (i = 0; i < arch->num_directs; i++) {
|
|
fprintf(Echo, "\tDirect[%d]: name %s from_pin %s to_pin %s\n", i + 1,
|
|
arch->Directs[i].name, arch->Directs[i].from_pin,
|
|
arch->Directs[i].to_pin);
|
|
fprintf(Echo, "\t\t\t\t x_offset %d y_offset %d z_offset %d\n",
|
|
arch->Directs[i].x_offset, arch->Directs[i].y_offset,
|
|
arch->Directs[i].z_offset);
|
|
}
|
|
fprintf(Echo, "*************************************************\n\n");
|
|
|
|
//Architecture Power
|
|
fprintf(Echo, "*************************************************\n");
|
|
fprintf(Echo, "Power:\n");
|
|
if (arch->power) {
|
|
fprintf(Echo, "\tlocal_interconnect C_wire %e factor %f\n",
|
|
arch->power->C_wire_local, arch->power->local_interc_factor);
|
|
fprintf(Echo, "\tlogical_effort_factor %f trans_per_sram_bit %f\n",
|
|
arch->power->logical_effort_factor,
|
|
arch->power->transistors_per_SRAM_bit);
|
|
}
|
|
|
|
fprintf(Echo, "*************************************************\n\n");
|
|
//Architecture Clock
|
|
fprintf(Echo, "*************************************************\n");
|
|
fprintf(Echo, "Clock:\n");
|
|
if (arch->clocks) {
|
|
for (i = 0; i < arch->clocks->num_global_clocks; i++) {
|
|
if (arch->clocks->clock_inf[i].autosize_buffer) {
|
|
fprintf(Echo, "\tClock[%d]: buffer_size auto C_wire %e", i + 1,
|
|
arch->clocks->clock_inf->C_wire);
|
|
} else {
|
|
fprintf(Echo, "\tClock[%d]: buffer_size %e C_wire %e", i + 1,
|
|
arch->clocks->clock_inf[i].buffer_size,
|
|
arch->clocks->clock_inf[i].C_wire);
|
|
}
|
|
fprintf(Echo, "\t\t\t\tstat_prob %f switch_density %f period %e",
|
|
arch->clocks->clock_inf[i].prob,
|
|
arch->clocks->clock_inf[i].dens,
|
|
arch->clocks->clock_inf[i].period);
|
|
}
|
|
}
|
|
|
|
fprintf(Echo, "*************************************************\n\n");
|
|
}
|
|
|
|
static void PrintPb_types_rec(FILE* Echo, const t_pb_type* pb_type, int level) {
|
|
int i, j, k;
|
|
char* tabs;
|
|
|
|
tabs = (char*)vtr::malloc((level + 1) * sizeof(char));
|
|
for (i = 0; i < level; i++) {
|
|
tabs[i] = '\t';
|
|
}
|
|
tabs[level] = '\0';
|
|
|
|
fprintf(Echo, "%spb_type name: %s\n", tabs, pb_type->name);
|
|
fprintf(Echo, "%s\tblif_model: %s\n", tabs, pb_type->blif_model);
|
|
fprintf(Echo, "%s\tclass_type: %d\n", tabs, pb_type->class_type);
|
|
fprintf(Echo, "%s\tnum_modes: %d\n", tabs, pb_type->num_modes);
|
|
fprintf(Echo, "%s\tnum_ports: %d\n", tabs, pb_type->num_ports);
|
|
for (i = 0; i < pb_type->num_ports; i++) {
|
|
fprintf(Echo, "%s\tport %s type %d num_pins %d\n", tabs,
|
|
pb_type->ports[i].name, pb_type->ports[i].type,
|
|
pb_type->ports[i].num_pins);
|
|
}
|
|
|
|
if (pb_type->num_modes > 0) { /*one or more modes*/
|
|
for (i = 0; i < pb_type->num_modes; i++) {
|
|
fprintf(Echo, "%s\tmode %s:\n", tabs, pb_type->modes[i].name);
|
|
for (j = 0; j < pb_type->modes[i].num_pb_type_children; j++) {
|
|
PrintPb_types_rec(Echo, &pb_type->modes[i].pb_type_children[j],
|
|
level + 2);
|
|
}
|
|
for (j = 0; j < pb_type->modes[i].num_interconnect; j++) {
|
|
fprintf(Echo, "%s\t\tinterconnect %d %s %s\n", tabs,
|
|
pb_type->modes[i].interconnect[j].type,
|
|
pb_type->modes[i].interconnect[j].input_string,
|
|
pb_type->modes[i].interconnect[j].output_string);
|
|
for (k = 0;
|
|
k < pb_type->modes[i].interconnect[j].num_annotations;
|
|
k++) {
|
|
fprintf(Echo, "%s\t\t\tannotation %s %s %d: %s\n", tabs,
|
|
pb_type->modes[i].interconnect[j].annotations[k].input_pins,
|
|
pb_type->modes[i].interconnect[j].annotations[k].output_pins,
|
|
pb_type->modes[i].interconnect[j].annotations[k].format,
|
|
pb_type->modes[i].interconnect[j].annotations[k].value[0]);
|
|
}
|
|
//Print power info for interconnects
|
|
if (pb_type->modes[i].interconnect[j].interconnect_power) {
|
|
if (pb_type->modes[i].interconnect[j].interconnect_power->power_usage.dynamic
|
|
|| pb_type->modes[i].interconnect[j].interconnect_power->power_usage.leakage) {
|
|
fprintf(Echo, "%s\t\t\tpower %e %e\n", tabs,
|
|
pb_type->modes[i].interconnect[j].interconnect_power->power_usage.dynamic,
|
|
pb_type->modes[i].interconnect[j].interconnect_power->power_usage.leakage);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else { /*leaf pb with unknown model*/
|
|
/*LUT(names) already handled, it naturally has 2 modes.
|
|
* I/O has no annotations to be displayed
|
|
* All other library or user models may have delays specificied, e.g. Tsetup and Tcq
|
|
* Display the additional information*/
|
|
if (strcmp(pb_type->model->name, MODEL_NAMES)
|
|
&& strcmp(pb_type->model->name, MODEL_INPUT)
|
|
&& strcmp(pb_type->model->name, MODEL_OUTPUT)) {
|
|
for (k = 0; k < pb_type->num_annotations; k++) {
|
|
fprintf(Echo, "%s\t\t\tannotation %s %s %s %d: %s\n", tabs,
|
|
pb_type->annotations[k].clock,
|
|
pb_type->annotations[k].input_pins,
|
|
pb_type->annotations[k].output_pins,
|
|
pb_type->annotations[k].format,
|
|
pb_type->annotations[k].value[0]);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pb_type->pb_type_power) {
|
|
PrintPb_types_recPower(Echo, pb_type, tabs);
|
|
}
|
|
free(tabs);
|
|
}
|
|
|
|
//Added May 2013 Daniel Chen, help dump arch info after loading from XML
|
|
static void PrintPb_types_recPower(FILE* Echo,
|
|
const t_pb_type* pb_type,
|
|
const char* tabs) {
|
|
int i = 0;
|
|
/*Print power information for each pb if available*/
|
|
switch (pb_type->pb_type_power->estimation_method) {
|
|
case POWER_METHOD_UNDEFINED:
|
|
fprintf(Echo, "%s\tpower method: undefined\n", tabs);
|
|
break;
|
|
case POWER_METHOD_IGNORE:
|
|
if (pb_type->parent_mode) {
|
|
/*if NOT top-level pb (all top-level pb has NULL parent_mode, check parent's power method
|
|
* This is because of the inheritance property of auto-size*/
|
|
if (pb_type->parent_mode->parent_pb_type->pb_type_power->estimation_method
|
|
== POWER_METHOD_IGNORE)
|
|
break;
|
|
}
|
|
fprintf(Echo, "%s\tpower method: ignore\n", tabs);
|
|
break;
|
|
case POWER_METHOD_SUM_OF_CHILDREN:
|
|
fprintf(Echo, "%s\tpower method: sum-of-children\n", tabs);
|
|
break;
|
|
case POWER_METHOD_AUTO_SIZES:
|
|
if (pb_type->parent_mode) {
|
|
/*if NOT top-level pb (all top-level pb has NULL parent_mode, check parent's power method
|
|
* This is because of the inheritance property of auto-size*/
|
|
if (pb_type->parent_mode->parent_pb_type->pb_type_power->estimation_method
|
|
== POWER_METHOD_AUTO_SIZES)
|
|
break;
|
|
}
|
|
fprintf(Echo, "%s\tpower method: auto-size\n", tabs);
|
|
break;
|
|
case POWER_METHOD_SPECIFY_SIZES:
|
|
if (pb_type->parent_mode) {
|
|
/*if NOT top-level pb (all top-level pb has NULL parent_mode, check parent's power method
|
|
* This is because of the inheritance property of specify-size*/
|
|
if (pb_type->parent_mode->parent_pb_type->pb_type_power->estimation_method
|
|
== POWER_METHOD_SPECIFY_SIZES)
|
|
break;
|
|
}
|
|
|
|
fprintf(Echo, "%s\tpower method: specify-size\n", tabs);
|
|
for (i = 0; i < pb_type->num_ports; i++) {
|
|
//Print all the power information on each port, only if available,
|
|
//will not print if value is 0 or NULL
|
|
if (pb_type->ports[i].port_power->buffer_type
|
|
|| pb_type->ports[i].port_power->wire_type
|
|
|| pb_type->pb_type_power->absolute_power_per_instance.leakage
|
|
|| pb_type->pb_type_power->absolute_power_per_instance.dynamic) {
|
|
fprintf(Echo, "%s\t\tport %s type %d num_pins %d\n", tabs,
|
|
pb_type->ports[i].name, pb_type->ports[i].type,
|
|
pb_type->ports[i].num_pins);
|
|
//Buffer size
|
|
switch (pb_type->ports[i].port_power->buffer_type) {
|
|
case (POWER_BUFFER_TYPE_UNDEFINED):
|
|
case (POWER_BUFFER_TYPE_NONE):
|
|
break;
|
|
case (POWER_BUFFER_TYPE_AUTO):
|
|
fprintf(Echo, "%s\t\t\tbuffer_size %s\n", tabs, "auto");
|
|
break;
|
|
case (POWER_BUFFER_TYPE_ABSOLUTE_SIZE):
|
|
fprintf(Echo, "%s\t\t\tbuffer_size %f\n", tabs,
|
|
pb_type->ports[i].port_power->buffer_size);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
switch (pb_type->ports[i].port_power->wire_type) {
|
|
case (POWER_WIRE_TYPE_UNDEFINED):
|
|
case (POWER_WIRE_TYPE_IGNORED):
|
|
break;
|
|
case (POWER_WIRE_TYPE_C):
|
|
fprintf(Echo, "%s\t\t\twire_cap: %e\n", tabs,
|
|
pb_type->ports[i].port_power->wire.C);
|
|
break;
|
|
case (POWER_WIRE_TYPE_ABSOLUTE_LENGTH):
|
|
fprintf(Echo, "%s\t\t\twire_len(abs): %e\n", tabs,
|
|
pb_type->ports[i].port_power->wire.absolute_length);
|
|
break;
|
|
case (POWER_WIRE_TYPE_RELATIVE_LENGTH):
|
|
fprintf(Echo, "%s\t\t\twire_len(rel): %f\n", tabs,
|
|
pb_type->ports[i].port_power->wire.relative_length);
|
|
break;
|
|
case (POWER_WIRE_TYPE_AUTO):
|
|
fprintf(Echo, "%s\t\t\twire_len: %s\n", tabs, "auto");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
//Output static power even if non zero
|
|
if (pb_type->pb_type_power->absolute_power_per_instance.leakage)
|
|
fprintf(Echo, "%s\t\tstatic power_per_instance: %e \n", tabs,
|
|
pb_type->pb_type_power->absolute_power_per_instance.leakage);
|
|
|
|
if (pb_type->pb_type_power->absolute_power_per_instance.dynamic)
|
|
fprintf(Echo, "%s\t\tdynamic power_per_instance: %e \n", tabs,
|
|
pb_type->pb_type_power->absolute_power_per_instance.dynamic);
|
|
break;
|
|
case POWER_METHOD_TOGGLE_PINS:
|
|
if (pb_type->parent_mode) {
|
|
/*if NOT top-level pb (all top-level pb has NULL parent_mode, check parent's power method
|
|
* This is because once energy_per_toggle is specified at one level,
|
|
* all children pb's are energy_per_toggle and only want to display once*/
|
|
if (pb_type->parent_mode->parent_pb_type->pb_type_power->estimation_method
|
|
== POWER_METHOD_TOGGLE_PINS)
|
|
break;
|
|
}
|
|
|
|
fprintf(Echo, "%s\tpower method: pin-toggle\n", tabs);
|
|
for (i = 0; i < pb_type->num_ports; i++) {
|
|
/*Print all the power information on each port, only if available,
|
|
* will not print if value is 0 or NULL*/
|
|
if (pb_type->ports[i].port_power->energy_per_toggle
|
|
|| pb_type->ports[i].port_power->scaled_by_port
|
|
|| pb_type->pb_type_power->absolute_power_per_instance.leakage
|
|
|| pb_type->pb_type_power->absolute_power_per_instance.dynamic) {
|
|
fprintf(Echo, "%s\t\tport %s type %d num_pins %d\n", tabs,
|
|
pb_type->ports[i].name, pb_type->ports[i].type,
|
|
pb_type->ports[i].num_pins);
|
|
//Toggle Energy
|
|
if (pb_type->ports[i].port_power->energy_per_toggle) {
|
|
fprintf(Echo, "%s\t\t\tenergy_per_toggle %e\n", tabs,
|
|
pb_type->ports[i].port_power->energy_per_toggle);
|
|
}
|
|
//Scaled by port (could be reversed)
|
|
if (pb_type->ports[i].port_power->scaled_by_port) {
|
|
if (pb_type->ports[i].port_power->scaled_by_port->num_pins
|
|
> 1) {
|
|
fprintf(Echo,
|
|
(pb_type->ports[i].port_power->reverse_scaled ? "%s\t\t\tscaled_by_static_prob_n: %s[%d]\n" : "%s\t\t\tscaled_by_static_prob: %s[%d]\n"),
|
|
tabs,
|
|
pb_type->ports[i].port_power->scaled_by_port->name,
|
|
pb_type->ports[i].port_power->scaled_by_port_pin_idx);
|
|
} else {
|
|
fprintf(Echo,
|
|
(pb_type->ports[i].port_power->reverse_scaled ? "%s\t\t\tscaled_by_static_prob_n: %s\n" : "%s\t\t\tscaled_by_static_prob: %s\n"),
|
|
tabs,
|
|
pb_type->ports[i].port_power->scaled_by_port->name);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//Output static power even if non zero
|
|
if (pb_type->pb_type_power->absolute_power_per_instance.leakage)
|
|
fprintf(Echo, "%s\t\tstatic power_per_instance: %e \n", tabs,
|
|
pb_type->pb_type_power->absolute_power_per_instance.leakage);
|
|
|
|
if (pb_type->pb_type_power->absolute_power_per_instance.dynamic)
|
|
fprintf(Echo, "%s\t\tdynamic power_per_instance: %e \n", tabs,
|
|
pb_type->pb_type_power->absolute_power_per_instance.dynamic);
|
|
|
|
break;
|
|
case POWER_METHOD_C_INTERNAL:
|
|
if (pb_type->parent_mode) {
|
|
/*if NOT top-level pb (all top-level pb has NULL parent_mode, check parent's power method
|
|
* This is because of values at this level includes all children pb's*/
|
|
if (pb_type->parent_mode->parent_pb_type->pb_type_power->estimation_method
|
|
== POWER_METHOD_C_INTERNAL)
|
|
break;
|
|
}
|
|
fprintf(Echo, "%s\tpower method: C-internal\n", tabs);
|
|
|
|
if (pb_type->pb_type_power->absolute_power_per_instance.leakage)
|
|
fprintf(Echo, "%s\t\tstatic power_per_instance: %e \n", tabs,
|
|
pb_type->pb_type_power->absolute_power_per_instance.leakage);
|
|
|
|
if (pb_type->pb_type_power->C_internal)
|
|
fprintf(Echo, "%s\t\tdynamic c-internal: %e \n", tabs,
|
|
pb_type->pb_type_power->C_internal);
|
|
break;
|
|
case POWER_METHOD_ABSOLUTE:
|
|
if (pb_type->parent_mode) {
|
|
/*if NOT top-level pb (all top-level pb has NULL parent_mode, check parent's power method
|
|
* This is because of values at this level includes all children pb's*/
|
|
if (pb_type->parent_mode->parent_pb_type->pb_type_power->estimation_method
|
|
== POWER_METHOD_ABSOLUTE)
|
|
break;
|
|
}
|
|
fprintf(Echo, "%s\tpower method: absolute\n", tabs);
|
|
if (pb_type->pb_type_power->absolute_power_per_instance.leakage)
|
|
fprintf(Echo, "%s\t\tstatic power_per_instance: %e \n", tabs,
|
|
pb_type->pb_type_power->absolute_power_per_instance.leakage);
|
|
|
|
if (pb_type->pb_type_power->absolute_power_per_instance.dynamic)
|
|
fprintf(Echo, "%s\t\tdynamic power_per_instance: %e \n", tabs,
|
|
pb_type->pb_type_power->absolute_power_per_instance.dynamic);
|
|
break;
|
|
default:
|
|
fprintf(Echo, "%s\tpower method: error has occcured\n", tabs);
|
|
break;
|
|
}
|
|
}
|