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