RingModulator.cc revision 10447
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