/* Copyright (c) 2012 Massachusetts Institute of Technology * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "model/optical/RingModulator.h" #include #include "util/Constants.h" #include "model/PortInfo.h" #include "model/TransitionInfo.h" #include "model/EventInfo.h" #include "model/std_cells/StdCell.h" #include "model/std_cells/StdCellLib.h" #include "model/optical_graph/OpticalWaveguide.h" #include "model/optical_graph/OpticalModulator.h" #include "model/optical_graph/OpticalFilter.h" #include "model/optical_graph/OpticalTransmitter.h" #include "model/timing_graph/ElectricalNet.h" #include "model/timing_graph/ElectricalLoad.h" #include "model/timing_graph/ElectricalTimingTree.h" namespace DSENT { using std::max; using std::min; // TODO: Don't like the way this is written right now. Probably fix in a future version RingModulator::RingModulator(const String& instance_name_, const TechModel* tech_model_) : OpticalModel(instance_name_, tech_model_) { initParameters(); initProperties(); } RingModulator::~RingModulator() {} void RingModulator::initParameters() { addParameterName("DataRate"); addParameterName("InStart"); addParameterName("InEnd"); addParameterName("ModStart"); addParameterName("ModEnd"); addParameterName("OptimizeLoss", "TRUE"); return; } void RingModulator::initProperties() { addPropertyName("ExtinctionRatio", 6); //default properties addPropertyName("InsertionLoss", 2); //default properties return; } void RingModulator::constructModel() { // Create electrical results createElectricalAtomicResults(); // Create Area result addAreaResult(new AtomicResult("Photonic")); // Create Modulate result createElectricalEventAtomicResult("Modulate"); // Get parameters WavelengthGroup in_wavelengths = makeWavelengthGroup(getParameter("InStart"), getParameter("InEnd")); WavelengthGroup mod_wavelengths = makeWavelengthGroup(getParameter("ModStart"), getParameter("ModEnd")); int number_wavelengths = mod_wavelengths.second - mod_wavelengths.first + 1; bool optimize_loss = getParameter("OptimizeLoss"); getGenProperties()->set("NumberWavelengths", number_wavelengths); // Create optical ports createOpticalInputPort( "In", in_wavelengths); createOpticalOutputPort( "Out", in_wavelengths); // Create the filter and modulator createFilter( "RingFilter", in_wavelengths, true, mod_wavelengths); createModulator( "RingModulator", mod_wavelengths, optimize_loss, this); createWaveguide( "RingTemp", mod_wavelengths); OpticalFilter* ring_filter = getFilter("RingFilter"); OpticalModulator* ring_modulator = getModulator("RingModulator"); // Connect the filter and modulator getWaveguide("In")->addDownstreamNode(ring_filter); ring_filter->addDownstreamNode(getWaveguide("Out")); ring_filter->setDropPort(ring_modulator); ring_modulator->addDownstreamNode(getWaveguide("Out")); // Create electrical ports createInputPort( "In", makeNetIndex(0, number_wavelengths-1)); // Create driver createNet("PredriverIn"); // VFI from In to PredriverIn assignVirtualFanin("PredriverIn", "In"); // Create input load (due to predrivers) createLoad("PredriverCap"); getNet("PredriverIn")->addDownstreamNode(getLoad("PredriverCap")); // Precompute some values precomputeTech(); return; } void RingModulator::updateModel() { // Get properties double ER_dB = getProperty("ExtinctionRatio").toDouble(); double IL_dB = getProperty("InsertionLoss").toDouble(); // Get Gen properties int number_wavelengths = getGenProperties()->get("NumberWavelengths"); // Get tech model parameters double ring_area = getTechModel()->get("Ring->Area").toDouble(); double thru_loss = getTechModel()->get("Ring->ThroughLoss").toDouble(); // Design the modulator and the modulator driver bool success = designModulator(IL_dB, ER_dB); getGenProperties()->set("Success", success); // If not successful, make the modulate energy extremely large if (!success) getEventResult("Modulate")->setValue(1e99); // Update losses // Connect the filter and modulator OpticalFilter* ring_filter = getFilter("RingFilter"); ring_filter->setLoss(thru_loss * number_wavelengths); ring_filter->setDropLoss(thru_loss * number_wavelengths); // Assume worst-case through loss for a dropped wavelength // Update area getAreaResult("Photonic")->setValue(ring_area * (number_wavelengths)); } void RingModulator::useModel() { // Propagate the transition info and get the 0->1 transtion count propagateTransitionInfo(); double P_In = getInputPort("In")->getTransitionInfo().getProbability1(); double P_num_trans_01 = getInputPort("In")->getTransitionInfo().getNumberTransitions01(); // Get Gen properties int number_wavelengths = getGenProperties()->get("NumberWavelengths"); // If I can't build it...then it is infinitely expensive! bool success = getGenProperties()->get("Success"); double driver_size = 1e99; double total_predriver_size = 1e99; if (success) { driver_size = getGenProperties()->get("DriverSize"); total_predriver_size = getGenProperties()->get("TotalPredriverSize"); } // Get parameters corresponding to a unit-inverter double unit_leak_0 = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Leakage->!A"); double unit_leak_1 = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Leakage->A"); // Approximate leakage double total_leakage = number_wavelengths * 0.5 * ((driver_size + total_predriver_size) * P_In * unit_leak_1 + (driver_size + total_predriver_size) * (1 - P_In) * unit_leak_0); getNddPowerResult("Leakage")->setValue(total_leakage); getEventResult("Modulate")->setValue(calcModulatorEnergy() * P_num_trans_01); return; } void RingModulator::propagateTransitionInfo() { // Very simple...whatever comes in electrically is encoded optically getOpticalOutputPort("Out")->setTransitionInfo(getInputPort("In")->getTransitionInfo()); return; } void RingModulator::precomputeTech() { // Get parameters double data_rate = getParameter("DataRate"); // Constants shortcuts double pi = Constants::pi; double c = Constants::c; double k = Constants::k; double e0 = Constants::e0; double es = Constants::es; double q = Constants::q; double T = getTechModel()->get("Temperature"); // Get modulator parameters double lambda = getTechModel()->get("Ring->Lambda").toDouble(); double n_f = getTechModel()->get("Modulator->Ring->FCPDEffect").toDouble(); double NA = getTechModel()->get("Modulator->Ring->NA").toDouble(); double ND = getTechModel()->get("Modulator->Ring->ND").toDouble(); double ni = getTechModel()->get("Modulator->Ring->ni").toDouble(); double L_j = getTechModel()->get("Modulator->Ring->JunctionRatio").toDouble(); double H = getTechModel()->get("Modulator->Ring->Height").toDouble(); double W = getTechModel()->get("Modulator->Ring->Width").toDouble(); double g_c = getTechModel()->get("Modulator->Ring->ConfinementFactor").toDouble(); // Get ring parameters double R = getTechModel()->get("Ring->Radius").toDouble(); double n_g = getTechModel()->get("Ring->GroupIndex").toDouble(); double Q_max = getTechModel()->get("Ring->MaxQualityFactor").toDouble(); // Setup calculations double f0 = c / lambda; double BW = data_rate; // Modulator bandwidth double Q_f = std::min(f0 / BW, Q_max); // Quality factor double L_tot = 2 * pi * R; // Optical length of the ring double V_bi = k * T / q * log(NA * ND / (ni * ni)); // Junction Built-in voltage double x_d0 = sqrt(2 * e0 * es / q * V_bi * (NA + ND) / (NA * ND)); // Junction nominal depletion width double C_j0 = e0 * es * L_tot * L_j * W / x_d0; // Junction nominal cap double Q_0 = q * n_g * (L_tot * H * W) / (2 * n_f * Q_f * g_c); // Charge in depletion region // Store into precomputed values m_precompute_V_bi_ = V_bi; m_precompute_x_d0_ = x_d0; m_precompute_C_j0_ = C_j0; m_precompute_Q_0_ = Q_0; return; } bool RingModulator::designModulator(double IL_dB_, double ER_dB_) { // Get parameters double vdd = getTechModel()->get("Vdd"); double data_rate = getParameter("DataRate"); unsigned int max_predriver_stages = 20; //TODO: Make this not hardcoded // Get modulator parameters double boost_ratio = getTechModel()->get("Modulator->Ring->SupplyBoostRatio"); double Tn = getTechModel()->get("Modulator->Ring->Tn").toDouble();; double H = getTechModel()->get("Modulator->Ring->Height").toDouble(); // Get Gen properties int number_wavelengths = getGenProperties()->get("NumberWavelengths"); // Checking ASSERTions (input properties that don't make any sense) ASSERT(ER_dB_ > 0, "[Error] " + getInstanceName() + " -> Extinction ratio must be > 0!"); ASSERT(IL_dB_ > 0, "[Error] " + getInstanceName() + " -> Insertion loss must be > 0!"); // Setup calculations double ER = pow(10, ER_dB_ / 10); // Extinction ratio double T1 = pow(10, -IL_dB_ / 10); // Transmisivity on double T0 = T1 / ER; // Transmisivity off // Get precomputed values double V_bi = m_precompute_V_bi_; double x_d0 = m_precompute_x_d0_; double C_j0 = m_precompute_C_j0_; double Q_0 = m_precompute_Q_0_; // Charge double int_c = -2 * V_bi * C_j0; // Calculate shift using lorentzian double gamma = sqrt((1 - Tn)/(1 - T1) - 1) - sqrt((1 - Tn)/(1 - T0) - 1); // gamma = delta_f / delta_f_FWHM double Q = gamma * Q_0; // Charge required to hit given Tf // Voltage required double V_a = V_bi * (pow( (Q - int_c)/(2 * V_bi * C_j0), 2) - 1); // Calculate driver vdd double hvdd = V_a * boost_ratio; // Depletion region required double x_d = x_d0 * sqrt((V_bi + V_a) / V_bi); // Calculate C_eff double c_eff = Q / V_a; // Feasibility checks // Not feasible if the transmisivity when transmitting an optical 1 is greater than 1.0... if (T1 >= 1) return false; // Not feasible if the transmisivity when transmitting an optical 0 is smaller than the notch of the ring if (T0 <= Tn) return false; // Not feasible if the extinction ratio is greater than the notch of the ring if (ER >= 1 / Tn) return false; // Not feasible if the required depletion width is greater than the height of the junction if (x_d >= H) return false; // Analytically calculate driver sizes // Get parameters corresponding to a unit-inverter double unit_c_g = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->A"); double unit_c_d = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->Y"); double unit_r_o = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->DriveRes->Y"); double unit_area_active = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Area->Active"); double unit_area_metal1 = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Area->Metal1Wire"); // Get device resistance/cap double device_par_res = getTechModel()->get("Modulator->Ring->ParasiticRes"); double device_par_cap = getTechModel()->get("Modulator->Ring->ParasiticCap"); // Use timing tree to size modulator drivers // Coefficient of R*C to give a 0->V_a transition double transition_scale = log(hvdd / (hvdd - V_a)); double transition_required = 1 / (4 * data_rate); // I am not sure what the factor of 4 is for... // Calculate inverter intrinsic transition time double transition_intrinsic = transition_scale * unit_c_d * unit_r_o; // Calculate minimum possible device transition time double min_transition_intrinsic = transition_intrinsic + transition_scale * device_par_res * c_eff; // If the minimum possible transition time is already bigger // than the required transition, then this particular driver is not possible... if (min_transition_intrinsic > transition_required) return false; // Calculate driver size double driver_size = max(1.0, transition_scale * unit_r_o * (c_eff + device_par_cap) / (transition_required - min_transition_intrinsic)); // Keep track of the total multiplier of unit inverters (for area, leakage calculations) double total_unit_inverters = driver_size * max(1.0, hvdd / vdd); // Calculate load cap for predriver stages double current_load_cap = driver_size * unit_c_g; // Number of predriver stages unsigned int predriver_stages = 0; // Add predriver stages until the input cap is less than the unit INV_X1 gate cap or // if the signal is still inverted (need an odd number of predriver stages) while (current_load_cap > unit_c_g || (predriver_stages == 0) || ((predriver_stages & 0x1) == 0)) { // Calculate the size of the current predriver stage double current_predriver_size = max(1.0, unit_r_o * current_load_cap / (transition_required - transition_intrinsic)); // Calculate load cap for the next predriver stage current_load_cap = current_predriver_size * unit_c_g; // Add cap to total predriver total cap total_unit_inverters += current_predriver_size; // Consider this a failure if the number of predriver stages exceed some maximum if (predriver_stages > max_predriver_stages) return false; ++predriver_stages; } // Set the input load capacitance getLoad("PredriverCap")->setLoadCap(current_load_cap); // Set generated properties getGenProperties()->set("DriverSize", driver_size); getGenProperties()->set("FirstPredriverSize", current_load_cap); getGenProperties()->set("TotalPredriverSize", total_unit_inverters - driver_size); getGenProperties()->set("Hvdd", hvdd); getGenProperties()->set("Ceff", c_eff); // Calculate leakage, area, energy consumption double area_active = total_unit_inverters * unit_area_active; double area_metal1 = total_unit_inverters * unit_area_metal1; // Set results getAreaResult("Active")->setValue(area_active * number_wavelengths); getAreaResult("Metal1Wire")->setValue(area_metal1 * number_wavelengths); // Only if everything was successful do we set the modulator specification getModulator("RingModulator")->setLosses(IL_dB_, ER_dB_); return true; } double RingModulator::calcModulatorEnergy() const { // Get tech parameters double vdd = getTechModel()->get("Vdd"); double device_par_cap = getTechModel()->get("Modulator->Ring->ParasiticCap"); // Get Gen properties int number_wavelengths = getGenProperties()->get("NumberWavelengths"); bool success = getGenProperties()->get("Success"); if (success) { double driver_size = getGenProperties()->get("DriverSize"); double total_predriver_size = getGenProperties()->get("TotalPredriverSize"); double first_predriver_size = getGenProperties()->get("FirstPredriverSize"); double c_eff = getGenProperties()->get("Ceff"); double hvdd = getGenProperties()->get("Hvdd"); // Get parameters corresponding to a unit-inverter double unit_c_g = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->A"); double unit_c_d = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->Y"); // Approximate leakage double energy_predriver = number_wavelengths * vdd * vdd * ((unit_c_d * total_predriver_size + unit_c_g * (total_predriver_size + driver_size - first_predriver_size))); double energy_driver = number_wavelengths * hvdd * std::max(hvdd, vdd) * (driver_size * unit_c_d + c_eff + device_par_cap); return (energy_predriver + energy_driver); } else return 1e99; // An infinitely expensive modulator } bool RingModulator::setTransmitterSpec(double IL_dB_, double ER_dB_) { setProperty("InsertionLoss", IL_dB_); setProperty("ExtinctionRatio", ER_dB_); update(); evaluate(); return getGenProperties()->get("Success"); } double RingModulator::getPower(double util_) const { // Get parameters double data_rate = getParameter("DataRate"); // Check arguments ASSERT((util_ <= 1.0) && (util_ >= 0.0), "[Error] " + getInstanceName() + " -> Modulator utilization must be between 0.0 and 1.0!"); return calcModulatorEnergy() * 0.25 * util_ * data_rate; } } // namespace DSENT