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