| /***************************************************************************** |
| * 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 "bank.h" |
| #include "component.h" |
| #include "decoder.h" |
| |
| using namespace std; |
| |
| |
| |
| Component::Component() |
| : area(), power(), rt_power(), delay(0) { |
| } |
| |
| |
| |
| Component::~Component() { |
| } |
| |
| |
| |
| double Component::compute_diffusion_width(int num_stacked_in, int num_folded_tr) { |
| double w_poly = g_ip->F_sz_um; |
| double spacing_poly_to_poly = g_tp.w_poly_contact + 2 * g_tp.spacing_poly_to_contact; |
| double total_diff_w = 2 * spacing_poly_to_poly + // for both source and drain |
| num_stacked_in * w_poly + |
| (num_stacked_in - 1) * g_tp.spacing_poly_to_poly; |
| |
| if (num_folded_tr > 1) { |
| total_diff_w += (num_folded_tr - 2) * 2 * spacing_poly_to_poly + |
| (num_folded_tr - 1) * num_stacked_in * w_poly + |
| (num_folded_tr - 1) * (num_stacked_in - 1) * g_tp.spacing_poly_to_poly; |
| } |
| |
| return total_diff_w; |
| } |
| |
| |
| |
| double Component::compute_gate_area( |
| int gate_type, |
| int num_inputs, |
| double w_pmos, |
| double w_nmos, |
| double h_gate) { |
| if (w_pmos <= 0.0 || w_nmos <= 0.0) { |
| return 0.0; |
| } |
| |
| double w_folded_pmos, w_folded_nmos; |
| int num_folded_pmos, num_folded_nmos; |
| double total_ndiff_w, total_pdiff_w; |
| Area gate; |
| |
| double h_tr_region = h_gate - 2 * g_tp.HPOWERRAIL; |
| double ratio_p_to_n = w_pmos / (w_pmos + w_nmos); |
| |
| if (ratio_p_to_n >= 1 || ratio_p_to_n <= 0) { |
| return 0.0; |
| } |
| |
| w_folded_pmos = (h_tr_region - g_tp.MIN_GAP_BET_P_AND_N_DIFFS) * ratio_p_to_n; |
| w_folded_nmos = (h_tr_region - g_tp.MIN_GAP_BET_P_AND_N_DIFFS) * (1 - ratio_p_to_n); |
| assert(w_folded_pmos > 0); |
| |
| num_folded_pmos = (int) (ceil(w_pmos / w_folded_pmos)); |
| num_folded_nmos = (int) (ceil(w_nmos / w_folded_nmos)); |
| |
| switch (gate_type) { |
| case INV: |
| total_ndiff_w = compute_diffusion_width(1, num_folded_nmos); |
| total_pdiff_w = compute_diffusion_width(1, num_folded_pmos); |
| break; |
| |
| case NOR: |
| total_ndiff_w = compute_diffusion_width(1, num_inputs * num_folded_nmos); |
| total_pdiff_w = compute_diffusion_width(num_inputs, num_folded_pmos); |
| break; |
| |
| case NAND: |
| total_ndiff_w = compute_diffusion_width(num_inputs, num_folded_nmos); |
| total_pdiff_w = compute_diffusion_width(1, num_inputs * num_folded_pmos); |
| break; |
| default: |
| cout << "Unknown gate type: " << gate_type << endl; |
| exit(1); |
| } |
| |
| gate.w = MAX(total_ndiff_w, total_pdiff_w); |
| |
| if (w_folded_nmos > w_nmos) { |
| //means that the height of the gate can |
| //be made smaller than the input height specified, so calculate the height of the gate. |
| gate.h = w_nmos + w_pmos + g_tp.MIN_GAP_BET_P_AND_N_DIFFS + 2 * g_tp.HPOWERRAIL; |
| } else { |
| gate.h = h_gate; |
| } |
| return gate.get_area(); |
| } |
| |
| |
| |
| double Component::compute_tr_width_after_folding( |
| double input_width, |
| double threshold_folding_width) { |
| //This is actually the width of the cell not the width of a device. |
| //The width of a cell and the width of a device is orthogonal. |
| if (input_width <= 0) { |
| return 0; |
| } |
| |
| int num_folded_tr = (int) (ceil(input_width / threshold_folding_width)); |
| double spacing_poly_to_poly = g_tp.w_poly_contact + 2 * g_tp.spacing_poly_to_contact; |
| double width_poly = g_ip->F_sz_um; |
| double total_diff_width = num_folded_tr * width_poly + (num_folded_tr + 1) * spacing_poly_to_poly; |
| |
| return total_diff_width; |
| } |
| |
| |
| |
| double Component::height_sense_amplifier(double pitch_sense_amp) { |
| // compute the height occupied by all PMOS transistors |
| double h_pmos_tr = compute_tr_width_after_folding(g_tp.w_sense_p, pitch_sense_amp) * 2 + |
| compute_tr_width_after_folding(g_tp.w_iso, pitch_sense_amp) + |
| 2 * g_tp.MIN_GAP_BET_SAME_TYPE_DIFFS; |
| |
| // compute the height occupied by all NMOS transistors |
| double h_nmos_tr = compute_tr_width_after_folding(g_tp.w_sense_n, pitch_sense_amp) * 2 + |
| compute_tr_width_after_folding(g_tp.w_sense_en, pitch_sense_amp) + |
| 2 * g_tp.MIN_GAP_BET_SAME_TYPE_DIFFS; |
| |
| // compute total height by considering gap between the p and n diffusion areas |
| return h_pmos_tr + h_nmos_tr + g_tp.MIN_GAP_BET_P_AND_N_DIFFS; |
| } |
| |
| |
| |
| int Component::logical_effort( |
| int num_gates_min, |
| double g, |
| double F, |
| double * w_n, |
| double * w_p, |
| double C_load, |
| double p_to_n_sz_ratio, |
| bool is_dram_, |
| bool is_wl_tr_, |
| double max_w_nmos) { |
| int num_gates = (int) (log(F) / log(fopt)); |
| |
| // check if num_gates is odd. if so, add 1 to make it even |
| num_gates += (num_gates % 2) ? 1 : 0; |
| num_gates = MAX(num_gates, num_gates_min); |
| |
| // recalculate the effective fanout of each stage |
| double f = pow(F, 1.0 / num_gates); |
| int i = num_gates - 1; |
| double C_in = C_load / f; |
| w_n[i] = (1.0 / (1.0 + p_to_n_sz_ratio)) * C_in / gate_C(1, 0, is_dram_, false, is_wl_tr_); |
| w_n[i] = MAX(w_n[i], g_tp.min_w_nmos_); |
| w_p[i] = p_to_n_sz_ratio * w_n[i]; |
| |
| if (w_n[i] > max_w_nmos) { |
| double C_ld = gate_C((1 + p_to_n_sz_ratio) * max_w_nmos, 0, is_dram_, false, is_wl_tr_); |
| F = g * C_ld / gate_C(w_n[0] + w_p[0], 0, is_dram_, false, is_wl_tr_); |
| num_gates = (int) (log(F) / log(fopt)) + 1; |
| num_gates += (num_gates % 2) ? 1 : 0; |
| num_gates = MAX(num_gates, num_gates_min); |
| f = pow(F, 1.0 / (num_gates - 1)); |
| i = num_gates - 1; |
| w_n[i] = max_w_nmos; |
| w_p[i] = p_to_n_sz_ratio * w_n[i]; |
| } |
| |
| for (i = num_gates - 2; i >= 1; i--) { |
| w_n[i] = MAX(w_n[i+1] / f, g_tp.min_w_nmos_); |
| w_p[i] = p_to_n_sz_ratio * w_n[i]; |
| } |
| |
| assert(num_gates <= MAX_NUMBER_GATES_STAGE); |
| return num_gates; |
| } |
| |