1 /* Copyright (c) 2012 Massachusetts Institute of Technology
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:
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
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
22 #include "model/optical/RingModulator.h"
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"
45 // TODO: Don't like the way this is written right now. Probably fix in a future version
47 RingModulator::RingModulator(const String
& instance_name_
, const TechModel
* tech_model_
)
48 : OpticalModel(instance_name_
, tech_model_
)
54 RingModulator::~RingModulator()
57 void RingModulator::initParameters()
59 addParameterName("DataRate");
60 addParameterName("InStart");
61 addParameterName("InEnd");
62 addParameterName("ModStart");
63 addParameterName("ModEnd");
64 addParameterName("OptimizeLoss", "TRUE");
68 void RingModulator::initProperties()
70 addPropertyName("ExtinctionRatio", 6); //default properties
71 addPropertyName("InsertionLoss", 2); //default properties
75 void RingModulator::constructModel()
77 // Create electrical results
78 createElectricalAtomicResults();
80 addAreaResult(new AtomicResult("Photonic"));
81 // Create Modulate result
82 createElectricalEventAtomicResult("Modulate");
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");
90 getGenProperties()->set("NumberWavelengths", number_wavelengths
);
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"));
107 // Create electrical ports
108 createInputPort( "In", makeNetIndex(0, number_wavelengths
-1));
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"));
117 // Precompute some values
123 void RingModulator::updateModel()
126 double ER_dB
= getProperty("ExtinctionRatio").toDouble();
127 double IL_dB
= getProperty("InsertionLoss").toDouble();
129 // Get Gen properties
130 int number_wavelengths
= getGenProperties()->get("NumberWavelengths");
132 // Get tech model parameters
133 double ring_area
= getTechModel()->get("Ring->Area").toDouble();
134 double thru_loss
= getTechModel()->get("Ring->ThroughLoss").toDouble();
136 // Design the modulator and the modulator driver
137 bool success
= designModulator(IL_dB
, ER_dB
);
138 getGenProperties()->set("Success", success
);
140 // If not successful, make the modulate energy extremely large
141 if (!success
) getEventResult("Modulate")->setValue(1e99
);
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
149 getAreaResult("Photonic")->setValue(ring_area
* (number_wavelengths
));
152 void RingModulator::useModel()
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();
159 // Get Gen properties
160 int number_wavelengths
= getGenProperties()->get("NumberWavelengths");
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
;
168 driver_size
= getGenProperties()->get("DriverSize");
169 total_predriver_size
= getGenProperties()->get("TotalPredriverSize");
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");
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
);
180 getNddPowerResult("Leakage")->setValue(total_leakage
);
181 getEventResult("Modulate")->setValue(calcModulatorEnergy() * P_num_trans_01
);
186 void RingModulator::propagateTransitionInfo()
188 // Very simple...whatever comes in electrically is encoded optically
189 getOpticalOutputPort("Out")->setTransitionInfo(getInputPort("In")->getTransitionInfo());
194 void RingModulator::precomputeTech()
197 double data_rate
= getParameter("DataRate");
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");
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();
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
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
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
;
243 bool RingModulator::designModulator(double IL_dB_
, double ER_dB_
)
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();
254 // Get Gen properties
255 int number_wavelengths
= getGenProperties()->get("NumberWavelengths");
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!");
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
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_
;
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
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
);
285 double c_eff
= Q
/ V_a
;
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;
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");
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");
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...
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
)
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))
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
)
347 // Set the input load capacitance
348 getLoad("PredriverCap")->setLoadCap(current_load_cap
);
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
);
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
;
362 getAreaResult("Active")->setValue(area_active
* number_wavelengths
);
363 getAreaResult("Metal1Wire")->setValue(area_metal1
* number_wavelengths
);
365 // Only if everything was successful do we set the modulator specification
366 getModulator("RingModulator")->setLosses(IL_dB_
, ER_dB_
);
370 double RingModulator::calcModulatorEnergy() const
372 // Get tech parameters
373 double vdd
= getTechModel()->get("Vdd");
374 double device_par_cap
= getTechModel()->get("Modulator->Ring->ParasiticCap");
376 // Get Gen properties
377 int number_wavelengths
= getGenProperties()->get("NumberWavelengths");
379 bool success
= getGenProperties()->get("Success");
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");
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");
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
);
397 return (energy_predriver
+ energy_driver
);
400 return 1e99
; // An infinitely expensive modulator
403 bool RingModulator::setTransmitterSpec(double IL_dB_
, double ER_dB_
)
405 setProperty("InsertionLoss", IL_dB_
);
406 setProperty("ExtinctionRatio", ER_dB_
);
410 return getGenProperties()->get("Success");
413 double RingModulator::getPower(double util_
) const
416 double data_rate
= getParameter("DataRate");
418 ASSERT((util_
<= 1.0) && (util_
>= 0.0), "[Error] " + getInstanceName() + " -> Modulator utilization must be between 0.0 and 1.0!");
420 return calcModulatorEnergy() * 0.25 * util_
* data_rate
;