902 lines
28 KiB
C
902 lines
28 KiB
C
|
/*********************************************************************
|
||
|
* The following code is part of the power modelling feature of VTR.
|
||
|
*
|
||
|
* For support:
|
||
|
* http://code.google.com/p/vtr-verilog-to-routing/wiki/Power
|
||
|
*
|
||
|
* or email:
|
||
|
* vtr.power.estimation@gmail.com
|
||
|
*
|
||
|
* If you are using power estimation for your researach please cite:
|
||
|
*
|
||
|
* Jeffrey Goeders and Steven Wilton. VersaPower: Power Estimation
|
||
|
* for Diverse FPGA Architectures. In International Conference on
|
||
|
* Field Programmable Technology, 2012.
|
||
|
*
|
||
|
********************************************************************/
|
||
|
|
||
|
/**
|
||
|
* This file provides functions relating to the cmos technology. It
|
||
|
* includes functions to read the transistor characteristics from the
|
||
|
* xml file into data structures, and functions to search within
|
||
|
* these data structures.
|
||
|
*/
|
||
|
|
||
|
/************************* INCLUDES *********************************/
|
||
|
#include <cstring>
|
||
|
using namespace std;
|
||
|
|
||
|
#include <assert.h>
|
||
|
|
||
|
#include "power_cmos_tech.h"
|
||
|
#include "power.h"
|
||
|
#include "power_util.h"
|
||
|
#include "ezxml.h"
|
||
|
#include "util.h"
|
||
|
#include "read_xml_util.h"
|
||
|
#include "PowerSpicedComponent.h"
|
||
|
#include "power_callibrate.h"
|
||
|
|
||
|
/************************* GLOBALS **********************************/
|
||
|
static t_transistor_inf * g_transistor_last_searched;
|
||
|
static t_power_buffer_strength_inf * g_buffer_strength_last_searched;
|
||
|
static t_power_mux_volt_inf * g_mux_volt_last_searched;
|
||
|
|
||
|
/************************* FUNCTION DECLARATIONS ********************/
|
||
|
|
||
|
static void power_tech_load_xml_file(char * cmos_tech_behavior_filepath);
|
||
|
static void process_tech_xml_load_transistor_info(ezxml_t parent);
|
||
|
static void power_tech_xml_load_multiplexer_info(ezxml_t parent);
|
||
|
static void power_tech_xml_load_nmos_st_leakages(ezxml_t parent);
|
||
|
static int power_compare_transistor_size(const void * key_void,
|
||
|
const void * elem_void);
|
||
|
static int power_compare_voltage_pair(const void * key_void,
|
||
|
const void * elem_void);
|
||
|
static int power_compare_leakage_pair(const void * key_void,
|
||
|
const void * elem_void);
|
||
|
//static void power_tech_xml_load_sc(ezxml_t parent);
|
||
|
static int power_compare_buffer_strength(const void * key_void,
|
||
|
const void * elem_void);
|
||
|
static int power_compare_buffer_sc_levr(const void * key_void,
|
||
|
const void * elem_void);
|
||
|
static void power_tech_xml_load_components(ezxml_t parent);
|
||
|
static void power_tech_xml_load_component(ezxml_t parent,
|
||
|
PowerSpicedComponent ** component, char * name,
|
||
|
float (*usage_fn)(int num_inputs, float transistor_size));
|
||
|
/************************* FUNCTION DEFINITIONS *********************/
|
||
|
|
||
|
void power_tech_init(char * cmos_tech_behavior_filepath) {
|
||
|
power_tech_load_xml_file(cmos_tech_behavior_filepath);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Reads the transistor properties from the .xml file
|
||
|
*/
|
||
|
void power_tech_load_xml_file(char * cmos_tech_behavior_filepath) {
|
||
|
ezxml_t cur, child, prev;
|
||
|
const char * prop;
|
||
|
char msg[BUFSIZE];
|
||
|
|
||
|
if (!file_exists(cmos_tech_behavior_filepath)) {
|
||
|
/* .xml transistor characteristics is missing */
|
||
|
sprintf(msg,
|
||
|
"The CMOS technology behavior file ('%s') does not exist. No power information will be calculated.",
|
||
|
cmos_tech_behavior_filepath);
|
||
|
power_log_msg(POWER_LOG_ERROR, msg);
|
||
|
|
||
|
g_power_tech->NMOS_inf.num_size_entries = 0;
|
||
|
g_power_tech->NMOS_inf.long_trans_inf = NULL;
|
||
|
g_power_tech->NMOS_inf.size_inf = NULL;
|
||
|
|
||
|
g_power_tech->PMOS_inf.num_size_entries = 0;
|
||
|
g_power_tech->PMOS_inf.long_trans_inf = NULL;
|
||
|
g_power_tech->PMOS_inf.size_inf = NULL;
|
||
|
|
||
|
g_power_tech->Vdd = 0.;
|
||
|
g_power_tech->temperature = 85;
|
||
|
g_power_tech->PN_ratio = 1.;
|
||
|
return;
|
||
|
}
|
||
|
cur = ezxml_parse_file(cmos_tech_behavior_filepath);
|
||
|
|
||
|
prop = FindProperty(cur, "file", TRUE);
|
||
|
ezxml_set_attr(cur, "file", NULL);
|
||
|
|
||
|
prop = FindProperty(cur, "size", TRUE);
|
||
|
g_power_tech->tech_size = atof(prop);
|
||
|
ezxml_set_attr(cur, "size", NULL);
|
||
|
|
||
|
child = FindElement(cur, "operating_point", TRUE);
|
||
|
g_power_tech->temperature = GetFloatProperty(child, "temperature", TRUE, 0);
|
||
|
g_power_tech->Vdd = GetFloatProperty(child, "Vdd", TRUE, 0);
|
||
|
FreeNode(child);
|
||
|
|
||
|
child = FindElement(cur, "p_to_n", TRUE);
|
||
|
g_power_tech->PN_ratio = GetFloatProperty(child, "ratio", TRUE, 0);
|
||
|
FreeNode(child);
|
||
|
|
||
|
/* Transistor Information */
|
||
|
child = FindFirstElement(cur, "transistor", TRUE);
|
||
|
process_tech_xml_load_transistor_info(child);
|
||
|
|
||
|
prev = child;
|
||
|
child = child->next;
|
||
|
FreeNode(prev);
|
||
|
|
||
|
process_tech_xml_load_transistor_info(child);
|
||
|
FreeNode(child);
|
||
|
|
||
|
/* Multiplexer Voltage Information */
|
||
|
child = FindElement(cur, "multiplexers", TRUE);
|
||
|
power_tech_xml_load_multiplexer_info(child);
|
||
|
FreeNode(child);
|
||
|
|
||
|
/* Vds Leakage Information */
|
||
|
child = FindElement(cur, "nmos_leakages", TRUE);
|
||
|
power_tech_xml_load_nmos_st_leakages(child);
|
||
|
FreeNode(child);
|
||
|
|
||
|
/* Buffer SC Info */
|
||
|
/*
|
||
|
child = FindElement(cur, "buffer_sc", TRUE);
|
||
|
power_tech_xml_load_sc(child);
|
||
|
FreeNode(child);
|
||
|
*/
|
||
|
|
||
|
/* Components */
|
||
|
child = FindElement(cur, "components", TRUE);
|
||
|
power_tech_xml_load_components(child);
|
||
|
FreeNode(child);
|
||
|
|
||
|
FreeNode(cur);
|
||
|
}
|
||
|
|
||
|
static void power_tech_xml_load_component(ezxml_t parent,
|
||
|
PowerSpicedComponent ** component, char * name,
|
||
|
float (*usage_fn)(int num_inputs, float transistor_size)) {
|
||
|
ezxml_t cur, child, gc, prev;
|
||
|
|
||
|
*component = new PowerSpicedComponent(usage_fn);
|
||
|
|
||
|
cur = FindElement(parent, name, TRUE);
|
||
|
|
||
|
child = FindFirstElement(cur, "inputs", TRUE);
|
||
|
while (child) {
|
||
|
int num_inputs = GetIntProperty(child, "num_inputs", TRUE, 0);
|
||
|
|
||
|
gc = FindFirstElement(child, "size", TRUE);
|
||
|
while (gc) {
|
||
|
float transistor_size = GetFloatProperty(gc, "transistor_size",
|
||
|
TRUE, 0.);
|
||
|
float power = GetFloatProperty(gc, "power", TRUE, 0.);
|
||
|
(*component)->add_data_point(num_inputs, transistor_size, power);
|
||
|
|
||
|
prev = gc;
|
||
|
gc = gc->next;
|
||
|
FreeNode(prev);
|
||
|
}
|
||
|
prev = child;
|
||
|
child = child->next;
|
||
|
FreeNode(prev);
|
||
|
}
|
||
|
FreeNode(cur);
|
||
|
}
|
||
|
|
||
|
static void power_tech_xml_load_components(ezxml_t parent) {
|
||
|
|
||
|
g_power_commonly_used->component_callibration =
|
||
|
(PowerSpicedComponent**) my_calloc(POWER_CALLIB_COMPONENT_MAX,
|
||
|
sizeof(PowerSpicedComponent*));
|
||
|
|
||
|
power_tech_xml_load_component(parent,
|
||
|
&g_power_commonly_used->component_callibration[POWER_CALLIB_COMPONENT_BUFFER],
|
||
|
"buf", power_usage_buf_for_callibration);
|
||
|
|
||
|
power_tech_xml_load_component(parent,
|
||
|
&g_power_commonly_used->component_callibration[POWER_CALLIB_COMPONENT_BUFFER_WITH_LEVR],
|
||
|
"buf_levr", power_usage_buf_levr_for_callibration);
|
||
|
|
||
|
power_tech_xml_load_component(parent,
|
||
|
&g_power_commonly_used->component_callibration[POWER_CALLIB_COMPONENT_FF],
|
||
|
"dff", power_usage_ff_for_callibration);
|
||
|
|
||
|
power_tech_xml_load_component(parent,
|
||
|
&g_power_commonly_used->component_callibration[POWER_CALLIB_COMPONENT_MUX],
|
||
|
"mux", power_usage_mux_for_callibration);
|
||
|
|
||
|
power_tech_xml_load_component(parent,
|
||
|
&g_power_commonly_used->component_callibration[POWER_CALLIB_COMPONENT_LUT],
|
||
|
"lut", power_usage_lut_for_callibration);
|
||
|
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Read short-circuit buffer information from the transistor .xml file.
|
||
|
* This contains values for buffers of various 1) # Stages 2) Stage strength 3) Input type & capacitance
|
||
|
*/
|
||
|
#if 0
|
||
|
static void power_tech_xml_load_sc(ezxml_t parent) {
|
||
|
ezxml_t child, prev, gc, ggc;
|
||
|
int i, j, k;
|
||
|
int num_buffer_sizes;
|
||
|
|
||
|
/* Information for buffers, based on # of stages in buffer */
|
||
|
num_buffer_sizes = CountChildren(parent, "stages", 1);
|
||
|
g_power_tech->max_buffer_size = num_buffer_sizes; /* buffer size starts at 1, not 0 */
|
||
|
g_power_tech->buffer_size_inf = (t_power_buffer_size_inf*) my_calloc(
|
||
|
g_power_tech->max_buffer_size + 1, sizeof(t_power_buffer_size_inf));
|
||
|
|
||
|
child = FindFirstElement(parent, "stages", TRUE);
|
||
|
i = 1;
|
||
|
while (child) {
|
||
|
t_power_buffer_size_inf * size_inf = &g_power_tech->buffer_size_inf[i];
|
||
|
|
||
|
GetIntProperty(child, "num_stages", TRUE, 1);
|
||
|
|
||
|
/* For the given # of stages, find the records for the strength of each stage */
|
||
|
size_inf->num_strengths = CountChildren(child, "strength", 1);
|
||
|
size_inf->strength_inf = (t_power_buffer_strength_inf*) my_calloc(
|
||
|
size_inf->num_strengths, sizeof(t_power_buffer_strength_inf));
|
||
|
|
||
|
gc = FindFirstElement(child, "strength", TRUE);
|
||
|
j = 0;
|
||
|
while (gc) {
|
||
|
t_power_buffer_strength_inf * strength_inf =
|
||
|
&size_inf->strength_inf[j];
|
||
|
|
||
|
/* Get the short circuit factor for a buffer with no level restorer at the input */
|
||
|
strength_inf->stage_gain = GetFloatProperty(gc, "gain", TRUE, 0.0);
|
||
|
strength_inf->sc_no_levr = GetFloatProperty(gc, "sc_nolevr", TRUE,
|
||
|
0.0);
|
||
|
|
||
|
/* Get the short circuit factor for buffers with level restorers at the input */
|
||
|
strength_inf->num_levr_entries = CountChildren(gc, "input_cap", 1);
|
||
|
strength_inf->sc_levr_inf = (t_power_buffer_sc_levr_inf*) my_calloc(
|
||
|
strength_inf->num_levr_entries,
|
||
|
sizeof(t_power_buffer_sc_levr_inf));
|
||
|
|
||
|
ggc = FindFirstElement(gc, "input_cap", TRUE);
|
||
|
k = 0;
|
||
|
while (ggc) {
|
||
|
t_power_buffer_sc_levr_inf * levr_inf =
|
||
|
&strength_inf->sc_levr_inf[k];
|
||
|
|
||
|
/* Short circuit factor is depdent on size of mux that drives the buffer */
|
||
|
levr_inf->mux_size = GetIntProperty(ggc, "mux_size", TRUE, 0);
|
||
|
levr_inf->sc_levr = GetFloatProperty(ggc, "sc_levr", TRUE, 0.0);
|
||
|
|
||
|
prev = ggc;
|
||
|
ggc = ggc->next;
|
||
|
FreeNode(prev);
|
||
|
k++;
|
||
|
}
|
||
|
|
||
|
prev = gc;
|
||
|
gc = gc->next;
|
||
|
FreeNode(prev);
|
||
|
j++;
|
||
|
}
|
||
|
|
||
|
prev = child;
|
||
|
child = child->next;
|
||
|
FreeNode(prev);
|
||
|
i++;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/**
|
||
|
* Read NMOS subthreshold leakage currents from the .xml transistor characteristics
|
||
|
* This builds a table of (Vds,Ids) value pairs
|
||
|
* */
|
||
|
static void power_tech_xml_load_nmos_st_leakages(ezxml_t parent) {
|
||
|
ezxml_t me, child, prev;
|
||
|
int num_nmos_sizes;
|
||
|
int num_leakage_pairs;
|
||
|
int i;
|
||
|
int nmos_idx;
|
||
|
|
||
|
num_nmos_sizes = CountChildren(parent, "nmos", 1);
|
||
|
g_power_tech->num_nmos_leakage_info = num_nmos_sizes;
|
||
|
g_power_tech->nmos_leakage_info = (t_power_nmos_leakage_inf*) my_calloc(
|
||
|
num_nmos_sizes, sizeof(t_power_nmos_leakage_inf));
|
||
|
|
||
|
me = FindFirstElement(parent, "nmos", TRUE);
|
||
|
nmos_idx = 0;
|
||
|
while (me) {
|
||
|
t_power_nmos_leakage_inf * nmos_info =
|
||
|
&g_power_tech->nmos_leakage_info[nmos_idx];
|
||
|
nmos_info->nmos_size = GetFloatProperty(me, "size", TRUE, 0.);
|
||
|
|
||
|
num_leakage_pairs = CountChildren(me, "nmos_leakage", 1);
|
||
|
nmos_info->num_leakage_pairs = num_leakage_pairs;
|
||
|
nmos_info->leakage_pairs = (t_power_nmos_leakage_pair*) my_calloc(
|
||
|
num_leakage_pairs, sizeof(t_power_nmos_leakage_pair));
|
||
|
|
||
|
child = FindFirstElement(me, "nmos_leakage", TRUE);
|
||
|
i = 0;
|
||
|
while (child) {
|
||
|
nmos_info->leakage_pairs[i].v_ds = GetFloatProperty(child, "Vds",
|
||
|
TRUE, 0.0);
|
||
|
nmos_info->leakage_pairs[i].i_ds = GetFloatProperty(child, "Ids",
|
||
|
TRUE, 0.0);
|
||
|
|
||
|
prev = child;
|
||
|
child = child->next;
|
||
|
FreeNode(prev);
|
||
|
i++;
|
||
|
}
|
||
|
|
||
|
prev = me;
|
||
|
me = me->next;
|
||
|
FreeNode(prev);
|
||
|
nmos_idx++;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Read multiplexer information from the .xml transistor characteristics.
|
||
|
* This contains the estimates of mux output voltages, depending on 1) Mux Size 2) Mux Vin
|
||
|
* */
|
||
|
static void power_tech_xml_load_multiplexer_info(ezxml_t parent) {
|
||
|
ezxml_t me, child, prev, gc;
|
||
|
int num_nmos_sizes;
|
||
|
int num_mux_sizes;
|
||
|
int i, j, nmos_idx;
|
||
|
|
||
|
/* Process all nmos sizes */
|
||
|
num_nmos_sizes = CountChildren(parent, "nmos", 1);
|
||
|
g_power_tech->num_nmos_mux_info = num_nmos_sizes;
|
||
|
g_power_tech->nmos_mux_info = (t_power_nmos_mux_inf*) my_calloc(
|
||
|
num_nmos_sizes, sizeof(t_power_nmos_mux_inf));
|
||
|
|
||
|
me = FindFirstElement(parent, "nmos", TRUE);
|
||
|
nmos_idx = 0;
|
||
|
while (me) {
|
||
|
t_power_nmos_mux_inf * nmos_inf = &g_power_tech->nmos_mux_info[nmos_idx];
|
||
|
nmos_inf->nmos_size = GetFloatProperty(me, "size", TRUE, 0.0);
|
||
|
// ezxml_set_attr(me, "size", NULL);
|
||
|
|
||
|
/* Process all multiplexer sizes */
|
||
|
num_mux_sizes = CountChildren(me, "multiplexer", 1);
|
||
|
|
||
|
/* Add entries for 0 and 1, for convenience, although
|
||
|
* they will never be used
|
||
|
*/
|
||
|
nmos_inf->max_mux_sl_size = 1 + num_mux_sizes;
|
||
|
nmos_inf->mux_voltage_inf = (t_power_mux_volt_inf*) my_calloc(
|
||
|
nmos_inf->max_mux_sl_size + 1, sizeof(t_power_mux_volt_inf));
|
||
|
|
||
|
child = FindFirstElement(me, "multiplexer", TRUE);
|
||
|
i = 1;
|
||
|
while (child) {
|
||
|
int num_voltages;
|
||
|
|
||
|
assert(i == GetFloatProperty(child, "size", TRUE, 0));
|
||
|
|
||
|
/* For each mux size, process all of the Vin levels */
|
||
|
num_voltages = CountChildren(child, "voltages", 1);
|
||
|
|
||
|
nmos_inf->mux_voltage_inf[i].num_voltage_pairs = num_voltages;
|
||
|
nmos_inf->mux_voltage_inf[i].mux_voltage_pairs =
|
||
|
(t_power_mux_volt_pair*) my_calloc(num_voltages,
|
||
|
sizeof(t_power_mux_volt_pair));
|
||
|
|
||
|
gc = FindFirstElement(child, "voltages", TRUE);
|
||
|
j = 0;
|
||
|
while (gc) {
|
||
|
/* For each mux size, and Vin level, get the min/max V_out */
|
||
|
nmos_inf->mux_voltage_inf[i].mux_voltage_pairs[j].v_in =
|
||
|
GetFloatProperty(gc, "in", TRUE, 0.0);
|
||
|
nmos_inf->mux_voltage_inf[i].mux_voltage_pairs[j].v_out_min =
|
||
|
GetFloatProperty(gc, "out_min", TRUE, 0.0);
|
||
|
nmos_inf->mux_voltage_inf[i].mux_voltage_pairs[j].v_out_max =
|
||
|
GetFloatProperty(gc, "out_max", TRUE, 0.0);
|
||
|
|
||
|
prev = gc;
|
||
|
gc = gc->next;
|
||
|
FreeNode(prev);
|
||
|
j++;
|
||
|
}
|
||
|
|
||
|
prev = child;
|
||
|
child = child->next;
|
||
|
FreeNode(prev);
|
||
|
i++;
|
||
|
}
|
||
|
|
||
|
prev = me;
|
||
|
me = me->next;
|
||
|
FreeNode(prev);
|
||
|
nmos_idx++;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Read the transistor information from the .xml transistor characteristics.
|
||
|
* For each transistor size, it extracts the:
|
||
|
* - transistor node capacitances
|
||
|
* - subthreshold leakage
|
||
|
* - gate leakage
|
||
|
*/
|
||
|
static void process_tech_xml_load_transistor_info(ezxml_t parent) {
|
||
|
t_transistor_inf * trans_inf;
|
||
|
const char * prop;
|
||
|
ezxml_t child, prev, grandchild;
|
||
|
int i;
|
||
|
|
||
|
/* Get transistor type: NMOS or PMOS */
|
||
|
prop = FindProperty(parent, "type", TRUE);
|
||
|
trans_inf = NULL;
|
||
|
if (strcmp(prop, "nmos") == 0) {
|
||
|
trans_inf = &g_power_tech->NMOS_inf;
|
||
|
} else if (strcmp(prop, "pmos") == 0) {
|
||
|
trans_inf = &g_power_tech->PMOS_inf;
|
||
|
} else {
|
||
|
assert(0);
|
||
|
}
|
||
|
ezxml_set_attr(parent, "type", NULL);
|
||
|
|
||
|
/* Get long transistor information (W=1,L=2) */
|
||
|
trans_inf->long_trans_inf = (t_transistor_size_inf*) my_malloc(
|
||
|
sizeof(t_transistor_size_inf));
|
||
|
|
||
|
child = FindElement(parent, "long_size", TRUE);
|
||
|
assert(GetIntProperty(child, "L", TRUE, 0) == 2);
|
||
|
trans_inf->long_trans_inf->size = GetFloatProperty(child, "W", TRUE, 0);
|
||
|
|
||
|
grandchild = FindElement(child, "leakage_current", TRUE);
|
||
|
trans_inf->long_trans_inf->leakage_subthreshold = GetFloatProperty(
|
||
|
grandchild, "subthreshold", TRUE, 0);
|
||
|
FreeNode(grandchild);
|
||
|
|
||
|
grandchild = FindElement(child, "capacitance", TRUE);
|
||
|
trans_inf->long_trans_inf->C_g = GetFloatProperty(grandchild, "C_g", TRUE,
|
||
|
0);
|
||
|
trans_inf->long_trans_inf->C_d = GetFloatProperty(grandchild, "C_d", TRUE,
|
||
|
0);
|
||
|
trans_inf->long_trans_inf->C_s = GetFloatProperty(grandchild, "C_s", TRUE,
|
||
|
0);
|
||
|
FreeNode(grandchild);
|
||
|
|
||
|
/* Process all transistor sizes */
|
||
|
trans_inf->num_size_entries = CountChildren(parent, "size", 1);
|
||
|
trans_inf->size_inf = (t_transistor_size_inf*) my_calloc(
|
||
|
trans_inf->num_size_entries, sizeof(t_transistor_size_inf));
|
||
|
FreeNode(child);
|
||
|
|
||
|
child = FindFirstElement(parent, "size", TRUE);
|
||
|
i = 0;
|
||
|
while (child) {
|
||
|
assert(GetIntProperty(child, "L", TRUE, 0) == 1);
|
||
|
|
||
|
trans_inf->size_inf[i].size = GetFloatProperty(child, "W", TRUE, 0);
|
||
|
|
||
|
/* Get leakage currents */
|
||
|
grandchild = FindElement(child, "leakage_current", TRUE);
|
||
|
trans_inf->size_inf[i].leakage_subthreshold = GetFloatProperty(
|
||
|
grandchild, "subthreshold", TRUE, 0);
|
||
|
trans_inf->size_inf[i].leakage_gate = GetFloatProperty(grandchild,
|
||
|
"gate", TRUE, 0);
|
||
|
FreeNode(grandchild);
|
||
|
|
||
|
/* Get node capacitances */
|
||
|
grandchild = FindElement(child, "capacitance", TRUE);
|
||
|
trans_inf->size_inf[i].C_g = GetFloatProperty(grandchild, "C_g", TRUE,
|
||
|
0);
|
||
|
trans_inf->size_inf[i].C_s = GetFloatProperty(grandchild, "C_s", TRUE,
|
||
|
0);
|
||
|
trans_inf->size_inf[i].C_d = GetFloatProperty(grandchild, "C_d", TRUE,
|
||
|
0);
|
||
|
FreeNode(grandchild);
|
||
|
|
||
|
prev = child;
|
||
|
child = child->next;
|
||
|
FreeNode(prev);
|
||
|
i++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* This function searches for a transistor by size
|
||
|
* - lower: (Return value) The lower-bound matching transistor
|
||
|
* - upper: (Return value) The upper-bound matching transistor
|
||
|
* - type: The transistor type to search for
|
||
|
* - size: The transistor size to search for (size = W/L)
|
||
|
*/
|
||
|
boolean power_find_transistor_info(t_transistor_size_inf ** lower,
|
||
|
t_transistor_size_inf ** upper, e_tx_type type, float size) {
|
||
|
char msg[1024];
|
||
|
t_transistor_size_inf key;
|
||
|
t_transistor_size_inf * found;
|
||
|
t_transistor_inf * trans_info;
|
||
|
float min_size, max_size;
|
||
|
boolean error = FALSE;
|
||
|
|
||
|
key.size = size;
|
||
|
|
||
|
/* Find the appropriate global transistor records */
|
||
|
trans_info = NULL;
|
||
|
if (type == NMOS) {
|
||
|
trans_info = &g_power_tech->NMOS_inf;
|
||
|
} else if (type == PMOS) {
|
||
|
trans_info = &g_power_tech->PMOS_inf;
|
||
|
} else {
|
||
|
assert(0);
|
||
|
}
|
||
|
|
||
|
/* No transistor data exists */
|
||
|
if (trans_info->size_inf == NULL) {
|
||
|
power_log_msg(POWER_LOG_ERROR,
|
||
|
"No transistor information exists. Cannot determine transistor properties.");
|
||
|
error = TRUE;
|
||
|
return error;
|
||
|
}
|
||
|
|
||
|
/* Make note of the transistor record we are searching in, and the bounds */
|
||
|
g_transistor_last_searched = trans_info;
|
||
|
min_size = trans_info->size_inf[0].size;
|
||
|
max_size = trans_info->size_inf[trans_info->num_size_entries - 1].size;
|
||
|
|
||
|
found = (t_transistor_size_inf*) bsearch(&key, trans_info->size_inf,
|
||
|
trans_info->num_size_entries, sizeof(t_transistor_size_inf),
|
||
|
&power_compare_transistor_size);
|
||
|
assert(found);
|
||
|
|
||
|
if (size < min_size) {
|
||
|
/* Too small */
|
||
|
assert(found == &trans_info->size_inf[0]);
|
||
|
sprintf(msg,
|
||
|
"Using %s transistor of size '%f', which is smaller than the smallest modeled transistor (%f) in the technology behavior file.",
|
||
|
transistor_type_name(type), size, min_size);
|
||
|
power_log_msg(POWER_LOG_WARNING, msg);
|
||
|
*lower = NULL;
|
||
|
*upper = found;
|
||
|
} else if (size > max_size) {
|
||
|
/* Too large */
|
||
|
assert(
|
||
|
found
|
||
|
== &trans_info->size_inf[trans_info->num_size_entries
|
||
|
- 1]);
|
||
|
sprintf(msg,
|
||
|
"Using %s transistor of size '%f', which is larger than the largest modeled transistor (%f) in the technology behavior file.",
|
||
|
transistor_type_name(type), size, max_size);
|
||
|
power_log_msg(POWER_LOG_WARNING, msg);
|
||
|
*lower = found;
|
||
|
*upper = NULL;
|
||
|
} else {
|
||
|
*lower = found;
|
||
|
*upper = found + 1;
|
||
|
}
|
||
|
|
||
|
return error;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* This function searches for the Ids leakage current, based on a given Vds.
|
||
|
* This function is used for minimum-sized NMOS transistors (used in muxs).
|
||
|
* - lower: (Return value) The lower-bound matching V/I pair
|
||
|
* - upper: (Return value) The upper-bound matching V/I pair
|
||
|
* - v_ds: The drain/source voltage to search for
|
||
|
*/
|
||
|
t_power_nmos_leakage_inf * g_power_searching_nmos_leakage_info;
|
||
|
void power_find_nmos_leakage(t_power_nmos_leakage_inf * nmos_leakage_info,
|
||
|
t_power_nmos_leakage_pair ** lower, t_power_nmos_leakage_pair ** upper,
|
||
|
float v_ds) {
|
||
|
t_power_nmos_leakage_pair key;
|
||
|
t_power_nmos_leakage_pair * found;
|
||
|
|
||
|
key.v_ds = v_ds;
|
||
|
|
||
|
g_power_searching_nmos_leakage_info = nmos_leakage_info;
|
||
|
|
||
|
found = (t_power_nmos_leakage_pair*) bsearch(&key,
|
||
|
nmos_leakage_info->leakage_pairs,
|
||
|
nmos_leakage_info->num_leakage_pairs,
|
||
|
sizeof(t_power_nmos_leakage_pair), power_compare_leakage_pair);
|
||
|
if (!found) {
|
||
|
assert(found);
|
||
|
}
|
||
|
|
||
|
if (found
|
||
|
== &nmos_leakage_info->leakage_pairs[nmos_leakage_info->num_leakage_pairs
|
||
|
- 1]) {
|
||
|
/* The results equal to the max voltage (Vdd) */
|
||
|
*lower = found;
|
||
|
*upper = NULL;
|
||
|
} else {
|
||
|
*lower = found;
|
||
|
*upper = found + 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* This function searches for the information for a given buffer strength.
|
||
|
* - lower: (Return value) The lower-bound matching record
|
||
|
* - upper: (Return value) The upper-bound matching record
|
||
|
* - stage_gain: The buffer strength to search for
|
||
|
*/
|
||
|
void power_find_buffer_strength_inf(t_power_buffer_strength_inf ** lower,
|
||
|
t_power_buffer_strength_inf ** upper,
|
||
|
t_power_buffer_size_inf * size_inf, float stage_gain) {
|
||
|
t_power_buffer_strength_inf key;
|
||
|
t_power_buffer_strength_inf * found;
|
||
|
|
||
|
float min_size;
|
||
|
float max_size;
|
||
|
|
||
|
min_size = size_inf->strength_inf[0].stage_gain;
|
||
|
max_size = size_inf->strength_inf[size_inf->num_strengths - 1].stage_gain;
|
||
|
|
||
|
assert(stage_gain >= min_size && stage_gain <= max_size);
|
||
|
|
||
|
key.stage_gain = stage_gain;
|
||
|
|
||
|
found = (t_power_buffer_strength_inf*) bsearch(&key, size_inf->strength_inf,
|
||
|
size_inf->num_strengths, sizeof(t_power_buffer_strength_inf),
|
||
|
power_compare_buffer_strength);
|
||
|
|
||
|
if (stage_gain == max_size) {
|
||
|
*lower = found;
|
||
|
*upper = NULL;
|
||
|
} else {
|
||
|
*lower = found;
|
||
|
*upper = found + 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* This function searches for short-circuit current information for a level-restoring buffer,
|
||
|
* based on the size of the multiplexer driving the input
|
||
|
* - lower: (Return value) The lower-bound matching record
|
||
|
* - upper: (Return value) The upper-bound matching record
|
||
|
* - buffer_strength: The set of records to search withing, which are for a specific buffer size/strength
|
||
|
* - input_mux_size: The input mux size to search for
|
||
|
*/
|
||
|
void power_find_buffer_sc_levr(t_power_buffer_sc_levr_inf ** lower,
|
||
|
t_power_buffer_sc_levr_inf ** upper,
|
||
|
t_power_buffer_strength_inf * buffer_strength, int input_mux_size) {
|
||
|
t_power_buffer_sc_levr_inf key;
|
||
|
t_power_buffer_sc_levr_inf * found;
|
||
|
char msg[1024];
|
||
|
int max_size;
|
||
|
|
||
|
assert(input_mux_size >= 1);
|
||
|
|
||
|
key.mux_size = input_mux_size;
|
||
|
|
||
|
g_buffer_strength_last_searched = buffer_strength;
|
||
|
found = (t_power_buffer_sc_levr_inf*) bsearch(&key,
|
||
|
buffer_strength->sc_levr_inf, buffer_strength->num_levr_entries,
|
||
|
sizeof(t_power_buffer_sc_levr_inf), power_compare_buffer_sc_levr);
|
||
|
|
||
|
max_size = buffer_strength->sc_levr_inf[buffer_strength->num_levr_entries
|
||
|
- 1].mux_size;
|
||
|
if (input_mux_size > max_size) {
|
||
|
/* Input mux too large */
|
||
|
assert(
|
||
|
found
|
||
|
== &buffer_strength->sc_levr_inf[buffer_strength->num_levr_entries
|
||
|
- 1]);
|
||
|
sprintf(msg,
|
||
|
"Using buffer driven by mux of size '%d', which is larger than the largest modeled size (%d) in the technology behavior file.",
|
||
|
input_mux_size, max_size);
|
||
|
power_log_msg(POWER_LOG_WARNING, msg);
|
||
|
*lower = found;
|
||
|
*upper = NULL;
|
||
|
} else {
|
||
|
*lower = found;
|
||
|
*upper = found + 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Comparison function, used by power_find_nmos_leakage
|
||
|
*/
|
||
|
static int power_compare_leakage_pair(const void * key_void,
|
||
|
const void * elem_void) {
|
||
|
const t_power_nmos_leakage_pair * key =
|
||
|
(const t_power_nmos_leakage_pair*) key_void;
|
||
|
const t_power_nmos_leakage_pair * elem =
|
||
|
(const t_power_nmos_leakage_pair*) elem_void;
|
||
|
const t_power_nmos_leakage_pair * next =
|
||
|
(const t_power_nmos_leakage_pair*) elem + 1;
|
||
|
|
||
|
/* Compare against last? */
|
||
|
if (elem
|
||
|
== &g_power_searching_nmos_leakage_info->leakage_pairs[g_power_searching_nmos_leakage_info->num_leakage_pairs
|
||
|
- 1]) {
|
||
|
if (key->v_ds >= elem->v_ds) {
|
||
|
return 0;
|
||
|
} else {
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Check for exact match to Vdd (upper end) */
|
||
|
if (key->v_ds == elem->v_ds) {
|
||
|
return 0;
|
||
|
} else if (key->v_ds < elem->v_ds) {
|
||
|
return -1;
|
||
|
} else if (key->v_ds > next->v_ds) {
|
||
|
return 1;
|
||
|
} else {
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* This function searches for multiplexer output voltage information, based on input voltage
|
||
|
* - lower: (Return value) The lower-bound matching record
|
||
|
* - upper: (Return value) The upper-bound matching record
|
||
|
* - volt_inf: The set of records to search within, which are for a specific mux size
|
||
|
* - v_in: The input voltage to search for
|
||
|
*/
|
||
|
void power_find_mux_volt_inf(t_power_mux_volt_pair ** lower,
|
||
|
t_power_mux_volt_pair ** upper, t_power_mux_volt_inf * volt_inf,
|
||
|
float v_in) {
|
||
|
t_power_mux_volt_pair key;
|
||
|
t_power_mux_volt_pair * found;
|
||
|
|
||
|
key.v_in = v_in;
|
||
|
|
||
|
g_mux_volt_last_searched = volt_inf;
|
||
|
found = (t_power_mux_volt_pair*) bsearch(&key, volt_inf->mux_voltage_pairs,
|
||
|
volt_inf->num_voltage_pairs, sizeof(t_power_mux_volt_pair),
|
||
|
power_compare_voltage_pair);
|
||
|
assert(found);
|
||
|
|
||
|
if (found
|
||
|
== &volt_inf->mux_voltage_pairs[volt_inf->num_voltage_pairs - 1]) {
|
||
|
*lower = found;
|
||
|
*upper = NULL;
|
||
|
} else {
|
||
|
*lower = found;
|
||
|
*upper = found + 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Comparison function, used by power_find_buffer_sc_levr
|
||
|
*/
|
||
|
static int power_compare_buffer_sc_levr(const void * key_void,
|
||
|
const void * elem_void) {
|
||
|
const t_power_buffer_sc_levr_inf * key =
|
||
|
(const t_power_buffer_sc_levr_inf*) key_void;
|
||
|
const t_power_buffer_sc_levr_inf * elem =
|
||
|
(const t_power_buffer_sc_levr_inf*) elem_void;
|
||
|
const t_power_buffer_sc_levr_inf * next;
|
||
|
|
||
|
/* Compare against last? */
|
||
|
if (elem
|
||
|
== &g_buffer_strength_last_searched->sc_levr_inf[g_buffer_strength_last_searched->num_levr_entries
|
||
|
- 1]) {
|
||
|
if (key->mux_size >= elem->mux_size) {
|
||
|
return 0;
|
||
|
} else {
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Compare against first? */
|
||
|
if (elem == &g_buffer_strength_last_searched->sc_levr_inf[0]) {
|
||
|
if (key->mux_size < elem->mux_size) {
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Check if the key is between elem and the next element */
|
||
|
next = elem + 1;
|
||
|
if (key->mux_size > next->mux_size) {
|
||
|
return 1;
|
||
|
} else if (key->mux_size < elem->mux_size) {
|
||
|
return -1;
|
||
|
} else {
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Comparison function, used by power_find_buffer_strength_inf
|
||
|
*/
|
||
|
static int power_compare_buffer_strength(const void * key_void,
|
||
|
const void * elem_void) {
|
||
|
const t_power_buffer_strength_inf * key =
|
||
|
(const t_power_buffer_strength_inf*) key_void;
|
||
|
const t_power_buffer_strength_inf * elem =
|
||
|
(const t_power_buffer_strength_inf*) elem_void;
|
||
|
const t_power_buffer_strength_inf * next =
|
||
|
(const t_power_buffer_strength_inf*) elem + 1;
|
||
|
|
||
|
/* Check for exact match */
|
||
|
if (key->stage_gain == elem->stage_gain) {
|
||
|
return 0;
|
||
|
} else if (key->stage_gain < elem->stage_gain) {
|
||
|
return -1;
|
||
|
} else if (key->stage_gain > next->stage_gain) {
|
||
|
return 1;
|
||
|
} else {
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Comparison function, used by power_find_transistor_info
|
||
|
*/
|
||
|
static int power_compare_transistor_size(const void * key_void,
|
||
|
const void * elem_void) {
|
||
|
const t_transistor_size_inf * key = (const t_transistor_size_inf*) key_void;
|
||
|
const t_transistor_size_inf * elem =
|
||
|
(const t_transistor_size_inf*) elem_void;
|
||
|
const t_transistor_size_inf * next;
|
||
|
|
||
|
/* Check if we are comparing against the last element */
|
||
|
if (elem
|
||
|
== &g_transistor_last_searched->size_inf[g_transistor_last_searched->num_size_entries
|
||
|
- 1]) {
|
||
|
/* Match if the desired value is larger than the largest item in the list */
|
||
|
if (key->size >= elem->size) {
|
||
|
return 0;
|
||
|
} else {
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Check if we are comparing against the first element */
|
||
|
if (elem == &g_transistor_last_searched->size_inf[0]) {
|
||
|
/* Match the smallest if it is smaller than the smallest */
|
||
|
if (key->size < elem->size) {
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Check if the key is between elem and the next element */
|
||
|
next = elem + 1;
|
||
|
if (key->size > next->size) {
|
||
|
return 1;
|
||
|
} else if (key->size < elem->size) {
|
||
|
return -1;
|
||
|
} else {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Comparison function, used by power_find_mux_volt_inf
|
||
|
*/
|
||
|
static int power_compare_voltage_pair(const void * key_void,
|
||
|
const void * elem_void) {
|
||
|
const t_power_mux_volt_pair * key = (const t_power_mux_volt_pair *) key_void;
|
||
|
const t_power_mux_volt_pair * elem =
|
||
|
(const t_power_mux_volt_pair *) elem_void;
|
||
|
const t_power_mux_volt_pair * next = (const t_power_mux_volt_pair *) elem
|
||
|
+ 1;
|
||
|
|
||
|
/* Check if we are comparing against the last element */
|
||
|
if (elem
|
||
|
== &g_mux_volt_last_searched->mux_voltage_pairs[g_mux_volt_last_searched->num_voltage_pairs
|
||
|
- 1]) {
|
||
|
/* Match if the desired value is larger than the largest item in the list */
|
||
|
if (key->v_in >= elem->v_in) {
|
||
|
return 0;
|
||
|
} else {
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Check for exact match to Vdd (upper end) */
|
||
|
if (key->v_in == elem->v_in) {
|
||
|
return 0;
|
||
|
} else if (key->v_in < elem->v_in) {
|
||
|
return -1;
|
||
|
} else if (key->v_in > next->v_in) {
|
||
|
return 1;
|
||
|
} else {
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|