| /********************************************************************* |
| * 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 that calculate the power of low-level |
| * components (inverters, simple multiplexers, etc) |
| */ |
| |
| /************************* INCLUDES *********************************/ |
| #include "vtr_assert.h" |
| |
| #include "power_lowlevel.h" |
| #include "power_util.h" |
| #include "power_cmos_tech.h" |
| #include "globals.h" |
| |
| /************************* FUNCTION DECLARATIONS ********************/ |
| static float power_calc_node_switching_v(float capacitance, float density, float period, float voltage); |
| static void power_calc_transistor_capacitance(float* C_d, float* C_s, float* C_g, e_tx_type transistor_type, float size); |
| static float power_calc_leakage_st(e_tx_type transistor_type, float size); |
| static float power_calc_leakage_st_pass_transistor(float size, float v_ds); |
| static float power_calc_leakage_gate(e_tx_type transistor_type, float size); |
| /*static float power_calc_buffer_sc_levr( |
| * t_power_buffer_strength_inf * buffer_strength, int input_mux_size);*/ |
| |
| /************************* FUNCTION DEFINITIONS *********************/ |
| |
| /** |
| * Initializer function for this module, called by power_init |
| */ |
| void power_lowlevel_init() { |
| float C_d, C_s, C_g; |
| |
| auto& power_ctx = g_vpr_ctx.power(); |
| |
| power_calc_transistor_capacitance(&C_d, &C_s, &C_g, NMOS, 1.0); |
| power_ctx.commonly_used->NMOS_1X_C_d = C_d; |
| power_ctx.commonly_used->NMOS_1X_C_g = C_g; |
| power_ctx.commonly_used->NMOS_1X_C_s = C_s; |
| |
| power_calc_transistor_capacitance(&C_d, &C_s, &C_g, PMOS, |
| power_ctx.tech->PN_ratio); |
| power_ctx.commonly_used->PMOS_1X_C_d = C_d; |
| power_ctx.commonly_used->PMOS_1X_C_g = C_g; |
| power_ctx.commonly_used->PMOS_1X_C_s = C_s; |
| |
| power_ctx.commonly_used->NMOS_1X_st_leakage = power_calc_leakage_st(NMOS, |
| 1.0); |
| power_ctx.commonly_used->PMOS_1X_st_leakage = power_calc_leakage_st(PMOS, |
| 1.0 * power_ctx.tech->PN_ratio); |
| |
| power_ctx.commonly_used->INV_1X_C_in = power_ctx.commonly_used->NMOS_1X_C_g |
| + power_ctx.commonly_used->PMOS_1X_C_g; |
| power_ctx.commonly_used->INV_1X_C = power_ctx.commonly_used->NMOS_1X_C_g |
| + power_ctx.commonly_used->PMOS_1X_C_g |
| + power_ctx.commonly_used->NMOS_1X_C_d |
| + power_ctx.commonly_used->PMOS_1X_C_d; |
| |
| power_calc_transistor_capacitance(&C_d, &C_s, &C_g, NMOS, 2.0); |
| power_ctx.commonly_used->INV_2X_C = C_g + C_d; |
| power_calc_transistor_capacitance(&C_d, &C_s, &C_g, PMOS, |
| 2.0 * power_ctx.tech->PN_ratio); |
| power_ctx.commonly_used->INV_2X_C += C_g + C_d; |
| } |
| |
| /** |
| * Calculates the switching power of a node |
| * - capacitance: The capacitance of the nodoe |
| * - density: The transition density of the node |
| */ |
| float power_calc_node_switching(float capacitance, float density, float period) { |
| auto& power_ctx = g_vpr_ctx.power(); |
| return 0.5 * power_ctx.tech->Vdd * power_ctx.tech->Vdd * capacitance * density |
| / period; |
| } |
| |
| /** |
| * Calculates the switching power of a node, with non-Vdd voltage |
| * - capacitance: The capacitance of the nodoe |
| * - density: The transition density of the node |
| * - voltage: The voltage when the node is charged |
| */ |
| static float power_calc_node_switching_v(float capacitance, float density, float period, float voltage) { |
| auto& power_ctx = g_vpr_ctx.power(); |
| return 0.5 * voltage * power_ctx.tech->Vdd * capacitance * density / period; |
| } |
| |
| /** |
| * Calculates the power of an inverter |
| * - power_usage: (Return value) The power usage of the inverter |
| * - in_dens: The transition density of the input |
| * - in_prob: The signal probability of the input |
| * - size: The inverter size, relative to a min-size inverter |
| */ |
| void power_usage_inverter(t_power_usage* power_usage, float in_dens, float in_prob, float size, float period) { |
| float C_drain, C_gate, C_source; |
| float C_inv; |
| |
| auto& power_ctx = g_vpr_ctx.power(); |
| float PMOS_size = power_ctx.tech->PN_ratio * size; |
| float NMOS_size = size; |
| |
| power_usage->dynamic = 0.; |
| power_usage->leakage = 0.; |
| |
| C_inv = 0.; |
| |
| power_calc_transistor_capacitance(&C_drain, &C_source, &C_gate, NMOS, |
| NMOS_size); |
| C_inv += C_gate + C_drain; |
| |
| power_calc_transistor_capacitance(&C_drain, &C_source, &C_gate, PMOS, |
| PMOS_size); |
| C_inv += C_gate + C_drain; |
| |
| power_usage->dynamic = power_calc_node_switching(C_inv, in_dens, period); |
| |
| power_usage->leakage = in_prob * power_calc_leakage_st(PMOS, PMOS_size) |
| + (1 - in_prob) * power_calc_leakage_st(NMOS, NMOS_size); |
| |
| power_usage->leakage += in_prob * power_calc_leakage_gate(NMOS, NMOS_size) |
| + (1 - in_prob) * power_calc_leakage_gate(PMOS, PMOS_size); |
| } |
| |
| /** |
| * Calculates the power of an inverter, with irregular P/N ratio |
| * - power_usage: (Return value) The power usage of the inverter |
| * - dy_power_input: (Return value) The dynamic power of the input node |
| * - in_dens: The transition density of the input |
| * - in_prob: The signal probability of the input |
| * - PMOS_size: (W/L) of the PMOS |
| * - NMOS_size: (W/L) of the NMOS |
| */ |
| void power_usage_inverter_irregular(t_power_usage* power_usage, |
| float* dyn_power_input, |
| float in_density, |
| float in_probability, |
| float PMOS_size, |
| float NMOS_size, |
| float period) { |
| float C_drain, C_gate, C_source; |
| float C_inv; |
| float C_in; |
| |
| power_usage->dynamic = 0.; |
| power_usage->leakage = 0.; |
| |
| C_inv = 0.; |
| C_in = 0.; |
| |
| power_calc_transistor_capacitance(&C_drain, &C_source, &C_gate, NMOS, |
| NMOS_size); |
| C_inv += C_gate + C_drain; |
| C_in += C_gate; |
| |
| power_calc_transistor_capacitance(&C_drain, &C_source, &C_gate, PMOS, |
| PMOS_size); |
| C_inv += C_gate + C_drain; |
| C_in += C_gate; |
| |
| power_usage->dynamic = power_calc_node_switching(C_inv, in_density, period); |
| *dyn_power_input = power_calc_node_switching(C_in, in_density, period); |
| |
| power_usage->leakage = in_probability |
| * power_calc_leakage_st(PMOS, PMOS_size) |
| + (1 - in_probability) * power_calc_leakage_st(NMOS, NMOS_size); |
| } |
| |
| /** |
| * Calculates the power of an inverter, also returning dynamic power of the input |
| * - power_usage: (Return value) The power usage of the inverter |
| * - input_dynamic_power: (Return value) The dynamic power of the input node |
| * - in_dens: The transition density of the input |
| * - in_prob: The signal probability of the input |
| * - size: The inverter size, relative to a min-size inverter |
| */ |
| #if 0 |
| void power_calc_inverter_with_input(t_power_usage * power_usage, |
| float * input_dynamic_power, float in_density, float in_prob, |
| float size) { |
| float C_drain, C_gate, C_source; |
| float C_inv; |
| float C_in; |
| |
| auto& power_ctx = g_vpr_ctx.power(); |
| float PMOS_size = power_ctx.tech->PN_ratio * size; |
| float NMOS_size = size; |
| |
| power_usage->dynamic = 0.; |
| power_usage->leakage = 0.; |
| |
| C_inv = 0.; |
| C_in = 0.; |
| |
| power_calc_transistor_capacitance(&C_drain, &C_source, &C_gate, NMOS, |
| NMOS_size); |
| C_inv += C_gate + C_drain; |
| C_in += C_gate; |
| |
| power_calc_transistor_capacitance(&C_drain, &C_source, &C_gate, PMOS, |
| PMOS_size); |
| C_inv += C_gate + C_drain; |
| C_in += C_gate; |
| |
| power_usage->dynamic = power_calc_node_switching(C_inv, in_density); |
| *input_dynamic_power = power_calc_node_switching(C_in, in_density); |
| |
| power_usage->leakage = in_prob * power_calc_leakage_st(PMOS, PMOS_size) |
| + (1 - in_prob) * power_calc_leakage_st(NMOS, NMOS_size); |
| |
| power_usage->leakage += in_prob * power_calc_leakage_gate(NMOS, NMOS_size) |
| + (1 - in_prob) * power_calc_leakage_gate(PMOS, PMOS_size); |
| } |
| #endif |
| |
| /** |
| * Calculate the capacitance for a transistor |
| * - C_d: (Return value) Drain capacitance |
| * - C_s: (Return value) Source capacitance |
| * - C_g: (Return value) Gate capacitance |
| * - transistor_type: NMOS or PMOS |
| * - size: (W/L) size of the transistor |
| */ |
| static void power_calc_transistor_capacitance(float* C_d, float* C_s, float* C_g, e_tx_type transistor_type, float size) { |
| t_transistor_size_inf* tx_info_lower; |
| t_transistor_size_inf* tx_info_upper; |
| bool error; |
| |
| /* Initialize to 0 */ |
| *C_d = 0.; |
| *C_s = 0.; |
| *C_g = 0.; |
| |
| error = power_find_transistor_info(&tx_info_lower, &tx_info_upper, |
| transistor_type, size); |
| if (error) { |
| return; |
| } |
| |
| if (tx_info_lower == nullptr) { |
| /* No lower bound */ |
| *C_d = tx_info_upper->C_d; |
| *C_s = tx_info_upper->C_s; |
| *C_g = tx_info_upper->C_g; |
| } else if (tx_info_upper == nullptr) { |
| /* No upper bound */ |
| *C_d = tx_info_lower->C_d; |
| *C_s = tx_info_lower->C_s; |
| *C_g = tx_info_lower->C_g; |
| } else { |
| /* Linear approximation between sizes */ |
| float percent_upper = (size - tx_info_lower->size) |
| / (tx_info_upper->size - tx_info_lower->size); |
| *C_d = (1 - percent_upper) * tx_info_lower->C_d |
| + percent_upper * tx_info_upper->C_d; |
| *C_s = (1 - percent_upper) * tx_info_lower->C_s |
| + percent_upper * tx_info_upper->C_s; |
| *C_g = (1 - percent_upper) * tx_info_lower->C_g |
| + percent_upper * tx_info_upper->C_g; |
| } |
| |
| return; |
| } |
| |
| /** |
| * Returns the subthreshold leakage power of a transistor, |
| * for V_ds = V_dd |
| * - transistor_type: NMOS or PMOS |
| * - size: (W/L) of transistor |
| */ |
| static float power_calc_leakage_st(e_tx_type transistor_type, float size) { |
| t_transistor_size_inf* tx_info_lower; |
| t_transistor_size_inf* tx_info_upper; |
| bool error; |
| float current; |
| |
| error = power_find_transistor_info(&tx_info_lower, &tx_info_upper, |
| transistor_type, size); |
| if (error) { |
| return 0; |
| } |
| |
| if (tx_info_lower == nullptr) { |
| /* No lower bound */ |
| current = tx_info_upper->leakage_subthreshold; |
| |
| } else if (tx_info_upper == nullptr) { |
| /* No upper bound */ |
| current = tx_info_lower->leakage_subthreshold; |
| } else { |
| /* Linear approximation between sizes */ |
| float percent_upper = (size - tx_info_lower->size) |
| / (tx_info_upper->size - tx_info_lower->size); |
| current = (1 - percent_upper) * tx_info_lower->leakage_subthreshold |
| + percent_upper * tx_info_upper->leakage_subthreshold; |
| } |
| |
| auto& power_ctx = g_vpr_ctx.power(); |
| return current * power_ctx.tech->Vdd; |
| } |
| |
| /** |
| * Returns the gate gate leakage power of a transistor |
| * - transistor_type: NMOS or PMOS |
| * - size: (W/L) of transistor |
| */ |
| static float power_calc_leakage_gate(e_tx_type transistor_type, float size) { |
| t_transistor_size_inf* tx_info_lower; |
| t_transistor_size_inf* tx_info_upper; |
| bool error; |
| float current; |
| |
| error = power_find_transistor_info(&tx_info_lower, &tx_info_upper, |
| transistor_type, size); |
| if (error) { |
| return 0; |
| } |
| |
| if (tx_info_lower == nullptr) { |
| /* No lower bound */ |
| current = tx_info_upper->leakage_gate; |
| |
| } else if (tx_info_upper == nullptr) { |
| /* No upper bound */ |
| current = tx_info_lower->leakage_gate; |
| } else { |
| /* Linear approximation between sizes */ |
| float percent_upper = (size - tx_info_lower->size) |
| / (tx_info_upper->size - tx_info_lower->size); |
| current = (1 - percent_upper) * tx_info_lower->leakage_gate |
| + percent_upper * tx_info_upper->leakage_gate; |
| } |
| |
| auto& power_ctx = g_vpr_ctx.power(); |
| return current * power_ctx.tech->Vdd; |
| } |
| |
| /** |
| * Returns the subthreshold leakage power of a pass-transistor, |
| * assumed to be a minimum-sized NMOS |
| * - size: (W/L) size of transistor (Must be 1.0) |
| * - v_ds: Drain-source voltage |
| */ |
| static float power_calc_leakage_st_pass_transistor(float size, float v_ds) { |
| t_power_nmos_leakage_inf* nmos_low = nullptr; |
| t_power_nmos_leakage_inf* nmos_high = nullptr; |
| |
| t_power_nmos_leakage_pair* lower; |
| t_power_nmos_leakage_pair* upper; |
| float i_ds; |
| float power_low; |
| float power_high; |
| bool over_range = false; |
| |
| VTR_ASSERT(size >= 1.0); |
| |
| auto& power_ctx = g_vpr_ctx.power(); |
| |
| // Check if nmos size is beyond range |
| if (size >= power_ctx.tech->nmos_leakage_info[power_ctx.tech->num_nmos_leakage_info - 1].nmos_size) { |
| nmos_low = &power_ctx.tech->nmos_leakage_info[power_ctx.tech->num_nmos_leakage_info - 1]; |
| over_range = true; |
| } else { |
| for (int i = 1; i < power_ctx.tech->num_nmos_leakage_info; i++) { |
| if (size < power_ctx.tech->nmos_leakage_info[i].nmos_size) { |
| nmos_low = &power_ctx.tech->nmos_leakage_info[i - 1]; |
| nmos_high = &power_ctx.tech->nmos_leakage_info[i]; |
| break; |
| } |
| } |
| } |
| |
| if (size |
| > power_ctx.tech->nmos_leakage_info[power_ctx.tech->num_nmos_leakage_info |
| - 1] |
| .nmos_size) { |
| power_log_msg(POWER_LOG_ERROR, |
| "The architectures uses multiplexers with \ |
| transistors sizes larger than what is defined in the <nmos_leakages> \ |
| section of the technology file."); |
| } |
| |
| VTR_ASSERT(nmos_low != nullptr); |
| power_find_nmos_leakage(nmos_low, &lower, &upper, v_ds); |
| if (lower->v_ds == v_ds || !upper) { |
| i_ds = lower->i_ds; |
| } else { |
| float perc_upper = (v_ds - lower->v_ds) / (upper->v_ds - lower->v_ds); |
| i_ds = (1 - perc_upper) * lower->i_ds + perc_upper * upper->i_ds; |
| } |
| power_low = i_ds * power_ctx.tech->Vdd; |
| |
| if (over_range) { |
| return power_low; |
| } else { |
| VTR_ASSERT(nmos_high != nullptr); |
| power_find_nmos_leakage(nmos_high, &lower, &upper, v_ds); |
| if (lower->v_ds == v_ds || !upper) { |
| i_ds = lower->i_ds; |
| } else { |
| float perc_upper = (v_ds - lower->v_ds) |
| / (upper->v_ds - lower->v_ds); |
| i_ds = (1 - perc_upper) * lower->i_ds + perc_upper * upper->i_ds; |
| } |
| power_high = i_ds * power_ctx.tech->Vdd; |
| |
| float perc_upper = (size - nmos_low->nmos_size) |
| / (nmos_high->nmos_size - nmos_low->nmos_size); |
| return power_high * perc_upper + power_low * (1 - perc_upper); |
| } |
| } |
| |
| /** |
| * Calculates the power of a wire |
| * - power_usage: (Return value) Power usage of the wire |
| * - capacitance: Capacitance of the wire (F) |
| * - density: Transition density of the wire |
| */ |
| void power_usage_wire(t_power_usage* power_usage, float capacitance, float density, float period) { |
| power_usage->leakage = 0.; |
| power_usage->dynamic = power_calc_node_switching(capacitance, density, |
| period); |
| } |
| |
| /** |
| * Calculates the power of a 2-input multiplexer, comprised of transmission gates |
| * - power_usage: (Return value) Power usage of the mux |
| * - in_dens: Array of input transition densities |
| * - in_prob: Array of input signal probabilities |
| * - sel_desn: Transition density of select line |
| * - sel_prob: Signal probability of select line |
| * - out_dens: Transition density of the output |
| */ |
| void power_usage_MUX2_transmission(t_power_usage* power_usage, float size, float* in_dens, float* in_prob, float sel_dens, float out_dens, float period) { |
| auto& power_ctx = g_vpr_ctx.power(); |
| |
| power_zero_usage(power_usage); |
| |
| float leakage_n, leakage_p; |
| leakage_n = power_calc_leakage_st(NMOS, size); |
| leakage_p = power_calc_leakage_st(PMOS, size * power_ctx.tech->PN_ratio); |
| |
| float C_g_n, C_d_n, C_s_n; |
| power_calc_transistor_capacitance(&C_d_n, &C_s_n, &C_g_n, NMOS, size); |
| |
| float C_g_p, C_d_p, C_s_p; |
| power_calc_transistor_capacitance(&C_d_p, &C_s_p, &C_g_p, PMOS, |
| size * power_ctx.tech->PN_ratio); |
| |
| /* A transmission gate leaks if the selected input != other input */ |
| power_usage->leakage += (in_prob[0] * (1 - in_prob[1]) |
| + (1 - in_prob[0]) * in_prob[1]) |
| * (leakage_n + leakage_p); |
| |
| /* Gate switching */ |
| power_usage->dynamic += 2 |
| * power_calc_node_switching(C_g_n + C_g_p, sel_dens, period); |
| |
| /* Input switching */ |
| power_usage->dynamic += power_calc_node_switching(C_d_n + C_s_p, in_dens[0], |
| period); |
| power_usage->dynamic += power_calc_node_switching(C_d_n + C_s_p, in_dens[1], |
| period); |
| |
| /* Output switching */ |
| power_usage->dynamic += power_calc_node_switching(2 * (C_s_n + C_d_p), |
| out_dens, period); |
| } |
| |
| /** |
| * Calucates the power of a static, single-level multiplexer |
| * - power_usage: (Return value) power usage of the mux |
| * - out_prob: (Return value) Signal probability of the output |
| * - out_dens: (Return value) Transition density of the output |
| * - num_inputs: Number of inputs of the mux |
| * - selected_idx: The input index that is selected by the select lines |
| * - in_prob: Array of input signal probabilities |
| * - in_dens: Array of input tranistion densities |
| * - v_in: Array of input max voltages |
| * - transistor_size: Size of the NMOS transistors (must be 1.0) |
| * - v_out_restored: Whether the output will be level restored to Vdd |
| */ |
| void power_usage_mux_singlelevel_static(t_power_usage* power_usage, |
| float* out_prob, |
| float* out_dens, |
| float* v_out, |
| int num_inputs, |
| int selected_idx, |
| float* in_prob, |
| float* in_dens, |
| float* v_in, |
| float transistor_size, |
| bool v_out_restored, |
| float period) { |
| int input_idx; |
| float v_in_selected; |
| float in_prob_avg; |
| |
| power_zero_usage(power_usage); |
| |
| VTR_ASSERT(transistor_size >= 1.0); |
| |
| if (selected_idx < num_inputs) { |
| *out_prob = in_prob[selected_idx]; |
| *out_dens = in_dens[selected_idx]; |
| v_in_selected = v_in[selected_idx]; |
| |
| } else { |
| /* In this case, the multiplexer is not symetrical. The |
| * other branch of the mux has more inputs than this one, |
| * and the selected input index is not a valid index for |
| * this portion of the mux. If the mux was actually built |
| * this way, there would likely be a weak pull-up to ensure |
| * that the node does not float. |
| */ |
| *out_prob = 1.0; |
| *out_dens = 0.0; |
| |
| v_in_selected = 0.; |
| for (input_idx = 0; input_idx < num_inputs; input_idx++) { |
| v_in_selected += v_in[input_idx]; |
| } |
| v_in_selected /= num_inputs; |
| } |
| |
| in_prob_avg = 0.; |
| |
| float C_d, C_g, C_s; |
| power_calc_transistor_capacitance(&C_d, &C_s, &C_g, NMOS, transistor_size); |
| |
| for (input_idx = 0; input_idx < num_inputs; input_idx++) { |
| /* Dynamic Power at Inputs */ |
| power_usage->dynamic += power_calc_node_switching_v(C_d, |
| in_dens[input_idx], period, v_in[input_idx]); |
| |
| if (input_idx != selected_idx) { |
| in_prob_avg += in_prob[input_idx]; |
| } |
| } |
| in_prob_avg /= (num_inputs - 1); |
| |
| if (v_out_restored) { |
| auto& power_ctx = g_vpr_ctx.power(); |
| *v_out = power_ctx.tech->Vdd; |
| } else { |
| *v_out = power_calc_mux_v_out(num_inputs, transistor_size, |
| v_in_selected, in_prob_avg); |
| } |
| |
| for (input_idx = 0; input_idx < num_inputs; input_idx++) { |
| /* Leakage */ |
| /* The selected input will never leak */ |
| if (input_idx == selected_idx) { |
| continue; |
| } |
| |
| /* Output is high and this input is low */ |
| power_usage->leakage += (*out_prob) * (1 - in_prob[input_idx]) |
| * power_calc_leakage_st_pass_transistor(transistor_size, |
| *v_out); |
| |
| /* Output is low and this input is high */ |
| power_usage->leakage += (1 - *out_prob) * in_prob[input_idx] |
| * power_calc_leakage_st_pass_transistor(transistor_size, |
| v_in[input_idx]); |
| } |
| |
| /* Dynamic Power at Output */ |
| power_usage->dynamic += power_calc_node_switching_v(C_s * num_inputs, |
| *out_dens, period, *v_out); |
| } |
| |
| /** |
| * This function calcualtes the output voltage of a single-level multiplexer |
| * - num_inputs: Number of inputs of the multiplexer |
| * - transistor_size: The size of the NMOS transistors (must be 1.0) |
| * - v_in: The input voltage of the selcted input |
| * - in_prob_avg: The average signal probabilities of the non-selected inputs |
| */ |
| float power_calc_mux_v_out(int num_inputs, float transistor_size, float v_in, float in_prob_avg) { |
| t_power_mux_volt_inf* mux_volt_inf_low; |
| t_power_mux_volt_inf* mux_volt_inf_high; |
| t_power_mux_volt_pair* lower; |
| t_power_mux_volt_pair* upper; |
| float v_out_min, v_out_max; |
| float v_out_low; |
| float v_out_high; |
| bool over_range = false; |
| |
| VTR_ASSERT(transistor_size >= 1.0); |
| |
| t_power_nmos_mux_inf* mux_nmos_inf_lower = nullptr; |
| t_power_nmos_mux_inf* mux_nmos_inf_upper = nullptr; |
| |
| auto& power_ctx = g_vpr_ctx.power(); |
| |
| // Check if nmos size is beyond range |
| if (transistor_size |
| >= power_ctx.tech->nmos_mux_info[power_ctx.tech->num_nmos_mux_info - 1].nmos_size) { |
| mux_nmos_inf_lower = &power_ctx.tech->nmos_mux_info[power_ctx.tech->num_nmos_mux_info - 1]; |
| over_range = true; |
| } else { |
| for (int i = 1; i < power_ctx.tech->num_nmos_mux_info; i++) { |
| if (transistor_size < power_ctx.tech->nmos_mux_info[i].nmos_size) { |
| mux_nmos_inf_lower = &power_ctx.tech->nmos_mux_info[i - 1]; |
| mux_nmos_inf_upper = &power_ctx.tech->nmos_mux_info[i]; |
| break; |
| } |
| } |
| } |
| |
| VTR_ASSERT(mux_nmos_inf_lower); |
| |
| if (transistor_size |
| > power_ctx.tech->nmos_mux_info[power_ctx.tech->num_nmos_mux_info - 1].nmos_size) { |
| power_log_msg(POWER_LOG_ERROR, |
| "The architectures uses multiplexers with \ |
| transistors sizes larger than what is defined in the <multiplexers> \ |
| section of the technology file."); |
| } |
| |
| if (num_inputs > mux_nmos_inf_lower->max_mux_sl_size |
| || (!over_range && mux_nmos_inf_upper && num_inputs > mux_nmos_inf_upper->max_mux_sl_size)) { |
| power_log_msg(POWER_LOG_ERROR, |
| "The circuit contains a single-level mux larger than \ |
| what is defined in the <multiplexers> section of the \ |
| technology file."); |
| } |
| |
| mux_volt_inf_low = &mux_nmos_inf_lower->mux_voltage_inf[num_inputs]; |
| |
| power_find_mux_volt_inf(&lower, &upper, mux_volt_inf_low, v_in); |
| if (lower->v_in == v_in || !upper) { |
| v_out_min = lower->v_out_min; |
| v_out_max = lower->v_out_max; |
| } else { |
| float perc_upper = (v_in - lower->v_in) / (upper->v_in - lower->v_in); |
| v_out_min = (1 - perc_upper) * lower->v_out_min |
| + perc_upper * upper->v_out_min; |
| v_out_max = (1 - perc_upper) * lower->v_out_max |
| + perc_upper * upper->v_out_max; |
| } |
| v_out_low = in_prob_avg * v_out_max + (1 - in_prob_avg) * v_out_min; |
| |
| if (over_range) { |
| return v_out_low; |
| } else { |
| VTR_ASSERT(mux_nmos_inf_upper); |
| mux_volt_inf_high = &mux_nmos_inf_upper->mux_voltage_inf[num_inputs]; |
| power_find_mux_volt_inf(&lower, &upper, mux_volt_inf_high, v_in); |
| if (lower->v_in == v_in || !upper) { |
| v_out_min = lower->v_out_min; |
| v_out_max = lower->v_out_max; |
| } else { |
| float perc_upper = (v_in - lower->v_in) |
| / (upper->v_in - lower->v_in); |
| v_out_min = (1 - perc_upper) * lower->v_out_min |
| + perc_upper * upper->v_out_min; |
| v_out_max = (1 - perc_upper) * lower->v_out_max |
| + perc_upper * upper->v_out_max; |
| } |
| v_out_high = in_prob_avg * v_out_max + (1 - in_prob_avg) * v_out_min; |
| |
| float perc_upper = (transistor_size - mux_nmos_inf_lower->nmos_size) |
| / (mux_nmos_inf_upper->nmos_size |
| - mux_nmos_inf_lower->nmos_size); |
| return v_out_high * perc_upper + (1 - perc_upper) * v_out_low; |
| } |
| } |
| |
| /** This function calculates the power of a single-level multiplexer, where the |
| * select lines are dynamic |
| * - power_usage: (Return value) The power usage of the mux |
| * - num_inputs: Number of multiplexer inputs (must be 2) |
| * - out_density: The transition density of the output |
| * - out_prob: The signal probability of the output |
| * - v_out: The output max voltage |
| * - in_prob: Array of input signal probabilities |
| * - in_dens: Array of input tranistion densities |
| * - v_in: Array of input voltages |
| * - sel_dens: Transition density of the select line |
| * - sel_prob: Signal probability of the select line |
| * - tranisistor_size: NMOS transistor sizes (must be 1.0) |
| */ |
| void power_usage_mux_singlelevel_dynamic(t_power_usage* power_usage, |
| int num_inputs, |
| float out_density, |
| float v_out, |
| float* in_prob, |
| float* in_dens, |
| float* v_in, |
| float sel_dens, |
| float sel_prob, |
| float transistor_size, |
| float period) { |
| VTR_ASSERT(num_inputs == 2); |
| |
| power_zero_usage(power_usage); |
| |
| /* Leakage occurs when input1 != input2. |
| * If the selected input is low, the other transistor leaks input->output |
| * If the selected input is high, the other transistor leaks output->input*/ |
| |
| /* 1st selected, 1st Low, 2nd High - Leakage from 2nd in->out */ |
| power_usage->leakage += (1 - sel_prob) * (1 - in_prob[0]) * in_prob[1] |
| * power_calc_leakage_st_pass_transistor(transistor_size, v_in[1]); |
| |
| /* 1st selected, 1st High, 2nd Low - Leakage from 2nd out->in */ |
| /* 2nd selected, 1st Low, 2nd High - Leakage from 1st out->in */ |
| power_usage->leakage += ((1 - sel_prob) * in_prob[0] * (1 - in_prob[1]) |
| + sel_prob * (1 - in_prob[0]) * in_prob[1]) |
| * power_calc_leakage_st_pass_transistor(transistor_size, v_out); |
| |
| /* 2nd selected, 1st High, 2nd Low - Leakage from 1st in->out */ |
| power_usage->leakage += sel_prob * in_prob[0] * (1 - in_prob[1]) |
| * power_calc_leakage_st_pass_transistor(transistor_size, v_in[0]); |
| |
| /* Gate switching */ |
| float C_d, C_s, C_g; |
| power_calc_transistor_capacitance(&C_d, &C_s, &C_g, NMOS, transistor_size); |
| power_usage->dynamic += 2 |
| * power_calc_node_switching(C_g, sel_dens, period); |
| |
| /* Input switching */ |
| power_usage->dynamic += power_calc_node_switching_v(C_d, in_dens[0], period, |
| v_in[0]); |
| power_usage->dynamic += power_calc_node_switching_v(C_d, in_dens[1], period, |
| v_in[1]); |
| |
| /* Output switching */ |
| power_usage->dynamic += power_calc_node_switching_v(2 * C_s, out_density, |
| period, v_out); |
| } |
| |
| /** |
| * This function calculates the power of a level restorer, which is a biased |
| * inverter with a pull-up PMOS transistor in feedback. |
| * - power_usage: (Return value) Power usage of the level restorer |
| * - dyn_power_in: (Return value) Dynamic power at the input |
| * - in_density: Transition density of the input |
| * - in_prob: Signal probability of the input |
| */ |
| void power_usage_level_restorer(t_power_usage* power_usage, |
| float* dyn_power_in, |
| float in_dens, |
| float in_prob, |
| float period) { |
| t_power_usage sub_power_usage; |
| float C; |
| float C_in; |
| float input_dyn_power = 0.; |
| |
| power_zero_usage(power_usage); |
| |
| /* Inverter */ |
| power_usage_inverter_irregular(&sub_power_usage, &input_dyn_power, in_dens, |
| in_prob, 1.0, 2.0, period); |
| power_add_usage(power_usage, &sub_power_usage); |
| |
| auto& power_ctx = g_vpr_ctx.power(); |
| |
| /* Pull-up PMOS */ |
| if (power_ctx.tech->PMOS_inf.long_trans_inf == nullptr) { |
| power_log_msg(POWER_LOG_ERROR, |
| "No long transistor information exists. Cannot determine transistor properties."); |
| return; |
| } |
| C = power_ctx.tech->PMOS_inf.long_trans_inf->C_d |
| + power_ctx.tech->PMOS_inf.long_trans_inf->C_g; |
| C_in = power_ctx.tech->PMOS_inf.long_trans_inf->C_d; |
| |
| input_dyn_power += power_calc_node_switching(C_in, in_dens, period); |
| power_usage->dynamic += power_calc_node_switching(C, in_dens, period); |
| power_usage->leakage += (1 - in_prob) |
| * power_ctx.tech->PMOS_inf.long_trans_inf->leakage_subthreshold; |
| |
| *dyn_power_in = input_dyn_power; |
| } |
| |
| /** |
| * This function calculates the short-circuit factor for a buffer. This factor |
| * represents the short-circuit power of a buffer, as a factor of switching power. |
| * - stages: Number of stages of the buffer |
| * - gain: The gain at each stage |
| * - level_restorer: Whether this buffer must level-restore the input to Vdd |
| * - input_mux_size: For level-restoring buffers, what is the size of the mux driving it |
| */ |
| // Not used anymore |
| #if 0 |
| float power_calc_buffer_sc(int stages, float gain, bool level_restorer, |
| int input_mux_size) { |
| |
| t_power_buffer_size_inf * size_inf; |
| t_power_buffer_strength_inf * strength_lower; |
| t_power_buffer_strength_inf * strength_upper; |
| float sc; |
| auto& power_ctx = g_vpr_ctx.power(); |
| |
| /* Find information for given buffer size */ |
| size_inf = &power_ctx.tech->buffer_size_inf[stages]; |
| |
| /* Find information for a given size/strength */ |
| power_find_buffer_strength_inf(&strength_lower, &strength_upper, size_inf, |
| gain); |
| |
| if (!level_restorer) { |
| if (strength_upper == NULL) { |
| sc = strength_lower->sc_no_levr; |
| } else { |
| float percent_upper = (gain - strength_lower->stage_gain) |
| / (strength_upper->stage_gain - strength_lower->stage_gain); |
| sc = (1 - percent_upper) * strength_lower->sc_no_levr |
| + percent_upper * strength_upper->sc_no_levr; |
| } |
| } else { |
| /* Level Restored - Short Circuit depends on input mux size */ |
| |
| if (strength_upper == NULL) { |
| sc = power_calc_buffer_sc_levr(strength_lower, input_mux_size); |
| } else { |
| float sc_buf_low; |
| float sc_buf_high; |
| |
| sc_buf_low = power_calc_buffer_sc_levr(strength_lower, |
| input_mux_size); |
| sc_buf_high = power_calc_buffer_sc_levr(strength_upper, |
| input_mux_size); |
| |
| float percent_upper = (gain - strength_lower->stage_gain) |
| / (strength_upper->stage_gain - strength_lower->stage_gain); |
| sc = (1 - percent_upper) * sc_buf_low + percent_upper * sc_buf_high; |
| } |
| } |
| return sc; |
| } |
| |
| /** |
| * This function calculates the short-circuit factor for a level-restoring buffer, |
| * used by power_calc_buffer_sc |
| * - buffer_strength: The buffer information, for a given size/strength |
| * - input_mux_size: The size of the mux driving this buffer |
| */ |
| static float power_calc_buffer_sc_levr( |
| t_power_buffer_strength_inf * buffer_strength, int input_mux_size) { |
| t_power_buffer_sc_levr_inf * mux_lower; |
| t_power_buffer_sc_levr_inf * mux_upper; |
| |
| power_find_buffer_sc_levr(&mux_lower, &mux_upper, buffer_strength, |
| input_mux_size); |
| if (mux_upper == NULL) { |
| return mux_lower->sc_levr; |
| } else { |
| float percent_upper = (input_mux_size - mux_lower->mux_size) |
| / (mux_upper->mux_size - mux_lower->mux_size); |
| return (1 - percent_upper) * mux_lower->sc_levr |
| + percent_upper * mux_upper->sc_levr; |
| } |
| } |
| #endif |
| |
| float power_calc_buffer_size_from_Cout(float C_out) { |
| int i; |
| float C_found; |
| auto& power_ctx = g_vpr_ctx.power(); |
| |
| t_transistor_inf* nmos_info = &power_ctx.tech->NMOS_inf; |
| t_transistor_inf* pmos_info = &power_ctx.tech->PMOS_inf; |
| |
| VTR_ASSERT(nmos_info->num_size_entries == pmos_info->num_size_entries); |
| |
| for (i = 0; i < nmos_info->num_size_entries; i++) { |
| C_found = nmos_info->size_inf[i].C_d + pmos_info->size_inf[i].C_d; |
| |
| /* Not likely, since floating point */ |
| if (C_out == C_found) { |
| return nmos_info->size_inf[i].size; |
| } |
| |
| /* Gone past */ |
| if (C_found > C_out) { |
| if (i == 0) { |
| power_log_msg(POWER_LOG_WARNING, |
| "Attempted to search for a transistor with a capacitance smaller than the smallest in the technology file.\n"); |
| return nmos_info->size_inf[i].size; |
| } else { |
| float C_prev = nmos_info->size_inf[i - 1].C_d |
| + pmos_info->size_inf[i - 1].C_d; |
| float percent_upper = (C_out - C_prev) / (C_found - C_prev); |
| return percent_upper * nmos_info->size_inf[i].size |
| + (1 - percent_upper) * nmos_info->size_inf[i - 1].size; |
| } |
| } |
| |
| /* Reached the End */ |
| if (i == nmos_info->num_size_entries - 1) { |
| power_log_msg(POWER_LOG_WARNING, |
| "Attempted to search for a transistor with a capacitance greater than the largest in the technology file.\n"); |
| return nmos_info->size_inf[i].size; |
| } |
| } |
| |
| return 0; |
| } |