sim, kvm: make KvmVM a System parameter
[gem5.git] / ext / dsent / model / optical / RingModulator.cc
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
40 namespace 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