/********************************************************************* * 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 using namespace std; #include #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; } }