1/* Copyright (c) 2012 Massachusetts Institute of Technology
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to deal
5 * in the Software without restriction, including without limitation the rights
6 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 * copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 * THE SOFTWARE.
20 */
21
22#include "model/optical/RingModulator.h"
23
24#include <cmath>
25
26#include "util/Constants.h"
27#include "model/PortInfo.h"
28#include "model/TransitionInfo.h"
29#include "model/EventInfo.h"
30#include "model/std_cells/StdCell.h"
31#include "model/std_cells/StdCellLib.h"
32#include "model/optical_graph/OpticalWaveguide.h"
33#include "model/optical_graph/OpticalModulator.h"
34#include "model/optical_graph/OpticalFilter.h"
35#include "model/optical_graph/OpticalTransmitter.h"
36#include "model/timing_graph/ElectricalNet.h"
37#include "model/timing_graph/ElectricalLoad.h"
38#include "model/timing_graph/ElectricalTimingTree.h"
39
40namespace DSENT
41{
42    using std::max;
43    using std::min;
44
45    // TODO: Don't like the way this is written right now. Probably fix in a future version
46
47    RingModulator::RingModulator(const String& instance_name_, const TechModel* tech_model_)
48        : OpticalModel(instance_name_, tech_model_)
49    {
50        initParameters();
51        initProperties();
52    }
53
54    RingModulator::~RingModulator()
55    {}
56
57    void RingModulator::initParameters()
58    {
59        addParameterName("DataRate");
60        addParameterName("InStart");
61        addParameterName("InEnd");
62        addParameterName("ModStart");
63        addParameterName("ModEnd");
64        addParameterName("OptimizeLoss", "TRUE");
65        return;
66    }
67
68    void RingModulator::initProperties()
69    {
70        addPropertyName("ExtinctionRatio", 6);  //default properties
71        addPropertyName("InsertionLoss", 2);    //default properties
72        return;
73    }
74
75    void RingModulator::constructModel()
76    {
77        // Create electrical results
78        createElectricalAtomicResults();
79        // Create Area result
80        addAreaResult(new AtomicResult("Photonic"));
81        // Create Modulate result
82        createElectricalEventAtomicResult("Modulate");
83
84        // Get parameters
85        WavelengthGroup in_wavelengths = makeWavelengthGroup(getParameter("InStart"), getParameter("InEnd"));
86        WavelengthGroup mod_wavelengths = makeWavelengthGroup(getParameter("ModStart"), getParameter("ModEnd"));
87        int number_wavelengths = mod_wavelengths.second - mod_wavelengths.first + 1;
88        bool optimize_loss = getParameter("OptimizeLoss");
89
90        getGenProperties()->set("NumberWavelengths", number_wavelengths);
91
92        // Create optical ports
93        createOpticalInputPort(         "In",   in_wavelengths);
94        createOpticalOutputPort(        "Out",  in_wavelengths);
95        // Create the filter and modulator
96        createFilter(                   "RingFilter",       in_wavelengths, true, mod_wavelengths);
97        createModulator(                "RingModulator",    mod_wavelengths, optimize_loss, this);
98        createWaveguide(                "RingTemp",         mod_wavelengths);
99        OpticalFilter* ring_filter = getFilter("RingFilter");
100        OpticalModulator* ring_modulator = getModulator("RingModulator");
101        // Connect the filter and modulator
102        getWaveguide("In")->addDownstreamNode(ring_filter);
103        ring_filter->addDownstreamNode(getWaveguide("Out"));
104        ring_filter->setDropPort(ring_modulator);
105        ring_modulator->addDownstreamNode(getWaveguide("Out"));
106
107        // Create electrical ports
108        createInputPort(                "In", makeNetIndex(0, number_wavelengths-1));
109        // Create driver
110        createNet("PredriverIn");
111        // VFI from In to PredriverIn
112        assignVirtualFanin("PredriverIn", "In");
113        // Create input load (due to predrivers)
114        createLoad("PredriverCap");
115        getNet("PredriverIn")->addDownstreamNode(getLoad("PredriverCap"));
116
117        // Precompute some values
118        precomputeTech();
119
120        return;
121    }
122
123    void RingModulator::updateModel()
124    {
125        // Get properties
126        double ER_dB = getProperty("ExtinctionRatio").toDouble();
127        double IL_dB = getProperty("InsertionLoss").toDouble();
128
129        // Get Gen properties
130        int number_wavelengths = getGenProperties()->get("NumberWavelengths");
131
132        // Get tech model parameters
133        double ring_area = getTechModel()->get("Ring->Area").toDouble();
134        double thru_loss = getTechModel()->get("Ring->ThroughLoss").toDouble();
135
136        // Design the modulator and the modulator driver
137        bool success = designModulator(IL_dB, ER_dB);
138        getGenProperties()->set("Success", success);
139
140        // If not successful, make the modulate energy extremely large
141        if (!success) getEventResult("Modulate")->setValue(1e99);
142
143        // Update losses
144        // Connect the filter and modulator
145        OpticalFilter* ring_filter = getFilter("RingFilter");
146        ring_filter->setLoss(thru_loss * number_wavelengths);
147        ring_filter->setDropLoss(thru_loss * number_wavelengths);     // Assume worst-case through loss for a dropped wavelength
148        // Update area
149        getAreaResult("Photonic")->setValue(ring_area * (number_wavelengths));
150    }
151
152    void RingModulator::useModel()
153    {
154        // Propagate the transition info and get the 0->1 transtion count
155        propagateTransitionInfo();
156        double P_In = getInputPort("In")->getTransitionInfo().getProbability1();
157        double P_num_trans_01 = getInputPort("In")->getTransitionInfo().getNumberTransitions01();
158
159        // Get Gen properties
160        int number_wavelengths = getGenProperties()->get("NumberWavelengths");
161
162        // If I can't build it...then it is infinitely expensive!
163        bool success = getGenProperties()->get("Success");
164        double driver_size = 1e99;
165        double total_predriver_size = 1e99;
166        if (success)
167        {
168            driver_size = getGenProperties()->get("DriverSize");
169            total_predriver_size = getGenProperties()->get("TotalPredriverSize");
170        }
171
172        // Get parameters corresponding to a unit-inverter
173        double unit_leak_0 = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Leakage->!A");
174        double unit_leak_1 = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Leakage->A");
175
176        // Approximate leakage
177        double total_leakage = number_wavelengths * 0.5 * ((driver_size + total_predriver_size) * P_In * unit_leak_1 +
178                                                            (driver_size + total_predriver_size) * (1 - P_In) * unit_leak_0);
179
180        getNddPowerResult("Leakage")->setValue(total_leakage);
181        getEventResult("Modulate")->setValue(calcModulatorEnergy() * P_num_trans_01);
182
183        return;
184    }
185
186    void RingModulator::propagateTransitionInfo()
187    {
188        // Very simple...whatever comes in electrically is encoded optically
189        getOpticalOutputPort("Out")->setTransitionInfo(getInputPort("In")->getTransitionInfo());
190
191        return;
192    }
193
194    void RingModulator::precomputeTech()
195    {
196        // Get parameters
197        double data_rate = getParameter("DataRate");
198
199        // Constants shortcuts
200        double pi = Constants::pi;
201        double c = Constants::c;
202        double k = Constants::k;
203        double e0 = Constants::e0;
204        double es = Constants::es;
205        double q = Constants::q;
206        double T = getTechModel()->get("Temperature");
207
208        // Get modulator parameters
209        double lambda = getTechModel()->get("Ring->Lambda").toDouble();
210        double n_f = getTechModel()->get("Modulator->Ring->FCPDEffect").toDouble();
211        double NA = getTechModel()->get("Modulator->Ring->NA").toDouble();
212        double ND = getTechModel()->get("Modulator->Ring->ND").toDouble();
213        double ni = getTechModel()->get("Modulator->Ring->ni").toDouble();
214        double L_j = getTechModel()->get("Modulator->Ring->JunctionRatio").toDouble();
215        double H = getTechModel()->get("Modulator->Ring->Height").toDouble();
216        double W = getTechModel()->get("Modulator->Ring->Width").toDouble();
217        double g_c = getTechModel()->get("Modulator->Ring->ConfinementFactor").toDouble();
218        // Get ring parameters
219        double R = getTechModel()->get("Ring->Radius").toDouble();
220        double n_g = getTechModel()->get("Ring->GroupIndex").toDouble();
221        double Q_max = getTechModel()->get("Ring->MaxQualityFactor").toDouble();
222
223        // Setup calculations
224        double f0 = c / lambda;
225        double BW = data_rate;                      // Modulator bandwidth
226        double Q_f = std::min(f0 / BW, Q_max);      // Quality factor
227        double L_tot = 2 * pi * R;                  // Optical length of the ring
228
229        double V_bi = k * T / q * log(NA * ND / (ni * ni));                     // Junction Built-in voltage
230        double x_d0 = sqrt(2 * e0 * es / q * V_bi * (NA + ND) / (NA * ND));     // Junction nominal depletion width
231        double C_j0 = e0 * es * L_tot * L_j * W / x_d0;                         // Junction nominal cap
232        double Q_0 = q * n_g * (L_tot * H * W) / (2 * n_f * Q_f * g_c);         // Charge in depletion region
233
234        // Store into precomputed values
235        m_precompute_V_bi_ = V_bi;
236        m_precompute_x_d0_ = x_d0;
237        m_precompute_C_j0_ = C_j0;
238        m_precompute_Q_0_ = Q_0;
239
240        return;
241    }
242
243    bool RingModulator::designModulator(double IL_dB_, double ER_dB_)
244    {
245        // Get parameters
246        double vdd = getTechModel()->get("Vdd");
247        double data_rate = getParameter("DataRate");
248        unsigned int max_predriver_stages = 20;         //TODO: Make this not hardcoded
249        // Get modulator parameters
250        double boost_ratio = getTechModel()->get("Modulator->Ring->SupplyBoostRatio");
251        double Tn = getTechModel()->get("Modulator->Ring->Tn").toDouble();;
252        double H = getTechModel()->get("Modulator->Ring->Height").toDouble();
253
254        // Get Gen properties
255        int number_wavelengths = getGenProperties()->get("NumberWavelengths");
256
257        // Checking ASSERTions (input properties that don't make any sense)
258        ASSERT(ER_dB_ > 0, "[Error] " + getInstanceName() + " -> Extinction ratio must be > 0!");
259        ASSERT(IL_dB_ > 0, "[Error] " + getInstanceName() + " -> Insertion loss must be > 0!");
260
261        // Setup calculations
262        double ER = pow(10, ER_dB_ / 10);            // Extinction ratio
263        double T1 = pow(10, -IL_dB_ / 10);           // Transmisivity on
264        double T0 = T1 / ER;                        // Transmisivity off
265
266        // Get precomputed values
267        double V_bi = m_precompute_V_bi_;
268        double x_d0 = m_precompute_x_d0_;
269        double C_j0 = m_precompute_C_j0_;
270        double Q_0 = m_precompute_Q_0_;
271
272        // Charge
273        double int_c = -2 * V_bi * C_j0;
274        // Calculate shift using lorentzian
275        double gamma = sqrt((1 - Tn)/(1 - T1) - 1) - sqrt((1 - Tn)/(1 - T0) - 1);   // gamma = delta_f / delta_f_FWHM
276        double Q = gamma * Q_0;                                                     // Charge required to hit given Tf
277        // Voltage required
278        double V_a = V_bi * (pow( (Q - int_c)/(2 * V_bi * C_j0), 2) - 1);
279        // Calculate driver vdd
280        double hvdd = V_a * boost_ratio;
281        // Depletion region required
282        double x_d = x_d0 * sqrt((V_bi + V_a) / V_bi);
283
284        // Calculate C_eff
285        double c_eff = Q / V_a;
286
287        // Feasibility checks
288        // Not feasible if the transmisivity when transmitting an optical 1 is greater than 1.0...
289        if (T1 >= 1) return false;
290        // Not feasible if the transmisivity when transmitting an optical 0 is smaller than the notch of the ring
291        if (T0 <= Tn) return false;
292        // Not feasible if the extinction ratio is greater than the notch of the ring
293        if (ER >= 1 / Tn) return false;
294        // Not feasible if the required depletion width is greater than the height of the junction
295        if (x_d >= H) return false;
296
297        // Analytically calculate driver sizes
298        // Get parameters corresponding to a unit-inverter
299        double unit_c_g = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->A");
300        double unit_c_d = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->Y");
301        double unit_r_o = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->DriveRes->Y");
302        double unit_area_active = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Area->Active");
303        double unit_area_metal1 = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Area->Metal1Wire");
304
305        // Get device resistance/cap
306        double device_par_res = getTechModel()->get("Modulator->Ring->ParasiticRes");
307        double device_par_cap = getTechModel()->get("Modulator->Ring->ParasiticCap");
308
309        // Use timing tree to size modulator drivers
310        // Coefficient of R*C to give a 0->V_a transition
311        double transition_scale = log(hvdd / (hvdd - V_a));
312        double transition_required = 1 / (4 * data_rate);      // I am not sure what the factor of 4 is for...
313
314        // Calculate inverter intrinsic transition time
315        double transition_intrinsic = transition_scale * unit_c_d * unit_r_o;
316        // Calculate minimum possible device transition time
317        double min_transition_intrinsic = transition_intrinsic + transition_scale * device_par_res * c_eff;
318        // If the minimum possible transition time is already bigger
319        // than the required transition, then this particular driver is not possible...
320        if (min_transition_intrinsic > transition_required)
321            return false;
322
323        // Calculate driver size
324        double driver_size = max(1.0, transition_scale * unit_r_o * (c_eff + device_par_cap) / (transition_required - min_transition_intrinsic));
325        // Keep track of the total multiplier of unit inverters (for area, leakage calculations)
326        double total_unit_inverters = driver_size * max(1.0, hvdd / vdd);
327        // Calculate load cap for predriver stages
328        double current_load_cap = driver_size * unit_c_g;
329        // Number of predriver stages
330        unsigned int predriver_stages = 0;
331        // Add predriver stages until the input cap is less than the unit INV_X1 gate cap or
332        // if the signal is still inverted (need an odd number of predriver stages)
333        while (current_load_cap > unit_c_g || (predriver_stages == 0) || ((predriver_stages & 0x1) == 0))
334        {
335            // Calculate the size of the current predriver stage
336            double current_predriver_size = max(1.0, unit_r_o * current_load_cap / (transition_required - transition_intrinsic));
337            // Calculate load cap for the next predriver stage
338            current_load_cap = current_predriver_size * unit_c_g;
339            // Add cap to total predriver total cap
340            total_unit_inverters += current_predriver_size;
341            // Consider this a failure if the number of predriver stages exceed some maximum
342            if (predriver_stages > max_predriver_stages)
343                return false;
344
345            ++predriver_stages;
346        }
347        // Set the input load capacitance
348        getLoad("PredriverCap")->setLoadCap(current_load_cap);
349
350        // Set generated properties
351        getGenProperties()->set("DriverSize", driver_size);
352        getGenProperties()->set("FirstPredriverSize", current_load_cap);
353        getGenProperties()->set("TotalPredriverSize", total_unit_inverters - driver_size);
354        getGenProperties()->set("Hvdd", hvdd);
355        getGenProperties()->set("Ceff", c_eff);
356
357        // Calculate leakage, area, energy consumption
358        double area_active = total_unit_inverters * unit_area_active;
359        double area_metal1 = total_unit_inverters * unit_area_metal1;
360
361        // Set results
362        getAreaResult("Active")->setValue(area_active * number_wavelengths);
363        getAreaResult("Metal1Wire")->setValue(area_metal1 * number_wavelengths);
364
365        // Only if everything was successful do we set the modulator specification
366        getModulator("RingModulator")->setLosses(IL_dB_, ER_dB_);
367        return true;
368    }
369
370    double RingModulator::calcModulatorEnergy() const
371    {
372        // Get tech parameters
373        double vdd = getTechModel()->get("Vdd");
374        double device_par_cap = getTechModel()->get("Modulator->Ring->ParasiticCap");
375
376        // Get Gen properties
377        int number_wavelengths = getGenProperties()->get("NumberWavelengths");
378
379        bool success = getGenProperties()->get("Success");
380        if (success)
381        {
382            double driver_size = getGenProperties()->get("DriverSize");
383            double total_predriver_size = getGenProperties()->get("TotalPredriverSize");
384            double first_predriver_size = getGenProperties()->get("FirstPredriverSize");
385            double c_eff = getGenProperties()->get("Ceff");
386            double hvdd = getGenProperties()->get("Hvdd");
387
388            // Get parameters corresponding to a unit-inverter
389            double unit_c_g = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->A");
390            double unit_c_d = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->Y");
391
392            // Approximate leakage
393            double energy_predriver = number_wavelengths * vdd * vdd * ((unit_c_d * total_predriver_size +
394                                            unit_c_g * (total_predriver_size + driver_size - first_predriver_size)));
395            double energy_driver = number_wavelengths * hvdd * std::max(hvdd, vdd) * (driver_size * unit_c_d + c_eff + device_par_cap);
396
397            return (energy_predriver + energy_driver);
398        }
399        else
400            return 1e99;    // An infinitely expensive modulator
401    }
402
403    bool RingModulator::setTransmitterSpec(double IL_dB_, double ER_dB_)
404    {
405        setProperty("InsertionLoss", IL_dB_);
406        setProperty("ExtinctionRatio", ER_dB_);
407        update();
408        evaluate();
409
410        return getGenProperties()->get("Success");
411    }
412
413    double RingModulator::getPower(double util_) const
414    {
415        // Get parameters
416        double data_rate = getParameter("DataRate");
417		// Check arguments
418        ASSERT((util_ <= 1.0) && (util_ >= 0.0), "[Error] " + getInstanceName() + " -> Modulator utilization must be between 0.0 and 1.0!");
419
420        return calcModulatorEnergy() * 0.25 * util_ * data_rate;
421    }
422
423} // namespace DSENT
424
425