/* Copyright (c) 2012 Massachusetts Institute of Technology * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "tech/TechModel.h" #include #include "model/std_cells/StdCellLib.h" namespace DSENT { TechModel::TechModel() : m_std_cell_lib_(NULL), m_available_wire_layers_(NULL) {} TechModel::~TechModel() {} const String& TechModel::get(const String &key_) const { return params.at(key_); } void TechModel::setStdCellLib(const StdCellLib* std_cell_lib_) { m_std_cell_lib_ = std_cell_lib_; return; } const StdCellLib* TechModel::getStdCellLib() const { return m_std_cell_lib_; } TechModel* TechModel::clone() const { return new TechModel(*this); } void TechModel::readFile(const String& filename_) { // Read the main technology file LibUtil::readFile(filename_, params); // Search for "INCLUDE" to include more technology files for (const auto &it : params) { const String& key = it.first; if(key.compare(0, 8, "INCLUDE_") == 0) { const String& include_filename = it.second; LibUtil::readFile(include_filename, params); } } // Set the available wire layers const vector& available_wire_layer_vector = get("Wire->AvailableLayers").split("[,]"); m_available_wire_layers_ = new std::set; for(unsigned int i = 0; i < available_wire_layer_vector.size(); ++i) { m_available_wire_layers_->insert(available_wire_layer_vector[i]); } } //------------------------------------------------------------------------- // Transistor Related Functions //------------------------------------------------------------------------- //Returns the leakage current of NMOS transistors, given the transistor stakcing, transistor widths, and input combination double TechModel::calculateNmosLeakageCurrent(unsigned int num_stacks_, double uni_stacked_mos_width_, unsigned int input_vector_) const { vector stacked_mos_widths_(num_stacks_, uni_stacked_mos_width_); return calculateNmosLeakageCurrent(num_stacks_, stacked_mos_widths_, input_vector_); } //Returns the leakage current of NMOS transistors, given the transistor stakcing, transistor widths, and input combination double TechModel::calculateNmosLeakageCurrent(unsigned int num_stacks_, const vector& stacked_mos_widths_, unsigned int input_vector_) const { // Get technology parameters double vdd = get("Vdd"); double temp = get("Temperature"); double char_temp = get("Nmos->CharacterizedTemperature"); double min_off_current = get("Nmos->MinOffCurrent"); double off_current = get("Nmos->OffCurrent"); double subthreshold_swing = get("Nmos->SubthresholdSwing"); double dibl = get("Nmos->DIBL"); double temp_swing = get("Nmos->SubthresholdTempSwing"); // Map dibl to a swing value for easier calculation double dibl_swing = subthreshold_swing / dibl; //Calculate the leakage current factor double leakage_current_factor = calculateLeakageCurrentFactor(num_stacks_, stacked_mos_widths_, input_vector_, vdd, subthreshold_swing, dibl_swing); // Calcualte actual leakage current at characterized temperature double leakage_current_char_tmp = stacked_mos_widths_[0] * off_current * std::pow(10.0, leakage_current_factor); leakage_current_char_tmp = std::max(min_off_current, leakage_current_char_tmp); // Calculate actual leakage current at temp double leakage_current = leakage_current_char_tmp * std::pow(10.0, (temp - char_temp) / temp_swing); return leakage_current; } double TechModel::calculatePmosLeakageCurrent(unsigned int num_stacks_, double uni_stacked_mos_width_, unsigned int input_vector_) const { vector stacked_mos_widths_(num_stacks_, uni_stacked_mos_width_); return calculatePmosLeakageCurrent(num_stacks_, stacked_mos_widths_, input_vector_); } //Returns the leakage current of PMOS transistors, given the transistor stakcing, transistor widths, and input combination double TechModel::calculatePmosLeakageCurrent(unsigned int num_stacks_, const vector& stacked_mos_widths_, unsigned int input_vector_) const { // Get technology parameters double vdd = get("Vdd"); double temp = get("Temperature"); double char_temp = get("Pmos->CharacterizedTemperature"); double min_off_current = get("Pmos->MinOffCurrent"); double off_current = get("Pmos->OffCurrent"); double dibl = get("Pmos->DIBL"); double subthreshold_swing = get("Pmos->SubthresholdSwing"); double temp_swing = get("Nmos->SubthresholdTempSwing"); // Map dibl to a swing value for easier calculation double dibl_swing = subthreshold_swing / dibl; //Calculate the leakage current factor double leakage_current_factor = calculateLeakageCurrentFactor(num_stacks_, stacked_mos_widths_, input_vector_, vdd, subthreshold_swing, dibl_swing); // Calcualte actual leakage current at characterized temperature double leakage_current_char_tmp = stacked_mos_widths_[0] * off_current * std::pow(10.0, leakage_current_factor); leakage_current_char_tmp = std::max(min_off_current, leakage_current_char_tmp); // Calculate actual leakage current at temp double leakage_current = leakage_current_char_tmp * std::pow(10.0, (temp - char_temp) / temp_swing); return leakage_current; } //Returns the leakage current, given the transistor stakcing, transistor widths, input combination, //and technology information (vdd, subthreshold swing, subthreshold dibl swing) double TechModel::calculateLeakageCurrentFactor(unsigned int num_stacks_, const vector& stacked_mos_widths_, unsigned int input_vector_, double vdd_, double subthreshold_swing_, double dibl_swing_) const { // check everything is valid ASSERT(num_stacks_ >= 1, "[Error] Number of stacks must be >= 1!"); ASSERT(stacked_mos_widths_.size() == num_stacks_, "[Error] Mismatch in number of stacks and the widths specified!"); //Use short name in this method const double s1 = subthreshold_swing_; const double s2 = dibl_swing_; // Decode input combinations from input_vector_ std::vector vs(num_stacks_, 0.0); for(int i = 0; i < (int)num_stacks_; ++i) { double current_input = (double(input_vector_ & 0x1))*vdd_; vs[i] = (current_input); input_vector_ >>= 1; } // If the widths pointer is NULL, width is set to 1 by default vector ws = stacked_mos_widths_; //Solve voltages at internal nodes of stacked transistors // v[0] = 0 // v[num_stacks_] = vdd_ // v[i] = (1.0/(2*s1 + s2))*((s1 + s2)*v[i - 1] + s1*v[i + 1] // + s2*(vs[i + 1] - vs[i]) + s1*s2*log10(ws[i + 1]/ws[i])) //Use tri-matrix solver to solve the above linear system double A = -(s1 + s2); double B = 2*s1 + s2; double C = -s1; std::vector a(num_stacks_ - 1, 0); std::vector b(num_stacks_ - 1, 0); std::vector c(num_stacks_ - 1, 0); std::vector d(num_stacks_ - 1, 0); std::vector v(num_stacks_ + 1, 0); unsigned int eff_num_stacks = num_stacks_; bool is_found_valid_v = false; do { //Set boundary condition v[0] = 0; v[eff_num_stacks] = vdd_; //If the effective number of stacks is 1, no matrix needs to be solved if(eff_num_stacks == 1) { break; } //---------------------------------------------------------------------- //Setup the tri-matrix //---------------------------------------------------------------------- for(int i = 0; i < (int)eff_num_stacks-2; ++i) { a[i + 1] = A; c[i] = C; } for(int i = 0; i < (int)eff_num_stacks-1; ++i) { b[i] = B; d[i] = s2*(vs[i + 1] - vs[i]) + s1*s2*std::log10(ws[i + 1]/ws[i]); if(i == ((int)eff_num_stacks - 2)) { d[i] -= C*vdd_; } } //---------------------------------------------------------------------- //---------------------------------------------------------------------- //Solve the tri-matrix //---------------------------------------------------------------------- for(int i = 1; i < (int)eff_num_stacks-1; ++i) { double m = a[i]/b[i - 1]; b[i] -= m*c[i - 1]; d[i] -= m*d[i - 1]; } v[eff_num_stacks - 1] = d[eff_num_stacks - 2]/b[eff_num_stacks - 2]; for(int i = eff_num_stacks - 3; i >= 0; --i) { v[i + 1] = (d[i] - c[i]*v[i + 2])/b[i]; } //---------------------------------------------------------------------- //Check if the internal voltages are in increasing order is_found_valid_v = true; for(int i = 1; i <= (int)eff_num_stacks; ++i) { //If the ith internal voltage is not in increasing order //(i-1)th transistor is in triode region //Remove the transistors in triode region as it does not exist if(v[i] < v[i - 1]) { is_found_valid_v = false; eff_num_stacks--; vs.erase(vs.begin() + i - 1); ws.erase(ws.begin() + i - 1); break; } } } while(!is_found_valid_v); //Calculate the leakage current of the bottom transistor (first not in triode region) double vgs = vs[0] - v[0]; double vds = v[1] - v[0]; double leakage_current_factor = vgs/s1 + (vds - vdd_)/s2; //TODO - Check if the leakage current calculate for other transistors is identical return leakage_current_factor; } //------------------------------------------------------------------------- //------------------------------------------------------------------------- // Wire Related Functions //------------------------------------------------------------------------- bool TechModel::isWireLayerExist(const String& layer_name_) const { std::set::const_iterator it; it = m_available_wire_layers_->find(layer_name_); return (it != m_available_wire_layers_->end()); } const std::set* TechModel::getAvailableWireLayers() const { return m_available_wire_layers_; } double TechModel::calculateWireCapacitance(const String& layer_name_, double width_, double spacing_, double length_) const { // Get technology parameter double min_width = get("Wire->" + layer_name_ + "->MinWidth").toDouble(); double min_spacing = get("Wire->" + layer_name_ + "->MinSpacing").toDouble(); double metal_thickness = get("Wire->" + layer_name_ + "->MetalThickness").toDouble(); double dielec_thickness = get("Wire->" + layer_name_ + "->DielectricThickness").toDouble(); double dielec_const = get("Wire->" + layer_name_ + "->DielectricConstant").toDouble(); ASSERT(width_ >= min_width, "[Error] Wire width must be >= " + (String) min_width + "!"); ASSERT(spacing_ >= min_spacing, "[Error] Wire spacing must be >= " + (String) min_spacing + "!"); ASSERT(length_ >= 0, "[Error] Wire length must be >= 0!"); double A, B, C; // Calculate ground capacitance A = width_ / dielec_thickness; B = 2.04*std::pow((spacing_ / (spacing_ + 0.54 * dielec_thickness)), 1.77); C = std::pow((metal_thickness / (metal_thickness + 4.53 * dielec_thickness)), 0.07); double unit_gnd_cap = dielec_const * 8.85e-12 * (A + B * C); A = 1.14 * (metal_thickness / spacing_) * std::exp(-4.0 * spacing_ / (spacing_ + 8.01 * dielec_thickness)); B = 2.37 * std::pow((width_ / (width_ + 0.31 * spacing_)), 0.28); C = std::pow((dielec_thickness / (dielec_thickness + 8.96 * spacing_)), 0.76) * std::exp(-2.0 * spacing_ / (spacing_ + 6.0 * dielec_thickness)); double unit_coupling_cap = dielec_const * 8.85e-12 * (A + B * C); double total_cap = 2 * (unit_gnd_cap + unit_coupling_cap) * length_; return total_cap; } double TechModel::calculateWireResistance(const String& layer_name_, double width_, double length_) const { // Get technology parameter double min_width = get("Wire->" + layer_name_ + "->MinWidth"); //double barrier_thickness = get("Wire->" + layer_name_ + "->BarrierThickness"); double resistivity = get("Wire->" + layer_name_ + "->Resistivity"); double metal_thickness = get("Wire->" + layer_name_ + "->MetalThickness"); ASSERT(width_ >= min_width, "[Error] Wire width must be >= " + (String) min_width + "!"); ASSERT(length_ >= 0, "[Error] Wire length must be >= 0!"); // Calculate Rho // double rho = 2.202e-8 + (1.030e-15 / (width_ - 2.0 * barrier_thickness)); double unit_res = resistivity / (width_ * metal_thickness); //double unit_res = rho / ((width_ - 2.0 * barrier_thickness) * (metal_thickness - barrier_thickness)); double total_res = unit_res * length_; return total_res; } //------------------------------------------------------------------------- TechModel::TechModel(const TechModel& tech_model_) : m_std_cell_lib_(tech_model_.m_std_cell_lib_), params(tech_model_.params) {} } // namespace DSENT