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/RingDetector.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/OpticalDetector.h"
3410447Snilay@cs.wisc.edu#include "model/optical_graph/OpticalFilter.h"
3510447Snilay@cs.wisc.edu#include "model/timing_graph/ElectricalDriver.h"
3610447Snilay@cs.wisc.edu#include "model/timing_graph/ElectricalNet.h"
3710447Snilay@cs.wisc.edu
3810447Snilay@cs.wisc.edunamespace DSENT
3910447Snilay@cs.wisc.edu{
4010447Snilay@cs.wisc.edu    // TODOs for this model
4110447Snilay@cs.wisc.edu    // Add the other receiver topologies from [Georgas, CICC 2011]
4210447Snilay@cs.wisc.edu    // Split integ_time_ratio = SA integ time ratio
4310447Snilay@cs.wisc.edu    // Right now perfect clock gating is assumed...may not be what we want
4410447Snilay@cs.wisc.edu
4510447Snilay@cs.wisc.edu    // Constants
4610447Snilay@cs.wisc.edu    const String RingDetector::INTEGRATINGSENSEAMP = "INTSA";
4710447Snilay@cs.wisc.edu
4810447Snilay@cs.wisc.edu    RingDetector::RingDetector(const String& instance_name_, const TechModel* tech_model_)
4910447Snilay@cs.wisc.edu        : OpticalModel(instance_name_, tech_model_), OpticalReceiver()
5010447Snilay@cs.wisc.edu    {
5110447Snilay@cs.wisc.edu        initParameters();
5210447Snilay@cs.wisc.edu        initProperties();
5310447Snilay@cs.wisc.edu    }
5410447Snilay@cs.wisc.edu
5510447Snilay@cs.wisc.edu    RingDetector::~RingDetector()
5610447Snilay@cs.wisc.edu    {}
5710447Snilay@cs.wisc.edu
5810447Snilay@cs.wisc.edu    void RingDetector::initParameters()
5910447Snilay@cs.wisc.edu    {
6010447Snilay@cs.wisc.edu        addParameterName("DataRate");
6110447Snilay@cs.wisc.edu        addParameterName("InStart");
6210447Snilay@cs.wisc.edu        addParameterName("InEnd");
6310447Snilay@cs.wisc.edu        addParameterName("DetStart");
6410447Snilay@cs.wisc.edu        addParameterName("DetEnd");
6510447Snilay@cs.wisc.edu        addParameterName("DropAll");
6610447Snilay@cs.wisc.edu        addParameterName("Topology");
6710447Snilay@cs.wisc.edu        return;
6810447Snilay@cs.wisc.edu    }
6910447Snilay@cs.wisc.edu
7010447Snilay@cs.wisc.edu    void RingDetector::initProperties()
7110447Snilay@cs.wisc.edu    {
7210447Snilay@cs.wisc.edu        return;
7310447Snilay@cs.wisc.edu    }
7410447Snilay@cs.wisc.edu
7510447Snilay@cs.wisc.edu    void RingDetector::constructModel()
7610447Snilay@cs.wisc.edu    {
7710447Snilay@cs.wisc.edu        // Get parameters
7810447Snilay@cs.wisc.edu        WavelengthGroup in_wavelengths = makeWavelengthGroup(getParameter("InStart"), getParameter("InEnd"));
7910447Snilay@cs.wisc.edu        WavelengthGroup det_wavelengths = makeWavelengthGroup(getParameter("DetStart"), getParameter("DetEnd"));
8010447Snilay@cs.wisc.edu        int number_wavelengths = det_wavelengths.second - det_wavelengths.first + 1;
8110447Snilay@cs.wisc.edu        bool drop_all = getParameter("DropAll");
8210447Snilay@cs.wisc.edu        const String& topology = getParameter("Topology");
8310447Snilay@cs.wisc.edu
8410447Snilay@cs.wisc.edu        // Set some generated properties
8510447Snilay@cs.wisc.edu        getGenProperties()->set("NumberWavelengths", number_wavelengths);
8610447Snilay@cs.wisc.edu
8710447Snilay@cs.wisc.edu        // Create device area result
8810447Snilay@cs.wisc.edu        addAreaResult(new AtomicResult("Photonic"));
8910447Snilay@cs.wisc.edu        // Create electrical results
9010447Snilay@cs.wisc.edu        createElectricalAtomicResults();
9110447Snilay@cs.wisc.edu        if (topology == INTEGRATINGSENSEAMP) addEventResult(new AtomicResult("Receive"));
9210447Snilay@cs.wisc.edu        else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology + ")!");
9310447Snilay@cs.wisc.edu
9410447Snilay@cs.wisc.edu        // Create optical ports
9510447Snilay@cs.wisc.edu        createOpticalInputPort(         "In",   in_wavelengths);
9610447Snilay@cs.wisc.edu        createOpticalOutputPort(        "Out",  in_wavelengths);
9710447Snilay@cs.wisc.edu        // Create the filter and modulator
9810447Snilay@cs.wisc.edu        createFilter(                   "RingFilter",   in_wavelengths, drop_all, det_wavelengths);
9910447Snilay@cs.wisc.edu        createDetector(                 "RingDetector", det_wavelengths, this);
10010447Snilay@cs.wisc.edu        OpticalFilter* ring_filter = getFilter("RingFilter");
10110447Snilay@cs.wisc.edu        OpticalDetector* ring_detector = getDetector("RingDetector");
10210447Snilay@cs.wisc.edu        // Connect the filter and modulator
10310447Snilay@cs.wisc.edu        getWaveguide("In")->addDownstreamNode(ring_filter);
10410447Snilay@cs.wisc.edu        ring_filter->addDownstreamNode(getWaveguide("Out"));
10510447Snilay@cs.wisc.edu        ring_filter->setDropPort(ring_detector);
10610447Snilay@cs.wisc.edu
10710447Snilay@cs.wisc.edu        // Create electrical ports
10810447Snilay@cs.wisc.edu        createOutputPort("Out", makeNetIndex(0, number_wavelengths-1));
10910447Snilay@cs.wisc.edu        // Create net
11010447Snilay@cs.wisc.edu        createNet("OutVFO");
11110447Snilay@cs.wisc.edu        // Create output driver
11210447Snilay@cs.wisc.edu        createDriver("OutDriver", false);
11310447Snilay@cs.wisc.edu        // Connect driver
11410447Snilay@cs.wisc.edu        getDriver("OutDriver")->addDownstreamNode(getNet("OutVFO"));
11510447Snilay@cs.wisc.edu        // Connect output
11610447Snilay@cs.wisc.edu        assignVirtualFanout("Out", "OutVFO");
11710447Snilay@cs.wisc.edu
11810447Snilay@cs.wisc.edu        // Precompute some technology values
11910447Snilay@cs.wisc.edu        precomputeTech();
12010447Snilay@cs.wisc.edu
12110447Snilay@cs.wisc.edu        return;
12210447Snilay@cs.wisc.edu    }
12310447Snilay@cs.wisc.edu
12410447Snilay@cs.wisc.edu    void RingDetector::updateModel()
12510447Snilay@cs.wisc.edu    {
12610447Snilay@cs.wisc.edu        // Get some generated properties
12710447Snilay@cs.wisc.edu        unsigned int number_wavelengths = getGenProperties()->get("NumberWavelengths");
12810447Snilay@cs.wisc.edu
12910447Snilay@cs.wisc.edu        // Get tech model numbers
13010447Snilay@cs.wisc.edu        double ring_area = getTechModel()->get("Ring->Area");
13110447Snilay@cs.wisc.edu        double thru_loss = getTechModel()->get("Ring->ThroughLoss");
13210447Snilay@cs.wisc.edu        double drop_loss = getTechModel()->get("Ring->DropLoss");
13310447Snilay@cs.wisc.edu        double pd_loss = getTechModel()->get("Photodetector->Loss");
13410447Snilay@cs.wisc.edu        double pd_responsivity = getTechModel()->get("Photodetector->Responsivity");
13510447Snilay@cs.wisc.edu
13610447Snilay@cs.wisc.edu        // Design the receiver
13710447Snilay@cs.wisc.edu        designReceiver();
13810447Snilay@cs.wisc.edu
13910447Snilay@cs.wisc.edu        // Update losses
14010447Snilay@cs.wisc.edu        // Connect the filter and modulator
14110447Snilay@cs.wisc.edu        OpticalFilter* ring_filter = getFilter("RingFilter");
14210447Snilay@cs.wisc.edu        OpticalDetector* ring_detector = getDetector("RingDetector");
14310447Snilay@cs.wisc.edu        ring_filter->setLoss(thru_loss * number_wavelengths);
14410447Snilay@cs.wisc.edu        ring_filter->setDropLoss(drop_loss + thru_loss * number_wavelengths);
14510447Snilay@cs.wisc.edu        ring_detector->setLoss(pd_loss);
14610447Snilay@cs.wisc.edu        ring_detector->setResponsivity(pd_responsivity);
14710447Snilay@cs.wisc.edu        // Update device area
14810447Snilay@cs.wisc.edu        getAreaResult("Photonic")->setValue(ring_area * (number_wavelengths));
14910447Snilay@cs.wisc.edu
15010447Snilay@cs.wisc.edu        return;
15110447Snilay@cs.wisc.edu    }
15210447Snilay@cs.wisc.edu
15310447Snilay@cs.wisc.edu    void RingDetector::useModel()
15410447Snilay@cs.wisc.edu    {
15510447Snilay@cs.wisc.edu        // Get parameters
15610447Snilay@cs.wisc.edu        const String& topology = getParameter("Topology");
15710447Snilay@cs.wisc.edu
15810447Snilay@cs.wisc.edu        // Get some generated properties
15910447Snilay@cs.wisc.edu        unsigned int number_wavelengths = getGenProperties()->get("NumberWavelengths");
16010447Snilay@cs.wisc.edu
16110447Snilay@cs.wisc.edu        // Get optical input transition info
16210447Snilay@cs.wisc.edu        const TransitionInfo& in_trans = getOpticalInputPort("In")->getTransitionInfo();
16310447Snilay@cs.wisc.edu
16410447Snilay@cs.wisc.edu        // Get tech models
16510447Snilay@cs.wisc.edu        double vdd = getTechModel()->get("Vdd");
16610447Snilay@cs.wisc.edu        // Get caps
16710447Snilay@cs.wisc.edu        double unit_gate_cap = getTechModel()->get("Gate->MinWidth").toDouble() * getTechModel()->get("Gate->CapPerWidth").toDouble();
16810447Snilay@cs.wisc.edu        double unit_drain_cap = getTechModel()->get("Gate->MinWidth").toDouble() * getTechModel()->get("Drain->CapPerWidth").toDouble();
16910447Snilay@cs.wisc.edu        double inv_x1_gate_cap = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->A");
17010447Snilay@cs.wisc.edu        double inv_x1_drain_cap = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->Y");
17110447Snilay@cs.wisc.edu
17210447Snilay@cs.wisc.edu        // Construct a simple sense-amp model
17310447Snilay@cs.wisc.edu        if(topology == INTEGRATINGSENSEAMP)
17410447Snilay@cs.wisc.edu        {
17510447Snilay@cs.wisc.edu            // Use ratios from the receiver published in [Georgas, ESSCIRC 2011]
17610447Snilay@cs.wisc.edu            // Note:
17710447Snilay@cs.wisc.edu            // The numbers in the paper (43fJ/b, 50 fJ/b in the cited work) is done with the clock buffer (there are 4 receivers),
17810447Snilay@cs.wisc.edu            // capacitive DAC, and extra output flops used in the physical layout, as the compared receiver is extremely conservative
17910447Snilay@cs.wisc.edu            // We simplified this model to not have the capacitive DAC, the clock buffer (since this is an individual receiver), or
18010447Snilay@cs.wisc.edu            // the extra output flops (since receiver structure is already a posedge flop functionally).
18110447Snilay@cs.wisc.edu            // Look for an upcoming paper [Georgas, JSSC 2012] (when it is published) for the power breakdown pie-chart for the receiver.
18210447Snilay@cs.wisc.edu            // This model only models the latch (sampler) and the dynamic to static (RS latch) part of the design, which is all you really
18310447Snilay@cs.wisc.edu            // need in the receiver.
18410447Snilay@cs.wisc.edu
18510447Snilay@cs.wisc.edu            // Gate caps
18610447Snilay@cs.wisc.edu            double c_gate_sampler = unit_gate_cap * (4 * 2.0 + 2 * 1.0 + 2 * 3.0 + 2 * 5.0) + unit_gate_cap * (2 * 6.0 + 2 * 1.0) + inv_x1_gate_cap;
18710447Snilay@cs.wisc.edu            double c_gate_rslatch = unit_gate_cap * (4 * 1.0) + inv_x1_gate_cap;
18810447Snilay@cs.wisc.edu            // Drain caps
18910447Snilay@cs.wisc.edu            double c_drain_sampler = unit_drain_cap * (2 * 2.0 + 2 * 1.0 + 3 * 5.0 + 1 * 3.0) + inv_x1_drain_cap;
19010447Snilay@cs.wisc.edu            double c_drain_rslatch = unit_drain_cap * (2 * 6.0) + inv_x1_drain_cap;
19110447Snilay@cs.wisc.edu            // Sum up cap switched for the sampler
19210447Snilay@cs.wisc.edu            double c_sampler = c_gate_sampler + c_drain_sampler;
19310447Snilay@cs.wisc.edu            double c_rslatch = c_gate_rslatch + c_drain_rslatch;
19410447Snilay@cs.wisc.edu            // Average cap switched
19510447Snilay@cs.wisc.edu            // Sampler is differential, one side will always switch (R or S in the latch) regardless of probability
19610447Snilay@cs.wisc.edu            double avg_cap = c_sampler + c_rslatch * in_trans.getProbability0() * in_trans.getProbability1();
19710447Snilay@cs.wisc.edu
19810447Snilay@cs.wisc.edu            // Get parameters corresponding to a unit-inverter
19910447Snilay@cs.wisc.edu            double unit_leak_0 = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Leakage->!A");
20010447Snilay@cs.wisc.edu            double unit_leak_1 = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Leakage->A");
20110447Snilay@cs.wisc.edu
20210447Snilay@cs.wisc.edu            // Approximate leakage (curve fit with design)
20310447Snilay@cs.wisc.edu            double total_leakage = 0.5 * (unit_leak_0 + unit_leak_1) * 7.43;
20410447Snilay@cs.wisc.edu
20510447Snilay@cs.wisc.edu            // Create results
20610447Snilay@cs.wisc.edu            getEventResult("Receive")->setValue(vdd * vdd * avg_cap * number_wavelengths);
20710447Snilay@cs.wisc.edu            getNddPowerResult("Leakage")->setValue(total_leakage * number_wavelengths);
20810447Snilay@cs.wisc.edu
20910447Snilay@cs.wisc.edu        }
21010447Snilay@cs.wisc.edu        else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology + ")!");
21110447Snilay@cs.wisc.edu
21210447Snilay@cs.wisc.edu        return;
21310447Snilay@cs.wisc.edu    }
21410447Snilay@cs.wisc.edu
21510447Snilay@cs.wisc.edu    void RingDetector::propagateTransitionInfo()
21610447Snilay@cs.wisc.edu    {
21710447Snilay@cs.wisc.edu        // Propagate probabilities from optical input to electrical output port
21810447Snilay@cs.wisc.edu        getOutputPort("Out")->setTransitionInfo(getOpticalInputPort("In")->getTransitionInfo());
21910447Snilay@cs.wisc.edu
22010447Snilay@cs.wisc.edu        return;
22110447Snilay@cs.wisc.edu    }
22210447Snilay@cs.wisc.edu
22310447Snilay@cs.wisc.edu    void RingDetector::precomputeTech()
22410447Snilay@cs.wisc.edu    {
22510447Snilay@cs.wisc.edu        // Get parameters
22610447Snilay@cs.wisc.edu        const double data_rate = getParameter("DataRate");
22710447Snilay@cs.wisc.edu        const String& topology = getParameter("Topology");
22810447Snilay@cs.wisc.edu
22910447Snilay@cs.wisc.edu        // Get tech model numbers
23010447Snilay@cs.wisc.edu        double pd_cap = getTechModel()->get("Photodetector->Cap");
23110447Snilay@cs.wisc.edu        double parasitic_cap = getTechModel()->get("Photodetector->ParasiticCap");
23210447Snilay@cs.wisc.edu        double apd = getTechModel()->get("Photodetector->AvalancheGain");
23310447Snilay@cs.wisc.edu        double vdd = getTechModel()->get("Vdd");
23410447Snilay@cs.wisc.edu
23510447Snilay@cs.wisc.edu        // Constants shortcuts
23610447Snilay@cs.wisc.edu        double pi = Constants::pi;
23710447Snilay@cs.wisc.edu        double k = Constants::k;
23810447Snilay@cs.wisc.edu        double q = Constants::q;
23910447Snilay@cs.wisc.edu        double T = getTechModel()->get("Temperature");
24010447Snilay@cs.wisc.edu
24110447Snilay@cs.wisc.edu        if(topology == INTEGRATINGSENSEAMP)
24210447Snilay@cs.wisc.edu        {
24310447Snilay@cs.wisc.edu            // Get more tech parameters
24410447Snilay@cs.wisc.edu            double integ_time_ratio = getTechModel()->get("Receiver->Int->IntegrationTimeRatio");
24510447Snilay@cs.wisc.edu            double BER = getTechModel()->get("SenseAmp->BER");
24610447Snilay@cs.wisc.edu            double CMRR = getTechModel()->get("SenseAmp->CMRR");
24710447Snilay@cs.wisc.edu            double offset_comp_bits = getTechModel()->get("SenseAmp->OffsetCompensationBits");
24810447Snilay@cs.wisc.edu            double offset = getTechModel()->get("SenseAmp->OffsetRatio").toDouble() * vdd;
24910447Snilay@cs.wisc.edu            double supply_noise_rand = getTechModel()->get("SenseAmp->SupplyNoiseRandRatio").toDouble() * vdd;
25010447Snilay@cs.wisc.edu            double supply_noise_det = getTechModel()->get("SenseAmp->SupplyNoiseDetRatio").toDouble() * vdd;
25110447Snilay@cs.wisc.edu            double noise_margin = getTechModel()->get("SenseAmp->NoiseMargin");
25210447Snilay@cs.wisc.edu            double jitter_ratio = getTechModel()->get("SenseAmp->JitterRatio");
25310447Snilay@cs.wisc.edu
25410447Snilay@cs.wisc.edu            // Approximate tao using FO4
25510447Snilay@cs.wisc.edu            double unit_drain_cap = getTechModel()->get("Gate->MinWidth").toDouble() * getTechModel()->get("Drain->CapPerWidth").toDouble();
25610447Snilay@cs.wisc.edu            double c_g = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->A");
25710447Snilay@cs.wisc.edu            double c_d = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->Y");
25810447Snilay@cs.wisc.edu            double r_o = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->DriveRes->Y");
25910447Snilay@cs.wisc.edu            // Calculate sense amp tau from sense amp output loading
26010447Snilay@cs.wisc.edu            double tau = r_o * (c_g + c_d);
26110447Snilay@cs.wisc.edu            // Set output inverter drive strength
26210447Snilay@cs.wisc.edu            getDriver("OutDriver")->setOutputRes(r_o);
26310447Snilay@cs.wisc.edu
26410447Snilay@cs.wisc.edu            // Calculate sense amp input cap based on schematic
26510447Snilay@cs.wisc.edu            double sense_amp_cap_in = unit_drain_cap * (2.0 + 3.0 + 5.0 + 1.0);
26610447Snilay@cs.wisc.edu
26710447Snilay@cs.wisc.edu            // Residual offset
26810447Snilay@cs.wisc.edu            double v_residual = 3 * offset / pow(2, offset_comp_bits);
26910447Snilay@cs.wisc.edu            // Noise
27010447Snilay@cs.wisc.edu            double v_noise = supply_noise_rand * supply_noise_rand / (CMRR * CMRR);
27110447Snilay@cs.wisc.edu            // Sense amp voltage build-up minimum
27210447Snilay@cs.wisc.edu            double v_sense = vdd * exp(-(1 - integ_time_ratio) / (data_rate * tau)) + noise_margin + v_residual + supply_noise_det / CMRR;
27310447Snilay@cs.wisc.edu            // Sigmas corresponding to BER
27410447Snilay@cs.wisc.edu            double sigma = calcInvNormCdf(BER);
27510447Snilay@cs.wisc.edu
27610447Snilay@cs.wisc.edu            //K_int is the time the bit is valid for evaluation
27710447Snilay@cs.wisc.edu
27810447Snilay@cs.wisc.edu            // Total input cap load
27910447Snilay@cs.wisc.edu            double input_node_cap = sense_amp_cap_in + pd_cap + parasitic_cap;
28010447Snilay@cs.wisc.edu            double z_int = integ_time_ratio / (data_rate * input_node_cap); //should use K_int
28110447Snilay@cs.wisc.edu
28210447Snilay@cs.wisc.edu            // Store precalculated values
28310447Snilay@cs.wisc.edu            m_quad_a_ = 1 - (sigma * sigma * jitter_ratio * jitter_ratio);
28410447Snilay@cs.wisc.edu            m_quad_b1_ = - 2 * pi / 2 * sigma * sigma * q * 0.7 * data_rate;
28510447Snilay@cs.wisc.edu            m_quad_b2_ = -2 * v_sense / (z_int * apd);
28610447Snilay@cs.wisc.edu            m_quad_c_ = 1 / (z_int * z_int) * (v_sense * v_sense - sigma * sigma * (k * T / input_node_cap + v_noise));
28710447Snilay@cs.wisc.edu        }
28810447Snilay@cs.wisc.edu        else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology + ")!");
28910447Snilay@cs.wisc.edu
29010447Snilay@cs.wisc.edu        return;
29110447Snilay@cs.wisc.edu    }
29210447Snilay@cs.wisc.edu
29310447Snilay@cs.wisc.edu    void RingDetector::designReceiver()
29410447Snilay@cs.wisc.edu    {
29510447Snilay@cs.wisc.edu        // Get some generated properties
29610447Snilay@cs.wisc.edu        unsigned int number_wavelengths = getGenProperties()->get("NumberWavelengths");
29710447Snilay@cs.wisc.edu
29810447Snilay@cs.wisc.edu        // Get relevant properties/parameters
29910447Snilay@cs.wisc.edu        const String& topology = getParameter("Topology");
30010447Snilay@cs.wisc.edu
30110447Snilay@cs.wisc.edu        // Construct a simple sense-amp model
30210447Snilay@cs.wisc.edu        if(topology == INTEGRATINGSENSEAMP)
30310447Snilay@cs.wisc.edu        {
30410447Snilay@cs.wisc.edu            // No really good way to estimate the area...can assume each receiver is the size of 40 inverters, which is
30510447Snilay@cs.wisc.edu            // about the right size for just the sense amp in the layout
30610447Snilay@cs.wisc.edu            double unit_area_active = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Area->Active");
30710447Snilay@cs.wisc.edu            double unit_area_metal1 = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Area->Metal1Wire");
30810447Snilay@cs.wisc.edu            getAreaResult("Active")->setValue(unit_area_active * 40 * number_wavelengths);
30910447Snilay@cs.wisc.edu            getAreaResult("Metal1Wire")->setValue(unit_area_metal1 * 40 * number_wavelengths);
31010447Snilay@cs.wisc.edu        }
31110447Snilay@cs.wisc.edu        else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology + ")!");
31210447Snilay@cs.wisc.edu
31310447Snilay@cs.wisc.edu        return;
31410447Snilay@cs.wisc.edu    }
31510447Snilay@cs.wisc.edu
31610447Snilay@cs.wisc.edu    double RingDetector::getSensitivity(double ER_dB_) const
31710447Snilay@cs.wisc.edu    {
31810447Snilay@cs.wisc.edu        // Get parameters
31910447Snilay@cs.wisc.edu        const String& topology = getParameter("Topology");
32010447Snilay@cs.wisc.edu        // Turn extinction ratio into a ratio from dB scale
32110447Snilay@cs.wisc.edu        double ER = pow(10, ER_dB_ / 10);
32210447Snilay@cs.wisc.edu
32310447Snilay@cs.wisc.edu        // Initialize sensitivity
32410447Snilay@cs.wisc.edu        double sensitivity = 1e99;
32510447Snilay@cs.wisc.edu        // Construct a simple sense-amp model
32610447Snilay@cs.wisc.edu        if(topology == INTEGRATINGSENSEAMP)
32710447Snilay@cs.wisc.edu        {
32810447Snilay@cs.wisc.edu            // Scale photodetector shot noise using ER, add rest of noise source
32910447Snilay@cs.wisc.edu            double b = m_quad_b1_ * (1 + ER) / (2 * (ER - 1)) + m_quad_b2_;
33010447Snilay@cs.wisc.edu
33110447Snilay@cs.wisc.edu            // Find sensitivity (-b + sqrt(b^2-4ac)) / 2a
33210447Snilay@cs.wisc.edu            sensitivity = ((-b + sqrt(b * b - 4 * m_quad_a_ * m_quad_c_)) / (2 * m_quad_a_));
33310447Snilay@cs.wisc.edu        }
33410447Snilay@cs.wisc.edu        else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology + ")!");
33510447Snilay@cs.wisc.edu
33610447Snilay@cs.wisc.edu        return sensitivity;
33710447Snilay@cs.wisc.edu    }
33810447Snilay@cs.wisc.edu
33910447Snilay@cs.wisc.edu    double RingDetector::calcInvNormCdf(double num_)
34010447Snilay@cs.wisc.edu    {
34110447Snilay@cs.wisc.edu        // 53 bit precision for double FP
34210447Snilay@cs.wisc.edu        unsigned int num_iterations = 20;
34310447Snilay@cs.wisc.edu        // Upperbound the step
34410447Snilay@cs.wisc.edu        double step = 20;
34510447Snilay@cs.wisc.edu        double out = step;
34610447Snilay@cs.wisc.edu        // Iteratively guess and check calculation
34710447Snilay@cs.wisc.edu        for (unsigned int i = 0; i < num_iterations; ++i)
34810447Snilay@cs.wisc.edu        {
34910447Snilay@cs.wisc.edu            double current = 0.5 * erfc(out / sqrt(2));
35010447Snilay@cs.wisc.edu            if (current > num_) out += step;
35110447Snilay@cs.wisc.edu            else out -= step;
35210447Snilay@cs.wisc.edu            step = step * 0.5;
35310447Snilay@cs.wisc.edu        }
35410447Snilay@cs.wisc.edu
35510447Snilay@cs.wisc.edu        return out;
35610447Snilay@cs.wisc.edu    }
35710447Snilay@cs.wisc.edu
35810447Snilay@cs.wisc.edu} // namespace DSENT
35910447Snilay@cs.wisc.edu
360