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/optical/RingModulator.h"
2310447Snilay@cs.wisc.edu
2410447Snilay@cs.wisc.edu#include <cmath>
2510447Snilay@cs.wisc.edu
2610447Snilay@cs.wisc.edu#include "util/Constants.h"
2710447Snilay@cs.wisc.edu#include "model/PortInfo.h"
2810447Snilay@cs.wisc.edu#include "model/TransitionInfo.h"
2910447Snilay@cs.wisc.edu#include "model/EventInfo.h"
3010447Snilay@cs.wisc.edu#include "model/std_cells/StdCell.h"
3110447Snilay@cs.wisc.edu#include "model/std_cells/StdCellLib.h"
3210447Snilay@cs.wisc.edu#include "model/optical_graph/OpticalWaveguide.h"
3310447Snilay@cs.wisc.edu#include "model/optical_graph/OpticalModulator.h"
3410447Snilay@cs.wisc.edu#include "model/optical_graph/OpticalFilter.h"
3510447Snilay@cs.wisc.edu#include "model/optical_graph/OpticalTransmitter.h"
3610447Snilay@cs.wisc.edu#include "model/timing_graph/ElectricalNet.h"
3710447Snilay@cs.wisc.edu#include "model/timing_graph/ElectricalLoad.h"
3810447Snilay@cs.wisc.edu#include "model/timing_graph/ElectricalTimingTree.h"
3910447Snilay@cs.wisc.edu
4010447Snilay@cs.wisc.edunamespace DSENT
4110447Snilay@cs.wisc.edu{
4210447Snilay@cs.wisc.edu    using std::max;
4310447Snilay@cs.wisc.edu    using std::min;
4410447Snilay@cs.wisc.edu
4510447Snilay@cs.wisc.edu    // TODO: Don't like the way this is written right now. Probably fix in a future version
4610447Snilay@cs.wisc.edu
4710447Snilay@cs.wisc.edu    RingModulator::RingModulator(const String& instance_name_, const TechModel* tech_model_)
4810447Snilay@cs.wisc.edu        : OpticalModel(instance_name_, tech_model_)
4910447Snilay@cs.wisc.edu    {
5010447Snilay@cs.wisc.edu        initParameters();
5110447Snilay@cs.wisc.edu        initProperties();
5210447Snilay@cs.wisc.edu    }
5310447Snilay@cs.wisc.edu
5410447Snilay@cs.wisc.edu    RingModulator::~RingModulator()
5510447Snilay@cs.wisc.edu    {}
5610447Snilay@cs.wisc.edu
5710447Snilay@cs.wisc.edu    void RingModulator::initParameters()
5810447Snilay@cs.wisc.edu    {
5910447Snilay@cs.wisc.edu        addParameterName("DataRate");
6010447Snilay@cs.wisc.edu        addParameterName("InStart");
6110447Snilay@cs.wisc.edu        addParameterName("InEnd");
6210447Snilay@cs.wisc.edu        addParameterName("ModStart");
6310447Snilay@cs.wisc.edu        addParameterName("ModEnd");
6410447Snilay@cs.wisc.edu        addParameterName("OptimizeLoss", "TRUE");
6510447Snilay@cs.wisc.edu        return;
6610447Snilay@cs.wisc.edu    }
6710447Snilay@cs.wisc.edu
6810447Snilay@cs.wisc.edu    void RingModulator::initProperties()
6910447Snilay@cs.wisc.edu    {
7010447Snilay@cs.wisc.edu        addPropertyName("ExtinctionRatio", 6);  //default properties
7110447Snilay@cs.wisc.edu        addPropertyName("InsertionLoss", 2);    //default properties
7210447Snilay@cs.wisc.edu        return;
7310447Snilay@cs.wisc.edu    }
7410447Snilay@cs.wisc.edu
7510447Snilay@cs.wisc.edu    void RingModulator::constructModel()
7610447Snilay@cs.wisc.edu    {
7710447Snilay@cs.wisc.edu        // Create electrical results
7810447Snilay@cs.wisc.edu        createElectricalAtomicResults();
7910447Snilay@cs.wisc.edu        // Create Area result
8010447Snilay@cs.wisc.edu        addAreaResult(new AtomicResult("Photonic"));
8110447Snilay@cs.wisc.edu        // Create Modulate result
8210447Snilay@cs.wisc.edu        createElectricalEventAtomicResult("Modulate");
8310447Snilay@cs.wisc.edu
8410447Snilay@cs.wisc.edu        // Get parameters
8510447Snilay@cs.wisc.edu        WavelengthGroup in_wavelengths = makeWavelengthGroup(getParameter("InStart"), getParameter("InEnd"));
8610447Snilay@cs.wisc.edu        WavelengthGroup mod_wavelengths = makeWavelengthGroup(getParameter("ModStart"), getParameter("ModEnd"));
8710447Snilay@cs.wisc.edu        int number_wavelengths = mod_wavelengths.second - mod_wavelengths.first + 1;
8810447Snilay@cs.wisc.edu        bool optimize_loss = getParameter("OptimizeLoss");
8910447Snilay@cs.wisc.edu
9010447Snilay@cs.wisc.edu        getGenProperties()->set("NumberWavelengths", number_wavelengths);
9110447Snilay@cs.wisc.edu
9210447Snilay@cs.wisc.edu        // Create optical ports
9310447Snilay@cs.wisc.edu        createOpticalInputPort(         "In",   in_wavelengths);
9410447Snilay@cs.wisc.edu        createOpticalOutputPort(        "Out",  in_wavelengths);
9510447Snilay@cs.wisc.edu        // Create the filter and modulator
9610447Snilay@cs.wisc.edu        createFilter(                   "RingFilter",       in_wavelengths, true, mod_wavelengths);
9710447Snilay@cs.wisc.edu        createModulator(                "RingModulator",    mod_wavelengths, optimize_loss, this);
9810447Snilay@cs.wisc.edu        createWaveguide(                "RingTemp",         mod_wavelengths);
9910447Snilay@cs.wisc.edu        OpticalFilter* ring_filter = getFilter("RingFilter");
10010447Snilay@cs.wisc.edu        OpticalModulator* ring_modulator = getModulator("RingModulator");
10110447Snilay@cs.wisc.edu        // Connect the filter and modulator
10210447Snilay@cs.wisc.edu        getWaveguide("In")->addDownstreamNode(ring_filter);
10310447Snilay@cs.wisc.edu        ring_filter->addDownstreamNode(getWaveguide("Out"));
10410447Snilay@cs.wisc.edu        ring_filter->setDropPort(ring_modulator);
10510447Snilay@cs.wisc.edu        ring_modulator->addDownstreamNode(getWaveguide("Out"));
10610447Snilay@cs.wisc.edu
10710447Snilay@cs.wisc.edu        // Create electrical ports
10810447Snilay@cs.wisc.edu        createInputPort(                "In", makeNetIndex(0, number_wavelengths-1));
10910447Snilay@cs.wisc.edu        // Create driver
11010447Snilay@cs.wisc.edu        createNet("PredriverIn");
11110447Snilay@cs.wisc.edu        // VFI from In to PredriverIn
11210447Snilay@cs.wisc.edu        assignVirtualFanin("PredriverIn", "In");
11310447Snilay@cs.wisc.edu        // Create input load (due to predrivers)
11410447Snilay@cs.wisc.edu        createLoad("PredriverCap");
11510447Snilay@cs.wisc.edu        getNet("PredriverIn")->addDownstreamNode(getLoad("PredriverCap"));
11610447Snilay@cs.wisc.edu
11710447Snilay@cs.wisc.edu        // Precompute some values
11810447Snilay@cs.wisc.edu        precomputeTech();
11910447Snilay@cs.wisc.edu
12010447Snilay@cs.wisc.edu        return;
12110447Snilay@cs.wisc.edu    }
12210447Snilay@cs.wisc.edu
12310447Snilay@cs.wisc.edu    void RingModulator::updateModel()
12410447Snilay@cs.wisc.edu    {
12510447Snilay@cs.wisc.edu        // Get properties
12610447Snilay@cs.wisc.edu        double ER_dB = getProperty("ExtinctionRatio").toDouble();
12710447Snilay@cs.wisc.edu        double IL_dB = getProperty("InsertionLoss").toDouble();
12810447Snilay@cs.wisc.edu
12910447Snilay@cs.wisc.edu        // Get Gen properties
13010447Snilay@cs.wisc.edu        int number_wavelengths = getGenProperties()->get("NumberWavelengths");
13110447Snilay@cs.wisc.edu
13210447Snilay@cs.wisc.edu        // Get tech model parameters
13310447Snilay@cs.wisc.edu        double ring_area = getTechModel()->get("Ring->Area").toDouble();
13410447Snilay@cs.wisc.edu        double thru_loss = getTechModel()->get("Ring->ThroughLoss").toDouble();
13510447Snilay@cs.wisc.edu
13610447Snilay@cs.wisc.edu        // Design the modulator and the modulator driver
13710447Snilay@cs.wisc.edu        bool success = designModulator(IL_dB, ER_dB);
13810447Snilay@cs.wisc.edu        getGenProperties()->set("Success", success);
13910447Snilay@cs.wisc.edu
14010447Snilay@cs.wisc.edu        // If not successful, make the modulate energy extremely large
14110447Snilay@cs.wisc.edu        if (!success) getEventResult("Modulate")->setValue(1e99);
14210447Snilay@cs.wisc.edu
14310447Snilay@cs.wisc.edu        // Update losses
14410447Snilay@cs.wisc.edu        // Connect the filter and modulator
14510447Snilay@cs.wisc.edu        OpticalFilter* ring_filter = getFilter("RingFilter");
14610447Snilay@cs.wisc.edu        ring_filter->setLoss(thru_loss * number_wavelengths);
14710447Snilay@cs.wisc.edu        ring_filter->setDropLoss(thru_loss * number_wavelengths);     // Assume worst-case through loss for a dropped wavelength
14810447Snilay@cs.wisc.edu        // Update area
14910447Snilay@cs.wisc.edu        getAreaResult("Photonic")->setValue(ring_area * (number_wavelengths));
15010447Snilay@cs.wisc.edu    }
15110447Snilay@cs.wisc.edu
15210447Snilay@cs.wisc.edu    void RingModulator::useModel()
15310447Snilay@cs.wisc.edu    {
15410447Snilay@cs.wisc.edu        // Propagate the transition info and get the 0->1 transtion count
15510447Snilay@cs.wisc.edu        propagateTransitionInfo();
15610447Snilay@cs.wisc.edu        double P_In = getInputPort("In")->getTransitionInfo().getProbability1();
15710447Snilay@cs.wisc.edu        double P_num_trans_01 = getInputPort("In")->getTransitionInfo().getNumberTransitions01();
15810447Snilay@cs.wisc.edu
15910447Snilay@cs.wisc.edu        // Get Gen properties
16010447Snilay@cs.wisc.edu        int number_wavelengths = getGenProperties()->get("NumberWavelengths");
16110447Snilay@cs.wisc.edu
16210447Snilay@cs.wisc.edu        // If I can't build it...then it is infinitely expensive!
16310447Snilay@cs.wisc.edu        bool success = getGenProperties()->get("Success");
16410447Snilay@cs.wisc.edu        double driver_size = 1e99;
16510447Snilay@cs.wisc.edu        double total_predriver_size = 1e99;
16610447Snilay@cs.wisc.edu        if (success)
16710447Snilay@cs.wisc.edu        {
16810447Snilay@cs.wisc.edu            driver_size = getGenProperties()->get("DriverSize");
16910447Snilay@cs.wisc.edu            total_predriver_size = getGenProperties()->get("TotalPredriverSize");
17010447Snilay@cs.wisc.edu        }
17110447Snilay@cs.wisc.edu
17210447Snilay@cs.wisc.edu        // Get parameters corresponding to a unit-inverter
17310447Snilay@cs.wisc.edu        double unit_leak_0 = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Leakage->!A");
17410447Snilay@cs.wisc.edu        double unit_leak_1 = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Leakage->A");
17510447Snilay@cs.wisc.edu
17610447Snilay@cs.wisc.edu        // Approximate leakage
17710447Snilay@cs.wisc.edu        double total_leakage = number_wavelengths * 0.5 * ((driver_size + total_predriver_size) * P_In * unit_leak_1 +
17810447Snilay@cs.wisc.edu                                                            (driver_size + total_predriver_size) * (1 - P_In) * unit_leak_0);
17910447Snilay@cs.wisc.edu
18010447Snilay@cs.wisc.edu        getNddPowerResult("Leakage")->setValue(total_leakage);
18110447Snilay@cs.wisc.edu        getEventResult("Modulate")->setValue(calcModulatorEnergy() * P_num_trans_01);
18210447Snilay@cs.wisc.edu
18310447Snilay@cs.wisc.edu        return;
18410447Snilay@cs.wisc.edu    }
18510447Snilay@cs.wisc.edu
18610447Snilay@cs.wisc.edu    void RingModulator::propagateTransitionInfo()
18710447Snilay@cs.wisc.edu    {
18810447Snilay@cs.wisc.edu        // Very simple...whatever comes in electrically is encoded optically
18910447Snilay@cs.wisc.edu        getOpticalOutputPort("Out")->setTransitionInfo(getInputPort("In")->getTransitionInfo());
19010447Snilay@cs.wisc.edu
19110447Snilay@cs.wisc.edu        return;
19210447Snilay@cs.wisc.edu    }
19310447Snilay@cs.wisc.edu
19410447Snilay@cs.wisc.edu    void RingModulator::precomputeTech()
19510447Snilay@cs.wisc.edu    {
19610447Snilay@cs.wisc.edu        // Get parameters
19710447Snilay@cs.wisc.edu        double data_rate = getParameter("DataRate");
19810447Snilay@cs.wisc.edu
19910447Snilay@cs.wisc.edu        // Constants shortcuts
20010447Snilay@cs.wisc.edu        double pi = Constants::pi;
20110447Snilay@cs.wisc.edu        double c = Constants::c;
20210447Snilay@cs.wisc.edu        double k = Constants::k;
20310447Snilay@cs.wisc.edu        double e0 = Constants::e0;
20410447Snilay@cs.wisc.edu        double es = Constants::es;
20510447Snilay@cs.wisc.edu        double q = Constants::q;
20610447Snilay@cs.wisc.edu        double T = getTechModel()->get("Temperature");
20710447Snilay@cs.wisc.edu
20810447Snilay@cs.wisc.edu        // Get modulator parameters
20910447Snilay@cs.wisc.edu        double lambda = getTechModel()->get("Ring->Lambda").toDouble();
21010447Snilay@cs.wisc.edu        double n_f = getTechModel()->get("Modulator->Ring->FCPDEffect").toDouble();
21110447Snilay@cs.wisc.edu        double NA = getTechModel()->get("Modulator->Ring->NA").toDouble();
21210447Snilay@cs.wisc.edu        double ND = getTechModel()->get("Modulator->Ring->ND").toDouble();
21310447Snilay@cs.wisc.edu        double ni = getTechModel()->get("Modulator->Ring->ni").toDouble();
21410447Snilay@cs.wisc.edu        double L_j = getTechModel()->get("Modulator->Ring->JunctionRatio").toDouble();
21510447Snilay@cs.wisc.edu        double H = getTechModel()->get("Modulator->Ring->Height").toDouble();
21610447Snilay@cs.wisc.edu        double W = getTechModel()->get("Modulator->Ring->Width").toDouble();
21710447Snilay@cs.wisc.edu        double g_c = getTechModel()->get("Modulator->Ring->ConfinementFactor").toDouble();
21810447Snilay@cs.wisc.edu        // Get ring parameters
21910447Snilay@cs.wisc.edu        double R = getTechModel()->get("Ring->Radius").toDouble();
22010447Snilay@cs.wisc.edu        double n_g = getTechModel()->get("Ring->GroupIndex").toDouble();
22110447Snilay@cs.wisc.edu        double Q_max = getTechModel()->get("Ring->MaxQualityFactor").toDouble();
22210447Snilay@cs.wisc.edu
22310447Snilay@cs.wisc.edu        // Setup calculations
22410447Snilay@cs.wisc.edu        double f0 = c / lambda;
22510447Snilay@cs.wisc.edu        double BW = data_rate;                      // Modulator bandwidth
22610447Snilay@cs.wisc.edu        double Q_f = std::min(f0 / BW, Q_max);      // Quality factor
22710447Snilay@cs.wisc.edu        double L_tot = 2 * pi * R;                  // Optical length of the ring
22810447Snilay@cs.wisc.edu
22910447Snilay@cs.wisc.edu        double V_bi = k * T / q * log(NA * ND / (ni * ni));                     // Junction Built-in voltage
23010447Snilay@cs.wisc.edu        double x_d0 = sqrt(2 * e0 * es / q * V_bi * (NA + ND) / (NA * ND));     // Junction nominal depletion width
23110447Snilay@cs.wisc.edu        double C_j0 = e0 * es * L_tot * L_j * W / x_d0;                         // Junction nominal cap
23210447Snilay@cs.wisc.edu        double Q_0 = q * n_g * (L_tot * H * W) / (2 * n_f * Q_f * g_c);         // Charge in depletion region
23310447Snilay@cs.wisc.edu
23410447Snilay@cs.wisc.edu        // Store into precomputed values
23510447Snilay@cs.wisc.edu        m_precompute_V_bi_ = V_bi;
23610447Snilay@cs.wisc.edu        m_precompute_x_d0_ = x_d0;
23710447Snilay@cs.wisc.edu        m_precompute_C_j0_ = C_j0;
23810447Snilay@cs.wisc.edu        m_precompute_Q_0_ = Q_0;
23910447Snilay@cs.wisc.edu
24010447Snilay@cs.wisc.edu        return;
24110447Snilay@cs.wisc.edu    }
24210447Snilay@cs.wisc.edu
24310447Snilay@cs.wisc.edu    bool RingModulator::designModulator(double IL_dB_, double ER_dB_)
24410447Snilay@cs.wisc.edu    {
24510447Snilay@cs.wisc.edu        // Get parameters
24610447Snilay@cs.wisc.edu        double vdd = getTechModel()->get("Vdd");
24710447Snilay@cs.wisc.edu        double data_rate = getParameter("DataRate");
24810447Snilay@cs.wisc.edu        unsigned int max_predriver_stages = 20;         //TODO: Make this not hardcoded
24910447Snilay@cs.wisc.edu        // Get modulator parameters
25010447Snilay@cs.wisc.edu        double boost_ratio = getTechModel()->get("Modulator->Ring->SupplyBoostRatio");
25110447Snilay@cs.wisc.edu        double Tn = getTechModel()->get("Modulator->Ring->Tn").toDouble();;
25210447Snilay@cs.wisc.edu        double H = getTechModel()->get("Modulator->Ring->Height").toDouble();
25310447Snilay@cs.wisc.edu
25410447Snilay@cs.wisc.edu        // Get Gen properties
25510447Snilay@cs.wisc.edu        int number_wavelengths = getGenProperties()->get("NumberWavelengths");
25610447Snilay@cs.wisc.edu
25710447Snilay@cs.wisc.edu        // Checking ASSERTions (input properties that don't make any sense)
25810447Snilay@cs.wisc.edu        ASSERT(ER_dB_ > 0, "[Error] " + getInstanceName() + " -> Extinction ratio must be > 0!");
25910447Snilay@cs.wisc.edu        ASSERT(IL_dB_ > 0, "[Error] " + getInstanceName() + " -> Insertion loss must be > 0!");
26010447Snilay@cs.wisc.edu
26110447Snilay@cs.wisc.edu        // Setup calculations
26210447Snilay@cs.wisc.edu        double ER = pow(10, ER_dB_ / 10);            // Extinction ratio
26310447Snilay@cs.wisc.edu        double T1 = pow(10, -IL_dB_ / 10);           // Transmisivity on
26410447Snilay@cs.wisc.edu        double T0 = T1 / ER;                        // Transmisivity off
26510447Snilay@cs.wisc.edu
26610447Snilay@cs.wisc.edu        // Get precomputed values
26710447Snilay@cs.wisc.edu        double V_bi = m_precompute_V_bi_;
26810447Snilay@cs.wisc.edu        double x_d0 = m_precompute_x_d0_;
26910447Snilay@cs.wisc.edu        double C_j0 = m_precompute_C_j0_;
27010447Snilay@cs.wisc.edu        double Q_0 = m_precompute_Q_0_;
27110447Snilay@cs.wisc.edu
27210447Snilay@cs.wisc.edu        // Charge
27310447Snilay@cs.wisc.edu        double int_c = -2 * V_bi * C_j0;
27410447Snilay@cs.wisc.edu        // Calculate shift using lorentzian
27510447Snilay@cs.wisc.edu        double gamma = sqrt((1 - Tn)/(1 - T1) - 1) - sqrt((1 - Tn)/(1 - T0) - 1);   // gamma = delta_f / delta_f_FWHM
27610447Snilay@cs.wisc.edu        double Q = gamma * Q_0;                                                     // Charge required to hit given Tf
27710447Snilay@cs.wisc.edu        // Voltage required
27810447Snilay@cs.wisc.edu        double V_a = V_bi * (pow( (Q - int_c)/(2 * V_bi * C_j0), 2) - 1);
27910447Snilay@cs.wisc.edu        // Calculate driver vdd
28010447Snilay@cs.wisc.edu        double hvdd = V_a * boost_ratio;
28110447Snilay@cs.wisc.edu        // Depletion region required
28210447Snilay@cs.wisc.edu        double x_d = x_d0 * sqrt((V_bi + V_a) / V_bi);
28310447Snilay@cs.wisc.edu
28410447Snilay@cs.wisc.edu        // Calculate C_eff
28510447Snilay@cs.wisc.edu        double c_eff = Q / V_a;
28610447Snilay@cs.wisc.edu
28710447Snilay@cs.wisc.edu        // Feasibility checks
28810447Snilay@cs.wisc.edu        // Not feasible if the transmisivity when transmitting an optical 1 is greater than 1.0...
28910447Snilay@cs.wisc.edu        if (T1 >= 1) return false;
29010447Snilay@cs.wisc.edu        // Not feasible if the transmisivity when transmitting an optical 0 is smaller than the notch of the ring
29110447Snilay@cs.wisc.edu        if (T0 <= Tn) return false;
29210447Snilay@cs.wisc.edu        // Not feasible if the extinction ratio is greater than the notch of the ring
29310447Snilay@cs.wisc.edu        if (ER >= 1 / Tn) return false;
29410447Snilay@cs.wisc.edu        // Not feasible if the required depletion width is greater than the height of the junction
29510447Snilay@cs.wisc.edu        if (x_d >= H) return false;
29610447Snilay@cs.wisc.edu
29710447Snilay@cs.wisc.edu        // Analytically calculate driver sizes
29810447Snilay@cs.wisc.edu        // Get parameters corresponding to a unit-inverter
29910447Snilay@cs.wisc.edu        double unit_c_g = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->A");
30010447Snilay@cs.wisc.edu        double unit_c_d = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->Y");
30110447Snilay@cs.wisc.edu        double unit_r_o = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->DriveRes->Y");
30210447Snilay@cs.wisc.edu        double unit_area_active = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Area->Active");
30310447Snilay@cs.wisc.edu        double unit_area_metal1 = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Area->Metal1Wire");
30410447Snilay@cs.wisc.edu
30510447Snilay@cs.wisc.edu        // Get device resistance/cap
30610447Snilay@cs.wisc.edu        double device_par_res = getTechModel()->get("Modulator->Ring->ParasiticRes");
30710447Snilay@cs.wisc.edu        double device_par_cap = getTechModel()->get("Modulator->Ring->ParasiticCap");
30810447Snilay@cs.wisc.edu
30910447Snilay@cs.wisc.edu        // Use timing tree to size modulator drivers
31010447Snilay@cs.wisc.edu        // Coefficient of R*C to give a 0->V_a transition
31110447Snilay@cs.wisc.edu        double transition_scale = log(hvdd / (hvdd - V_a));
31210447Snilay@cs.wisc.edu        double transition_required = 1 / (4 * data_rate);      // I am not sure what the factor of 4 is for...
31310447Snilay@cs.wisc.edu
31410447Snilay@cs.wisc.edu        // Calculate inverter intrinsic transition time
31510447Snilay@cs.wisc.edu        double transition_intrinsic = transition_scale * unit_c_d * unit_r_o;
31610447Snilay@cs.wisc.edu        // Calculate minimum possible device transition time
31710447Snilay@cs.wisc.edu        double min_transition_intrinsic = transition_intrinsic + transition_scale * device_par_res * c_eff;
31810447Snilay@cs.wisc.edu        // If the minimum possible transition time is already bigger
31910447Snilay@cs.wisc.edu        // than the required transition, then this particular driver is not possible...
32010447Snilay@cs.wisc.edu        if (min_transition_intrinsic > transition_required)
32110447Snilay@cs.wisc.edu            return false;
32210447Snilay@cs.wisc.edu
32310447Snilay@cs.wisc.edu        // Calculate driver size
32410447Snilay@cs.wisc.edu        double driver_size = max(1.0, transition_scale * unit_r_o * (c_eff + device_par_cap) / (transition_required - min_transition_intrinsic));
32510447Snilay@cs.wisc.edu        // Keep track of the total multiplier of unit inverters (for area, leakage calculations)
32610447Snilay@cs.wisc.edu        double total_unit_inverters = driver_size * max(1.0, hvdd / vdd);
32710447Snilay@cs.wisc.edu        // Calculate load cap for predriver stages
32810447Snilay@cs.wisc.edu        double current_load_cap = driver_size * unit_c_g;
32910447Snilay@cs.wisc.edu        // Number of predriver stages
33010447Snilay@cs.wisc.edu        unsigned int predriver_stages = 0;
33110447Snilay@cs.wisc.edu        // Add predriver stages until the input cap is less than the unit INV_X1 gate cap or
33210447Snilay@cs.wisc.edu        // if the signal is still inverted (need an odd number of predriver stages)
33310447Snilay@cs.wisc.edu        while (current_load_cap > unit_c_g || (predriver_stages == 0) || ((predriver_stages & 0x1) == 0))
33410447Snilay@cs.wisc.edu        {
33510447Snilay@cs.wisc.edu            // Calculate the size of the current predriver stage
33610447Snilay@cs.wisc.edu            double current_predriver_size = max(1.0, unit_r_o * current_load_cap / (transition_required - transition_intrinsic));
33710447Snilay@cs.wisc.edu            // Calculate load cap for the next predriver stage
33810447Snilay@cs.wisc.edu            current_load_cap = current_predriver_size * unit_c_g;
33910447Snilay@cs.wisc.edu            // Add cap to total predriver total cap
34010447Snilay@cs.wisc.edu            total_unit_inverters += current_predriver_size;
34110447Snilay@cs.wisc.edu            // Consider this a failure if the number of predriver stages exceed some maximum
34210447Snilay@cs.wisc.edu            if (predriver_stages > max_predriver_stages)
34310447Snilay@cs.wisc.edu                return false;
34410447Snilay@cs.wisc.edu
34510447Snilay@cs.wisc.edu            ++predriver_stages;
34610447Snilay@cs.wisc.edu        }
34710447Snilay@cs.wisc.edu        // Set the input load capacitance
34810447Snilay@cs.wisc.edu        getLoad("PredriverCap")->setLoadCap(current_load_cap);
34910447Snilay@cs.wisc.edu
35010447Snilay@cs.wisc.edu        // Set generated properties
35110447Snilay@cs.wisc.edu        getGenProperties()->set("DriverSize", driver_size);
35210447Snilay@cs.wisc.edu        getGenProperties()->set("FirstPredriverSize", current_load_cap);
35310447Snilay@cs.wisc.edu        getGenProperties()->set("TotalPredriverSize", total_unit_inverters - driver_size);
35410447Snilay@cs.wisc.edu        getGenProperties()->set("Hvdd", hvdd);
35510447Snilay@cs.wisc.edu        getGenProperties()->set("Ceff", c_eff);
35610447Snilay@cs.wisc.edu
35710447Snilay@cs.wisc.edu        // Calculate leakage, area, energy consumption
35810447Snilay@cs.wisc.edu        double area_active = total_unit_inverters * unit_area_active;
35910447Snilay@cs.wisc.edu        double area_metal1 = total_unit_inverters * unit_area_metal1;
36010447Snilay@cs.wisc.edu
36110447Snilay@cs.wisc.edu        // Set results
36210447Snilay@cs.wisc.edu        getAreaResult("Active")->setValue(area_active * number_wavelengths);
36310447Snilay@cs.wisc.edu        getAreaResult("Metal1Wire")->setValue(area_metal1 * number_wavelengths);
36410447Snilay@cs.wisc.edu
36510447Snilay@cs.wisc.edu        // Only if everything was successful do we set the modulator specification
36610447Snilay@cs.wisc.edu        getModulator("RingModulator")->setLosses(IL_dB_, ER_dB_);
36710447Snilay@cs.wisc.edu        return true;
36810447Snilay@cs.wisc.edu    }
36910447Snilay@cs.wisc.edu
37010447Snilay@cs.wisc.edu    double RingModulator::calcModulatorEnergy() const
37110447Snilay@cs.wisc.edu    {
37210447Snilay@cs.wisc.edu        // Get tech parameters
37310447Snilay@cs.wisc.edu        double vdd = getTechModel()->get("Vdd");
37410447Snilay@cs.wisc.edu        double device_par_cap = getTechModel()->get("Modulator->Ring->ParasiticCap");
37510447Snilay@cs.wisc.edu
37610447Snilay@cs.wisc.edu        // Get Gen properties
37710447Snilay@cs.wisc.edu        int number_wavelengths = getGenProperties()->get("NumberWavelengths");
37810447Snilay@cs.wisc.edu
37910447Snilay@cs.wisc.edu        bool success = getGenProperties()->get("Success");
38010447Snilay@cs.wisc.edu        if (success)
38110447Snilay@cs.wisc.edu        {
38210447Snilay@cs.wisc.edu            double driver_size = getGenProperties()->get("DriverSize");
38310447Snilay@cs.wisc.edu            double total_predriver_size = getGenProperties()->get("TotalPredriverSize");
38410447Snilay@cs.wisc.edu            double first_predriver_size = getGenProperties()->get("FirstPredriverSize");
38510447Snilay@cs.wisc.edu            double c_eff = getGenProperties()->get("Ceff");
38610447Snilay@cs.wisc.edu            double hvdd = getGenProperties()->get("Hvdd");
38710447Snilay@cs.wisc.edu
38810447Snilay@cs.wisc.edu            // Get parameters corresponding to a unit-inverter
38910447Snilay@cs.wisc.edu            double unit_c_g = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->A");
39010447Snilay@cs.wisc.edu            double unit_c_d = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->Y");
39110447Snilay@cs.wisc.edu
39210447Snilay@cs.wisc.edu            // Approximate leakage
39310447Snilay@cs.wisc.edu            double energy_predriver = number_wavelengths * vdd * vdd * ((unit_c_d * total_predriver_size +
39410447Snilay@cs.wisc.edu                                            unit_c_g * (total_predriver_size + driver_size - first_predriver_size)));
39510447Snilay@cs.wisc.edu            double energy_driver = number_wavelengths * hvdd * std::max(hvdd, vdd) * (driver_size * unit_c_d + c_eff + device_par_cap);
39610447Snilay@cs.wisc.edu
39710447Snilay@cs.wisc.edu            return (energy_predriver + energy_driver);
39810447Snilay@cs.wisc.edu        }
39910447Snilay@cs.wisc.edu        else
40010447Snilay@cs.wisc.edu            return 1e99;    // An infinitely expensive modulator
40110447Snilay@cs.wisc.edu    }
40210447Snilay@cs.wisc.edu
40310447Snilay@cs.wisc.edu    bool RingModulator::setTransmitterSpec(double IL_dB_, double ER_dB_)
40410447Snilay@cs.wisc.edu    {
40510447Snilay@cs.wisc.edu        setProperty("InsertionLoss", IL_dB_);
40610447Snilay@cs.wisc.edu        setProperty("ExtinctionRatio", ER_dB_);
40710447Snilay@cs.wisc.edu        update();
40810447Snilay@cs.wisc.edu        evaluate();
40910447Snilay@cs.wisc.edu
41010447Snilay@cs.wisc.edu        return getGenProperties()->get("Success");
41110447Snilay@cs.wisc.edu    }
41210447Snilay@cs.wisc.edu
41310447Snilay@cs.wisc.edu    double RingModulator::getPower(double util_) const
41410447Snilay@cs.wisc.edu    {
41510447Snilay@cs.wisc.edu        // Get parameters
41610447Snilay@cs.wisc.edu        double data_rate = getParameter("DataRate");
41710447Snilay@cs.wisc.edu		// Check arguments
41810447Snilay@cs.wisc.edu        ASSERT((util_ <= 1.0) && (util_ >= 0.0), "[Error] " + getInstanceName() + " -> Modulator utilization must be between 0.0 and 1.0!");
41910447Snilay@cs.wisc.edu
42010447Snilay@cs.wisc.edu        return calcModulatorEnergy() * 0.25 * util_ * data_rate;
42110447Snilay@cs.wisc.edu    }
42210447Snilay@cs.wisc.edu
42310447Snilay@cs.wisc.edu} // namespace DSENT
42410447Snilay@cs.wisc.edu
425