| /********************************************************************* | |
| * 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 offers functions to estimate power of major components | |
| * within the FPGA (flip-flops, LUTs, interconnect structures, etc). | |
| */ | |
| /************************* INCLUDES *********************************/ | |
| #include <cstring> | |
| using namespace std; | |
| #include <assert.h> | |
| #include "power_components.h" | |
| #include "power_lowlevel.h" | |
| #include "power_util.h" | |
| #include "power_callibrate.h" | |
| #include "globals.h" | |
| /************************* STRUCTS **********************************/ | |
| /************************* GLOBALS **********************************/ | |
| t_power_components g_power_by_component; | |
| /************************* FUNCTION DECLARATIONS ********************/ | |
| static void power_usage_mux_rec(t_power_usage * power_usage, float * out_prob, | |
| float * out_dens, float * v_out, t_mux_node * mux_node, | |
| t_mux_arch * mux_arch, int * selector_values, | |
| float * primary_input_prob, float * primary_input_dens, | |
| boolean v_out_restored, float period); | |
| /************************* FUNCTION DEFINITIONS *********************/ | |
| /** | |
| * Module initializer function, called by power_init | |
| */ | |
| void power_components_init(void) { | |
| int i; | |
| g_power_by_component.components = (t_power_usage*) my_calloc( | |
| POWER_COMPONENT_MAX_NUM, sizeof(t_power_usage)); | |
| for (i = 0; i < POWER_COMPONENT_MAX_NUM; i++) { | |
| power_zero_usage(&g_power_by_component.components[i]); | |
| } | |
| } | |
| /** | |
| * Module un-initializer function, called by power_uninit | |
| */ | |
| void power_components_uninit(void) { | |
| free(g_power_by_component.components); | |
| } | |
| /** | |
| * Adds power usage for a component to the global component tracker | |
| * - power_usage: Power usage to add | |
| * - component_idx: Type of component | |
| */ | |
| void power_component_add_usage(t_power_usage * power_usage, | |
| e_power_component_type component_idx) { | |
| power_add_usage(&g_power_by_component.components[component_idx], | |
| power_usage); | |
| } | |
| /** | |
| * Gets power usage for a component | |
| * - power_usage: (Return value) Power usage for the given component | |
| * - component_idx: Type of component | |
| */ | |
| void power_component_get_usage(t_power_usage * power_usage, | |
| e_power_component_type component_idx) { | |
| memcpy(power_usage, &g_power_by_component.components[component_idx], | |
| sizeof(t_power_usage)); | |
| } | |
| /** | |
| * Returns total power for a given component | |
| * - component_idx: Type of component | |
| */ | |
| float power_component_get_usage_sum(e_power_component_type component_idx) { | |
| return power_sum_usage(&g_power_by_component.components[component_idx]); | |
| } | |
| /** | |
| * Calculates power of a D flip-flop | |
| * - power_usage: (Return value) power usage of the flip-flop | |
| * - D_prob: Signal probability of the input | |
| * - D_dens: Transition density of the input | |
| * - Q_prob: Signal probability of the output | |
| * - Q_dens: Transition density of the output | |
| * - clk_prob: Signal probability of the clock | |
| * - clk_dens: Transition density of the clock | |
| */ | |
| void power_usage_ff(t_power_usage * power_usage, float size, float D_prob, | |
| float D_dens, float Q_prob, float Q_dens, float clk_prob, | |
| float clk_dens, float period) { | |
| t_power_usage sub_power_usage; | |
| float mux_in_dens[2]; | |
| float mux_in_prob[2]; | |
| PowerSpicedComponent * callibration; | |
| float scale_factor; | |
| power_zero_usage(power_usage); | |
| /* DFF is build using a master loop and slave loop. | |
| * Each loop begins with a MUX and contains 2 inverters | |
| * in a feedback loop to the mux. | |
| * Each mux is built using two transmission gates. | |
| */ | |
| /* Master */ | |
| mux_in_dens[0] = D_dens; | |
| mux_in_dens[1] = (1 - clk_prob) * D_dens; | |
| mux_in_prob[0] = D_prob; | |
| mux_in_prob[1] = D_prob; | |
| power_usage_MUX2_transmission(&sub_power_usage, size, mux_in_dens, | |
| mux_in_prob, clk_dens, (1 - clk_prob) * D_dens, period); | |
| power_add_usage(power_usage, &sub_power_usage); | |
| power_usage_inverter(&sub_power_usage, (1 - clk_prob) * D_dens, D_prob, | |
| size, period); | |
| power_add_usage(power_usage, &sub_power_usage); | |
| power_usage_inverter(&sub_power_usage, (1 - clk_prob) * D_dens, 1 - D_prob, | |
| size, period); | |
| power_add_usage(power_usage, &sub_power_usage); | |
| /* Slave */ | |
| mux_in_dens[0] = Q_dens; | |
| mux_in_dens[1] = (1 - clk_prob) * D_dens; | |
| mux_in_prob[0] = (1 - Q_prob); | |
| mux_in_prob[1] = (1 - D_prob); | |
| power_usage_MUX2_transmission(&sub_power_usage, size, mux_in_dens, | |
| mux_in_prob, clk_dens, Q_dens, period); | |
| power_add_usage(power_usage, &sub_power_usage); | |
| power_usage_inverter(&sub_power_usage, Q_dens, 1 - Q_prob, size, period); | |
| power_add_usage(power_usage, &sub_power_usage); | |
| power_usage_inverter(&sub_power_usage, Q_dens, Q_prob, size, period); | |
| power_add_usage(power_usage, &sub_power_usage); | |
| /* Callibration */ | |
| callibration = | |
| g_power_commonly_used->component_callibration[POWER_CALLIB_COMPONENT_FF]; | |
| if (callibration->is_done_callibration()) { | |
| scale_factor = callibration->scale_factor(1, size); | |
| power_scale_usage(power_usage, scale_factor); | |
| } | |
| return; | |
| } | |
| /** | |
| * Calculated power of a look-up table (LUT) | |
| * - power_usage: (Return value) The power usage of the LUT | |
| * - LUT_size: Number of LUT inputs | |
| * - SRAM_values: The 2^(LUT_size) truth table values. String of '0' and '1' characters. | |
| * First characters is for all inputs = 0 and last characters is for all inputs = 1. | |
| * - input_prob: Array of input signal probabilities | |
| * - input_dens: Array of input transition densities | |
| * | |
| * NOTE: The following provides a diagram of a 3-LUT, the sram bit ordering, and | |
| * the input array ordering. | |
| * | |
| * X - NMOS gate controlled by complement of input | |
| * Z - NMOS gate controlled by input | |
| * | |
| * S | |
| * R I I I | |
| * A N N N | |
| * M 2 1 0 | |
| * | | | | | |
| * v v | | | |
| * v | | |
| * 0 _X_ | | |
| * |_X_ v | |
| * 1 _Z_| | | |
| * |_X_ | |
| * 2 _X_ | | | |
| * |_Z_| | | |
| * 3 _Z_| | | |
| * |------ out | |
| * 4 _X_ | | |
| * |_X_ | | |
| * 5 _Z_| | | | |
| * |_Z_| | |
| * 6 _X_ | | |
| * |_Z_| | |
| * 7 _Z_| | |
| * | |
| */ | |
| void power_usage_lut(t_power_usage * power_usage, int lut_size, | |
| float transistor_size, char * SRAM_values, float * input_prob, | |
| float * input_dens, float period) { | |
| float **internal_prob; | |
| float **internal_dens; | |
| float **internal_v; | |
| int i; | |
| int level_idx; | |
| PowerSpicedComponent * callibration; | |
| float scale_factor; | |
| int num_SRAM_bits; | |
| boolean level_restorer_this_level = FALSE; | |
| power_zero_usage(power_usage); | |
| num_SRAM_bits = 1 << lut_size; | |
| /* Initialize internal node data */ | |
| internal_prob = (float**) my_calloc(lut_size + 1, sizeof(float*)); | |
| internal_dens = (float**) my_calloc(lut_size + 1, sizeof(float*)); | |
| internal_v = (float**) my_calloc(lut_size + 1, sizeof(float*)); | |
| for (i = 0; i <= lut_size; i++) { | |
| internal_prob[i] = (float*) my_calloc(1 << (lut_size - i), | |
| sizeof(float)); | |
| internal_dens[i] = (float*) my_calloc(1 << (lut_size - i), | |
| sizeof(float)); | |
| internal_v[i] = (float*) my_calloc(1 << (lut_size - i), sizeof(float)); | |
| } | |
| /* Initialize internal probabilities/densities from SRAM bits */ | |
| for (i = 0; i < num_SRAM_bits; i++) { | |
| if (SRAM_values[i] == '0') { | |
| internal_prob[0][i] = 0.; | |
| } else { | |
| internal_prob[0][i] = 1.; | |
| } | |
| internal_dens[0][i] = 0.; | |
| internal_v[0][i] = g_power_tech->Vdd; | |
| } | |
| for (level_idx = 0; level_idx < lut_size; level_idx++) { | |
| t_power_usage driver_power_usage; | |
| int MUXs_this_level; | |
| int MUX_idx; | |
| int reverse_idx = lut_size - level_idx - 1; | |
| MUXs_this_level = 1 << (reverse_idx); | |
| /* Power of input drivers */ | |
| power_usage_inverter(&driver_power_usage, input_dens[reverse_idx], | |
| input_prob[reverse_idx], 1.0, period); | |
| power_add_usage(power_usage, &driver_power_usage); | |
| power_usage_inverter(&driver_power_usage, input_dens[reverse_idx], | |
| input_prob[reverse_idx], 2.0, period); | |
| power_add_usage(power_usage, &driver_power_usage); | |
| power_usage_inverter(&driver_power_usage, input_dens[reverse_idx], | |
| 1 - input_prob[reverse_idx], 2.0, period); | |
| power_add_usage(power_usage, &driver_power_usage); | |
| /* Add level restorer after every 2 stages (level_idx %2 == 1) | |
| * But if there is an odd # of stages, just put one at the last | |
| * stage (level_idx == LUT_size - 1) and not at the stage just before | |
| * the last stage (level_idx != LUT_size - 2) | |
| */ | |
| if (((level_idx % 2 == 1) && (level_idx != lut_size - 2)) | |
| || (level_idx == lut_size - 1)) { | |
| level_restorer_this_level = TRUE; | |
| } else { | |
| level_restorer_this_level = FALSE; | |
| } | |
| /* Loop through the 2-muxs at each level */ | |
| for (MUX_idx = 0; MUX_idx < MUXs_this_level; MUX_idx++) { | |
| t_power_usage sub_power; | |
| float out_prob; | |
| float out_dens; | |
| float sum_prob = 0; | |
| int sram_offset = MUX_idx * ipow(2, level_idx + 1); | |
| int sram_per_branch = ipow(2, level_idx); | |
| int branch_lvl_idx; | |
| int sram_idx; | |
| float v_out; | |
| /* Calculate output probability of multiplexer */ | |
| out_prob = internal_prob[level_idx][MUX_idx * 2] | |
| * (1 - input_prob[reverse_idx]) | |
| + internal_prob[level_idx][MUX_idx * 2 + 1] | |
| * input_prob[reverse_idx]; | |
| /* Calculate output density of multiplexer */ | |
| out_dens = internal_dens[level_idx][MUX_idx * 2] | |
| * (1 - input_prob[reverse_idx]) | |
| + internal_dens[level_idx][MUX_idx * 2 + 1] | |
| * input_prob[reverse_idx]; | |
| #ifdef POWER_LUT_FAST | |
| out_dens += ((1 - internal_prob[level_idx][MUX_idx * 2]) * internal_prob[level_idx][MUX_idx * 2 + 1] | |
| + internal_prob[level_idx][MUX_idx * 2] * (1 - internal_prob[level_idx][MUX_idx * 2 + 1])) | |
| * input_dens[reverse_idx]; | |
| #elif defined(POWER_LUT_SLOW) | |
| for (sram_idx = sram_offset; | |
| sram_idx < sram_offset + sram_per_branch; sram_idx++) { | |
| float branch_prob = 1.; | |
| if (SRAM_values[sram_idx] | |
| == SRAM_values[sram_idx + sram_per_branch]) { | |
| continue; | |
| } | |
| for (branch_lvl_idx = 0; branch_lvl_idx < level_idx; | |
| branch_lvl_idx++) { | |
| int branch_lvl_reverse_idx = lut_size - branch_lvl_idx - 1; | |
| int even_odd = sram_idx / ipow(2, branch_lvl_idx); | |
| if (even_odd % 2 == 0) { | |
| branch_prob *= (1 - input_prob[branch_lvl_reverse_idx]); | |
| } else { | |
| branch_prob *= input_prob[branch_lvl_reverse_idx]; | |
| } | |
| } | |
| sum_prob += branch_prob; | |
| } | |
| out_dens += sum_prob * input_dens[reverse_idx]; | |
| #endif | |
| /* Calculate output voltage of multiplexer */ | |
| if (level_restorer_this_level) { | |
| v_out = g_power_tech->Vdd; | |
| } else { | |
| v_out = (1 - input_prob[reverse_idx]) | |
| * power_calc_mux_v_out(2, 1.0, | |
| internal_v[level_idx][MUX_idx * 2], | |
| internal_prob[level_idx][MUX_idx * 2 + 1]) | |
| + input_prob[reverse_idx] | |
| * power_calc_mux_v_out(2, 1.0, | |
| internal_v[level_idx][MUX_idx * 2 + 1], | |
| internal_prob[level_idx][MUX_idx * 2]); | |
| } | |
| /* Save internal node info */ | |
| internal_dens[level_idx + 1][MUX_idx] = out_dens; | |
| internal_prob[level_idx + 1][MUX_idx] = out_prob; | |
| internal_v[level_idx + 1][MUX_idx] = v_out; | |
| /* Calculate power of the 2-mux */ | |
| power_usage_mux_singlelevel_dynamic(&sub_power, 2, | |
| internal_dens[level_idx + 1][MUX_idx], | |
| internal_v[level_idx + 1][MUX_idx], | |
| &internal_prob[level_idx][MUX_idx * 2], | |
| &internal_dens[level_idx][MUX_idx * 2], | |
| &internal_v[level_idx][MUX_idx * 2], | |
| input_dens[reverse_idx], input_prob[reverse_idx], | |
| transistor_size, period); | |
| power_add_usage(power_usage, &sub_power); | |
| /* Add the level-restoring buffer if necessary */ | |
| if (level_restorer_this_level) { | |
| /* Level restorer */ | |
| power_usage_buffer(&sub_power, 1, | |
| internal_prob[level_idx + 1][MUX_idx], | |
| internal_dens[level_idx + 1][MUX_idx], TRUE, period); | |
| power_add_usage(power_usage, &sub_power); | |
| } | |
| } | |
| } | |
| /* Free allocated memory */ | |
| for (i = 0; i <= lut_size; i++) { | |
| free(internal_prob[i]); | |
| free(internal_dens[i]); | |
| free(internal_v[i]); | |
| } | |
| free(internal_prob); | |
| free(internal_dens); | |
| free(internal_v); | |
| /* Callibration */ | |
| callibration = | |
| g_power_commonly_used->component_callibration[POWER_CALLIB_COMPONENT_LUT]; | |
| if (callibration->is_done_callibration()) { | |
| scale_factor = callibration->scale_factor(lut_size, transistor_size); | |
| power_scale_usage(power_usage, scale_factor); | |
| } | |
| return; | |
| } | |
| /** | |
| * This function calculates power of a local interconnect structure | |
| * - power_usage: (Return value) Power usage of the structure | |
| * - pb: The physical block to which this interconnect belongs | |
| * - interc_pins: The interconnect input/ouput pin information | |
| * - interc_length: The physical length spanned by the interconnect (meters) | |
| */ | |
| void power_usage_local_interc_mux(t_power_usage * power_usage, t_pb * pb, | |
| t_interconnect_pins * interc_pins) { | |
| int pin_idx; | |
| int out_port_idx; | |
| int in_port_idx; | |
| float * in_dens; | |
| float * in_prob; | |
| t_power_usage MUX_power; | |
| t_interconnect * interc = interc_pins->interconnect; | |
| t_interconnect_power * interc_power = interc->interconnect_power; | |
| power_zero_usage(power_usage); | |
| /* Ensure port/pins are structured as expected */ | |
| switch (interc_pins->interconnect->type) { | |
| case DIRECT_INTERC: | |
| assert(interc_power->num_input_ports == 1); | |
| assert(interc_power->num_output_ports == 1); | |
| break; | |
| case MUX_INTERC: | |
| assert(interc_power->num_output_ports == 1); | |
| break; | |
| case COMPLETE_INTERC: | |
| break; | |
| } | |
| /* Power of transistors to build interconnect structure */ | |
| switch (interc_pins->interconnect->type) { | |
| case DIRECT_INTERC: | |
| /* Direct connections require no transistors */ | |
| break; | |
| case MUX_INTERC: | |
| case COMPLETE_INTERC: | |
| /* Many-to-1, or Many-to-Many | |
| * Implemented as a multiplexer for each output | |
| * */ | |
| in_dens = (float*) my_calloc( | |
| interc->interconnect_power->num_input_ports, sizeof(float)); | |
| in_prob = (float*) my_calloc( | |
| interc->interconnect_power->num_input_ports, sizeof(float)); | |
| for (out_port_idx = 0; | |
| out_port_idx < interc->interconnect_power->num_output_ports; | |
| out_port_idx++) { | |
| for (pin_idx = 0; | |
| pin_idx < interc->interconnect_power->num_pins_per_port; | |
| pin_idx++) { | |
| int selected_input = OPEN; | |
| /* Clear input densities */ | |
| for (in_port_idx = 0; | |
| in_port_idx | |
| < interc->interconnect_power->num_input_ports; | |
| in_port_idx++) { | |
| in_dens[in_port_idx] = 0.; | |
| in_prob[in_port_idx] = 0.; | |
| } | |
| /* Get probability/density of input signals */ | |
| if (pb) { | |
| int output_pin_net = | |
| pb->rr_graph[interc_pins->output_pins[out_port_idx][pin_idx]->pin_count_in_cluster].net_num; | |
| if (output_pin_net == OPEN) { | |
| selected_input = 0; | |
| } else { | |
| for (in_port_idx = 0; | |
| in_port_idx | |
| < interc->interconnect_power->num_input_ports; | |
| in_port_idx++) { | |
| t_pb_graph_pin * input_pin = | |
| interc_pins->input_pins[in_port_idx][pin_idx]; | |
| int input_pin_net = | |
| pb->rr_graph[input_pin->pin_count_in_cluster].net_num; | |
| /* Find input pin that connects through the mux to the output pin */ | |
| if (output_pin_net == input_pin_net) { | |
| selected_input = in_port_idx; | |
| } | |
| /* Initialize input densities */ | |
| if (input_pin_net != OPEN) { | |
| in_dens[in_port_idx] = pin_dens(pb, input_pin); | |
| in_prob[in_port_idx] = pin_prob(pb, input_pin); | |
| } | |
| } | |
| /* Check that the input pin was found with a matching net to the output pin */ | |
| assert(selected_input != OPEN); | |
| } | |
| } else { | |
| selected_input = 0; | |
| } | |
| /* Calculate power of the multiplexer */ | |
| power_usage_mux_multilevel(&MUX_power, | |
| power_get_mux_arch( | |
| interc_pins->interconnect->interconnect_power->num_input_ports, | |
| g_power_arch->mux_transistor_size), in_prob, | |
| in_dens, selected_input, TRUE, g_solution_inf.T_crit); | |
| power_add_usage(power_usage, &MUX_power); | |
| } | |
| } | |
| free(in_dens); | |
| free(in_prob); | |
| break; | |
| default: | |
| assert(0); | |
| } | |
| power_add_usage(&interc_pins->interconnect->interconnect_power->power_usage, | |
| power_usage); | |
| } | |
| /** | |
| * This calculates the power of a multilevel multiplexer, with static inputs | |
| * - power_usage: (Return value) The power usage of the multiplexer | |
| * - mux_arch: The information on the multiplexer architecture | |
| * - in_prob: Array of input signal probabilities | |
| * - in_dens: Array of input transition densitites | |
| * - selected_input: The index of the input that has been statically selected | |
| * - output_level_restored: Whether the output is level restored to Vdd. | |
| */ | |
| void power_usage_mux_multilevel(t_power_usage * power_usage, | |
| t_mux_arch * mux_arch, float * in_prob, float * in_dens, | |
| int selected_input, boolean output_level_restored, float period) { | |
| float output_density; | |
| float output_prob; | |
| float V_out; | |
| boolean found; | |
| PowerSpicedComponent * callibration; | |
| float scale_factor; | |
| int * selector_values = (int*) my_calloc(mux_arch->levels, sizeof(int)); | |
| assert(selected_input != OPEN); | |
| power_zero_usage(power_usage); | |
| /* Find selection index at each level */ | |
| found = mux_find_selector_values(selector_values, mux_arch->mux_graph_head, | |
| selected_input); | |
| assert(found); | |
| /* Calculate power of the multiplexor stages, from final stage, to first stages */ | |
| power_usage_mux_rec(power_usage, &output_density, &output_prob, &V_out, | |
| mux_arch->mux_graph_head, mux_arch, selector_values, in_prob, | |
| in_dens, output_level_restored, period); | |
| free(selector_values); | |
| callibration = | |
| g_power_commonly_used->component_callibration[POWER_CALLIB_COMPONENT_MUX]; | |
| if (callibration->is_done_callibration()) { | |
| scale_factor = callibration->scale_factor(mux_arch->num_inputs, | |
| mux_arch->transistor_size); | |
| power_scale_usage(power_usage, scale_factor); | |
| } | |
| } | |
| /** | |
| * Internal function, used recursively by power_calc_mux | |
| */ | |
| static void power_usage_mux_rec(t_power_usage * power_usage, float * out_prob, | |
| float * out_dens, float * v_out, t_mux_node * mux_node, | |
| t_mux_arch * mux_arch, int * selector_values, | |
| float * primary_input_prob, float * primary_input_dens, | |
| boolean v_out_restored, float period) { | |
| int input_idx; | |
| float * in_prob; | |
| float * in_dens; | |
| float * v_in; | |
| t_power_usage sub_power_usage; | |
| /* Single input mux is really just a wire, and has no power. | |
| * Ensure that it has no children before returning. */ | |
| if (mux_node->num_inputs == 1) { | |
| assert(mux_node->level == 0); | |
| return; | |
| } | |
| v_in = (float*) my_calloc(mux_node->num_inputs, sizeof(float)); | |
| if (mux_node->level == 0) { | |
| /* First level of mux - inputs are primar inputs */ | |
| in_prob = &primary_input_prob[mux_node->starting_pin_idx]; | |
| in_dens = &primary_input_dens[mux_node->starting_pin_idx]; | |
| for (input_idx = 0; input_idx < mux_node->num_inputs; input_idx++) { | |
| v_in[input_idx] = g_power_tech->Vdd; | |
| } | |
| } else { | |
| /* Higher level of mux - inputs recursive from lower levels */ | |
| in_prob = (float*) my_calloc(mux_node->num_inputs, sizeof(float)); | |
| in_dens = (float*) my_calloc(mux_node->num_inputs, sizeof(float)); | |
| for (input_idx = 0; input_idx < mux_node->num_inputs; input_idx++) { | |
| /* Call recursively for multiplexer driving the input */ | |
| power_usage_mux_rec(power_usage, &in_prob[input_idx], | |
| &in_dens[input_idx], &v_in[input_idx], | |
| &mux_node->children[input_idx], mux_arch, selector_values, | |
| primary_input_prob, primary_input_dens, FALSE, period); | |
| } | |
| } | |
| power_usage_mux_singlelevel_static(&sub_power_usage, out_prob, out_dens, | |
| v_out, mux_node->num_inputs, selector_values[mux_node->level], | |
| in_prob, in_dens, v_in, mux_arch->transistor_size, v_out_restored, | |
| period); | |
| power_add_usage(power_usage, &sub_power_usage); | |
| if (mux_node->level != 0) { | |
| free(in_prob); | |
| free(in_dens); | |
| } | |
| } | |
| /** | |
| * This function calculates the power of a multistage buffer | |
| * - power_usage: (Return value) Power usage of buffer | |
| * - size: The size of the final buffer stage, relative to min-sized inverter | |
| * - in_prob: The signal probability of the input | |
| * - in_dens: The transition density of the input | |
| * - level_restored: Whether this buffer must level restore the input | |
| * - input_mux_size: If fed by a mux, the size of this mutliplexer | |
| */ | |
| void power_usage_buffer(t_power_usage * power_usage, float size, float in_prob, | |
| float in_dens, boolean level_restorer, float period) { | |
| t_power_usage sub_power_usage; | |
| int i, num_stages; | |
| float stage_effort; | |
| float stage_inv_size; | |
| float stage_in_prob; | |
| float input_dyn_power; | |
| float scale_factor; | |
| PowerSpicedComponent * callibration; | |
| power_zero_usage(power_usage); | |
| if (size == 0.) { | |
| return; | |
| } | |
| num_stages = power_calc_buffer_num_stages(size, | |
| g_power_arch->logical_effort_factor); | |
| stage_effort = calc_buffer_stage_effort(num_stages, size); | |
| stage_in_prob = in_prob; | |
| for (i = 0; i < num_stages; i++) { | |
| stage_inv_size = pow(stage_effort, i); | |
| if (i == 0) { | |
| if (level_restorer) { | |
| /* Sense Buffer */ | |
| power_usage_level_restorer(&sub_power_usage, &input_dyn_power, | |
| in_dens, stage_in_prob, period); | |
| } else { | |
| power_usage_inverter(&sub_power_usage, in_dens, stage_in_prob, | |
| stage_inv_size, period); | |
| } | |
| } else { | |
| power_usage_inverter(&sub_power_usage, in_dens, stage_in_prob, | |
| stage_inv_size, period); | |
| } | |
| power_add_usage(power_usage, &sub_power_usage); | |
| stage_in_prob = 1 - stage_in_prob; | |
| } | |
| /* Callibration */ | |
| if (level_restorer) { | |
| callibration = | |
| g_power_commonly_used->component_callibration[POWER_CALLIB_COMPONENT_BUFFER_WITH_LEVR]; | |
| } else { | |
| callibration = | |
| g_power_commonly_used->component_callibration[POWER_CALLIB_COMPONENT_BUFFER]; | |
| } | |
| if (callibration->is_done_callibration()) { | |
| scale_factor = callibration->scale_factor(1, size); | |
| power_scale_usage(power_usage, scale_factor); | |
| } | |
| /* Short-circuit: add a factor to dynamic power, but the factor is not in addition to the input power | |
| * Need to subtract input before adding factor - this matters for small buffers | |
| */ | |
| /*power_usage->dynamic += (power_usage->dynamic - input_dyn_power) | |
| * power_calc_buffer_sc(num_stages, stage_effort, level_restorer, | |
| input_mux_size); */ | |
| } | |