| /********************************************************************* |
| * 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> |
| #include <cmath> |
| |
| #include "vtr_math.h" |
| #include "vtr_assert.h" |
| #include "vtr_memory.h" |
| |
| #include "power_components.h" |
| #include "power_lowlevel.h" |
| #include "power_util.h" |
| #include "power_callibrate.h" |
| #include "globals.h" |
| |
| /************************* STRUCTS **********************************/ |
| |
| /************************* 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, bool v_out_restored, float period); |
| |
| /************************* FUNCTION DEFINITIONS *********************/ |
| |
| /** |
| * Module initializer function, called by power_init |
| */ |
| void power_components_init() { |
| int i; |
| auto& power_ctx = g_vpr_ctx.mutable_power(); |
| |
| power_ctx.by_component.components = (t_power_usage*)vtr::calloc(POWER_COMPONENT_MAX_NUM, sizeof(t_power_usage)); |
| for (i = 0; i < POWER_COMPONENT_MAX_NUM; i++) { |
| power_zero_usage(&power_ctx.by_component.components[i]); |
| } |
| } |
| |
| /** |
| * Module un-initializer function, called by power_uninit |
| */ |
| void power_components_uninit() { |
| auto& power_ctx = g_vpr_ctx.mutable_power(); |
| free(power_ctx.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) { |
| auto& power_ctx = g_vpr_ctx.power(); |
| power_add_usage(&power_ctx.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) { |
| auto& power_ctx = g_vpr_ctx.power(); |
| memcpy(power_usage, &power_ctx.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) { |
| auto& power_ctx = g_vpr_ctx.power(); |
| return power_sum_usage(&power_ctx.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 */ |
| auto& power_ctx = g_vpr_ctx.power(); |
| callibration = power_ctx.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; |
| |
| bool level_restorer_this_level = false; |
| |
| auto& power_ctx = g_vpr_ctx.power(); |
| |
| power_zero_usage(power_usage); |
| |
| num_SRAM_bits = 1 << lut_size; |
| |
| /* Initialize internal node data */ |
| internal_prob = (float**)vtr::calloc(lut_size + 1, sizeof(float*)); |
| internal_dens = (float**)vtr::calloc(lut_size + 1, sizeof(float*)); |
| internal_v = (float**)vtr::calloc(lut_size + 1, sizeof(float*)); |
| for (i = 0; i <= lut_size; i++) { |
| internal_prob[i] = (float*)vtr::calloc(1 << (lut_size - i), |
| sizeof(float)); |
| internal_dens[i] = (float*)vtr::calloc(1 << (lut_size - i), |
| sizeof(float)); |
| internal_v[i] = (float*)vtr::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] = power_ctx.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 * vtr::ipow(2, level_idx + 1); |
| int sram_per_branch = vtr::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 / vtr::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 = power_ctx.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 = power_ctx.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, ClusterBlockId iblk) { |
| 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; |
| auto& cluster_ctx = g_vpr_ctx.clustering(); |
| auto& power_ctx = g_vpr_ctx.power(); |
| |
| power_zero_usage(power_usage); |
| |
| /* Ensure port/pins are structured as expected */ |
| switch (interc_pins->interconnect->type) { |
| case DIRECT_INTERC: |
| VTR_ASSERT(interc_power->num_input_ports == 1); |
| VTR_ASSERT(interc_power->num_output_ports == 1); |
| break; |
| case MUX_INTERC: |
| VTR_ASSERT(interc_power->num_output_ports == 1); |
| break; |
| case COMPLETE_INTERC: |
| break; |
| default: |
| //pass |
| 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*)vtr::calloc(interc->interconnect_power->num_input_ports, sizeof(float)); |
| in_prob = (float*)vtr::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 cluster_pin_idx = interc_pins->output_pins[out_port_idx][pin_idx]->pin_count_in_cluster; |
| if (!cluster_ctx.clb_nlist.block_pb(iblk)->pb_route.count(cluster_pin_idx)) { |
| selected_input = 0; |
| } else { |
| AtomNetId output_pin_net = cluster_ctx.clb_nlist.block_pb(iblk)->pb_route[cluster_pin_idx].atom_net_id; |
| 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]; |
| |
| if (!cluster_ctx.clb_nlist.block_pb(iblk)->pb_route.count(input_pin->pin_count_in_cluster)) continue; |
| |
| AtomNetId input_pin_net = cluster_ctx.clb_nlist.block_pb(iblk)->pb_route[input_pin->pin_count_in_cluster].atom_net_id; |
| /* 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) { |
| in_dens[in_port_idx] = pin_dens(pb, input_pin, iblk); |
| in_prob[in_port_idx] = pin_prob(pb, input_pin, iblk); |
| } |
| } |
| |
| /* Check that the input pin was found with a matching net to the output pin */ |
| VTR_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, |
| power_ctx.arch->mux_transistor_size), |
| in_prob, |
| in_dens, selected_input, true, power_ctx.solution_inf.T_crit); |
| |
| power_add_usage(power_usage, &MUX_power); |
| } |
| } |
| |
| free(in_dens); |
| free(in_prob); |
| break; |
| default: |
| VTR_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, |
| bool output_level_restored, |
| float period) { |
| float output_density; |
| float output_prob; |
| float V_out; |
| bool found; |
| PowerSpicedComponent* callibration; |
| float scale_factor; |
| int* selector_values = (int*)vtr::calloc(mux_arch->levels, sizeof(int)); |
| auto& power_ctx = g_vpr_ctx.power(); |
| |
| VTR_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); |
| |
| VTR_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 = power_ctx.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, bool v_out_restored, float period) { |
| int input_idx; |
| float* in_prob; |
| float* in_dens; |
| float* v_in; |
| t_power_usage sub_power_usage; |
| auto& power_ctx = g_vpr_ctx.power(); |
| |
| /* 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) { |
| VTR_ASSERT(mux_node->level == 0); |
| return; |
| } |
| |
| v_in = (float*)vtr::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] = power_ctx.tech->Vdd; |
| } |
| } else { |
| /* Higher level of mux - inputs recursive from lower levels */ |
| in_prob = (float*)vtr::calloc(mux_node->num_inputs, sizeof(float)); |
| in_dens = (float*)vtr::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); |
| } |
| |
| free(v_in); |
| } |
| |
| /** |
| * 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, bool 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; |
| } |
| |
| auto& power_ctx = g_vpr_ctx.power(); |
| |
| num_stages = power_calc_buffer_num_stages(size, |
| power_ctx.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 = power_ctx.commonly_used->component_callibration[POWER_CALLIB_COMPONENT_BUFFER_WITH_LEVR]; |
| } else { |
| callibration = power_ctx.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); */ |
| } |