RingDetector.cc revision 10447
1#include "model/optical/RingDetector.h"
2
3#include <cmath>
4
5#include "util/Constants.h"
6#include "model/PortInfo.h"
7#include "model/TransitionInfo.h"
8#include "model/EventInfo.h"
9#include "model/std_cells/StdCell.h"
10#include "model/std_cells/StdCellLib.h"
11#include "model/optical_graph/OpticalWaveguide.h"
12#include "model/optical_graph/OpticalDetector.h"
13#include "model/optical_graph/OpticalFilter.h"
14#include "model/timing_graph/ElectricalDriver.h"
15#include "model/timing_graph/ElectricalNet.h"
16
17namespace DSENT
18{
19    // TODOs for this model
20    // Add the other receiver topologies from [Georgas, CICC 2011]
21    // Split integ_time_ratio = SA integ time ratio
22    // Right now perfect clock gating is assumed...may not be what we want
23
24    // Constants
25    const String RingDetector::INTEGRATINGSENSEAMP = "INTSA";
26
27    RingDetector::RingDetector(const String& instance_name_, const TechModel* tech_model_)
28        : OpticalModel(instance_name_, tech_model_), OpticalReceiver()
29    {
30        initParameters();
31        initProperties();
32    }
33
34    RingDetector::~RingDetector()
35    {}
36
37    void RingDetector::initParameters()
38    {
39        addParameterName("DataRate");
40        addParameterName("InStart");
41        addParameterName("InEnd");
42        addParameterName("DetStart");
43        addParameterName("DetEnd");
44        addParameterName("DropAll");
45        addParameterName("Topology");
46        return;
47    }
48
49    void RingDetector::initProperties()
50    {
51        return;
52    }
53
54    void RingDetector::constructModel()
55    {
56        // Get parameters
57        WavelengthGroup in_wavelengths = makeWavelengthGroup(getParameter("InStart"), getParameter("InEnd"));
58        WavelengthGroup det_wavelengths = makeWavelengthGroup(getParameter("DetStart"), getParameter("DetEnd"));
59        int number_wavelengths = det_wavelengths.second - det_wavelengths.first + 1;
60        bool drop_all = getParameter("DropAll");
61        const String& topology = getParameter("Topology");
62
63        // Set some generated properties
64        getGenProperties()->set("NumberWavelengths", number_wavelengths);
65
66        // Create device area result
67        addAreaResult(new AtomicResult("Photonic"));
68        // Create electrical results
69        createElectricalAtomicResults();
70        if (topology == INTEGRATINGSENSEAMP) addEventResult(new AtomicResult("Receive"));
71        else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology + ")!");
72
73        // Create optical ports
74        createOpticalInputPort(         "In",   in_wavelengths);
75        createOpticalOutputPort(        "Out",  in_wavelengths);
76        // Create the filter and modulator
77        createFilter(                   "RingFilter",   in_wavelengths, drop_all, det_wavelengths);
78        createDetector(                 "RingDetector", det_wavelengths, this);
79        OpticalFilter* ring_filter = getFilter("RingFilter");
80        OpticalDetector* ring_detector = getDetector("RingDetector");
81        // Connect the filter and modulator
82        getWaveguide("In")->addDownstreamNode(ring_filter);
83        ring_filter->addDownstreamNode(getWaveguide("Out"));
84        ring_filter->setDropPort(ring_detector);
85
86        // Create electrical ports
87        createOutputPort("Out", makeNetIndex(0, number_wavelengths-1));
88        // Create net
89        createNet("OutVFO");
90        // Create output driver
91        createDriver("OutDriver", false);
92        // Connect driver
93        getDriver("OutDriver")->addDownstreamNode(getNet("OutVFO"));
94        // Connect output
95        assignVirtualFanout("Out", "OutVFO");
96
97        // Precompute some technology values
98        precomputeTech();
99
100        return;
101    }
102
103    void RingDetector::updateModel()
104    {
105        // Get some generated properties
106        unsigned int number_wavelengths = getGenProperties()->get("NumberWavelengths");
107
108        // Get tech model numbers
109        double ring_area = getTechModel()->get("Ring->Area");
110        double thru_loss = getTechModel()->get("Ring->ThroughLoss");
111        double drop_loss = getTechModel()->get("Ring->DropLoss");
112        double pd_loss = getTechModel()->get("Photodetector->Loss");
113        double pd_responsivity = getTechModel()->get("Photodetector->Responsivity");
114
115        // Design the receiver
116        designReceiver();
117
118        // Update losses
119        // Connect the filter and modulator
120        OpticalFilter* ring_filter = getFilter("RingFilter");
121        OpticalDetector* ring_detector = getDetector("RingDetector");
122        ring_filter->setLoss(thru_loss * number_wavelengths);
123        ring_filter->setDropLoss(drop_loss + thru_loss * number_wavelengths);
124        ring_detector->setLoss(pd_loss);
125        ring_detector->setResponsivity(pd_responsivity);
126        // Update device area
127        getAreaResult("Photonic")->setValue(ring_area * (number_wavelengths));
128
129        return;
130    }
131
132    void RingDetector::useModel()
133    {
134        // Get parameters
135        const String& topology = getParameter("Topology");
136
137        // Get some generated properties
138        unsigned int number_wavelengths = getGenProperties()->get("NumberWavelengths");
139
140        // Get optical input transition info
141        const TransitionInfo& in_trans = getOpticalInputPort("In")->getTransitionInfo();
142
143        // Get tech models
144        double vdd = getTechModel()->get("Vdd");
145        // Get caps
146        double unit_gate_cap = getTechModel()->get("Gate->MinWidth").toDouble() * getTechModel()->get("Gate->CapPerWidth").toDouble();
147        double unit_drain_cap = getTechModel()->get("Gate->MinWidth").toDouble() * getTechModel()->get("Drain->CapPerWidth").toDouble();
148        double inv_x1_gate_cap = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->A");
149        double inv_x1_drain_cap = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->Y");
150
151        // Construct a simple sense-amp model
152        if(topology == INTEGRATINGSENSEAMP)
153        {
154            // Use ratios from the receiver published in [Georgas, ESSCIRC 2011]
155            // Note:
156            // The numbers in the paper (43fJ/b, 50 fJ/b in the cited work) is done with the clock buffer (there are 4 receivers),
157            // capacitive DAC, and extra output flops used in the physical layout, as the compared receiver is extremely conservative
158            // We simplified this model to not have the capacitive DAC, the clock buffer (since this is an individual receiver), or
159            // the extra output flops (since receiver structure is already a posedge flop functionally).
160            // Look for an upcoming paper [Georgas, JSSC 2012] (when it is published) for the power breakdown pie-chart for the receiver.
161            // This model only models the latch (sampler) and the dynamic to static (RS latch) part of the design, which is all you really
162            // need in the receiver.
163
164            // Gate caps
165            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;
166            double c_gate_rslatch = unit_gate_cap * (4 * 1.0) + inv_x1_gate_cap;
167            // Drain caps
168            double c_drain_sampler = unit_drain_cap * (2 * 2.0 + 2 * 1.0 + 3 * 5.0 + 1 * 3.0) + inv_x1_drain_cap;
169            double c_drain_rslatch = unit_drain_cap * (2 * 6.0) + inv_x1_drain_cap;
170            // Sum up cap switched for the sampler
171            double c_sampler = c_gate_sampler + c_drain_sampler;
172            double c_rslatch = c_gate_rslatch + c_drain_rslatch;
173            // Average cap switched
174            // Sampler is differential, one side will always switch (R or S in the latch) regardless of probability
175            double avg_cap = c_sampler + c_rslatch * in_trans.getProbability0() * in_trans.getProbability1();
176
177            // Get parameters corresponding to a unit-inverter
178            double unit_leak_0 = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Leakage->!A");
179            double unit_leak_1 = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Leakage->A");
180
181            // Approximate leakage (curve fit with design)
182            double total_leakage = 0.5 * (unit_leak_0 + unit_leak_1) * 7.43;
183
184            // Create results
185            getEventResult("Receive")->setValue(vdd * vdd * avg_cap * number_wavelengths);
186            getNddPowerResult("Leakage")->setValue(total_leakage * number_wavelengths);
187
188        }
189        else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology + ")!");
190
191        return;
192    }
193
194    void RingDetector::propagateTransitionInfo()
195    {
196        // Propagate probabilities from optical input to electrical output port
197        getOutputPort("Out")->setTransitionInfo(getOpticalInputPort("In")->getTransitionInfo());
198
199        return;
200    }
201
202    void RingDetector::precomputeTech()
203    {
204        // Get parameters
205        const double data_rate = getParameter("DataRate");
206        const String& topology = getParameter("Topology");
207
208        // Get tech model numbers
209        double pd_cap = getTechModel()->get("Photodetector->Cap");
210        double parasitic_cap = getTechModel()->get("Photodetector->ParasiticCap");
211        double apd = getTechModel()->get("Photodetector->AvalancheGain");
212        double vdd = getTechModel()->get("Vdd");
213
214        // Constants shortcuts
215        double pi = Constants::pi;
216        double k = Constants::k;
217        double q = Constants::q;
218        double T = getTechModel()->get("Temperature");
219
220        if(topology == INTEGRATINGSENSEAMP)
221        {
222            // Get more tech parameters
223            double integ_time_ratio = getTechModel()->get("Receiver->Int->IntegrationTimeRatio");
224            double BER = getTechModel()->get("SenseAmp->BER");
225            double CMRR = getTechModel()->get("SenseAmp->CMRR");
226            double offset_comp_bits = getTechModel()->get("SenseAmp->OffsetCompensationBits");
227            double offset = getTechModel()->get("SenseAmp->OffsetRatio").toDouble() * vdd;
228            double supply_noise_rand = getTechModel()->get("SenseAmp->SupplyNoiseRandRatio").toDouble() * vdd;
229            double supply_noise_det = getTechModel()->get("SenseAmp->SupplyNoiseDetRatio").toDouble() * vdd;
230            double noise_margin = getTechModel()->get("SenseAmp->NoiseMargin");
231            double jitter_ratio = getTechModel()->get("SenseAmp->JitterRatio");
232
233            // Approximate tao using FO4
234            double unit_drain_cap = getTechModel()->get("Gate->MinWidth").toDouble() * getTechModel()->get("Drain->CapPerWidth").toDouble();
235            double c_g = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->A");
236            double c_d = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->Y");
237            double r_o = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->DriveRes->Y");
238            // Calculate sense amp tau from sense amp output loading
239            double tau = r_o * (c_g + c_d);
240            // Set output inverter drive strength
241            getDriver("OutDriver")->setOutputRes(r_o);
242
243            // Calculate sense amp input cap based on schematic
244            double sense_amp_cap_in = unit_drain_cap * (2.0 + 3.0 + 5.0 + 1.0);
245
246            // Residual offset
247            double v_residual = 3 * offset / pow(2, offset_comp_bits);
248            // Noise
249            double v_noise = supply_noise_rand * supply_noise_rand / (CMRR * CMRR);
250            // Sense amp voltage build-up minimum
251            double v_sense = vdd * exp(-(1 - integ_time_ratio) / (data_rate * tau)) + noise_margin + v_residual + supply_noise_det / CMRR;
252            // Sigmas corresponding to BER
253            double sigma = calcInvNormCdf(BER);
254
255            //K_int is the time the bit is valid for evaluation
256
257            // Total input cap load
258            double input_node_cap = sense_amp_cap_in + pd_cap + parasitic_cap;
259            double z_int = integ_time_ratio / (data_rate * input_node_cap); //should use K_int
260
261            // Store precalculated values
262            m_quad_a_ = 1 - (sigma * sigma * jitter_ratio * jitter_ratio);
263            m_quad_b1_ = - 2 * pi / 2 * sigma * sigma * q * 0.7 * data_rate;
264            m_quad_b2_ = -2 * v_sense / (z_int * apd);
265            m_quad_c_ = 1 / (z_int * z_int) * (v_sense * v_sense - sigma * sigma * (k * T / input_node_cap + v_noise));
266        }
267        else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology + ")!");
268
269        return;
270    }
271
272    void RingDetector::designReceiver()
273    {
274        // Get some generated properties
275        unsigned int number_wavelengths = getGenProperties()->get("NumberWavelengths");
276
277        // Get relevant properties/parameters
278        const String& topology = getParameter("Topology");
279
280        // Construct a simple sense-amp model
281        if(topology == INTEGRATINGSENSEAMP)
282        {
283            // No really good way to estimate the area...can assume each receiver is the size of 40 inverters, which is
284            // about the right size for just the sense amp in the layout
285            double unit_area_active = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Area->Active");
286            double unit_area_metal1 = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Area->Metal1Wire");
287            getAreaResult("Active")->setValue(unit_area_active * 40 * number_wavelengths);
288            getAreaResult("Metal1Wire")->setValue(unit_area_metal1 * 40 * number_wavelengths);
289        }
290        else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology + ")!");
291
292        return;
293    }
294
295    double RingDetector::getSensitivity(double ER_dB_) const
296    {
297        // Get parameters
298        const String& topology = getParameter("Topology");
299        // Turn extinction ratio into a ratio from dB scale
300        double ER = pow(10, ER_dB_ / 10);
301
302        // Initialize sensitivity
303        double sensitivity = 1e99;
304        // Construct a simple sense-amp model
305        if(topology == INTEGRATINGSENSEAMP)
306        {
307            // Scale photodetector shot noise using ER, add rest of noise source
308            double b = m_quad_b1_ * (1 + ER) / (2 * (ER - 1)) + m_quad_b2_;
309
310            // Find sensitivity (-b + sqrt(b^2-4ac)) / 2a
311            sensitivity = ((-b + sqrt(b * b - 4 * m_quad_a_ * m_quad_c_)) / (2 * m_quad_a_));
312        }
313        else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology + ")!");
314
315        return sensitivity;
316    }
317
318    double RingDetector::calcInvNormCdf(double num_)
319    {
320        // 53 bit precision for double FP
321        unsigned int num_iterations = 20;
322        // Upperbound the step
323        double step = 20;
324        double out = step;
325        // Iteratively guess and check calculation
326        for (unsigned int i = 0; i < num_iterations; ++i)
327        {
328            double current = 0.5 * erfc(out / sqrt(2));
329            if (current > num_) out += step;
330            else out -= step;
331            step = step * 0.5;
332        }
333
334        return out;
335    }
336
337} // namespace DSENT
338
339