OpenFPGA/vpr/src/power/power_cmos_tech.cpp

740 lines
29 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>
#include "vtr_assert.h"
#include "pugixml.hpp"
#include "pugixml_util.hpp"
#include "vtr_util.h"
#include "vtr_memory.h"
#include "vtr_math.h"
#include "vpr_error.h"
#include "globals.h"
#include "power_cmos_tech.h"
#include "power.h"
#include "power_util.h"
#include "read_xml_util.h"
#include "PowerSpicedComponent.h"
#include "power_callibrate.h"
/************************* FILE SCOPE **********************************/
static t_transistor_inf* f_transistor_last_searched;
static t_power_buffer_strength_inf* f_buffer_strength_last_searched;
static t_power_mux_volt_inf* f_mux_volt_last_searched;
static t_power_nmos_leakage_inf* f_power_searching_nmos_leakage_info;
/************************* FUNCTION DECLARATIONS ********************/
static void power_tech_load_xml_file(const char* cmos_tech_behavior_filepath);
static void process_tech_xml_load_transistor_info(pugi::xml_node parent, const pugiutil::loc_data& loc_data);
static void power_tech_xml_load_multiplexer_info(pugi::xml_node parent, const pugiutil::loc_data& loc_data);
static void power_tech_xml_load_nmos_st_leakages(pugi::xml_node parent, const pugiutil::loc_data& loc_data);
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(pugi::xml_node parent, const pugiutil::loc_data& loc_data);
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(pugi::xml_node parent, const pugiutil::loc_data& loc_data);
static void power_tech_xml_load_component(pugi::xml_node parent, const pugiutil::loc_data& loc_data, PowerSpicedComponent** component, const char* name, float (*usage_fn)(int num_inputs, float transistor_size));
/************************* FUNCTION DEFINITIONS *********************/
void power_tech_init(const 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(const char* cmos_tech_behavior_filepath) {
pugi::xml_document doc;
pugiutil::loc_data loc_data;
try {
loc_data = pugiutil::load_xml(doc, cmos_tech_behavior_filepath);
} catch (const pugiutil::XmlError& e) {
vpr_throw(VPR_ERROR_POWER, cmos_tech_behavior_filepath, 0,
"Failed to load CMOS Tech Properties file '%s' (%s).", cmos_tech_behavior_filepath, e.what());
}
auto technology = get_single_child(doc, "technology", loc_data);
get_attribute(technology, "file", loc_data); //Check exists
auto& power_ctx = g_vpr_ctx.power();
auto tech_size = get_attribute(technology, "size", loc_data);
power_ctx.tech->tech_size = tech_size.as_float();
auto operating_point = get_single_child(technology, "operating_point", loc_data);
power_ctx.tech->temperature = get_attribute(operating_point, "temperature", loc_data).as_float();
power_ctx.tech->Vdd = get_attribute(operating_point, "Vdd", loc_data).as_float();
auto p_to_n = get_single_child(technology, "p_to_n", loc_data);
power_ctx.tech->PN_ratio = get_attribute(p_to_n, "ratio", loc_data).as_float();
/* Transistor Information
* We expect two <transistor> sections for P and N types
*/
auto child = get_first_child(technology, "transistor", loc_data);
process_tech_xml_load_transistor_info(child, loc_data);
child = child.next_sibling("transistor");
process_tech_xml_load_transistor_info(child, loc_data);
//Should be no more
auto next = child.next_sibling("transistor");
if (next) {
vpr_throw(VPR_ERROR_POWER, loc_data.filename_c_str(), loc_data.line(next),
"Encountered extra <transitor> section (expect 2 only: pmos and nmos)\n");
}
/* Multiplexer Voltage Information */
child = get_single_child(technology, "multiplexers", loc_data);
power_tech_xml_load_multiplexer_info(child, loc_data);
/* Vds Leakage Information */
child = get_single_child(technology, "nmos_leakages", loc_data);
power_tech_xml_load_nmos_st_leakages(child, loc_data);
/* Buffer SC Info */
/*
* child = get_single_child(technology, "buffer_sc", loc_data);
* power_tech_xml_load_sc(child);
*/
/* Components */
child = get_single_child(technology, "components", loc_data);
power_tech_xml_load_components(child, loc_data);
}
static void power_tech_xml_load_component(pugi::xml_node parent, const pugiutil::loc_data& loc_data, PowerSpicedComponent** component, const char* name, float (*usage_fn)(int num_inputs, float transistor_size)) {
std::string component_name(name);
*component = new PowerSpicedComponent(component_name, usage_fn);
auto cur = get_single_child(parent, name, loc_data);
auto child = get_first_child(cur, "inputs", loc_data);
while (child) {
int num_inputs = get_attribute(child, "num_inputs", loc_data).as_int(0);
auto gc = get_first_child(child, "size", loc_data);
while (gc) {
float transistor_size = get_attribute(gc, "transistor_size", loc_data).as_float(0.);
float power = get_attribute(gc, "power", loc_data).as_float(0.);
(*component)->add_data_point(num_inputs, transistor_size, power);
gc = gc.next_sibling("size");
}
child = child.next_sibling("inputs");
}
}
static void power_tech_xml_load_components(pugi::xml_node parent, const pugiutil::loc_data& loc_data) {
auto& power_ctx = g_vpr_ctx.power();
power_ctx.commonly_used->component_callibration = (PowerSpicedComponent**)vtr::calloc(POWER_CALLIB_COMPONENT_MAX,
sizeof(PowerSpicedComponent*));
power_tech_xml_load_component(parent, loc_data,
&power_ctx.commonly_used->component_callibration[POWER_CALLIB_COMPONENT_BUFFER],
"buf", power_usage_buf_for_callibration);
power_tech_xml_load_component(parent, loc_data,
&power_ctx.commonly_used->component_callibration[POWER_CALLIB_COMPONENT_BUFFER_WITH_LEVR],
"buf_levr", power_usage_buf_levr_for_callibration);
power_tech_xml_load_component(parent, loc_data,
&power_ctx.commonly_used->component_callibration[POWER_CALLIB_COMPONENT_FF],
"dff", power_usage_ff_for_callibration);
power_tech_xml_load_component(parent, loc_data,
&power_ctx.commonly_used->component_callibration[POWER_CALLIB_COMPONENT_MUX],
"mux", power_usage_mux_for_callibration);
power_tech_xml_load_component(parent, loc_data,
&power_ctx.commonly_used->component_callibration[POWER_CALLIB_COMPONENT_LUT],
"lut", power_usage_lut_for_callibration);
}
/**
* 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(pugi::xml_node parent, const pugiutil::loc_data& loc_data) {
int num_nmos_sizes;
int num_leakage_pairs;
int i;
int nmos_idx;
auto& power_ctx = g_vpr_ctx.power();
num_nmos_sizes = count_children(parent, "nmos", loc_data);
power_ctx.tech->num_nmos_leakage_info = num_nmos_sizes;
power_ctx.tech->nmos_leakage_info = (t_power_nmos_leakage_inf*)vtr::calloc(num_nmos_sizes, sizeof(t_power_nmos_leakage_inf));
auto me = get_first_child(parent, "nmos", loc_data);
nmos_idx = 0;
while (me) {
t_power_nmos_leakage_inf* nmos_info = &power_ctx.tech->nmos_leakage_info[nmos_idx];
nmos_info->nmos_size = get_attribute(me, "size", loc_data).as_float(0.);
num_leakage_pairs = count_children(me, "nmos_leakage", loc_data);
nmos_info->num_leakage_pairs = num_leakage_pairs;
nmos_info->leakage_pairs = (t_power_nmos_leakage_pair*)vtr::calloc(num_leakage_pairs, sizeof(t_power_nmos_leakage_pair));
auto child = get_first_child(me, "nmos_leakage", loc_data);
i = 0;
while (child) {
nmos_info->leakage_pairs[i].v_ds = get_attribute(child, "Vds", loc_data).as_float(0.0);
nmos_info->leakage_pairs[i].i_ds = get_attribute(child, "Ids", loc_data).as_float(0.0);
child = child.next_sibling("nmos_leakage");
i++;
}
me = me.next_sibling("nmos");
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(pugi::xml_node parent, const pugiutil::loc_data& loc_data) {
int num_nmos_sizes;
int num_mux_sizes;
int i, j, nmos_idx;
auto& power_ctx = g_vpr_ctx.power();
/* Process all nmos sizes */
num_nmos_sizes = count_children(parent, "nmos", loc_data);
VTR_ASSERT(num_nmos_sizes > 0);
power_ctx.tech->num_nmos_mux_info = num_nmos_sizes;
power_ctx.tech->nmos_mux_info = (t_power_nmos_mux_inf*)vtr::calloc(num_nmos_sizes, sizeof(t_power_nmos_mux_inf));
auto me = get_first_child(parent, "nmos", loc_data);
nmos_idx = 0;
while (me) {
t_power_nmos_mux_inf* nmos_inf = &power_ctx.tech->nmos_mux_info[nmos_idx];
nmos_inf->nmos_size = get_attribute(me, "size", loc_data).as_float(0.0);
/* Process all multiplexer sizes */
num_mux_sizes = count_children(me, "multiplexer", loc_data);
/* 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*)vtr::calloc(nmos_inf->max_mux_sl_size + 1, sizeof(t_power_mux_volt_inf));
auto child = get_first_child(me, "multiplexer", loc_data);
i = 1;
while (child) {
int num_voltages;
VTR_ASSERT(i == get_attribute(child, "size", loc_data).as_int(0));
/* For each mux size, process all of the Vin levels */
num_voltages = count_children(child, "voltages", loc_data);
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*)vtr::calloc(num_voltages,
sizeof(t_power_mux_volt_pair));
auto gc = get_first_child(child, "voltages", loc_data);
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 = get_attribute(gc, "in", loc_data).as_float(0.0);
nmos_inf->mux_voltage_inf[i].mux_voltage_pairs[j].v_out_min = get_attribute(gc, "out_min", loc_data).as_float(0.0);
nmos_inf->mux_voltage_inf[i].mux_voltage_pairs[j].v_out_max = get_attribute(gc, "out_max", loc_data).as_float(0.0);
gc = gc.next_sibling("voltages");
j++;
}
child = child.next_sibling("multiplexer");
i++;
}
me = me.next_sibling("nmos");
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(pugi::xml_node parent, const pugiutil::loc_data& loc_data) {
t_transistor_inf* trans_inf;
int i;
auto& power_ctx = g_vpr_ctx.power();
/* Get transistor type: NMOS or PMOS */
auto prop = get_attribute(parent, "type", loc_data);
trans_inf = nullptr;
if (strcmp(prop.value(), "nmos") == 0) {
trans_inf = &power_ctx.tech->NMOS_inf;
} else if (strcmp(prop.value(), "pmos") == 0) {
trans_inf = &power_ctx.tech->PMOS_inf;
} else {
vpr_throw(VPR_ERROR_POWER, loc_data.filename_c_str(), loc_data.line(parent),
"Unrecognized transistor type '%s', expected 'nmos' or 'pmos'\n", prop.value());
}
/* Get long transistor information (W=1,L=2) */
trans_inf->long_trans_inf = (t_transistor_size_inf*)vtr::malloc(sizeof(t_transistor_size_inf));
auto child = get_single_child(parent, "long_size", loc_data);
VTR_ASSERT(get_attribute(child, "L", loc_data).as_int(0) == 2);
trans_inf->long_trans_inf->size = get_attribute(child, "W", loc_data).as_float(0.);
auto grandchild = get_single_child(child, "leakage_current", loc_data);
trans_inf->long_trans_inf->leakage_subthreshold = get_attribute(grandchild, "subthreshold", loc_data).as_float(0.);
grandchild = get_single_child(child, "capacitance", loc_data);
trans_inf->long_trans_inf->C_g = get_attribute(grandchild, "C_g", loc_data).as_float(0);
trans_inf->long_trans_inf->C_d = get_attribute(grandchild, "C_d", loc_data).as_float(0);
trans_inf->long_trans_inf->C_s = get_attribute(grandchild, "C_s", loc_data).as_float(0);
/* Process all transistor sizes */
trans_inf->num_size_entries = count_children(parent, "size", loc_data);
trans_inf->size_inf = (t_transistor_size_inf*)vtr::calloc(trans_inf->num_size_entries, sizeof(t_transistor_size_inf));
child = get_first_child(parent, "size", loc_data);
i = 0;
while (child) {
VTR_ASSERT(get_attribute(child, "L", loc_data).as_int(0) == 1);
trans_inf->size_inf[i].size = get_attribute(child, "W", loc_data).as_float(0);
/* Get leakage currents */
grandchild = get_single_child(child, "leakage_current", loc_data);
trans_inf->size_inf[i].leakage_subthreshold = get_attribute(grandchild, "subthreshold", loc_data).as_float(0);
trans_inf->size_inf[i].leakage_gate = get_attribute(grandchild, "gate", loc_data).as_float(0);
/* Get node capacitances */
grandchild = get_single_child(child, "capacitance", loc_data);
trans_inf->size_inf[i].C_g = get_attribute(grandchild, "C_g", loc_data).as_float(0);
trans_inf->size_inf[i].C_s = get_attribute(grandchild, "C_s", loc_data).as_float(0);
trans_inf->size_inf[i].C_d = get_attribute(grandchild, "C_d", loc_data).as_float(0);
child = child.next_sibling("size");
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)
*/
bool 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;
bool error = false;
auto& power_ctx = g_vpr_ctx.power();
key.size = size;
/* Find the appropriate global transistor records */
trans_info = nullptr;
if (type == NMOS) {
trans_info = &power_ctx.tech->NMOS_inf;
} else if (type == PMOS) {
trans_info = &power_ctx.tech->PMOS_inf;
} else {
VTR_ASSERT(0);
}
/* No transistor data exists */
if (trans_info->size_inf == nullptr) {
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 */
f_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);
VTR_ASSERT(found);
if (size < min_size) {
/* Too small */
VTR_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 = nullptr;
*upper = found;
} else if (size > max_size) {
/* Too large */
VTR_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 = nullptr;
} 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
*/
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;
f_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);
VTR_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 = nullptr;
} 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;
VTR_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 = nullptr;
} 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;
VTR_ASSERT(input_mux_size >= 1);
key.mux_size = input_mux_size;
f_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 */
VTR_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 = nullptr;
} 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 == &f_power_searching_nmos_leakage_info->leakage_pairs[f_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;
f_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);
VTR_ASSERT(found);
if (found
== &volt_inf->mux_voltage_pairs[volt_inf->num_voltage_pairs - 1]) {
*lower = found;
*upper = nullptr;
} 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
== &f_buffer_strength_last_searched->sc_levr_inf[f_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 == &f_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
== &f_transistor_last_searched->size_inf[f_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 == &f_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
== &f_mux_volt_last_searched->mux_voltage_pairs[f_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;
}
}