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