| /***************************************************************************** | |
| * McPAT/CACTI | |
| * SOFTWARE LICENSE AGREEMENT | |
| * Copyright 2012 Hewlett-Packard Development Company, L.P. | |
| * Copyright (c) 2010-2013 Advanced Micro Devices, Inc. | |
| * All Rights Reserved | |
| * | |
| * Redistribution and use in source and binary forms, with or without | |
| * modification, are permitted provided that the following conditions are | |
| * met: redistributions of source code must retain the above copyright | |
| * notice, this list of conditions and the following disclaimer; | |
| * redistributions in binary form must reproduce the above copyright | |
| * notice, this list of conditions and the following disclaimer in the | |
| * documentation and/or other materials provided with the distribution; | |
| * neither the name of the copyright holders nor the names of its | |
| * contributors may be used to endorse or promote products derived from | |
| * this software without specific prior written permission. | |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| * | |
| ***************************************************************************/ | |
| #include <cassert> | |
| #include <cmath> | |
| #include <iostream> | |
| #include "area.h" | |
| #include "decoder.h" | |
| #include "parameter.h" | |
| using namespace std; | |
| Decoder::Decoder( | |
| int _num_dec_signals, | |
| bool flag_way_select, | |
| double _C_ld_dec_out, | |
| double _R_wire_dec_out, | |
| bool fully_assoc_, | |
| bool is_dram_, | |
| bool is_wl_tr_, | |
| const Area & cell_) | |
| : exist(false), | |
| C_ld_dec_out(_C_ld_dec_out), | |
| R_wire_dec_out(_R_wire_dec_out), | |
| num_gates(0), num_gates_min(2), | |
| delay(0), | |
| //power(), | |
| fully_assoc(fully_assoc_), is_dram(is_dram_), | |
| is_wl_tr(is_wl_tr_), cell(cell_) { | |
| for (int i = 0; i < MAX_NUMBER_GATES_STAGE; i++) { | |
| w_dec_n[i] = 0; | |
| w_dec_p[i] = 0; | |
| } | |
| /* | |
| * _num_dec_signals is the number of decoded signal as output | |
| * num_addr_bits_dec is the number of signal to be decoded | |
| * as the decoders input. | |
| */ | |
| int num_addr_bits_dec = _log2(_num_dec_signals); | |
| if (num_addr_bits_dec < 4) { | |
| if (flag_way_select) { | |
| exist = true; | |
| num_in_signals = 2; | |
| } else { | |
| num_in_signals = 0; | |
| } | |
| } else { | |
| exist = true; | |
| if (flag_way_select) { | |
| num_in_signals = 3; | |
| } else { | |
| num_in_signals = 2; | |
| } | |
| } | |
| assert(cell.h > 0); | |
| assert(cell.w > 0); | |
| // the height of a row-decoder-driver cell is fixed to be 4 * cell.h; | |
| //area.h = 4 * cell.h; | |
| area.h = g_tp.h_dec * cell.h; | |
| compute_widths(); | |
| compute_area(); | |
| } | |
| void Decoder::compute_widths() { | |
| double F; | |
| double p_to_n_sz_ratio = pmos_to_nmos_sz_ratio(is_dram, is_wl_tr); | |
| double gnand2 = (2 + p_to_n_sz_ratio) / (1 + p_to_n_sz_ratio); | |
| double gnand3 = (3 + p_to_n_sz_ratio) / (1 + p_to_n_sz_ratio); | |
| if (exist) { | |
| if (num_in_signals == 2 || fully_assoc) { | |
| w_dec_n[0] = 2 * g_tp.min_w_nmos_; | |
| w_dec_p[0] = p_to_n_sz_ratio * g_tp.min_w_nmos_; | |
| F = gnand2; | |
| } else { | |
| w_dec_n[0] = 3 * g_tp.min_w_nmos_; | |
| w_dec_p[0] = p_to_n_sz_ratio * g_tp.min_w_nmos_; | |
| F = gnand3; | |
| } | |
| F *= C_ld_dec_out / (gate_C(w_dec_n[0], 0, is_dram, false, is_wl_tr) + | |
| gate_C(w_dec_p[0], 0, is_dram, false, is_wl_tr)); | |
| num_gates = logical_effort( | |
| num_gates_min, | |
| num_in_signals == 2 ? gnand2 : gnand3, | |
| F, | |
| w_dec_n, | |
| w_dec_p, | |
| C_ld_dec_out, | |
| p_to_n_sz_ratio, | |
| is_dram, | |
| is_wl_tr, | |
| g_tp.max_w_nmos_dec); | |
| } | |
| } | |
| void Decoder::compute_area() { | |
| double cumulative_area = 0; | |
| double cumulative_curr = 0; // cumulative leakage current | |
| double cumulative_curr_Ig = 0; // cumulative leakage current | |
| if (exist) { // First check if this decoder exists | |
| if (num_in_signals == 2) { | |
| cumulative_area = | |
| compute_gate_area(NAND, 2, w_dec_p[0], w_dec_n[0], area.h); | |
| cumulative_curr = | |
| cmos_Isub_leakage(w_dec_n[0], w_dec_p[0], 2, nand, is_dram); | |
| cumulative_curr_Ig = | |
| cmos_Ig_leakage(w_dec_n[0], w_dec_p[0], 2, nand, is_dram); | |
| } else if (num_in_signals == 3) { | |
| cumulative_area = | |
| compute_gate_area(NAND, 3, w_dec_p[0], w_dec_n[0], area.h); | |
| cumulative_curr = | |
| cmos_Isub_leakage(w_dec_n[0], w_dec_p[0], 3, nand, is_dram);; | |
| cumulative_curr_Ig = | |
| cmos_Ig_leakage(w_dec_n[0], w_dec_p[0], 3, nand, is_dram); | |
| } | |
| for (int i = 1; i < num_gates; i++) { | |
| cumulative_area += | |
| compute_gate_area(INV, 1, w_dec_p[i], w_dec_n[i], area.h); | |
| cumulative_curr += | |
| cmos_Isub_leakage(w_dec_n[i], w_dec_p[i], 1, inv, is_dram); | |
| cumulative_curr_Ig = | |
| cmos_Ig_leakage(w_dec_n[i], w_dec_p[i], 1, inv, is_dram); | |
| } | |
| power.readOp.leakage = cumulative_curr * g_tp.peri_global.Vdd; | |
| power.readOp.gate_leakage = cumulative_curr_Ig * g_tp.peri_global.Vdd; | |
| area.w = (cumulative_area / area.h); | |
| } | |
| } | |
| double Decoder::compute_delays(double inrisetime) { | |
| if (exist) { | |
| double ret_val = 0; // outrisetime | |
| int i; | |
| double rd, tf, this_delay, c_load, c_intrinsic, Vpp; | |
| double Vdd = g_tp.peri_global.Vdd; | |
| if ((is_wl_tr) && (is_dram)) { | |
| Vpp = g_tp.vpp; | |
| } else if (is_wl_tr) { | |
| Vpp = g_tp.sram_cell.Vdd; | |
| } else { | |
| Vpp = g_tp.peri_global.Vdd; | |
| } | |
| // first check whether a decoder is required at all | |
| rd = tr_R_on(w_dec_n[0], NCH, num_in_signals, is_dram, false, is_wl_tr); | |
| c_load = gate_C(w_dec_n[1] + w_dec_p[1], 0.0, is_dram, false, is_wl_tr); | |
| c_intrinsic = drain_C_(w_dec_p[0], PCH, 1, 1, area.h, is_dram, false, is_wl_tr) * num_in_signals + | |
| drain_C_(w_dec_n[0], NCH, num_in_signals, 1, area.h, is_dram, false, is_wl_tr); | |
| tf = rd * (c_intrinsic + c_load); | |
| this_delay = horowitz(inrisetime, tf, 0.5, 0.5, RISE); | |
| delay += this_delay; | |
| inrisetime = this_delay / (1.0 - 0.5); | |
| power.readOp.dynamic += (c_load + c_intrinsic) * Vdd * Vdd; | |
| for (i = 1; i < num_gates - 1; ++i) { | |
| rd = tr_R_on(w_dec_n[i], NCH, 1, is_dram, false, is_wl_tr); | |
| c_load = gate_C(w_dec_p[i+1] + w_dec_n[i+1], 0.0, is_dram, false, is_wl_tr); | |
| c_intrinsic = drain_C_(w_dec_p[i], PCH, 1, 1, area.h, is_dram, false, is_wl_tr) + | |
| drain_C_(w_dec_n[i], NCH, 1, 1, area.h, is_dram, false, is_wl_tr); | |
| tf = rd * (c_intrinsic + c_load); | |
| this_delay = horowitz(inrisetime, tf, 0.5, 0.5, RISE); | |
| delay += this_delay; | |
| inrisetime = this_delay / (1.0 - 0.5); | |
| power.readOp.dynamic += (c_load + c_intrinsic) * Vdd * Vdd; | |
| } | |
| // add delay of final inverter that drives the wordline | |
| i = num_gates - 1; | |
| c_load = C_ld_dec_out; | |
| rd = tr_R_on(w_dec_n[i], NCH, 1, is_dram, false, is_wl_tr); | |
| c_intrinsic = drain_C_(w_dec_p[i], PCH, 1, 1, area.h, is_dram, false, is_wl_tr) + | |
| drain_C_(w_dec_n[i], NCH, 1, 1, area.h, is_dram, false, is_wl_tr); | |
| tf = rd * (c_intrinsic + c_load) + R_wire_dec_out * c_load / 2; | |
| this_delay = horowitz(inrisetime, tf, 0.5, 0.5, RISE); | |
| delay += this_delay; | |
| ret_val = this_delay / (1.0 - 0.5); | |
| power.readOp.dynamic += c_load * Vpp * Vpp + c_intrinsic * Vdd * Vdd; | |
| return ret_val; | |
| } else { | |
| return 0.0; | |
| } | |
| } | |
| void Decoder::leakage_feedback(double temperature) | |
| { | |
| double cumulative_curr = 0; // cumulative leakage current | |
| double cumulative_curr_Ig = 0; // cumulative leakage current | |
| if (exist) | |
| { // First check if this decoder exists | |
| if (num_in_signals == 2) | |
| { | |
| cumulative_curr = cmos_Isub_leakage(w_dec_n[0], w_dec_p[0], 2, nand,is_dram); | |
| cumulative_curr_Ig = cmos_Ig_leakage(w_dec_n[0], w_dec_p[0], 2, nand,is_dram); | |
| } | |
| else if (num_in_signals == 3) | |
| { | |
| cumulative_curr = cmos_Isub_leakage(w_dec_n[0], w_dec_p[0], 3, nand, is_dram);; | |
| cumulative_curr_Ig = cmos_Ig_leakage(w_dec_n[0], w_dec_p[0], 3, nand, is_dram); | |
| } | |
| for (int i = 1; i < num_gates; i++) | |
| { | |
| cumulative_curr += cmos_Isub_leakage(w_dec_n[i], w_dec_p[i], 1, inv, is_dram); | |
| cumulative_curr_Ig = cmos_Ig_leakage(w_dec_n[i], w_dec_p[i], 1, inv, is_dram); | |
| } | |
| power.readOp.leakage = cumulative_curr * g_tp.peri_global.Vdd; | |
| power.readOp.gate_leakage = cumulative_curr_Ig * g_tp.peri_global.Vdd; | |
| } | |
| } | |
| PredecBlk::PredecBlk( | |
| int num_dec_signals, | |
| Decoder * dec_, | |
| double C_wire_predec_blk_out, | |
| double R_wire_predec_blk_out_, | |
| int num_dec_per_predec, | |
| bool is_dram, | |
| bool is_blk1) | |
| : dec(dec_), | |
| exist(false), | |
| number_input_addr_bits(0), | |
| C_ld_predec_blk_out(0), | |
| R_wire_predec_blk_out(0), | |
| branch_effort_nand2_gate_output(1), | |
| branch_effort_nand3_gate_output(1), | |
| flag_two_unique_paths(false), | |
| flag_L2_gate(0), | |
| number_inputs_L1_gate(0), | |
| number_gates_L1_nand2_path(0), | |
| number_gates_L1_nand3_path(0), | |
| number_gates_L2(0), | |
| min_number_gates_L1(2), | |
| min_number_gates_L2(2), | |
| num_L1_active_nand2_path(0), | |
| num_L1_active_nand3_path(0), | |
| delay_nand2_path(0), | |
| delay_nand3_path(0), | |
| power_nand2_path(), | |
| power_nand3_path(), | |
| power_L2(), | |
| is_dram_(is_dram) { | |
| int branch_effort_predec_out; | |
| double C_ld_dec_gate; | |
| int num_addr_bits_dec = _log2(num_dec_signals); | |
| int blk1_num_input_addr_bits = (num_addr_bits_dec + 1) / 2; | |
| int blk2_num_input_addr_bits = num_addr_bits_dec - blk1_num_input_addr_bits; | |
| w_L1_nand2_n[0] = 0; | |
| w_L1_nand2_p[0] = 0; | |
| w_L1_nand3_n[0] = 0; | |
| w_L1_nand3_p[0] = 0; | |
| if (is_blk1 == true) { | |
| if (num_addr_bits_dec <= 0) { | |
| return; | |
| } else if (num_addr_bits_dec < 4) { | |
| // Just one predecoder block is required with NAND2 gates. No decoder required. | |
| // The first level of predecoding directly drives the decoder output load | |
| exist = true; | |
| number_input_addr_bits = num_addr_bits_dec; | |
| R_wire_predec_blk_out = dec->R_wire_dec_out; | |
| C_ld_predec_blk_out = dec->C_ld_dec_out; | |
| } else { | |
| exist = true; | |
| number_input_addr_bits = blk1_num_input_addr_bits; | |
| branch_effort_predec_out = (1 << blk2_num_input_addr_bits); | |
| C_ld_dec_gate = num_dec_per_predec * gate_C(dec->w_dec_n[0] + dec->w_dec_p[0], 0, is_dram_, false, false); | |
| R_wire_predec_blk_out = R_wire_predec_blk_out_; | |
| C_ld_predec_blk_out = branch_effort_predec_out * C_ld_dec_gate + C_wire_predec_blk_out; | |
| } | |
| } else { | |
| if (num_addr_bits_dec >= 4) { | |
| exist = true; | |
| number_input_addr_bits = blk2_num_input_addr_bits; | |
| branch_effort_predec_out = (1 << blk1_num_input_addr_bits); | |
| C_ld_dec_gate = num_dec_per_predec * gate_C(dec->w_dec_n[0] + dec->w_dec_p[0], 0, is_dram_, false, false); | |
| R_wire_predec_blk_out = R_wire_predec_blk_out_; | |
| C_ld_predec_blk_out = branch_effort_predec_out * C_ld_dec_gate + C_wire_predec_blk_out; | |
| } | |
| } | |
| compute_widths(); | |
| compute_area(); | |
| } | |
| void PredecBlk::compute_widths() { | |
| double F, c_load_nand3_path, c_load_nand2_path; | |
| double p_to_n_sz_ratio = pmos_to_nmos_sz_ratio(is_dram_); | |
| double gnand2 = (2 + p_to_n_sz_ratio) / (1 + p_to_n_sz_ratio); | |
| double gnand3 = (3 + p_to_n_sz_ratio) / (1 + p_to_n_sz_ratio); | |
| if (exist == false) return; | |
| switch (number_input_addr_bits) { | |
| case 1: | |
| flag_two_unique_paths = false; | |
| number_inputs_L1_gate = 2; | |
| flag_L2_gate = 0; | |
| break; | |
| case 2: | |
| flag_two_unique_paths = false; | |
| number_inputs_L1_gate = 2; | |
| flag_L2_gate = 0; | |
| break; | |
| case 3: | |
| flag_two_unique_paths = false; | |
| number_inputs_L1_gate = 3; | |
| flag_L2_gate = 0; | |
| break; | |
| case 4: | |
| flag_two_unique_paths = false; | |
| number_inputs_L1_gate = 2; | |
| flag_L2_gate = 2; | |
| branch_effort_nand2_gate_output = 4; | |
| break; | |
| case 5: | |
| flag_two_unique_paths = true; | |
| flag_L2_gate = 2; | |
| branch_effort_nand2_gate_output = 8; | |
| branch_effort_nand3_gate_output = 4; | |
| break; | |
| case 6: | |
| flag_two_unique_paths = false; | |
| number_inputs_L1_gate = 3; | |
| flag_L2_gate = 2; | |
| branch_effort_nand3_gate_output = 8; | |
| break; | |
| case 7: | |
| flag_two_unique_paths = true; | |
| flag_L2_gate = 3; | |
| branch_effort_nand2_gate_output = 32; | |
| branch_effort_nand3_gate_output = 16; | |
| break; | |
| case 8: | |
| flag_two_unique_paths = true; | |
| flag_L2_gate = 3; | |
| branch_effort_nand2_gate_output = 64; | |
| branch_effort_nand3_gate_output = 32; | |
| break; | |
| case 9: | |
| flag_two_unique_paths = false; | |
| number_inputs_L1_gate = 3; | |
| flag_L2_gate = 3; | |
| branch_effort_nand3_gate_output = 64; | |
| break; | |
| default: | |
| assert(0); | |
| break; | |
| } | |
| // find the number of gates and sizing in second level of predecoder (if there is a second level) | |
| if (flag_L2_gate) { | |
| if (flag_L2_gate == 2) { // 2nd level is a NAND2 gate | |
| w_L2_n[0] = 2 * g_tp.min_w_nmos_; | |
| F = gnand2; | |
| } else { // 2nd level is a NAND3 gate | |
| w_L2_n[0] = 3 * g_tp.min_w_nmos_; | |
| F = gnand3; | |
| } | |
| w_L2_p[0] = p_to_n_sz_ratio * g_tp.min_w_nmos_; | |
| F *= C_ld_predec_blk_out / (gate_C(w_L2_n[0], 0, is_dram_) + gate_C(w_L2_p[0], 0, is_dram_)); | |
| number_gates_L2 = logical_effort( | |
| min_number_gates_L2, | |
| flag_L2_gate == 2 ? gnand2 : gnand3, | |
| F, | |
| w_L2_n, | |
| w_L2_p, | |
| C_ld_predec_blk_out, | |
| p_to_n_sz_ratio, | |
| is_dram_, false, | |
| g_tp.max_w_nmos_); | |
| // Now find the number of gates and widths in first level of predecoder | |
| if ((flag_two_unique_paths) || (number_inputs_L1_gate == 2)) { | |
| // Whenever flag_two_unique_paths is true, it means first level of | |
| // decoder employs | |
| // both NAND2 and NAND3 gates. Or when number_inputs_L1_gate is 2, | |
| // it means | |
| // a NAND2 gate is used in the first level of the predecoder | |
| c_load_nand2_path = branch_effort_nand2_gate_output * | |
| (gate_C(w_L2_n[0], 0, is_dram_) + | |
| gate_C(w_L2_p[0], 0, is_dram_)); | |
| w_L1_nand2_n[0] = 2 * g_tp.min_w_nmos_; | |
| w_L1_nand2_p[0] = p_to_n_sz_ratio * g_tp.min_w_nmos_; | |
| F = gnand2 * c_load_nand2_path / | |
| (gate_C(w_L1_nand2_n[0], 0, is_dram_) + | |
| gate_C(w_L1_nand2_p[0], 0, is_dram_)); | |
| number_gates_L1_nand2_path = logical_effort( | |
| min_number_gates_L1, | |
| gnand2, | |
| F, | |
| w_L1_nand2_n, | |
| w_L1_nand2_p, | |
| c_load_nand2_path, | |
| p_to_n_sz_ratio, | |
| is_dram_, false, | |
| g_tp.max_w_nmos_); | |
| } | |
| //Now find widths of gates along path in which first gate is a NAND3 | |
| if ((flag_two_unique_paths) || (number_inputs_L1_gate == 3)) { // Whenever flag_two_unique_paths is TRUE, it means first level of decoder employs | |
| // both NAND2 and NAND3 gates. Or when number_inputs_L1_gate is 3, it means | |
| // a NAND3 gate is used in the first level of the predecoder | |
| c_load_nand3_path = branch_effort_nand3_gate_output * | |
| (gate_C(w_L2_n[0], 0, is_dram_) + | |
| gate_C(w_L2_p[0], 0, is_dram_)); | |
| w_L1_nand3_n[0] = 3 * g_tp.min_w_nmos_; | |
| w_L1_nand3_p[0] = p_to_n_sz_ratio * g_tp.min_w_nmos_; | |
| F = gnand3 * c_load_nand3_path / | |
| (gate_C(w_L1_nand3_n[0], 0, is_dram_) + | |
| gate_C(w_L1_nand3_p[0], 0, is_dram_)); | |
| number_gates_L1_nand3_path = logical_effort( | |
| min_number_gates_L1, | |
| gnand3, | |
| F, | |
| w_L1_nand3_n, | |
| w_L1_nand3_p, | |
| c_load_nand3_path, | |
| p_to_n_sz_ratio, | |
| is_dram_, false, | |
| g_tp.max_w_nmos_); | |
| } | |
| } else { // find number of gates and widths in first level of predecoder block when there is no second level | |
| if (number_inputs_L1_gate == 2) { | |
| w_L1_nand2_n[0] = 2 * g_tp.min_w_nmos_; | |
| w_L1_nand2_p[0] = p_to_n_sz_ratio * g_tp.min_w_nmos_; | |
| F = gnand2 * C_ld_predec_blk_out / | |
| (gate_C(w_L1_nand2_n[0], 0, is_dram_) + | |
| gate_C(w_L1_nand2_p[0], 0, is_dram_)); | |
| number_gates_L1_nand2_path = logical_effort( | |
| min_number_gates_L1, | |
| gnand2, | |
| F, | |
| w_L1_nand2_n, | |
| w_L1_nand2_p, | |
| C_ld_predec_blk_out, | |
| p_to_n_sz_ratio, | |
| is_dram_, false, | |
| g_tp.max_w_nmos_); | |
| } else if (number_inputs_L1_gate == 3) { | |
| w_L1_nand3_n[0] = 3 * g_tp.min_w_nmos_; | |
| w_L1_nand3_p[0] = p_to_n_sz_ratio * g_tp.min_w_nmos_; | |
| F = gnand3 * C_ld_predec_blk_out / | |
| (gate_C(w_L1_nand3_n[0], 0, is_dram_) + | |
| gate_C(w_L1_nand3_p[0], 0, is_dram_)); | |
| number_gates_L1_nand3_path = logical_effort( | |
| min_number_gates_L1, | |
| gnand3, | |
| F, | |
| w_L1_nand3_n, | |
| w_L1_nand3_p, | |
| C_ld_predec_blk_out, | |
| p_to_n_sz_ratio, | |
| is_dram_, false, | |
| g_tp.max_w_nmos_); | |
| } | |
| } | |
| } | |
| void PredecBlk::compute_area() { | |
| if (exist) { // First check whether a predecoder block is needed | |
| int num_L1_nand2 = 0; | |
| int num_L1_nand3 = 0; | |
| int num_L2 = 0; | |
| double tot_area_L1_nand3 = 0; | |
| double leak_L1_nand3 = 0; | |
| double gate_leak_L1_nand3 = 0; | |
| double tot_area_L1_nand2 = compute_gate_area(NAND, 2, w_L1_nand2_p[0], w_L1_nand2_n[0], g_tp.cell_h_def); | |
| double leak_L1_nand2 = cmos_Isub_leakage(w_L1_nand2_n[0], w_L1_nand2_p[0], 2, nand, is_dram_); | |
| double gate_leak_L1_nand2 = cmos_Ig_leakage(w_L1_nand2_n[0], w_L1_nand2_p[0], 2, nand, is_dram_); | |
| if (number_inputs_L1_gate != 3) { | |
| tot_area_L1_nand3 = 0; | |
| leak_L1_nand3 = 0; | |
| gate_leak_L1_nand3 = 0; | |
| } else { | |
| tot_area_L1_nand3 = compute_gate_area(NAND, 3, w_L1_nand3_p[0], w_L1_nand3_n[0], g_tp.cell_h_def); | |
| leak_L1_nand3 = cmos_Isub_leakage(w_L1_nand3_n[0], w_L1_nand3_p[0], 3, nand); | |
| gate_leak_L1_nand3 = cmos_Ig_leakage(w_L1_nand3_n[0], w_L1_nand3_p[0], 3, nand); | |
| } | |
| switch (number_input_addr_bits) { | |
| case 1: //2 NAND2 gates | |
| num_L1_nand2 = 2; | |
| num_L2 = 0; | |
| num_L1_active_nand2_path = 1; | |
| num_L1_active_nand3_path = 0; | |
| break; | |
| case 2: //4 NAND2 gates | |
| num_L1_nand2 = 4; | |
| num_L2 = 0; | |
| num_L1_active_nand2_path = 1; | |
| num_L1_active_nand3_path = 0; | |
| break; | |
| case 3: //8 NAND3 gates | |
| num_L1_nand3 = 8; | |
| num_L2 = 0; | |
| num_L1_active_nand2_path = 0; | |
| num_L1_active_nand3_path = 1; | |
| break; | |
| case 4: //4 + 4 NAND2 gates | |
| num_L1_nand2 = 8; | |
| num_L2 = 16; | |
| num_L1_active_nand2_path = 2; | |
| num_L1_active_nand3_path = 0; | |
| break; | |
| case 5: //4 NAND2 gates, 8 NAND3 gates | |
| num_L1_nand2 = 4; | |
| num_L1_nand3 = 8; | |
| num_L2 = 32; | |
| num_L1_active_nand2_path = 1; | |
| num_L1_active_nand3_path = 1; | |
| break; | |
| case 6: //8 + 8 NAND3 gates | |
| num_L1_nand3 = 16; | |
| num_L2 = 64; | |
| num_L1_active_nand2_path = 0; | |
| num_L1_active_nand3_path = 2; | |
| break; | |
| case 7: //4 + 4 NAND2 gates, 8 NAND3 gates | |
| num_L1_nand2 = 8; | |
| num_L1_nand3 = 8; | |
| num_L2 = 128; | |
| num_L1_active_nand2_path = 2; | |
| num_L1_active_nand3_path = 1; | |
| break; | |
| case 8: //4 NAND2 gates, 8 + 8 NAND3 gates | |
| num_L1_nand2 = 4; | |
| num_L1_nand3 = 16; | |
| num_L2 = 256; | |
| num_L1_active_nand2_path = 2; | |
| num_L1_active_nand3_path = 2; | |
| break; | |
| case 9: //8 + 8 + 8 NAND3 gates | |
| num_L1_nand3 = 24; | |
| num_L2 = 512; | |
| num_L1_active_nand2_path = 0; | |
| num_L1_active_nand3_path = 3; | |
| break; | |
| default: | |
| break; | |
| } | |
| for (int i = 1; i < number_gates_L1_nand2_path; ++i) { | |
| tot_area_L1_nand2 += compute_gate_area(INV, 1, w_L1_nand2_p[i], w_L1_nand2_n[i], g_tp.cell_h_def); | |
| leak_L1_nand2 += cmos_Isub_leakage(w_L1_nand2_n[i], w_L1_nand2_p[i], 2, nand, is_dram_); | |
| gate_leak_L1_nand2 += cmos_Ig_leakage(w_L1_nand2_n[i], w_L1_nand2_p[i], 2, nand, is_dram_); | |
| } | |
| tot_area_L1_nand2 *= num_L1_nand2; | |
| leak_L1_nand2 *= num_L1_nand2; | |
| gate_leak_L1_nand2 *= num_L1_nand2; | |
| for (int i = 1; i < number_gates_L1_nand3_path; ++i) { | |
| tot_area_L1_nand3 += compute_gate_area(INV, 1, w_L1_nand3_p[i], w_L1_nand3_n[i], g_tp.cell_h_def); | |
| leak_L1_nand3 += cmos_Isub_leakage(w_L1_nand3_n[i], w_L1_nand3_p[i], 3, nand, is_dram_); | |
| gate_leak_L1_nand3 += cmos_Ig_leakage(w_L1_nand3_n[i], w_L1_nand3_p[i], 3, nand, is_dram_); | |
| } | |
| tot_area_L1_nand3 *= num_L1_nand3; | |
| leak_L1_nand3 *= num_L1_nand3; | |
| gate_leak_L1_nand3 *= num_L1_nand3; | |
| double cumulative_area_L1 = tot_area_L1_nand2 + tot_area_L1_nand3; | |
| double cumulative_area_L2 = 0.0; | |
| double leakage_L2 = 0.0; | |
| double gate_leakage_L2 = 0.0; | |
| if (flag_L2_gate == 2) { | |
| cumulative_area_L2 = compute_gate_area(NAND, 2, w_L2_p[0], w_L2_n[0], g_tp.cell_h_def); | |
| leakage_L2 = cmos_Isub_leakage(w_L2_n[0], w_L2_p[0], 2, nand, is_dram_); | |
| gate_leakage_L2 = cmos_Ig_leakage(w_L2_n[0], w_L2_p[0], 2, nand, is_dram_); | |
| } else if (flag_L2_gate == 3) { | |
| cumulative_area_L2 = compute_gate_area(NAND, 3, w_L2_p[0], w_L2_n[0], g_tp.cell_h_def); | |
| leakage_L2 = cmos_Isub_leakage(w_L2_n[0], w_L2_p[0], 3, nand, is_dram_); | |
| gate_leakage_L2 = cmos_Ig_leakage(w_L2_n[0], w_L2_p[0], 3, nand, is_dram_); | |
| } | |
| for (int i = 1; i < number_gates_L2; ++i) { | |
| cumulative_area_L2 += compute_gate_area(INV, 1, w_L2_p[i], w_L2_n[i], g_tp.cell_h_def); | |
| leakage_L2 += cmos_Isub_leakage(w_L2_n[i], w_L2_p[i], 2, inv, is_dram_); | |
| gate_leakage_L2 += cmos_Ig_leakage(w_L2_n[i], w_L2_p[i], 2, inv, is_dram_); | |
| } | |
| cumulative_area_L2 *= num_L2; | |
| leakage_L2 *= num_L2; | |
| gate_leakage_L2 *= num_L2; | |
| power_nand2_path.readOp.leakage = leak_L1_nand2 * g_tp.peri_global.Vdd; | |
| power_nand3_path.readOp.leakage = leak_L1_nand3 * g_tp.peri_global.Vdd; | |
| power_L2.readOp.leakage = leakage_L2 * g_tp.peri_global.Vdd; | |
| area.set_area(cumulative_area_L1 + cumulative_area_L2); | |
| power_nand2_path.readOp.gate_leakage = gate_leak_L1_nand2 * g_tp.peri_global.Vdd; | |
| power_nand3_path.readOp.gate_leakage = gate_leak_L1_nand3 * g_tp.peri_global.Vdd; | |
| power_L2.readOp.gate_leakage = gate_leakage_L2 * g_tp.peri_global.Vdd; | |
| } | |
| } | |
| pair<double, double> PredecBlk::compute_delays( | |
| pair<double, double> inrisetime) { // <nand2, nand3> | |
| pair<double, double> ret_val; | |
| ret_val.first = 0; // outrisetime_nand2_path | |
| ret_val.second = 0; // outrisetime_nand3_path | |
| double inrisetime_nand2_path = inrisetime.first; | |
| double inrisetime_nand3_path = inrisetime.second; | |
| int i; | |
| double rd, c_load, c_intrinsic, tf, this_delay; | |
| double Vdd = g_tp.peri_global.Vdd; | |
| // TODO: following delay calculation part can be greatly simplified. | |
| // first check whether a predecoder block is required | |
| if (exist) { | |
| //Find delay in first level of predecoder block | |
| //First find delay in path | |
| if ((flag_two_unique_paths) || (number_inputs_L1_gate == 2)) { | |
| //First gate is a NAND2 gate | |
| rd = tr_R_on(w_L1_nand2_n[0], NCH, 2, is_dram_); | |
| c_load = gate_C(w_L1_nand2_n[1] + w_L1_nand2_p[1], 0.0, is_dram_); | |
| c_intrinsic = 2 * drain_C_(w_L1_nand2_p[0], PCH, 1, 1, g_tp.cell_h_def, is_dram_) + | |
| drain_C_(w_L1_nand2_n[0], NCH, 2, 1, g_tp.cell_h_def, is_dram_); | |
| tf = rd * (c_intrinsic + c_load); | |
| this_delay = horowitz(inrisetime_nand2_path, tf, 0.5, 0.5, RISE); | |
| delay_nand2_path += this_delay; | |
| inrisetime_nand2_path = this_delay / (1.0 - 0.5); | |
| power_nand2_path.readOp.dynamic += (c_load + c_intrinsic) * Vdd * Vdd; | |
| //Add delays of all but the last inverter in the chain | |
| for (i = 1; i < number_gates_L1_nand2_path - 1; ++i) { | |
| rd = tr_R_on(w_L1_nand2_n[i], NCH, 1, is_dram_); | |
| c_load = gate_C(w_L1_nand2_n[i+1] + w_L1_nand2_p[i+1], 0.0, is_dram_); | |
| c_intrinsic = drain_C_(w_L1_nand2_p[i], PCH, 1, 1, g_tp.cell_h_def, is_dram_) + | |
| drain_C_(w_L1_nand2_n[i], NCH, 1, 1, g_tp.cell_h_def, is_dram_); | |
| tf = rd * (c_intrinsic + c_load); | |
| this_delay = horowitz(inrisetime_nand2_path, tf, 0.5, 0.5, RISE); | |
| delay_nand2_path += this_delay; | |
| inrisetime_nand2_path = this_delay / (1.0 - 0.5); | |
| power_nand2_path.readOp.dynamic += (c_intrinsic + c_load) * Vdd * Vdd; | |
| } | |
| //Add delay of the last inverter | |
| i = number_gates_L1_nand2_path - 1; | |
| rd = tr_R_on(w_L1_nand2_n[i], NCH, 1, is_dram_); | |
| if (flag_L2_gate) { | |
| c_load = branch_effort_nand2_gate_output * | |
| (gate_C(w_L2_n[0], 0, is_dram_) + | |
| gate_C(w_L2_p[0], 0, is_dram_)); | |
| c_intrinsic = drain_C_(w_L1_nand2_p[i], PCH, 1, 1, g_tp.cell_h_def, is_dram_) + | |
| drain_C_(w_L1_nand2_n[i], NCH, 1, 1, g_tp.cell_h_def, is_dram_); | |
| tf = rd * (c_intrinsic + c_load); | |
| this_delay = horowitz(inrisetime_nand2_path, tf, 0.5, 0.5, RISE); | |
| delay_nand2_path += this_delay; | |
| inrisetime_nand2_path = this_delay / (1.0 - 0.5); | |
| power_nand2_path.readOp.dynamic += (c_intrinsic + c_load) * Vdd * Vdd; | |
| } else { //First level directly drives decoder output load | |
| c_load = C_ld_predec_blk_out; | |
| c_intrinsic = drain_C_(w_L1_nand2_p[i], PCH, 1, 1, g_tp.cell_h_def, is_dram_) + | |
| drain_C_(w_L1_nand2_n[i], NCH, 1, 1, g_tp.cell_h_def, is_dram_); | |
| tf = rd * (c_intrinsic + c_load) + R_wire_predec_blk_out * c_load / 2; | |
| this_delay = horowitz(inrisetime_nand2_path, tf, 0.5, 0.5, RISE); | |
| delay_nand2_path += this_delay; | |
| ret_val.first = this_delay / (1.0 - 0.5); | |
| power_nand2_path.readOp.dynamic += (c_intrinsic + c_load) * Vdd * Vdd; | |
| } | |
| } | |
| if ((flag_two_unique_paths) || (number_inputs_L1_gate == 3)) { | |
| //Check if the number of gates in the first level is more than 1. | |
| //First gate is a NAND3 gate | |
| rd = tr_R_on(w_L1_nand3_n[0], NCH, 3, is_dram_); | |
| c_load = gate_C(w_L1_nand3_n[1] + w_L1_nand3_p[1], 0.0, is_dram_); | |
| c_intrinsic = 3 * drain_C_(w_L1_nand3_p[0], PCH, 1, 1, g_tp.cell_h_def, is_dram_) + | |
| drain_C_(w_L1_nand3_n[0], NCH, 3, 1, g_tp.cell_h_def, is_dram_); | |
| tf = rd * (c_intrinsic + c_load); | |
| this_delay = horowitz(inrisetime_nand3_path, tf, 0.5, 0.5, RISE); | |
| delay_nand3_path += this_delay; | |
| inrisetime_nand3_path = this_delay / (1.0 - 0.5); | |
| power_nand3_path.readOp.dynamic += (c_intrinsic + c_load) * Vdd * Vdd; | |
| //Add delays of all but the last inverter in the chain | |
| for (i = 1; i < number_gates_L1_nand3_path - 1; ++i) { | |
| rd = tr_R_on(w_L1_nand3_n[i], NCH, 1, is_dram_); | |
| c_load = gate_C(w_L1_nand3_n[i+1] + w_L1_nand3_p[i+1], 0.0, is_dram_); | |
| c_intrinsic = drain_C_(w_L1_nand3_p[i], PCH, 1, 1, g_tp.cell_h_def, is_dram_) + | |
| drain_C_(w_L1_nand3_n[i], NCH, 1, 1, g_tp.cell_h_def, is_dram_); | |
| tf = rd * (c_intrinsic + c_load); | |
| this_delay = horowitz(inrisetime_nand3_path, tf, 0.5, 0.5, RISE); | |
| delay_nand3_path += this_delay; | |
| inrisetime_nand3_path = this_delay / (1.0 - 0.5); | |
| power_nand3_path.readOp.dynamic += (c_intrinsic + c_load) * Vdd * Vdd; | |
| } | |
| //Add delay of the last inverter | |
| i = number_gates_L1_nand3_path - 1; | |
| rd = tr_R_on(w_L1_nand3_n[i], NCH, 1, is_dram_); | |
| if (flag_L2_gate) { | |
| c_load = branch_effort_nand3_gate_output * | |
| (gate_C(w_L2_n[0], 0, is_dram_) + gate_C(w_L2_p[0], 0, | |
| is_dram_)); | |
| c_intrinsic = drain_C_(w_L1_nand3_p[i], PCH, 1, 1, g_tp.cell_h_def, is_dram_) + | |
| drain_C_(w_L1_nand3_n[i], NCH, 1, 1, g_tp.cell_h_def, is_dram_); | |
| tf = rd * (c_intrinsic + c_load); | |
| this_delay = horowitz(inrisetime_nand3_path, tf, 0.5, 0.5, RISE); | |
| delay_nand3_path += this_delay; | |
| inrisetime_nand3_path = this_delay / (1.0 - 0.5); | |
| power_nand3_path.readOp.dynamic += (c_intrinsic + c_load) * Vdd * Vdd; | |
| } else { //First level directly drives decoder output load | |
| c_load = C_ld_predec_blk_out; | |
| c_intrinsic = drain_C_(w_L1_nand3_p[i], PCH, 1, 1, g_tp.cell_h_def, is_dram_) + | |
| drain_C_(w_L1_nand3_n[i], NCH, 1, 1, g_tp.cell_h_def, is_dram_); | |
| tf = rd * (c_intrinsic + c_load) + R_wire_predec_blk_out * c_load / 2; | |
| this_delay = horowitz(inrisetime_nand3_path, tf, 0.5, 0.5, RISE); | |
| delay_nand3_path += this_delay; | |
| ret_val.second = this_delay / (1.0 - 0.5); | |
| power_nand3_path.readOp.dynamic += (c_intrinsic + c_load) * Vdd * Vdd; | |
| } | |
| } | |
| // Find delay through second level | |
| if (flag_L2_gate) { | |
| if (flag_L2_gate == 2) { | |
| rd = tr_R_on(w_L2_n[0], NCH, 2, is_dram_); | |
| c_load = gate_C(w_L2_n[1] + w_L2_p[1], 0.0, is_dram_); | |
| c_intrinsic = 2 * drain_C_(w_L2_p[0], PCH, 1, 1, g_tp.cell_h_def, is_dram_) + | |
| drain_C_(w_L2_n[0], NCH, 2, 1, g_tp.cell_h_def, is_dram_); | |
| tf = rd * (c_intrinsic + c_load); | |
| this_delay = horowitz(inrisetime_nand2_path, tf, 0.5, 0.5, RISE); | |
| delay_nand2_path += this_delay; | |
| inrisetime_nand2_path = this_delay / (1.0 - 0.5); | |
| power_L2.readOp.dynamic += (c_intrinsic + c_load) * Vdd * Vdd; | |
| } else { // flag_L2_gate = 3 | |
| rd = tr_R_on(w_L2_n[0], NCH, 3, is_dram_); | |
| c_load = gate_C(w_L2_n[1] + w_L2_p[1], 0.0, is_dram_); | |
| c_intrinsic = 3 * drain_C_(w_L2_p[0], PCH, 1, 1, g_tp.cell_h_def, is_dram_) + | |
| drain_C_(w_L2_n[0], NCH, 3, 1, g_tp.cell_h_def, is_dram_); | |
| tf = rd * (c_intrinsic + c_load); | |
| this_delay = horowitz(inrisetime_nand3_path, tf, 0.5, 0.5, RISE); | |
| delay_nand3_path += this_delay; | |
| inrisetime_nand3_path = this_delay / (1.0 - 0.5); | |
| power_L2.readOp.dynamic += (c_intrinsic + c_load) * Vdd * Vdd; | |
| } | |
| for (i = 1; i < number_gates_L2 - 1; ++i) { | |
| rd = tr_R_on(w_L2_n[i], NCH, 1, is_dram_); | |
| c_load = gate_C(w_L2_n[i+1] + w_L2_p[i+1], 0.0, is_dram_); | |
| c_intrinsic = drain_C_(w_L2_p[i], PCH, 1, 1, g_tp.cell_h_def, is_dram_) + | |
| drain_C_(w_L2_n[i], NCH, 1, 1, g_tp.cell_h_def, is_dram_); | |
| tf = rd * (c_intrinsic + c_load); | |
| this_delay = horowitz(inrisetime_nand2_path, tf, 0.5, 0.5, RISE); | |
| delay_nand2_path += this_delay; | |
| inrisetime_nand2_path = this_delay / (1.0 - 0.5); | |
| this_delay = horowitz(inrisetime_nand3_path, tf, 0.5, 0.5, RISE); | |
| delay_nand3_path += this_delay; | |
| inrisetime_nand3_path = this_delay / (1.0 - 0.5); | |
| power_L2.readOp.dynamic += (c_intrinsic + c_load) * Vdd * Vdd; | |
| } | |
| //Add delay of final inverter that drives the wordline decoders | |
| i = number_gates_L2 - 1; | |
| c_load = C_ld_predec_blk_out; | |
| rd = tr_R_on(w_L2_n[i], NCH, 1, is_dram_); | |
| c_intrinsic = drain_C_(w_L2_p[i], PCH, 1, 1, g_tp.cell_h_def, is_dram_) + | |
| drain_C_(w_L2_n[i], NCH, 1, 1, g_tp.cell_h_def, is_dram_); | |
| tf = rd * (c_intrinsic + c_load) + R_wire_predec_blk_out * c_load / 2; | |
| this_delay = horowitz(inrisetime_nand2_path, tf, 0.5, 0.5, RISE); | |
| delay_nand2_path += this_delay; | |
| ret_val.first = this_delay / (1.0 - 0.5); | |
| this_delay = horowitz(inrisetime_nand3_path, tf, 0.5, 0.5, RISE); | |
| delay_nand3_path += this_delay; | |
| ret_val.second = this_delay / (1.0 - 0.5); | |
| power_L2.readOp.dynamic += (c_intrinsic + c_load) * Vdd * Vdd; | |
| } | |
| } | |
| delay = (ret_val.first > ret_val.second) ? ret_val.first : ret_val.second; | |
| return ret_val; | |
| } | |
| void PredecBlk::leakage_feedback(double temperature) | |
| { | |
| if (exist) | |
| { // First check whether a predecoder block is needed | |
| int num_L1_nand2 = 0; | |
| int num_L1_nand3 = 0; | |
| int num_L2 = 0; | |
| double leak_L1_nand3 =0; | |
| double gate_leak_L1_nand3 =0; | |
| double leak_L1_nand2 = cmos_Isub_leakage(w_L1_nand2_n[0], w_L1_nand2_p[0], 2, nand, is_dram_); | |
| double gate_leak_L1_nand2 = cmos_Ig_leakage(w_L1_nand2_n[0], w_L1_nand2_p[0], 2, nand, is_dram_); | |
| if (number_inputs_L1_gate != 3) { | |
| leak_L1_nand3 = 0; | |
| gate_leak_L1_nand3 =0; | |
| } | |
| else { | |
| leak_L1_nand3 = cmos_Isub_leakage(w_L1_nand3_n[0], w_L1_nand3_p[0], 3, nand); | |
| gate_leak_L1_nand3 = cmos_Ig_leakage(w_L1_nand3_n[0], w_L1_nand3_p[0], 3, nand); | |
| } | |
| switch (number_input_addr_bits) | |
| { | |
| case 1: //2 NAND2 gates | |
| num_L1_nand2 = 2; | |
| num_L2 = 0; | |
| num_L1_active_nand2_path =1; | |
| num_L1_active_nand3_path =0; | |
| break; | |
| case 2: //4 NAND2 gates | |
| num_L1_nand2 = 4; | |
| num_L2 = 0; | |
| num_L1_active_nand2_path =1; | |
| num_L1_active_nand3_path =0; | |
| break; | |
| case 3: //8 NAND3 gates | |
| num_L1_nand3 = 8; | |
| num_L2 = 0; | |
| num_L1_active_nand2_path =0; | |
| num_L1_active_nand3_path =1; | |
| break; | |
| case 4: //4 + 4 NAND2 gates | |
| num_L1_nand2 = 8; | |
| num_L2 = 16; | |
| num_L1_active_nand2_path =2; | |
| num_L1_active_nand3_path =0; | |
| break; | |
| case 5: //4 NAND2 gates, 8 NAND3 gates | |
| num_L1_nand2 = 4; | |
| num_L1_nand3 = 8; | |
| num_L2 = 32; | |
| num_L1_active_nand2_path =1; | |
| num_L1_active_nand3_path =1; | |
| break; | |
| case 6: //8 + 8 NAND3 gates | |
| num_L1_nand3 = 16; | |
| num_L2 = 64; | |
| num_L1_active_nand2_path =0; | |
| num_L1_active_nand3_path =2; | |
| break; | |
| case 7: //4 + 4 NAND2 gates, 8 NAND3 gates | |
| num_L1_nand2 = 8; | |
| num_L1_nand3 = 8; | |
| num_L2 = 128; | |
| num_L1_active_nand2_path =2; | |
| num_L1_active_nand3_path =1; | |
| break; | |
| case 8: //4 NAND2 gates, 8 + 8 NAND3 gates | |
| num_L1_nand2 = 4; | |
| num_L1_nand3 = 16; | |
| num_L2 = 256; | |
| num_L1_active_nand2_path =2; | |
| num_L1_active_nand3_path =2; | |
| break; | |
| case 9: //8 + 8 + 8 NAND3 gates | |
| num_L1_nand3 = 24; | |
| num_L2 = 512; | |
| num_L1_active_nand2_path =0; | |
| num_L1_active_nand3_path =3; | |
| break; | |
| default: | |
| break; | |
| } | |
| for (int i = 1; i < number_gates_L1_nand2_path; ++i) | |
| { | |
| leak_L1_nand2 += cmos_Isub_leakage(w_L1_nand2_n[i], w_L1_nand2_p[i], 2, nand, is_dram_); | |
| gate_leak_L1_nand2 += cmos_Ig_leakage(w_L1_nand2_n[i], w_L1_nand2_p[i], 2, nand, is_dram_); | |
| } | |
| leak_L1_nand2 *= num_L1_nand2; | |
| gate_leak_L1_nand2 *= num_L1_nand2; | |
| for (int i = 1; i < number_gates_L1_nand3_path; ++i) | |
| { | |
| leak_L1_nand3 += cmos_Isub_leakage(w_L1_nand3_n[i], w_L1_nand3_p[i], 3, nand, is_dram_); | |
| gate_leak_L1_nand3 += cmos_Ig_leakage(w_L1_nand3_n[i], w_L1_nand3_p[i], 3, nand, is_dram_); | |
| } | |
| leak_L1_nand3 *= num_L1_nand3; | |
| gate_leak_L1_nand3 *= num_L1_nand3; | |
| double leakage_L2 = 0.0; | |
| double gate_leakage_L2 = 0.0; | |
| if (flag_L2_gate == 2) | |
| { | |
| leakage_L2 = cmos_Isub_leakage(w_L2_n[0], w_L2_p[0], 2, nand, is_dram_); | |
| gate_leakage_L2 = cmos_Ig_leakage(w_L2_n[0], w_L2_p[0], 2, nand, is_dram_); | |
| } | |
| else if (flag_L2_gate == 3) | |
| { | |
| leakage_L2 = cmos_Isub_leakage(w_L2_n[0], w_L2_p[0], 3, nand, is_dram_); | |
| gate_leakage_L2 = cmos_Ig_leakage(w_L2_n[0], w_L2_p[0], 3, nand, is_dram_); | |
| } | |
| for (int i = 1; i < number_gates_L2; ++i) | |
| { | |
| leakage_L2 += cmos_Isub_leakage(w_L2_n[i], w_L2_p[i], 2, inv, is_dram_); | |
| gate_leakage_L2 += cmos_Ig_leakage(w_L2_n[i], w_L2_p[i], 2, inv, is_dram_); | |
| } | |
| leakage_L2 *= num_L2; | |
| gate_leakage_L2 *= num_L2; | |
| power_nand2_path.readOp.leakage = leak_L1_nand2 * g_tp.peri_global.Vdd; | |
| power_nand3_path.readOp.leakage = leak_L1_nand3 * g_tp.peri_global.Vdd; | |
| power_L2.readOp.leakage = leakage_L2 * g_tp.peri_global.Vdd; | |
| power_nand2_path.readOp.gate_leakage = gate_leak_L1_nand2 * g_tp.peri_global.Vdd; | |
| power_nand3_path.readOp.gate_leakage = gate_leak_L1_nand3 * g_tp.peri_global.Vdd; | |
| power_L2.readOp.gate_leakage = gate_leakage_L2 * g_tp.peri_global.Vdd; | |
| } | |
| } | |
| PredecBlkDrv::PredecBlkDrv( | |
| int way_select_, | |
| PredecBlk * blk_, | |
| bool is_dram) | |
| : flag_driver_exists(0), | |
| number_gates_nand2_path(0), | |
| number_gates_nand3_path(0), | |
| min_number_gates(2), | |
| num_buffers_driving_1_nand2_load(0), | |
| num_buffers_driving_2_nand2_load(0), | |
| num_buffers_driving_4_nand2_load(0), | |
| num_buffers_driving_2_nand3_load(0), | |
| num_buffers_driving_8_nand3_load(0), | |
| num_buffers_nand3_path(0), | |
| c_load_nand2_path_out(0), | |
| c_load_nand3_path_out(0), | |
| r_load_nand2_path_out(0), | |
| r_load_nand3_path_out(0), | |
| delay_nand2_path(0), | |
| delay_nand3_path(0), | |
| power_nand2_path(), | |
| power_nand3_path(), | |
| blk(blk_), dec(blk->dec), | |
| is_dram_(is_dram), | |
| way_select(way_select_) { | |
| for (int i = 0; i < MAX_NUMBER_GATES_STAGE; i++) { | |
| width_nand2_path_n[i] = 0; | |
| width_nand2_path_p[i] = 0; | |
| width_nand3_path_n[i] = 0; | |
| width_nand3_path_p[i] = 0; | |
| } | |
| number_input_addr_bits = blk->number_input_addr_bits; | |
| if (way_select > 1) { | |
| flag_driver_exists = 1; | |
| number_input_addr_bits = way_select; | |
| if (dec->num_in_signals == 2) { | |
| c_load_nand2_path_out = gate_C(dec->w_dec_n[0] + dec->w_dec_p[0], 0, is_dram_); | |
| num_buffers_driving_2_nand2_load = number_input_addr_bits; | |
| } else if (dec->num_in_signals == 3) { | |
| c_load_nand3_path_out = gate_C(dec->w_dec_n[0] + dec->w_dec_p[0], 0, is_dram_); | |
| num_buffers_driving_2_nand3_load = number_input_addr_bits; | |
| } | |
| } else if (way_select == 0) { | |
| if (blk->exist) { | |
| flag_driver_exists = 1; | |
| } | |
| } | |
| compute_widths(); | |
| compute_area(); | |
| } | |
| void PredecBlkDrv::compute_widths() { | |
| // The predecode block driver accepts as input the address bits from the h-tree network. For | |
| // each addr bit it then generates addr and addrbar as outputs. For now ignore the effect of | |
| // inversion to generate addrbar and simply treat addrbar as addr. | |
| double F; | |
| double p_to_n_sz_ratio = pmos_to_nmos_sz_ratio(is_dram_); | |
| if (flag_driver_exists) { | |
| double C_nand2_gate_blk = gate_C(blk->w_L1_nand2_n[0] + blk->w_L1_nand2_p[0], 0, is_dram_); | |
| double C_nand3_gate_blk = gate_C(blk->w_L1_nand3_n[0] + blk->w_L1_nand3_p[0], 0, is_dram_); | |
| if (way_select == 0) { | |
| if (blk->number_input_addr_bits == 1) { | |
| //2 NAND2 gates | |
| num_buffers_driving_2_nand2_load = 1; | |
| c_load_nand2_path_out = 2 * C_nand2_gate_blk; | |
| } else if (blk->number_input_addr_bits == 2) { | |
| //4 NAND2 gates one 2-4 decoder | |
| num_buffers_driving_4_nand2_load = 2; | |
| c_load_nand2_path_out = 4 * C_nand2_gate_blk; | |
| } else if (blk->number_input_addr_bits == 3) { | |
| //8 NAND3 gates one 3-8 decoder | |
| num_buffers_driving_8_nand3_load = 3; | |
| c_load_nand3_path_out = 8 * C_nand3_gate_blk; | |
| } else if (blk->number_input_addr_bits == 4) { | |
| //4 + 4 NAND2 gates two 2-4 decoder | |
| num_buffers_driving_4_nand2_load = 4; | |
| c_load_nand2_path_out = 4 * C_nand2_gate_blk; | |
| } else if (blk->number_input_addr_bits == 5) { | |
| //4 NAND2 gates, 8 NAND3 gates one 2-4 decoder and one 3-8 | |
| //decoder | |
| num_buffers_driving_4_nand2_load = 2; | |
| num_buffers_driving_8_nand3_load = 3; | |
| c_load_nand2_path_out = 4 * C_nand2_gate_blk; | |
| c_load_nand3_path_out = 8 * C_nand3_gate_blk; | |
| } else if (blk->number_input_addr_bits == 6) { | |
| //8 + 8 NAND3 gates two 3-8 decoder | |
| num_buffers_driving_8_nand3_load = 6; | |
| c_load_nand3_path_out = 8 * C_nand3_gate_blk; | |
| } else if (blk->number_input_addr_bits == 7) { | |
| //4 + 4 NAND2 gates, 8 NAND3 gates two 2-4 decoder and one 3-8 | |
| //decoder | |
| num_buffers_driving_4_nand2_load = 4; | |
| num_buffers_driving_8_nand3_load = 3; | |
| c_load_nand2_path_out = 4 * C_nand2_gate_blk; | |
| c_load_nand3_path_out = 8 * C_nand3_gate_blk; | |
| } else if (blk->number_input_addr_bits == 8) { | |
| //4 NAND2 gates, 8 + 8 NAND3 gates one 2-4 decoder and two 3-8 | |
| //decoder | |
| num_buffers_driving_4_nand2_load = 2; | |
| num_buffers_driving_8_nand3_load = 6; | |
| c_load_nand2_path_out = 4 * C_nand2_gate_blk; | |
| c_load_nand3_path_out = 8 * C_nand3_gate_blk; | |
| } else if (blk->number_input_addr_bits == 9) { | |
| //8 + 8 + 8 NAND3 gates three 3-8 decoder | |
| num_buffers_driving_8_nand3_load = 9; | |
| c_load_nand3_path_out = 8 * C_nand3_gate_blk; | |
| } | |
| } | |
| if ((blk->flag_two_unique_paths) || | |
| (blk->number_inputs_L1_gate == 2) || | |
| (number_input_addr_bits == 0) || | |
| ((way_select) && (dec->num_in_signals == 2))) { | |
| //this means that way_select is driving NAND2 in decoder. | |
| width_nand2_path_n[0] = g_tp.min_w_nmos_; | |
| width_nand2_path_p[0] = p_to_n_sz_ratio * width_nand2_path_n[0]; | |
| F = c_load_nand2_path_out / gate_C(width_nand2_path_n[0] + width_nand2_path_p[0], 0, is_dram_); | |
| number_gates_nand2_path = logical_effort( | |
| min_number_gates, | |
| 1, | |
| F, | |
| width_nand2_path_n, | |
| width_nand2_path_p, | |
| c_load_nand2_path_out, | |
| p_to_n_sz_ratio, | |
| is_dram_, false, g_tp.max_w_nmos_); | |
| } | |
| if ((blk->flag_two_unique_paths) || | |
| (blk->number_inputs_L1_gate == 3) || | |
| ((way_select) && (dec->num_in_signals == 3))) { | |
| //this means that way_select is driving NAND3 in decoder. | |
| width_nand3_path_n[0] = g_tp.min_w_nmos_; | |
| width_nand3_path_p[0] = p_to_n_sz_ratio * width_nand3_path_n[0]; | |
| F = c_load_nand3_path_out / gate_C(width_nand3_path_n[0] + width_nand3_path_p[0], 0, is_dram_); | |
| number_gates_nand3_path = logical_effort( | |
| min_number_gates, | |
| 1, | |
| F, | |
| width_nand3_path_n, | |
| width_nand3_path_p, | |
| c_load_nand3_path_out, | |
| p_to_n_sz_ratio, | |
| is_dram_, false, g_tp.max_w_nmos_); | |
| } | |
| } | |
| } | |
| void PredecBlkDrv::compute_area() { | |
| double area_nand2_path = 0; | |
| double area_nand3_path = 0; | |
| double leak_nand2_path = 0; | |
| double leak_nand3_path = 0; | |
| double gate_leak_nand2_path = 0; | |
| double gate_leak_nand3_path = 0; | |
| if (flag_driver_exists) { | |
| // first check whether a predecoder block driver is needed | |
| for (int i = 0; i < number_gates_nand2_path; ++i) { | |
| area_nand2_path += | |
| compute_gate_area(INV, 1, width_nand2_path_p[i], | |
| width_nand2_path_n[i], g_tp.cell_h_def); | |
| leak_nand2_path += | |
| cmos_Isub_leakage(width_nand2_path_n[i], width_nand2_path_p[i], | |
| 1, inv, is_dram_); | |
| gate_leak_nand2_path += | |
| cmos_Ig_leakage(width_nand2_path_n[i], width_nand2_path_p[i], | |
| 1, inv, is_dram_); | |
| } | |
| area_nand2_path *= (num_buffers_driving_1_nand2_load + | |
| num_buffers_driving_2_nand2_load + | |
| num_buffers_driving_4_nand2_load); | |
| leak_nand2_path *= (num_buffers_driving_1_nand2_load + | |
| num_buffers_driving_2_nand2_load + | |
| num_buffers_driving_4_nand2_load); | |
| gate_leak_nand2_path *= (num_buffers_driving_1_nand2_load + | |
| num_buffers_driving_2_nand2_load + | |
| num_buffers_driving_4_nand2_load); | |
| for (int i = 0; i < number_gates_nand3_path; ++i) { | |
| area_nand3_path += | |
| compute_gate_area(INV, 1, width_nand3_path_p[i], | |
| width_nand3_path_n[i], g_tp.cell_h_def); | |
| leak_nand3_path += | |
| cmos_Isub_leakage(width_nand3_path_n[i], width_nand3_path_p[i], | |
| 1, inv, is_dram_); | |
| gate_leak_nand3_path += | |
| cmos_Ig_leakage(width_nand3_path_n[i], width_nand3_path_p[i], | |
| 1, inv, is_dram_); | |
| } | |
| area_nand3_path *= (num_buffers_driving_2_nand3_load + num_buffers_driving_8_nand3_load); | |
| leak_nand3_path *= (num_buffers_driving_2_nand3_load + num_buffers_driving_8_nand3_load); | |
| gate_leak_nand3_path *= (num_buffers_driving_2_nand3_load + num_buffers_driving_8_nand3_load); | |
| power_nand2_path.readOp.leakage = leak_nand2_path * g_tp.peri_global.Vdd; | |
| power_nand3_path.readOp.leakage = leak_nand3_path * g_tp.peri_global.Vdd; | |
| power_nand2_path.readOp.gate_leakage = gate_leak_nand2_path * g_tp.peri_global.Vdd; | |
| power_nand3_path.readOp.gate_leakage = gate_leak_nand3_path * g_tp.peri_global.Vdd; | |
| area.set_area(area_nand2_path + area_nand3_path); | |
| } | |
| } | |
| pair<double, double> PredecBlkDrv::compute_delays( | |
| double inrisetime_nand2_path, | |
| double inrisetime_nand3_path) { | |
| pair<double, double> ret_val; | |
| ret_val.first = 0; // outrisetime_nand2_path | |
| ret_val.second = 0; // outrisetime_nand3_path | |
| int i; | |
| double rd, c_gate_load, c_load, c_intrinsic, tf, this_delay; | |
| double Vdd = g_tp.peri_global.Vdd; | |
| if (flag_driver_exists) { | |
| for (i = 0; i < number_gates_nand2_path - 1; ++i) { | |
| rd = tr_R_on(width_nand2_path_n[i], NCH, 1, is_dram_); | |
| c_gate_load = gate_C(width_nand2_path_p[i+1] + width_nand2_path_n[i+1], 0.0, is_dram_); | |
| c_intrinsic = drain_C_(width_nand2_path_p[i], PCH, 1, 1, g_tp.cell_h_def, is_dram_) + | |
| drain_C_(width_nand2_path_n[i], NCH, 1, 1, g_tp.cell_h_def, is_dram_); | |
| tf = rd * (c_intrinsic + c_gate_load); | |
| this_delay = horowitz(inrisetime_nand2_path, tf, 0.5, 0.5, RISE); | |
| delay_nand2_path += this_delay; | |
| inrisetime_nand2_path = this_delay / (1.0 - 0.5); | |
| power_nand2_path.readOp.dynamic += (c_gate_load + c_intrinsic) * 0.5 * Vdd * Vdd; | |
| } | |
| // Final inverter drives the predecoder block or the decoder output load | |
| if (number_gates_nand2_path != 0) { | |
| i = number_gates_nand2_path - 1; | |
| rd = tr_R_on(width_nand2_path_n[i], NCH, 1, is_dram_); | |
| c_intrinsic = drain_C_(width_nand2_path_p[i], PCH, 1, 1, g_tp.cell_h_def, is_dram_) + | |
| drain_C_(width_nand2_path_n[i], NCH, 1, 1, g_tp.cell_h_def, is_dram_); | |
| c_load = c_load_nand2_path_out; | |
| tf = rd * (c_intrinsic + c_load) + r_load_nand2_path_out * c_load / 2; | |
| this_delay = horowitz(inrisetime_nand2_path, tf, 0.5, 0.5, RISE); | |
| delay_nand2_path += this_delay; | |
| ret_val.first = this_delay / (1.0 - 0.5); | |
| power_nand2_path.readOp.dynamic += (c_intrinsic + c_load) * 0.5 * Vdd * Vdd; | |
| // cout<< "c_intrinsic = " << c_intrinsic << "c_load" << c_load <<endl; | |
| } | |
| for (i = 0; i < number_gates_nand3_path - 1; ++i) { | |
| rd = tr_R_on(width_nand3_path_n[i], NCH, 1, is_dram_); | |
| c_gate_load = gate_C(width_nand3_path_p[i+1] + width_nand3_path_n[i+1], 0.0, is_dram_); | |
| c_intrinsic = drain_C_(width_nand3_path_p[i], PCH, 1, 1, g_tp.cell_h_def, is_dram_) + | |
| drain_C_(width_nand3_path_n[i], NCH, 1, 1, g_tp.cell_h_def, is_dram_); | |
| tf = rd * (c_intrinsic + c_gate_load); | |
| this_delay = horowitz(inrisetime_nand3_path, tf, 0.5, 0.5, RISE); | |
| delay_nand3_path += this_delay; | |
| inrisetime_nand3_path = this_delay / (1.0 - 0.5); | |
| power_nand3_path.readOp.dynamic += (c_gate_load + c_intrinsic) * 0.5 * Vdd * Vdd; | |
| } | |
| // Final inverter drives the predecoder block or the decoder output load | |
| if (number_gates_nand3_path != 0) { | |
| i = number_gates_nand3_path - 1; | |
| rd = tr_R_on(width_nand3_path_n[i], NCH, 1, is_dram_); | |
| c_intrinsic = drain_C_(width_nand3_path_p[i], PCH, 1, 1, g_tp.cell_h_def, is_dram_) + | |
| drain_C_(width_nand3_path_n[i], NCH, 1, 1, g_tp.cell_h_def, is_dram_); | |
| c_load = c_load_nand3_path_out; | |
| tf = rd * (c_intrinsic + c_load) + r_load_nand3_path_out * c_load / 2; | |
| this_delay = horowitz(inrisetime_nand3_path, tf, 0.5, 0.5, RISE); | |
| delay_nand3_path += this_delay; | |
| ret_val.second = this_delay / (1.0 - 0.5); | |
| power_nand3_path.readOp.dynamic += (c_intrinsic + c_load) * 0.5 * Vdd * Vdd; | |
| } | |
| } | |
| return ret_val; | |
| } | |
| double PredecBlkDrv::get_rdOp_dynamic_E(int num_act_mats_hor_dir) { | |
| return (num_addr_bits_nand2_path()*power_nand2_path.readOp.dynamic + | |
| num_addr_bits_nand3_path()*power_nand3_path.readOp.dynamic) * num_act_mats_hor_dir; | |
| } | |
| Predec::Predec( | |
| PredecBlkDrv * drv1_, | |
| PredecBlkDrv * drv2_) | |
| : blk1(drv1_->blk), blk2(drv2_->blk), drv1(drv1_), drv2(drv2_) { | |
| driver_power.readOp.leakage = drv1->power_nand2_path.readOp.leakage + | |
| drv1->power_nand3_path.readOp.leakage + | |
| drv2->power_nand2_path.readOp.leakage + | |
| drv2->power_nand3_path.readOp.leakage; | |
| block_power.readOp.leakage = blk1->power_nand2_path.readOp.leakage + | |
| blk1->power_nand3_path.readOp.leakage + | |
| blk1->power_L2.readOp.leakage + | |
| blk2->power_nand2_path.readOp.leakage + | |
| blk2->power_nand3_path.readOp.leakage + | |
| blk2->power_L2.readOp.leakage; | |
| power.readOp.leakage = driver_power.readOp.leakage + block_power.readOp.leakage; | |
| driver_power.readOp.gate_leakage = drv1->power_nand2_path.readOp.gate_leakage + | |
| drv1->power_nand3_path.readOp.gate_leakage + | |
| drv2->power_nand2_path.readOp.gate_leakage + | |
| drv2->power_nand3_path.readOp.gate_leakage; | |
| block_power.readOp.gate_leakage = blk1->power_nand2_path.readOp.gate_leakage + | |
| blk1->power_nand3_path.readOp.gate_leakage + | |
| blk1->power_L2.readOp.gate_leakage + | |
| blk2->power_nand2_path.readOp.gate_leakage + | |
| blk2->power_nand3_path.readOp.gate_leakage + | |
| blk2->power_L2.readOp.gate_leakage; | |
| power.readOp.gate_leakage = driver_power.readOp.gate_leakage + block_power.readOp.gate_leakage; | |
| } | |
| void PredecBlkDrv::leakage_feedback(double temperature) | |
| { | |
| double leak_nand2_path = 0; | |
| double leak_nand3_path = 0; | |
| double gate_leak_nand2_path = 0; | |
| double gate_leak_nand3_path = 0; | |
| if (flag_driver_exists) | |
| { // first check whether a predecoder block driver is needed | |
| for (int i = 0; i < number_gates_nand2_path; ++i) | |
| { | |
| leak_nand2_path += cmos_Isub_leakage(width_nand2_path_n[i], width_nand2_path_p[i], 1, inv,is_dram_); | |
| gate_leak_nand2_path += cmos_Ig_leakage(width_nand2_path_n[i], width_nand2_path_p[i], 1, inv,is_dram_); | |
| } | |
| leak_nand2_path *= (num_buffers_driving_1_nand2_load + | |
| num_buffers_driving_2_nand2_load + | |
| num_buffers_driving_4_nand2_load); | |
| gate_leak_nand2_path *= (num_buffers_driving_1_nand2_load + | |
| num_buffers_driving_2_nand2_load + | |
| num_buffers_driving_4_nand2_load); | |
| for (int i = 0; i < number_gates_nand3_path; ++i) | |
| { | |
| leak_nand3_path += cmos_Isub_leakage(width_nand3_path_n[i], width_nand3_path_p[i], 1, inv,is_dram_); | |
| gate_leak_nand3_path += cmos_Ig_leakage(width_nand3_path_n[i], width_nand3_path_p[i], 1, inv,is_dram_); | |
| } | |
| leak_nand3_path *= (num_buffers_driving_2_nand3_load + num_buffers_driving_8_nand3_load); | |
| gate_leak_nand3_path *= (num_buffers_driving_2_nand3_load + num_buffers_driving_8_nand3_load); | |
| power_nand2_path.readOp.leakage = leak_nand2_path * g_tp.peri_global.Vdd; | |
| power_nand3_path.readOp.leakage = leak_nand3_path * g_tp.peri_global.Vdd; | |
| power_nand2_path.readOp.gate_leakage = gate_leak_nand2_path * g_tp.peri_global.Vdd; | |
| power_nand3_path.readOp.gate_leakage = gate_leak_nand3_path * g_tp.peri_global.Vdd; | |
| } | |
| } | |
| double Predec::compute_delays(double inrisetime) { | |
| // TODO: Jung Ho thinks that predecoder block driver locates between decoder and predecoder block. | |
| pair<double, double> tmp_pair1, tmp_pair2; | |
| tmp_pair1 = drv1->compute_delays(inrisetime, inrisetime); | |
| tmp_pair1 = blk1->compute_delays(tmp_pair1); | |
| tmp_pair2 = drv2->compute_delays(inrisetime, inrisetime); | |
| tmp_pair2 = blk2->compute_delays(tmp_pair2); | |
| tmp_pair1 = get_max_delay_before_decoder(tmp_pair1, tmp_pair2); | |
| driver_power.readOp.dynamic = | |
| drv1->num_addr_bits_nand2_path() * drv1->power_nand2_path.readOp.dynamic + | |
| drv1->num_addr_bits_nand3_path() * drv1->power_nand3_path.readOp.dynamic + | |
| drv2->num_addr_bits_nand2_path() * drv2->power_nand2_path.readOp.dynamic + | |
| drv2->num_addr_bits_nand3_path() * drv2->power_nand3_path.readOp.dynamic; | |
| block_power.readOp.dynamic = | |
| blk1->power_nand2_path.readOp.dynamic * blk1->num_L1_active_nand2_path + | |
| blk1->power_nand3_path.readOp.dynamic * blk1->num_L1_active_nand3_path + | |
| blk1->power_L2.readOp.dynamic + | |
| blk2->power_nand2_path.readOp.dynamic * blk1->num_L1_active_nand2_path + | |
| blk2->power_nand3_path.readOp.dynamic * blk1->num_L1_active_nand3_path + | |
| blk2->power_L2.readOp.dynamic; | |
| power.readOp.dynamic = driver_power.readOp.dynamic + block_power.readOp.dynamic; | |
| delay = tmp_pair1.first; | |
| return tmp_pair1.second; | |
| } | |
| void Predec::leakage_feedback(double temperature) | |
| { | |
| drv1->leakage_feedback(temperature); | |
| drv2->leakage_feedback(temperature); | |
| blk1->leakage_feedback(temperature); | |
| blk2->leakage_feedback(temperature); | |
| driver_power.readOp.leakage = drv1->power_nand2_path.readOp.leakage + | |
| drv1->power_nand3_path.readOp.leakage + | |
| drv2->power_nand2_path.readOp.leakage + | |
| drv2->power_nand3_path.readOp.leakage; | |
| block_power.readOp.leakage = blk1->power_nand2_path.readOp.leakage + | |
| blk1->power_nand3_path.readOp.leakage + | |
| blk1->power_L2.readOp.leakage + | |
| blk2->power_nand2_path.readOp.leakage + | |
| blk2->power_nand3_path.readOp.leakage + | |
| blk2->power_L2.readOp.leakage; | |
| power.readOp.leakage = driver_power.readOp.leakage + block_power.readOp.leakage; | |
| driver_power.readOp.gate_leakage = drv1->power_nand2_path.readOp.gate_leakage + | |
| drv1->power_nand3_path.readOp.gate_leakage + | |
| drv2->power_nand2_path.readOp.gate_leakage + | |
| drv2->power_nand3_path.readOp.gate_leakage; | |
| block_power.readOp.gate_leakage = blk1->power_nand2_path.readOp.gate_leakage + | |
| blk1->power_nand3_path.readOp.gate_leakage + | |
| blk1->power_L2.readOp.gate_leakage + | |
| blk2->power_nand2_path.readOp.gate_leakage + | |
| blk2->power_nand3_path.readOp.gate_leakage + | |
| blk2->power_L2.readOp.gate_leakage; | |
| power.readOp.gate_leakage = driver_power.readOp.gate_leakage + block_power.readOp.gate_leakage; | |
| } | |
| // returns <delay, risetime> | |
| pair<double, double> Predec::get_max_delay_before_decoder( | |
| pair<double, double> input_pair1, | |
| pair<double, double> input_pair2) { | |
| pair<double, double> ret_val; | |
| double delay; | |
| delay = drv1->delay_nand2_path + blk1->delay_nand2_path; | |
| ret_val.first = delay; | |
| ret_val.second = input_pair1.first; | |
| delay = drv1->delay_nand3_path + blk1->delay_nand3_path; | |
| if (ret_val.first < delay) { | |
| ret_val.first = delay; | |
| ret_val.second = input_pair1.second; | |
| } | |
| delay = drv2->delay_nand2_path + blk2->delay_nand2_path; | |
| if (ret_val.first < delay) { | |
| ret_val.first = delay; | |
| ret_val.second = input_pair2.first; | |
| } | |
| delay = drv2->delay_nand3_path + blk2->delay_nand3_path; | |
| if (ret_val.first < delay) { | |
| ret_val.first = delay; | |
| ret_val.second = input_pair2.second; | |
| } | |
| return ret_val; | |
| } | |
| Driver::Driver(double c_gate_load_, double c_wire_load_, double r_wire_load_, | |
| bool is_dram) | |
| : number_gates(0), | |
| min_number_gates(2), | |
| c_gate_load(c_gate_load_), | |
| c_wire_load(c_wire_load_), | |
| r_wire_load(r_wire_load_), | |
| delay(0), | |
| power(), | |
| is_dram_(is_dram) { | |
| for (int i = 0; i < MAX_NUMBER_GATES_STAGE; i++) { | |
| width_n[i] = 0; | |
| width_p[i] = 0; | |
| } | |
| compute_widths(); | |
| } | |
| void Driver::compute_widths() { | |
| double p_to_n_sz_ratio = pmos_to_nmos_sz_ratio(is_dram_); | |
| double c_load = c_gate_load + c_wire_load; | |
| width_n[0] = g_tp.min_w_nmos_; | |
| width_p[0] = p_to_n_sz_ratio * g_tp.min_w_nmos_; | |
| double F = c_load / gate_C(width_n[0] + width_p[0], 0, is_dram_); | |
| number_gates = logical_effort( | |
| min_number_gates, | |
| 1, | |
| F, | |
| width_n, | |
| width_p, | |
| c_load, | |
| p_to_n_sz_ratio, | |
| is_dram_, false, | |
| g_tp.max_w_nmos_); | |
| } | |
| double Driver::compute_delay(double inrisetime) { | |
| int i; | |
| double rd, c_load, c_intrinsic, tf; | |
| double this_delay = 0; | |
| for (i = 0; i < number_gates - 1; ++i) { | |
| rd = tr_R_on(width_n[i], NCH, 1, is_dram_); | |
| c_load = gate_C(width_n[i+1] + width_p[i+1], 0.0, is_dram_); | |
| c_intrinsic = drain_C_(width_p[i], PCH, 1, 1, g_tp.cell_h_def, is_dram_) + | |
| drain_C_(width_n[i], NCH, 1, 1, g_tp.cell_h_def, is_dram_); | |
| tf = rd * (c_intrinsic + c_load); | |
| this_delay = horowitz(inrisetime, tf, 0.5, 0.5, RISE); | |
| delay += this_delay; | |
| inrisetime = this_delay / (1.0 - 0.5); | |
| power.readOp.dynamic += (c_intrinsic + c_load) * g_tp.peri_global.Vdd * | |
| g_tp.peri_global.Vdd; | |
| power.readOp.leakage += | |
| cmos_Isub_leakage(width_n[i], width_p[i], 1, inv, is_dram_) * | |
| g_tp.peri_global.Vdd; | |
| power.readOp.gate_leakage += | |
| cmos_Ig_leakage(width_n[i], width_p[i], 1, inv, is_dram_) * | |
| g_tp.peri_global.Vdd; | |
| } | |
| i = number_gates - 1; | |
| c_load = c_gate_load + c_wire_load; | |
| rd = tr_R_on(width_n[i], NCH, 1, is_dram_); | |
| c_intrinsic = drain_C_(width_p[i], PCH, 1, 1, g_tp.cell_h_def, is_dram_) + | |
| drain_C_(width_n[i], NCH, 1, 1, g_tp.cell_h_def, is_dram_); | |
| tf = rd * (c_intrinsic + c_load) + r_wire_load * | |
| (c_wire_load / 2 + c_gate_load); | |
| this_delay = horowitz(inrisetime, tf, 0.5, 0.5, RISE); | |
| delay += this_delay; | |
| power.readOp.dynamic += (c_intrinsic + c_load) * g_tp.peri_global.Vdd * | |
| g_tp.peri_global.Vdd; | |
| power.readOp.leakage += | |
| cmos_Isub_leakage(width_n[i], width_p[i], 1, inv, is_dram_) * | |
| g_tp.peri_global.Vdd; | |
| power.readOp.gate_leakage += | |
| cmos_Ig_leakage(width_n[i], width_p[i], 1, inv, is_dram_) * | |
| g_tp.peri_global.Vdd; | |
| return this_delay / (1.0 - 0.5); | |
| } | |