CellMacros.cc revision 10448
110448Snilay@cs.wisc.edu/* Copyright (c) 2012 Massachusetts Institute of Technology 210448Snilay@cs.wisc.edu * 310448Snilay@cs.wisc.edu * Permission is hereby granted, free of charge, to any person obtaining a copy 410448Snilay@cs.wisc.edu * of this software and associated documentation files (the "Software"), to deal 510448Snilay@cs.wisc.edu * in the Software without restriction, including without limitation the rights 610448Snilay@cs.wisc.edu * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 710448Snilay@cs.wisc.edu * copies of the Software, and to permit persons to whom the Software is 810448Snilay@cs.wisc.edu * furnished to do so, subject to the following conditions: 910448Snilay@cs.wisc.edu * 1010448Snilay@cs.wisc.edu * The above copyright notice and this permission notice shall be included in 1110448Snilay@cs.wisc.edu * all copies or substantial portions of the Software. 1210448Snilay@cs.wisc.edu * 1310448Snilay@cs.wisc.edu * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1410448Snilay@cs.wisc.edu * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1510448Snilay@cs.wisc.edu * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1610448Snilay@cs.wisc.edu * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1710448Snilay@cs.wisc.edu * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 1810448Snilay@cs.wisc.edu * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 1910448Snilay@cs.wisc.edu * THE SOFTWARE. 2010448Snilay@cs.wisc.edu */ 2110448Snilay@cs.wisc.edu 2210447Snilay@cs.wisc.edu#include "model/std_cells/CellMacros.h" 2310447Snilay@cs.wisc.edu 2410447Snilay@cs.wisc.edu#include <cmath> 2510447Snilay@cs.wisc.edu#include <vector> 2610447Snilay@cs.wisc.edu 2710447Snilay@cs.wisc.edu#include "model/std_cells/StdCell.h" 2810447Snilay@cs.wisc.edu#include "model/timing_graph/ElectricalNet.h" 2910447Snilay@cs.wisc.edu#include "model/timing_graph/ElectricalDriver.h" 3010447Snilay@cs.wisc.edu#include "model/timing_graph/ElectricalLoad.h" 3110447Snilay@cs.wisc.edu 3210447Snilay@cs.wisc.edunamespace DSENT 3310447Snilay@cs.wisc.edu{ 3410447Snilay@cs.wisc.edu //------------------------------------------------------------------------- 3510447Snilay@cs.wisc.edu // NOR2 Macro (TODO: Generalize to N-input macro once leakage calc is done) 3610447Snilay@cs.wisc.edu //------------------------------------------------------------------------- 3710447Snilay@cs.wisc.edu void CellMacros::addNor2(StdCell* cell_, const String& name_, 3810447Snilay@cs.wisc.edu bool sizable_, bool a1_to_zn_path_, bool a2_to_zn_path_, 3910447Snilay@cs.wisc.edu const String& a1_net_, const String& a2_net_, const String& zn_net_) 4010447Snilay@cs.wisc.edu { 4110447Snilay@cs.wisc.edu //Create electrical timing model for the nand 4210447Snilay@cs.wisc.edu // Construct loads and drivers 4310447Snilay@cs.wisc.edu cell_->createLoad(name_ + "_CgA1"); 4410447Snilay@cs.wisc.edu cell_->createLoad(name_ + "_CgA2"); 4510447Snilay@cs.wisc.edu cell_->createLoad(name_ + "_CdZN"); 4610447Snilay@cs.wisc.edu cell_->createDriver(name_ + "_RonZN", sizable_); 4710447Snilay@cs.wisc.edu 4810447Snilay@cs.wisc.edu //Get references to loads and drivers 4910447Snilay@cs.wisc.edu ElectricalLoad* gate_a1_load = cell_->getLoad(name_ + "_CgA1"); 5010447Snilay@cs.wisc.edu ElectricalLoad* gate_a2_load = cell_->getLoad(name_ + "_CgA2"); 5110447Snilay@cs.wisc.edu ElectricalLoad* drain_load = cell_->getLoad(name_ + "_CdZN"); 5210447Snilay@cs.wisc.edu ElectricalDriver* zn_drive = cell_->getDriver(name_ + "_RonZN"); 5310447Snilay@cs.wisc.edu ElectricalNet* a1_net = cell_->getNet(a1_net_); 5410447Snilay@cs.wisc.edu ElectricalNet* a2_net = cell_->getNet(a2_net_); 5510447Snilay@cs.wisc.edu ElectricalNet* zn_net = cell_->getNet(zn_net_); 5610447Snilay@cs.wisc.edu 5710447Snilay@cs.wisc.edu //Add loads and drivers to the specified nets 5810447Snilay@cs.wisc.edu a1_net->addDownstreamNode(gate_a1_load); 5910447Snilay@cs.wisc.edu a2_net->addDownstreamNode(gate_a2_load); 6010447Snilay@cs.wisc.edu zn_net->addDownstreamNode(drain_load); 6110447Snilay@cs.wisc.edu if (a1_to_zn_path_) gate_a1_load->addDownstreamNode(zn_drive); 6210447Snilay@cs.wisc.edu if (a2_to_zn_path_) gate_a2_load->addDownstreamNode(zn_drive); 6310447Snilay@cs.wisc.edu zn_drive->addDownstreamNode(zn_net); 6410447Snilay@cs.wisc.edu 6510447Snilay@cs.wisc.edu return; 6610447Snilay@cs.wisc.edu } 6710447Snilay@cs.wisc.edu 6810447Snilay@cs.wisc.edu void CellMacros::updateNor2(StdCell* cell_, const String& name_, double normalized_size_) 6910447Snilay@cs.wisc.edu { 7010447Snilay@cs.wisc.edu ASSERT(normalized_size_ >= 0.0, "[Error] " + cell_->getInstanceName() + 7110447Snilay@cs.wisc.edu " -> Cannot update a macro with a negative normalized size!"); 7210447Snilay@cs.wisc.edu 7310447Snilay@cs.wisc.edu //Grab pointer to tech model 7410447Snilay@cs.wisc.edu const TechModel* tech = cell_->getTechModel(); 7510447Snilay@cs.wisc.edu 7610447Snilay@cs.wisc.edu // Get technology parameters 7710447Snilay@cs.wisc.edu double vdd = tech->get("Vdd"); 7810447Snilay@cs.wisc.edu double gate_cap = tech->get("Gate->CapPerWidth"); 7910447Snilay@cs.wisc.edu double drain_cap = tech->get("Drain->CapPerWidth"); 8010447Snilay@cs.wisc.edu double nmos_eff_res = tech->get("Nmos->EffResWidth"); 8110447Snilay@cs.wisc.edu double pmos_eff_res = tech->get("Pmos->EffResWidth"); 8210447Snilay@cs.wisc.edu double pmos_eff_res_stack_ratio = tech->get("Pmos->EffResStackRatio"); 8310447Snilay@cs.wisc.edu double gate_pitch_contacted = tech->get("Gate->PitchContacted"); 8410447Snilay@cs.wisc.edu double metal1_wire_min_width = tech->get("Wire->Metal1->MinWidth"); 8510447Snilay@cs.wisc.edu 8610447Snilay@cs.wisc.edu //Calculate number of folds and gate pitches needed 8710447Snilay@cs.wisc.edu unsigned int folds = (normalized_size_ < 1.0) ? 1 : (unsigned int)ceil(normalized_size_); 8810447Snilay@cs.wisc.edu cell_->getGenProperties()->set(name_ + "_GatePitches", 2 * folds); 8910447Snilay@cs.wisc.edu 9010447Snilay@cs.wisc.edu //Calculate widths, making sure they are above the minimum width 9110447Snilay@cs.wisc.edu double nmos_width = std::max(calculateNmosWidth(cell_, 1, 2, 1) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth")); 9210447Snilay@cs.wisc.edu double pmos_width = std::max(calculatePmosWidth(cell_, 1, 2, 2) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth")); 9310447Snilay@cs.wisc.edu 9410447Snilay@cs.wisc.edu //Calculate leakage power for each given input state 9510447Snilay@cs.wisc.edu double leakage_power_00 = vdd * folds * 2 * tech->calculateNmosLeakageCurrent(1, nmos_width, 0x0); 9610447Snilay@cs.wisc.edu double leakage_power_01 = vdd * folds * tech->calculatePmosLeakageCurrent(2, pmos_width, ~0x1); 9710447Snilay@cs.wisc.edu double leakage_power_10 = vdd * folds * tech->calculatePmosLeakageCurrent(2, pmos_width, ~0x2); 9810447Snilay@cs.wisc.edu double leakage_power_11 = vdd * folds * tech->calculatePmosLeakageCurrent(2, pmos_width, ~0x3); 9910447Snilay@cs.wisc.edu cell_->getGenProperties()->set(name_ + "_LeakagePower_00", leakage_power_00); 10010447Snilay@cs.wisc.edu cell_->getGenProperties()->set(name_ + "_LeakagePower_01", leakage_power_01); 10110447Snilay@cs.wisc.edu cell_->getGenProperties()->set(name_ + "_LeakagePower_10", leakage_power_10); 10210447Snilay@cs.wisc.edu cell_->getGenProperties()->set(name_ + "_LeakagePower_11", leakage_power_11); 10310447Snilay@cs.wisc.edu 10410447Snilay@cs.wisc.edu //Calculate R_on and capacitances 10510447Snilay@cs.wisc.edu double pmos_stack2_balance = 1.0 + pmos_eff_res_stack_ratio; 10610447Snilay@cs.wisc.edu double c_g = (nmos_width + pmos_width) * gate_cap * folds; 10710447Snilay@cs.wisc.edu double c_d = (2 * pmos_width + 2 * nmos_width) * drain_cap * folds; 10810447Snilay@cs.wisc.edu double r_on = (nmos_eff_res / nmos_width + pmos_stack2_balance * pmos_eff_res / pmos_width) / (folds * 2.0); 10910447Snilay@cs.wisc.edu 11010447Snilay@cs.wisc.edu // Estimate the wire cap and add them all at the output 11110447Snilay@cs.wisc.edu double cell_height = cell_->getTotalHeight(); 11210447Snilay@cs.wisc.edu double wire_width = metal1_wire_min_width; 11310447Snilay@cs.wisc.edu double wire_spacing = gate_pitch_contacted - metal1_wire_min_width; 11410447Snilay@cs.wisc.edu double wire_length = 2.0 * folds * cell_height; 11510447Snilay@cs.wisc.edu double wire_cap = tech->calculateWireCapacitance("Metal1", wire_width, wire_spacing, wire_length); 11610447Snilay@cs.wisc.edu 11710447Snilay@cs.wisc.edu // Construct equivalent load and drive strength 11810447Snilay@cs.wisc.edu cell_->getLoad(name_ + "_CgA1")->setLoadCap(c_g); 11910447Snilay@cs.wisc.edu cell_->getLoad(name_ + "_CgA2")->setLoadCap(c_g); 12010447Snilay@cs.wisc.edu cell_->getLoad(name_ + "_CdZN")->setLoadCap(c_d + wire_cap); 12110447Snilay@cs.wisc.edu cell_->getDriver(name_ + "_RonZN")->setOutputRes(r_on); 12210447Snilay@cs.wisc.edu 12310447Snilay@cs.wisc.edu // Calculate flip energies 12410447Snilay@cs.wisc.edu double zn_flip_energy = 0.5 * (c_d + wire_cap) * vdd * vdd; 12510447Snilay@cs.wisc.edu double a1_flip_energy = 0.5 * c_g * vdd * vdd; 12610447Snilay@cs.wisc.edu double a2_flip_energy = 0.5 * c_g * vdd * vdd; 12710447Snilay@cs.wisc.edu cell_->getGenProperties()->set(name_ + "_ZN_Flip", zn_flip_energy); 12810447Snilay@cs.wisc.edu cell_->getGenProperties()->set(name_ + "_A1_Flip", a1_flip_energy); 12910447Snilay@cs.wisc.edu cell_->getGenProperties()->set(name_ + "_A2_Flip", a2_flip_energy); 13010447Snilay@cs.wisc.edu } 13110447Snilay@cs.wisc.edu //------------------------------------------------------------------------- 13210447Snilay@cs.wisc.edu 13310447Snilay@cs.wisc.edu //------------------------------------------------------------------------- 13410447Snilay@cs.wisc.edu // NAND2 Macro (TODO: Generalize to N-input macro once leakage calc is done) 13510447Snilay@cs.wisc.edu //------------------------------------------------------------------------- 13610447Snilay@cs.wisc.edu //Adds a NAND2 to the standard cell, normalized to some size 13710447Snilay@cs.wisc.edu void CellMacros::addNand2(StdCell* cell_, const String& name_, 13810447Snilay@cs.wisc.edu bool sizable_, bool a1_to_zn_path_, bool a2_to_zn_path_, 13910447Snilay@cs.wisc.edu const String& a1_net_, const String& a2_net_, const String& zn_net_) 14010447Snilay@cs.wisc.edu { 14110447Snilay@cs.wisc.edu //Create electrical timing model for the nor 14210447Snilay@cs.wisc.edu // Construct loads and drivers 14310447Snilay@cs.wisc.edu cell_->createLoad(name_ + "_CgA1"); 14410447Snilay@cs.wisc.edu cell_->createLoad(name_ + "_CgA2"); 14510447Snilay@cs.wisc.edu cell_->createLoad(name_ + "_CdZN"); 14610447Snilay@cs.wisc.edu cell_->createDriver(name_ + "_RonZN", sizable_); 14710447Snilay@cs.wisc.edu 14810447Snilay@cs.wisc.edu //Get references to loads and drivers 14910447Snilay@cs.wisc.edu ElectricalLoad* gate_a1_load = cell_->getLoad(name_ + "_CgA1"); 15010447Snilay@cs.wisc.edu ElectricalLoad* gate_a2_load = cell_->getLoad(name_ + "_CgA2"); 15110447Snilay@cs.wisc.edu ElectricalLoad* drain_load = cell_->getLoad(name_ + "_CdZN"); 15210447Snilay@cs.wisc.edu ElectricalDriver* zn_drive = cell_->getDriver(name_ + "_RonZN"); 15310447Snilay@cs.wisc.edu ElectricalNet* a1_net = cell_->getNet(a1_net_); 15410447Snilay@cs.wisc.edu ElectricalNet* a2_net = cell_->getNet(a2_net_); 15510447Snilay@cs.wisc.edu ElectricalNet* zn_net = cell_->getNet(zn_net_); 15610447Snilay@cs.wisc.edu 15710447Snilay@cs.wisc.edu a1_net->addDownstreamNode(gate_a1_load); 15810447Snilay@cs.wisc.edu a2_net->addDownstreamNode(gate_a2_load); 15910447Snilay@cs.wisc.edu zn_net->addDownstreamNode(drain_load); 16010447Snilay@cs.wisc.edu if (a1_to_zn_path_) gate_a1_load->addDownstreamNode(zn_drive); 16110447Snilay@cs.wisc.edu if (a2_to_zn_path_) gate_a2_load->addDownstreamNode(zn_drive); 16210447Snilay@cs.wisc.edu zn_drive->addDownstreamNode(zn_net); 16310447Snilay@cs.wisc.edu 16410447Snilay@cs.wisc.edu return; 16510447Snilay@cs.wisc.edu } 16610447Snilay@cs.wisc.edu 16710447Snilay@cs.wisc.edu //Updates a NAND2 to to the standard cell, normalized to some size 16810447Snilay@cs.wisc.edu void CellMacros::updateNand2(StdCell* cell_, const String& name_, double normalized_size_) 16910447Snilay@cs.wisc.edu { 17010447Snilay@cs.wisc.edu ASSERT(normalized_size_ >= 0.0, "[Error] " + cell_->getInstanceName() + 17110447Snilay@cs.wisc.edu " -> Cannot update a macro with a negative normalized size!"); 17210447Snilay@cs.wisc.edu 17310447Snilay@cs.wisc.edu //Grab pointer to tech model 17410447Snilay@cs.wisc.edu const TechModel* tech = cell_->getTechModel(); 17510447Snilay@cs.wisc.edu 17610447Snilay@cs.wisc.edu // Get technology parameters 17710447Snilay@cs.wisc.edu double vdd = tech->get("Vdd"); 17810447Snilay@cs.wisc.edu double gate_cap = tech->get("Gate->CapPerWidth"); 17910447Snilay@cs.wisc.edu double drain_cap = tech->get("Drain->CapPerWidth"); 18010447Snilay@cs.wisc.edu double nmos_eff_res = tech->get("Nmos->EffResWidth"); 18110447Snilay@cs.wisc.edu double pmos_eff_res = tech->get("Pmos->EffResWidth"); 18210447Snilay@cs.wisc.edu double nmos_eff_res_stack_ratio = tech->get("Nmos->EffResStackRatio"); 18310447Snilay@cs.wisc.edu double gate_pitch_contacted = tech->get("Gate->PitchContacted"); 18410447Snilay@cs.wisc.edu double metal1_wire_min_width = tech->get("Wire->Metal1->MinWidth"); 18510447Snilay@cs.wisc.edu 18610447Snilay@cs.wisc.edu //Calculate number of folds needed 18710447Snilay@cs.wisc.edu unsigned int folds = (normalized_size_ < 1.0) ? 1 : (unsigned int)ceil(normalized_size_); 18810447Snilay@cs.wisc.edu cell_->getGenProperties()->set(name_ + "_GatePitches", 2 * folds); 18910447Snilay@cs.wisc.edu 19010447Snilay@cs.wisc.edu //Calculate widths, making sure they are above the minimum width 19110447Snilay@cs.wisc.edu double nmos_width = std::max(calculateNmosWidth(cell_, 2, 1, 2) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth")); 19210447Snilay@cs.wisc.edu double pmos_width = std::max(calculatePmosWidth(cell_, 2, 1, 1) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth")); 19310447Snilay@cs.wisc.edu 19410447Snilay@cs.wisc.edu // Leakage power calculation 19510447Snilay@cs.wisc.edu double leakage_power_00 = vdd * folds * tech->calculateNmosLeakageCurrent(2, nmos_width, 0x0); 19610447Snilay@cs.wisc.edu double leakage_power_01 = vdd * folds * tech->calculateNmosLeakageCurrent(2, nmos_width, 0x1); 19710447Snilay@cs.wisc.edu double leakage_power_10 = vdd * folds * tech->calculateNmosLeakageCurrent(2, nmos_width, 0x2); 19810447Snilay@cs.wisc.edu double leakage_power_11 = vdd * folds * 2 * tech->calculatePmosLeakageCurrent(1, pmos_width, ~0x3); 19910447Snilay@cs.wisc.edu cell_->getGenProperties()->set(name_ + "_LeakagePower_00", leakage_power_00); 20010447Snilay@cs.wisc.edu cell_->getGenProperties()->set(name_ + "_LeakagePower_01", leakage_power_01); 20110447Snilay@cs.wisc.edu cell_->getGenProperties()->set(name_ + "_LeakagePower_10", leakage_power_10); 20210447Snilay@cs.wisc.edu cell_->getGenProperties()->set(name_ + "_LeakagePower_11", leakage_power_11); 20310447Snilay@cs.wisc.edu 20410447Snilay@cs.wisc.edu // Get input parameters 20510447Snilay@cs.wisc.edu double nmos_stack2_balance = 1.0 + nmos_eff_res_stack_ratio; 20610447Snilay@cs.wisc.edu 20710447Snilay@cs.wisc.edu //Calculate caps 20810447Snilay@cs.wisc.edu double c_g = (nmos_width + pmos_width) * gate_cap * folds; 20910447Snilay@cs.wisc.edu double c_d = (2 * pmos_width + 2 * nmos_width) * drain_cap * folds; 21010447Snilay@cs.wisc.edu double r_on = (nmos_stack2_balance * nmos_eff_res / nmos_width + pmos_eff_res / pmos_width) / (folds * 2.0); 21110447Snilay@cs.wisc.edu 21210447Snilay@cs.wisc.edu // Estimate the wire cap and add them all at the output 21310447Snilay@cs.wisc.edu double cell_height = cell_->getTotalHeight(); 21410447Snilay@cs.wisc.edu double wire_width = metal1_wire_min_width; 21510447Snilay@cs.wisc.edu double wire_spacing = gate_pitch_contacted - metal1_wire_min_width; 21610447Snilay@cs.wisc.edu double wire_length = 2.0 * folds * cell_height; 21710447Snilay@cs.wisc.edu double wire_cap = tech->calculateWireCapacitance("Metal1", wire_width, wire_spacing, wire_length); 21810447Snilay@cs.wisc.edu 21910447Snilay@cs.wisc.edu // Construct equivalent load and drive strength 22010447Snilay@cs.wisc.edu cell_->getLoad(name_ + "_CgA1")->setLoadCap(c_g); 22110447Snilay@cs.wisc.edu cell_->getLoad(name_ + "_CgA2")->setLoadCap(c_g); 22210447Snilay@cs.wisc.edu cell_->getLoad(name_ + "_CdZN")->setLoadCap(c_d + wire_cap); 22310447Snilay@cs.wisc.edu cell_->getDriver(name_ + "_RonZN")->setOutputRes(r_on); 22410447Snilay@cs.wisc.edu 22510447Snilay@cs.wisc.edu // Calculate flip energies 22610447Snilay@cs.wisc.edu double zn_flip_energy = 0.5 * (c_d + wire_cap) * vdd * vdd; 22710447Snilay@cs.wisc.edu double a1_flip_energy = 0.5 * c_g * vdd * vdd; 22810447Snilay@cs.wisc.edu double a2_flip_energy = 0.5 * c_g * vdd * vdd; 22910447Snilay@cs.wisc.edu cell_->getGenProperties()->set(name_ + "_ZN_Flip", zn_flip_energy); 23010447Snilay@cs.wisc.edu cell_->getGenProperties()->set(name_ + "_A1_Flip", a1_flip_energy); 23110447Snilay@cs.wisc.edu cell_->getGenProperties()->set(name_ + "_A2_Flip", a2_flip_energy); 23210447Snilay@cs.wisc.edu } 23310447Snilay@cs.wisc.edu //------------------------------------------------------------------------- 23410447Snilay@cs.wisc.edu 23510447Snilay@cs.wisc.edu //------------------------------------------------------------------------- 23610447Snilay@cs.wisc.edu // INV Macro 23710447Snilay@cs.wisc.edu //------------------------------------------------------------------------- 23810447Snilay@cs.wisc.edu //Adds an inverter to the model, normalized to some size 23910447Snilay@cs.wisc.edu void CellMacros::addInverter(StdCell* cell_, const String& name_, 24010447Snilay@cs.wisc.edu bool sizable_, bool a_to_zn_path_, 24110447Snilay@cs.wisc.edu const String& a_net_, const String& zn_net_) 24210447Snilay@cs.wisc.edu { 24310447Snilay@cs.wisc.edu //Create electrical timing model for the inverter 24410447Snilay@cs.wisc.edu // Construct loads and drivers 24510447Snilay@cs.wisc.edu cell_->createLoad(name_ + "_CgA"); 24610447Snilay@cs.wisc.edu cell_->createLoad(name_ + "_CdZN"); 24710447Snilay@cs.wisc.edu cell_->createDriver(name_ + "_RonZN", sizable_); 24810447Snilay@cs.wisc.edu 24910447Snilay@cs.wisc.edu //Get references to loads and drivers 25010447Snilay@cs.wisc.edu ElectricalLoad* gate_load = cell_->getLoad(name_ + "_CgA"); 25110447Snilay@cs.wisc.edu ElectricalLoad* drain_load = cell_->getLoad(name_ + "_CdZN"); 25210447Snilay@cs.wisc.edu ElectricalDriver* out_drive = cell_->getDriver(name_ + "_RonZN"); 25310447Snilay@cs.wisc.edu ElectricalNet* a_net = cell_->getNet(a_net_); 25410447Snilay@cs.wisc.edu ElectricalNet* zn_net = cell_->getNet(zn_net_); 25510447Snilay@cs.wisc.edu 25610447Snilay@cs.wisc.edu // Setup connectivity of loads and drivers 25710447Snilay@cs.wisc.edu a_net->addDownstreamNode(gate_load); 25810447Snilay@cs.wisc.edu if (a_to_zn_path_) gate_load->addDownstreamNode(out_drive); 25910447Snilay@cs.wisc.edu zn_net->addDownstreamNode(drain_load); 26010447Snilay@cs.wisc.edu out_drive->addDownstreamNode(zn_net); 26110447Snilay@cs.wisc.edu 26210447Snilay@cs.wisc.edu return; 26310447Snilay@cs.wisc.edu } 26410447Snilay@cs.wisc.edu 26510447Snilay@cs.wisc.edu //Updates the numbers of an inverter for some normalized size 26610447Snilay@cs.wisc.edu void CellMacros::updateInverter(StdCell* cell_, const String& name_, double normalized_size_) 26710447Snilay@cs.wisc.edu { 26810447Snilay@cs.wisc.edu ASSERT(normalized_size_ >= 0.0, "[Error] " + cell_->getInstanceName() + 26910447Snilay@cs.wisc.edu " -> Cannot update a macro with a negative normalized size!"); 27010447Snilay@cs.wisc.edu 27110447Snilay@cs.wisc.edu //Grab pointer to tech model 27210447Snilay@cs.wisc.edu const TechModel* tech = cell_->getTechModel(); 27310447Snilay@cs.wisc.edu 27410447Snilay@cs.wisc.edu //Get values from technology library 27510447Snilay@cs.wisc.edu double vdd = tech->get("Vdd"); 27610447Snilay@cs.wisc.edu double gate_cap = tech->get("Gate->CapPerWidth"); 27710447Snilay@cs.wisc.edu double drain_cap = tech->get("Drain->CapPerWidth"); 27810447Snilay@cs.wisc.edu double nmos_eff_res = tech->get("Nmos->EffResWidth"); 27910447Snilay@cs.wisc.edu double pmos_eff_res = tech->get("Pmos->EffResWidth"); 28010447Snilay@cs.wisc.edu double gate_pitch_contacted = tech->get("Gate->PitchContacted"); 28110447Snilay@cs.wisc.edu double metal1_wire_min_width = tech->get("Wire->Metal1->MinWidth"); 28210447Snilay@cs.wisc.edu 28310447Snilay@cs.wisc.edu //Calculate number of folds needed 28410447Snilay@cs.wisc.edu unsigned int folds = (normalized_size_ < 1.0) ? 1 : (unsigned int)ceil(normalized_size_); 28510447Snilay@cs.wisc.edu cell_->getGenProperties()->set(name_ + "_GatePitches", folds); 28610447Snilay@cs.wisc.edu 28710447Snilay@cs.wisc.edu //Calculate widths, making sure they are above the minimum width 28810447Snilay@cs.wisc.edu double nmos_width = std::max(calculateNmosWidth(cell_, 1, 1, 1) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth")); 28910447Snilay@cs.wisc.edu double pmos_width = std::max(calculatePmosWidth(cell_, 1, 1, 1) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth")); 29010447Snilay@cs.wisc.edu 29110447Snilay@cs.wisc.edu //Calculate leakage power for each given input state 29210447Snilay@cs.wisc.edu double leakage_power_0 = vdd * folds * tech->calculateNmosLeakageCurrent(1, nmos_width, 0x0); 29310447Snilay@cs.wisc.edu double leakage_power_1 = vdd * folds * tech->calculatePmosLeakageCurrent(1, pmos_width, ~0x1); 29410447Snilay@cs.wisc.edu cell_->getGenProperties()->set(name_ + "_LeakagePower_0", leakage_power_0); 29510447Snilay@cs.wisc.edu cell_->getGenProperties()->set(name_ + "_LeakagePower_1", leakage_power_1); 29610447Snilay@cs.wisc.edu 29710447Snilay@cs.wisc.edu //Calculate caps 29810447Snilay@cs.wisc.edu double c_g = (nmos_width + pmos_width) * gate_cap * folds; 29910447Snilay@cs.wisc.edu double c_d = (pmos_width + nmos_width) * drain_cap * folds; 30010447Snilay@cs.wisc.edu double r_on = (nmos_eff_res / nmos_width + pmos_eff_res / pmos_width) / (folds * 2.0); 30110447Snilay@cs.wisc.edu 30210447Snilay@cs.wisc.edu // Estimate the wire cap and add them all at the output 30310447Snilay@cs.wisc.edu double cell_height = cell_->getTotalHeight(); 30410447Snilay@cs.wisc.edu double wire_width = metal1_wire_min_width; 30510447Snilay@cs.wisc.edu double wire_spacing = gate_pitch_contacted - metal1_wire_min_width; 30610447Snilay@cs.wisc.edu double wire_length = folds * cell_height; 30710447Snilay@cs.wisc.edu double wire_cap = tech->calculateWireCapacitance("Metal1", wire_width, wire_spacing, wire_length); 30810447Snilay@cs.wisc.edu 30910447Snilay@cs.wisc.edu // Construct equivalent load and drive strength 31010447Snilay@cs.wisc.edu cell_->getLoad(name_ + "_CgA")->setLoadCap(c_g); 31110447Snilay@cs.wisc.edu cell_->getLoad(name_ + "_CdZN")->setLoadCap(c_d + wire_cap); 31210447Snilay@cs.wisc.edu cell_->getDriver(name_ + "_RonZN")->setOutputRes(r_on); 31310447Snilay@cs.wisc.edu 31410447Snilay@cs.wisc.edu // Calculate flip energy (output flip) 31510447Snilay@cs.wisc.edu // Calculate flip energies 31610447Snilay@cs.wisc.edu double zn_flip_energy = 0.5 * (c_d + wire_cap) * vdd * vdd; 31710447Snilay@cs.wisc.edu double a_flip_energy = 0.5 * c_g * vdd * vdd; 31810447Snilay@cs.wisc.edu cell_->getGenProperties()->set(name_ + "_ZN_Flip", zn_flip_energy); 31910447Snilay@cs.wisc.edu cell_->getGenProperties()->set(name_ + "_A_Flip", a_flip_energy); 32010447Snilay@cs.wisc.edu 32110447Snilay@cs.wisc.edu return; 32210447Snilay@cs.wisc.edu } 32310447Snilay@cs.wisc.edu //------------------------------------------------------------------------- 32410447Snilay@cs.wisc.edu 32510447Snilay@cs.wisc.edu //------------------------------------------------------------------------- 32610447Snilay@cs.wisc.edu // INVZ Macro 32710447Snilay@cs.wisc.edu //------------------------------------------------------------------------- 32810447Snilay@cs.wisc.edu //Adds a tristated inverter to the model, normalized to some size 32910447Snilay@cs.wisc.edu void CellMacros::addTristate(StdCell* cell_, const String& name_, 33010447Snilay@cs.wisc.edu bool sizable_, bool a_to_zn_path_, bool oe_to_zn_path_, bool oen_to_zn_path_, 33110447Snilay@cs.wisc.edu const String& a_net_, const String& oe_net_, const String& oen_net_, const String& zn_net_) 33210447Snilay@cs.wisc.edu { 33310447Snilay@cs.wisc.edu // Construct loads and drivers 33410447Snilay@cs.wisc.edu cell_->createLoad(name_ + "_CgA"); 33510447Snilay@cs.wisc.edu cell_->createLoad(name_ + "_CgOE"); 33610447Snilay@cs.wisc.edu cell_->createLoad(name_ + "_CgOEN"); 33710447Snilay@cs.wisc.edu cell_->createLoad(name_ + "_CdZN"); 33810447Snilay@cs.wisc.edu cell_->createDriver(name_ + "_RonZN", sizable_); 33910447Snilay@cs.wisc.edu 34010447Snilay@cs.wisc.edu // Get references to loads, nets and drivers 34110447Snilay@cs.wisc.edu ElectricalLoad* gate_a_load = cell_->getLoad(name_ + "_CgA"); 34210447Snilay@cs.wisc.edu ElectricalLoad* gate_oe_load = cell_->getLoad(name_ + "_CgOE"); 34310447Snilay@cs.wisc.edu ElectricalLoad* gate_oen_load = cell_->getLoad(name_ + "_CgOEN"); 34410447Snilay@cs.wisc.edu ElectricalLoad* drain_load = cell_->getLoad(name_ + "_CdZN"); 34510447Snilay@cs.wisc.edu ElectricalDriver* out_drive = cell_->getDriver(name_ + "_RonZN"); 34610447Snilay@cs.wisc.edu ElectricalNet* a_net = cell_->getNet(a_net_); 34710447Snilay@cs.wisc.edu ElectricalNet* oe_net = cell_->getNet(oe_net_); 34810447Snilay@cs.wisc.edu ElectricalNet* oen_net = cell_->getNet(oen_net_); 34910447Snilay@cs.wisc.edu ElectricalNet* zn_net = cell_->getNet(zn_net_); 35010447Snilay@cs.wisc.edu 35110447Snilay@cs.wisc.edu // Setup connectivity of loads and drivers 35210447Snilay@cs.wisc.edu a_net->addDownstreamNode(gate_a_load); 35310447Snilay@cs.wisc.edu oe_net->addDownstreamNode(gate_oe_load); 35410447Snilay@cs.wisc.edu oen_net->addDownstreamNode(gate_oen_load); 35510447Snilay@cs.wisc.edu if (a_to_zn_path_) gate_a_load->addDownstreamNode(out_drive); 35610447Snilay@cs.wisc.edu if (oe_to_zn_path_) gate_oe_load->addDownstreamNode(out_drive); 35710447Snilay@cs.wisc.edu if (oen_to_zn_path_) gate_oen_load->addDownstreamNode(out_drive); 35810447Snilay@cs.wisc.edu zn_net->addDownstreamNode(drain_load); 35910447Snilay@cs.wisc.edu out_drive->addDownstreamNode(zn_net); 36010447Snilay@cs.wisc.edu 36110447Snilay@cs.wisc.edu return; 36210447Snilay@cs.wisc.edu } 36310447Snilay@cs.wisc.edu 36410447Snilay@cs.wisc.edu //Updates the numbers of an inverter for some normalized size 36510447Snilay@cs.wisc.edu void CellMacros::updateTristate(StdCell* cell_, const String& name_, double normalized_size_) 36610447Snilay@cs.wisc.edu { 36710447Snilay@cs.wisc.edu ASSERT(normalized_size_ >= 0.0, "[Error] " + cell_->getInstanceName() + 36810447Snilay@cs.wisc.edu " -> Cannot update a macro with a negative normalized size!"); 36910447Snilay@cs.wisc.edu 37010447Snilay@cs.wisc.edu //Grab pointer to tech model 37110447Snilay@cs.wisc.edu const TechModel* tech = cell_->getTechModel(); 37210447Snilay@cs.wisc.edu 37310447Snilay@cs.wisc.edu //Get values from technology library 37410447Snilay@cs.wisc.edu double vdd = tech->get("Vdd"); 37510447Snilay@cs.wisc.edu double gate_cap = tech->get("Gate->CapPerWidth"); 37610447Snilay@cs.wisc.edu double drain_cap = tech->get("Drain->CapPerWidth"); 37710447Snilay@cs.wisc.edu double nmos_eff_res = tech->get("Nmos->EffResWidth"); 37810447Snilay@cs.wisc.edu double pmos_eff_res = tech->get("Pmos->EffResWidth"); 37910447Snilay@cs.wisc.edu double pmos_eff_res_stack_ratio = tech->get("Pmos->EffResStackRatio"); 38010447Snilay@cs.wisc.edu double nmos_eff_res_stack_ratio = tech->get("Nmos->EffResStackRatio"); 38110447Snilay@cs.wisc.edu double gate_pitch_contacted = tech->get("Gate->PitchContacted"); 38210447Snilay@cs.wisc.edu double metal1_wire_min_width = tech->get("Wire->Metal1->MinWidth"); 38310447Snilay@cs.wisc.edu 38410447Snilay@cs.wisc.edu //Calculate number of folds and gate pitches needed 38510447Snilay@cs.wisc.edu unsigned int folds = (normalized_size_ < 1.0) ? 1 : (unsigned int)ceil(normalized_size_); 38610447Snilay@cs.wisc.edu cell_->getGenProperties()->set(name_ + "_GatePitches", 2 * folds); 38710447Snilay@cs.wisc.edu 38810447Snilay@cs.wisc.edu //Calculate widths, making sure they are above the minimum width 38910447Snilay@cs.wisc.edu double nmos_width = std::max(calculateNmosWidth(cell_, 2, 2, 2) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth")); 39010447Snilay@cs.wisc.edu double pmos_width = std::max(calculatePmosWidth(cell_, 2, 2, 2) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth")); 39110447Snilay@cs.wisc.edu 39210447Snilay@cs.wisc.edu //Calculate leakage power for each given input state 39310447Snilay@cs.wisc.edu //if output_enable = 0, then it is possible that the PMOS may leak (if output = 0), 39410447Snilay@cs.wisc.edu //or the NMOS will leak (if output = 1) 39510447Snilay@cs.wisc.edu 39610447Snilay@cs.wisc.edu //OE OEN A _ ZN 39710447Snilay@cs.wisc.edu double leakage_power_010_0 = vdd * folds * tech->calculatePmosLeakageCurrent(2, pmos_width, ~0x2); 39810447Snilay@cs.wisc.edu double leakage_power_010_1 = vdd * folds * tech->calculateNmosLeakageCurrent(2, nmos_width, 0x0); 39910447Snilay@cs.wisc.edu double leakage_power_011_0 = vdd * folds * tech->calculatePmosLeakageCurrent(2, pmos_width, ~0x3); 40010447Snilay@cs.wisc.edu double leakage_power_011_1 = vdd * folds * tech->calculateNmosLeakageCurrent(2, nmos_width, 0x1); 40110447Snilay@cs.wisc.edu double leakage_power_100_1 = vdd * folds * tech->calculateNmosLeakageCurrent(2, nmos_width, 0x2); 40210447Snilay@cs.wisc.edu double leakage_power_101_0 = vdd * folds * tech->calculatePmosLeakageCurrent(2, pmos_width, ~0x1); 40310447Snilay@cs.wisc.edu cell_->getGenProperties()->set(name_ + "_LeakagePower_010_0", leakage_power_010_0); 40410447Snilay@cs.wisc.edu cell_->getGenProperties()->set(name_ + "_LeakagePower_010_1", leakage_power_010_1); 40510447Snilay@cs.wisc.edu cell_->getGenProperties()->set(name_ + "_LeakagePower_011_0", leakage_power_011_0); 40610447Snilay@cs.wisc.edu cell_->getGenProperties()->set(name_ + "_LeakagePower_011_1", leakage_power_011_1); 40710447Snilay@cs.wisc.edu cell_->getGenProperties()->set(name_ + "_LeakagePower_100_1", leakage_power_100_1); 40810447Snilay@cs.wisc.edu cell_->getGenProperties()->set(name_ + "_LeakagePower_101_0", leakage_power_101_0); 40910447Snilay@cs.wisc.edu 41010447Snilay@cs.wisc.edu //Caculate stack balance 41110447Snilay@cs.wisc.edu double pmos_stack2_balance = 1.0 + pmos_eff_res_stack_ratio; 41210447Snilay@cs.wisc.edu double nmos_stack2_balance = 1.0 + nmos_eff_res_stack_ratio; 41310447Snilay@cs.wisc.edu 41410447Snilay@cs.wisc.edu //Calculate caps 41510447Snilay@cs.wisc.edu double c_g_a = (nmos_width + pmos_width) * gate_cap * folds; 41610447Snilay@cs.wisc.edu double c_g_oe = nmos_width * gate_cap * folds; 41710447Snilay@cs.wisc.edu double c_g_oen = pmos_width * gate_cap * folds; 41810447Snilay@cs.wisc.edu double c_d = (2 * pmos_width + 2 * nmos_width) * drain_cap * folds; 41910447Snilay@cs.wisc.edu double r_on = (nmos_stack2_balance * nmos_eff_res / nmos_width + pmos_stack2_balance * pmos_eff_res / pmos_width) / (folds * 2.0); 42010447Snilay@cs.wisc.edu 42110447Snilay@cs.wisc.edu // Estimate the wire cap and add them all at the output 42210447Snilay@cs.wisc.edu double cell_height = cell_->getTotalHeight(); 42310447Snilay@cs.wisc.edu double wire_width = metal1_wire_min_width; 42410447Snilay@cs.wisc.edu double wire_spacing = gate_pitch_contacted - metal1_wire_min_width; 42510447Snilay@cs.wisc.edu double wire_length = 2.0 * folds * cell_height; 42610447Snilay@cs.wisc.edu double wire_cap = tech->calculateWireCapacitance("Metal1", wire_width, wire_spacing, wire_length); 42710447Snilay@cs.wisc.edu 42810447Snilay@cs.wisc.edu // Construct equivalent load and drive strength 42910447Snilay@cs.wisc.edu cell_->getLoad(name_ + "_CgA")->setLoadCap(c_g_a); 43010447Snilay@cs.wisc.edu cell_->getLoad(name_ + "_CgOE")->setLoadCap(c_g_oe); 43110447Snilay@cs.wisc.edu cell_->getLoad(name_ + "_CgOEN")->setLoadCap(c_g_oen); 43210447Snilay@cs.wisc.edu cell_->getLoad(name_ + "_CdZN")->setLoadCap(c_d + wire_cap); 43310447Snilay@cs.wisc.edu cell_->getDriver(name_ + "_RonZN")->setOutputRes(r_on); 43410447Snilay@cs.wisc.edu 43510447Snilay@cs.wisc.edu // Calculate flip energy (output flip) 43610447Snilay@cs.wisc.edu double zn_flip_energy = 0.5 * (c_d + wire_cap) * vdd * vdd; 43710447Snilay@cs.wisc.edu double a_flip_energy = 0.5 * c_g_a * vdd * vdd; 43810447Snilay@cs.wisc.edu double oe_flip_energy = 0.5 * c_g_oe * vdd * vdd; 43910447Snilay@cs.wisc.edu double oen_flip_energy = 0.5 * c_g_oen * vdd * vdd; 44010447Snilay@cs.wisc.edu cell_->getGenProperties()->set(name_ + "_ZN_Flip", zn_flip_energy); 44110447Snilay@cs.wisc.edu cell_->getGenProperties()->set(name_ + "_A_Flip", a_flip_energy); 44210447Snilay@cs.wisc.edu cell_->getGenProperties()->set(name_ + "_OE_Flip", oe_flip_energy); 44310447Snilay@cs.wisc.edu cell_->getGenProperties()->set(name_ + "_OEN_Flip", oen_flip_energy); 44410447Snilay@cs.wisc.edu return; 44510447Snilay@cs.wisc.edu } 44610447Snilay@cs.wisc.edu //------------------------------------------------------------------------- 44710447Snilay@cs.wisc.edu 44810447Snilay@cs.wisc.edu 44910447Snilay@cs.wisc.edu //------------------------------------------------------------------------- 45010447Snilay@cs.wisc.edu // Helper Functions 45110447Snilay@cs.wisc.edu //------------------------------------------------------------------------- 45210447Snilay@cs.wisc.edu //Returns the width of NMOS transistors, given the NMOS and PMOS stacking 45310447Snilay@cs.wisc.edu double CellMacros::calculateNmosWidth(const StdCell* cell_, unsigned int max_stacked_nmos_, unsigned int max_stacked_pmos_, unsigned int current_stacked_nmos_) 45410447Snilay@cs.wisc.edu { 45510447Snilay@cs.wisc.edu //Grab pointer to tech model 45610447Snilay@cs.wisc.edu const TechModel* tech = cell_->getTechModel(); 45710447Snilay@cs.wisc.edu 45810447Snilay@cs.wisc.edu double nmos_eff_res_stack_ratio = tech->get("Nmos->EffResStackRatio"); 45910447Snilay@cs.wisc.edu double pmos_eff_res_stack_ratio = tech->get("Pmos->EffResStackRatio"); 46010447Snilay@cs.wisc.edu 46110447Snilay@cs.wisc.edu double nmos_stack_balance = 1.0 + nmos_eff_res_stack_ratio * (double) (max_stacked_nmos_ - 1); 46210447Snilay@cs.wisc.edu double pmos_stack_balance = 1.0 + pmos_eff_res_stack_ratio * (double) (max_stacked_pmos_ - 1); 46310447Snilay@cs.wisc.edu double current_nmos_stack_balance = 1.0 + nmos_eff_res_stack_ratio * (double) (current_stacked_nmos_ - 1); 46410447Snilay@cs.wisc.edu 46510447Snilay@cs.wisc.edu double pn_ratio = cell_->getPToNRatio(); 46610447Snilay@cs.wisc.edu double active_height = cell_->getActiveHeight(); 46710447Snilay@cs.wisc.edu 46810447Snilay@cs.wisc.edu //Calculate the width of the current device 46910447Snilay@cs.wisc.edu double nmos_width = active_height * current_nmos_stack_balance / (nmos_stack_balance + pn_ratio * pmos_stack_balance); 47010447Snilay@cs.wisc.edu 47110447Snilay@cs.wisc.edu return nmos_width; 47210447Snilay@cs.wisc.edu } 47310447Snilay@cs.wisc.edu 47410447Snilay@cs.wisc.edu //Returns the width of PMOS transistors, given the NMOS and PMOS stacking 47510447Snilay@cs.wisc.edu double CellMacros::calculatePmosWidth(const StdCell* cell_, unsigned int max_stacked_nmos_, unsigned int max_stacked_pmos_, unsigned int current_stacked_pmos_) 47610447Snilay@cs.wisc.edu { 47710447Snilay@cs.wisc.edu //Grab pointer to tech model 47810447Snilay@cs.wisc.edu const TechModel* tech = cell_->getTechModel(); 47910447Snilay@cs.wisc.edu 48010447Snilay@cs.wisc.edu double nmos_eff_res_stack_ratio = tech->get("Nmos->EffResStackRatio"); 48110447Snilay@cs.wisc.edu double pmos_eff_res_stack_ratio = tech->get("Pmos->EffResStackRatio"); 48210447Snilay@cs.wisc.edu 48310447Snilay@cs.wisc.edu double nmos_stack_balance = 1.0 + nmos_eff_res_stack_ratio * (double) (max_stacked_nmos_ - 1); 48410447Snilay@cs.wisc.edu double pmos_stack_balance = 1.0 + pmos_eff_res_stack_ratio * (double) (max_stacked_pmos_ - 1); 48510447Snilay@cs.wisc.edu double current_pmos_stack_balance = 1.0 + pmos_eff_res_stack_ratio * (double) (current_stacked_pmos_ - 1); 48610447Snilay@cs.wisc.edu 48710447Snilay@cs.wisc.edu double pn_ratio = cell_->getPToNRatio(); 48810447Snilay@cs.wisc.edu double active_height = cell_->getActiveHeight(); 48910447Snilay@cs.wisc.edu 49010447Snilay@cs.wisc.edu //Calculate the width of the current device 49110447Snilay@cs.wisc.edu double pmos_width = active_height * current_pmos_stack_balance * pn_ratio / (nmos_stack_balance + pn_ratio * pmos_stack_balance); 49210447Snilay@cs.wisc.edu 49310447Snilay@cs.wisc.edu return pmos_width; 49410447Snilay@cs.wisc.edu } 49510447Snilay@cs.wisc.edu //------------------------------------------------------------------------- 49610447Snilay@cs.wisc.edu 49710447Snilay@cs.wisc.edu} // namespace DSENT 49810447Snilay@cs.wisc.edu 499