From e8ed7b1d1b5bef31e9874f679a5797c2e00d06f1 Mon Sep 17 00:00:00 2001 From: Nilay Vaish Date: Sat, 11 Oct 2014 15:02:23 -0500 Subject: ext: add the source code for DSENT This patch adds a tool called DSENT to the ext/ directory. DSENT is a tool that models power and area for on-chip networks. The next patch adds a script for using the tool. --- ext/dsent/model/optical/RingModulator.cc | 403 +++++++++++++++++++++++++++++++ 1 file changed, 403 insertions(+) create mode 100644 ext/dsent/model/optical/RingModulator.cc (limited to 'ext/dsent/model/optical/RingModulator.cc') diff --git a/ext/dsent/model/optical/RingModulator.cc b/ext/dsent/model/optical/RingModulator.cc new file mode 100644 index 000000000..8fe320fbd --- /dev/null +++ b/ext/dsent/model/optical/RingModulator.cc @@ -0,0 +1,403 @@ +#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 + -- cgit v1.2.3