diff options
Diffstat (limited to 'ext/dsent/model/optical')
22 files changed, 3071 insertions, 0 deletions
diff --git a/ext/dsent/model/optical/GatedLaserSource.cc b/ext/dsent/model/optical/GatedLaserSource.cc new file mode 100644 index 000000000..e32474daf --- /dev/null +++ b/ext/dsent/model/optical/GatedLaserSource.cc @@ -0,0 +1,106 @@ +#include "model/optical/GatedLaserSource.h" + +#include "model/optical_graph/OpticalWaveguide.h" +#include "model/optical_graph/OpticalWavelength.h" +#include "model/optical_graph/OpticalLaser.h" +#include "model/optical_graph/OpticalGraph.h" + +namespace DSENT +{ + GatedLaserSource::GatedLaserSource(const String& instance_name_, const TechModel* tech_model_) + : OpticalModel(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + GatedLaserSource::~GatedLaserSource() + {} + + void GatedLaserSource::initParameters() + { + addParameterName("OutStart"); + addParameterName("OutEnd"); + addParameterName("MaxDetectors"); + return; + } + + void GatedLaserSource::initProperties() + { + addPropertyName("OptUtil", 1.0); + addPropertyName("LaserEventTime"); + return; + } + + void GatedLaserSource::constructModel() + { + // Create Area result + Result* area_result = new AtomicResult("Photonic"); + addAreaResult(area_result); + // Create NDD power result + Result* energy_result = new AtomicResult("Laser"); + addEventResult(energy_result); + + // Get parameters + WavelengthGroup laser_wavelengths = makeWavelengthGroup(getParameter("OutStart"), getParameter("OutEnd")); + + // Create optical ports + createOpticalOutputPort( "Out", laser_wavelengths); + // Create the filter + createLaser( "Laser", laser_wavelengths); + OpticalLaser* laser = getLaser("Laser"); + // Connect the laser to the output + laser->addDownstreamNode(getWaveguide("Out")); + } + + void GatedLaserSource::updateModel() + { + // Get properties + double laser_efficiency = getTechModel()->get("Laser->CW->Efficiency"); + double laser_area = getTechModel()->get("Laser->CW->Area"); + double laser_diode_loss = getTechModel()->get("Laser->CW->LaserDiodeLoss"); + + // Get parameters + WavelengthGroup laser_wavelengths = makeWavelengthGroup(getParameter("OutStart"), getParameter("OutEnd")); + unsigned int number_wavelengths = laser_wavelengths.second - laser_wavelengths.first + 1; + // Update losses + OpticalLaser* laser = getLaser("Laser"); + laser->setLoss(laser_diode_loss); + laser->setEfficiency(laser_efficiency); + // Update area + getAreaResult("Photonic")->setValue(laser_area * number_wavelengths); + } + + void GatedLaserSource::evaluateModel() + { + // Get parameters + unsigned int max_detectors = getParameter("MaxDetectors"); + double laser_event_time = getProperty("LaserEventTime"); + WavelengthGroup laser_wavelengths = makeWavelengthGroup(getParameter("OutStart"), getParameter("OutEnd")); + + // Get properties + double opt_util = getProperty("OptUtil"); + + // Create optical graph object + OpticalGraph* optical_graph = new OpticalGraph("LaserTrace", this); + // Ask optical graph object to perform power optimization + bool success = optical_graph->performPowerOpt(getLaser("Laser"), laser_wavelengths, max_detectors, opt_util); + if (!success) + { + Log::printLine(std::cerr, "[Warning] " + getInstanceName() + + " -> Wavelengths contains data paths with no possible modulator configurations!"); + } + // Trace the wavelengths the laser is outputting to find the output + // power needed by the laser + OpticalWavelength* wavelength = optical_graph->traceWavelength(laser_wavelengths, getLaser("Laser")); + // Calculate the power needed by the wavelength + double laser_power = wavelength->getLaserPower(max_detectors); + // Calculate NDD power + getEventResult("Laser")->setValue(laser_power * laser_event_time); + + delete wavelength; + delete optical_graph; + } + +} // namespace DSENT + diff --git a/ext/dsent/model/optical/GatedLaserSource.h b/ext/dsent/model/optical/GatedLaserSource.h new file mode 100644 index 000000000..b6413b047 --- /dev/null +++ b/ext/dsent/model/optical/GatedLaserSource.h @@ -0,0 +1,33 @@ +#ifndef __DSENT_MODEL_OPTICAL_GATEDLASERSOURCE_H__ +#define __DSENT_MODEL_OPTICAL_GATEDLASERSOURCE_H__ + +#include "util/CommonType.h" +#include "model/OpticalModel.h" + +namespace DSENT +{ + // A laser source that outputs some number of wavelengths. This laser + // full on/off power gating, thus all power are event-based energies + class GatedLaserSource : public OpticalModel + { + public: + GatedLaserSource(const String& instance_name_, const TechModel* tech_model_); + virtual ~GatedLaserSource(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + + protected: + // Build the model + void constructModel(); + void updateModel(); + void evaluateModel(); + + }; // class GatedLaserSource +} // namespace DSENT + +#endif // __DSENT_MODEL_OPTICAL_GATEDLASERSOURCE_H__ + diff --git a/ext/dsent/model/optical/LaserSource.cc b/ext/dsent/model/optical/LaserSource.cc new file mode 100644 index 000000000..e55de8cf7 --- /dev/null +++ b/ext/dsent/model/optical/LaserSource.cc @@ -0,0 +1,105 @@ +#include "model/optical/LaserSource.h" + +#include "model/optical_graph/OpticalWaveguide.h" +#include "model/optical_graph/OpticalWavelength.h" +#include "model/optical_graph/OpticalLaser.h" +#include "model/optical_graph/OpticalGraph.h" + +namespace DSENT +{ + LaserSource::LaserSource(const String& instance_name_, const TechModel* tech_model_) + : OpticalModel(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + LaserSource::~LaserSource() + {} + + void LaserSource::initParameters() + { + addParameterName("OutStart"); + addParameterName("OutEnd"); + addParameterName("MaxDetectors"); + return; + } + + void LaserSource::initProperties() + { + addPropertyName("OptUtil", 1.0); + return; + } + + void LaserSource::constructModel() + { + // Create Area result + Result* area_result = new AtomicResult("Photonic"); + addAreaResult(area_result); + // Create NDD power result + Result* power_result = new AtomicResult("Laser"); + addNddPowerResult(power_result); + + // Get parameters + WavelengthGroup laser_wavelengths = makeWavelengthGroup(getParameter("OutStart"), getParameter("OutEnd")); + + // Create optical ports + createOpticalOutputPort( "Out", laser_wavelengths); + // Create the filter + createLaser( "Laser", laser_wavelengths); + OpticalLaser* laser = getLaser("Laser"); + // Connect the laser to the output + laser->addDownstreamNode(getWaveguide("Out")); + } + + void LaserSource::updateModel() + { + // Get properties + double laser_efficiency = getTechModel()->get("Laser->CW->Efficiency").toDouble(); + double laser_area = getTechModel()->get("Laser->CW->Area").toDouble(); + double laser_diode_loss = getTechModel()->get("Laser->CW->LaserDiodeLoss"); + + // Get parameters + WavelengthGroup laser_wavelengths = makeWavelengthGroup(getParameter("OutStart"), getParameter("OutEnd")); + unsigned int number_wavelengths = laser_wavelengths.second - laser_wavelengths.first + 1; + // Update losses + OpticalLaser* laser = getLaser("Laser"); + laser->setLoss(laser_diode_loss); + laser->setEfficiency(laser_efficiency); + // Update area + getAreaResult("Photonic")->setValue(laser_area * number_wavelengths); + } + + void LaserSource::evaluateModel() + { + // Get parameters + unsigned int max_detectors = getParameter("MaxDetectors").toUInt(); + WavelengthGroup laser_wavelengths = makeWavelengthGroup(getParameter("OutStart"), getParameter("OutEnd")); + + // Get properties + double opt_util = getProperty("OptUtil"); + + // Create optical graph object + OpticalGraph* optical_graph = new OpticalGraph("LaserTrace", this); + // Ask optical graph object to perform power optimization + bool success = optical_graph->performPowerOpt(getLaser("Laser"), laser_wavelengths, max_detectors, opt_util); + if (!success) + { + Log::printLine(std::cerr, "[Warning] " + getInstanceName() + + " -> Wavelengths contains data paths with no possible modulator configurations!"); + } + // Trace the wavelengths the laser is outputting to find the output + // power needed by the laser + OpticalWavelength* wavelength = optical_graph->traceWavelength(laser_wavelengths, getLaser("Laser")); + // Calculate the power needed by the wavelength + double laser_power = wavelength->getLaserPower(max_detectors); + + // Calculate NDD power + getNddPowerResult("Laser")->setValue(laser_power); + + delete wavelength; + delete optical_graph; + } + +} // namespace DSENT + diff --git a/ext/dsent/model/optical/LaserSource.h b/ext/dsent/model/optical/LaserSource.h new file mode 100644 index 000000000..92c7658d5 --- /dev/null +++ b/ext/dsent/model/optical/LaserSource.h @@ -0,0 +1,33 @@ +#ifndef __DSENT_MODEL_OPTICAL_LASERSOURCE_H__ +#define __DSENT_MODEL_OPTICAL_LASERSOURCE_H__ + +#include "util/CommonType.h" +#include "model/OpticalModel.h" + +namespace DSENT +{ + // A laser source that outputs some number of wavelengths. This laser cannot + // be gated on/off at will and thus constitutes an NDD Power consumer + class LaserSource : public OpticalModel + { + public: + LaserSource(const String& instance_name_, const TechModel* tech_model_); + virtual ~LaserSource(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + + protected: + // Build the model + void constructModel(); + void updateModel(); + void evaluateModel(); + + }; // class LaserSource +} // namespace DSENT + +#endif // __DSENT_MODEL_OPTICAL_LASERSOURCE_H__ + diff --git a/ext/dsent/model/optical/OpticalLinkBackendRx.cc b/ext/dsent/model/optical/OpticalLinkBackendRx.cc new file mode 100644 index 000000000..3a65cee62 --- /dev/null +++ b/ext/dsent/model/optical/OpticalLinkBackendRx.cc @@ -0,0 +1,364 @@ +#include "model/optical/OpticalLinkBackendRx.h" + +#include "util/Constants.h" +#include "model/PortInfo.h" +#include "model/TransitionInfo.h" +#include "model/EventInfo.h" +#include "model/electrical/DemuxTreeDeserializer.h" +#include "model/electrical/BarrelShifter.h" +#include "model/electrical/Multiplexer.h" +#include <cmath> + +namespace DSENT +{ + // TODO: Kind of don't like the way thermal tuning is written here. Maybe will switch + // to curve fitting the CICC paper, which uses results from a monte-carlo sim. Also, there is + // redundant code between this one and the tx one... + + OpticalLinkBackendRx::OpticalLinkBackendRx(const String& instance_name_, const TechModel* tech_model_) + : ElectricalModel(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + OpticalLinkBackendRx::~OpticalLinkBackendRx() + {} + + void OpticalLinkBackendRx::initParameters() + { + addParameterName("OutBits"); + addParameterName("CoreDataRate"); + addParameterName("LinkDataRate"); + addParameterName("RingTuningMethod"); + addParameterName("BitDuplicate"); + return; + } + + void OpticalLinkBackendRx::initProperties() + { + return; + } + + void OpticalLinkBackendRx::constructModel() + { + unsigned int out_bits = getParameter("OutBits"); + double core_data_rate = getParameter("CoreDataRate"); + double link_data_rate = getParameter("LinkDataRate"); + const String& tuning_method = getParameter("RingTuningMethod"); + bool bit_duplicate = getParameter("BitDuplicate"); + + // Calculate deserialization ratio + unsigned int deserialization_ratio = (unsigned int) floor(link_data_rate / core_data_rate); + ASSERT(deserialization_ratio == link_data_rate / core_data_rate, + "[Error] " + getInstanceName() + " -> Cannot have non-integer deserialization ratios!"); + ASSERT((deserialization_ratio & (deserialization_ratio - 1)) == 0, + "[Error] " + getInstanceName() + " -> Deserialization ratio must be a power of 2"); + + // Calculate output width + unsigned int in_bits = out_bits / deserialization_ratio; + ASSERT(out_bits >= deserialization_ratio, "[Error] " + getInstanceName() + + " -> Output width must be >= deserialization ratio!"); + ASSERT(floor((double) out_bits / deserialization_ratio) == in_bits, + "[Error] " + getInstanceName() + " -> Output width must be a multiple of the serialization ratio!"); + + getGenProperties()->set("DeserializationRatio", deserialization_ratio); + getGenProperties()->set("InBits", in_bits); + + // Create ports + createInputPort("In", makeNetIndex(0, in_bits-1)); + createInputPort("LinkCK"); + createOutputPort("Out", makeNetIndex(0, out_bits-1)); + + //Create energy, power, and area results + createElectricalResults(); + // Create ring heating power cost + addNddPowerResult(new AtomicResult("RingTuning")); + // Create process bits event + createElectricalEventResult("ProcessBits"); + getEventInfo("ProcessBits")->setTransitionInfo("LinkCK", TransitionInfo(0.0, (double) deserialization_ratio / 2.0, 0.0)); + // Set conditions during idle state + getEventInfo("Idle")->setStaticTransitionInfos(); + getEventInfo("Idle")->setTransitionInfo("LinkCK", TransitionInfo(0.0, (double) deserialization_ratio / 2.0, 0.0)); + + // Create deserializer + const String& deserializer_name = "Deserializer"; + DemuxTreeDeserializer* deserializer = new DemuxTreeDeserializer(deserializer_name, getTechModel()); + deserializer->setParameter("OutBits", out_bits); + deserializer->setParameter("InDataRate", link_data_rate); + deserializer->setParameter("OutDataRate", core_data_rate); + deserializer->setParameter("BitDuplicate", bit_duplicate); + deserializer->construct(); + + addSubInstances(deserializer, 1.0); + addElectricalSubResults(deserializer, 1.0); + getEventResult("ProcessBits")->addSubResult(deserializer->getEventResult("Deserialize"), deserializer_name, 1.0); + + if ((tuning_method == "ThermalWithBitReshuffle") || (tuning_method == "ElectricalAssistWithBitReshuffle")) + { + // If a bit reshuffling backend is present, create the reshuffling backend + unsigned int reorder_degree = getBitReorderDegree(); + + // Create intermediate nets + createNet("ReorderIn", makeNetIndex(0, in_bits+reorder_degree-1)); + assign("ReorderIn", makeNetIndex(0, in_bits-1), "In"); + assign("ReorderIn", makeNetIndex(in_bits, in_bits+reorder_degree-1), "ReorderIn", makeNetIndex(0, reorder_degree-1)); + createNet("DeserializerIn", makeNetIndex(0, in_bits-1)); + createNet("BarrelShiftIn", makeNetIndex(0, out_bits-1)); + + // Create bit reorder muxes + const String& reorder_mux_name = "ReorderMux"; + Multiplexer* reorder_mux = new Multiplexer(reorder_mux_name, getTechModel()); + reorder_mux->setParameter("NumberBits", in_bits); + reorder_mux->setParameter("NumberInputs", reorder_degree); + reorder_mux->setParameter("BitDuplicate", bit_duplicate); + reorder_mux->construct(); + + // Create barrelshifter + unsigned int shift_index_min = (unsigned int)ceil(log2(deserialization_ratio)); + unsigned int shift_index_max = std::max(shift_index_min, (unsigned int) ceil(log2(out_bits)) - 1); + + // Remember some things + getGenProperties()->set("ReorderDegree", reorder_degree); + getGenProperties()->set("ShiftIndexMin", shift_index_min); + getGenProperties()->set("ShiftIndexMax", shift_index_max); + + const String& barrel_shift_name = "BarrelShifter"; + BarrelShifter* barrel_shift = new BarrelShifter(barrel_shift_name, getTechModel()); + barrel_shift->setParameter("NumberBits", out_bits); + barrel_shift->setParameter("ShiftIndexMax", shift_index_max); + barrel_shift->setParameter("ShiftIndexMin", shift_index_min); + barrel_shift->setParameter("BitDuplicate", bit_duplicate); + barrel_shift->construct(); + + // Connect serializer + portConnect(deserializer, "In", "DeserializerIn"); + portConnect(deserializer, "Out", "BarrelShiftIn"); + portConnect(deserializer, "InCK", "LinkCK"); + + // Connect barrelshifter + // TODO: Connect barrelshift shifts! + portConnect(barrel_shift, "In", "BarrelShiftIn"); + portConnect(barrel_shift, "Out", "Out"); + + // Connect bit reorder muxes + // TODO: Connect re-order multiplex select signals! + for (unsigned int i = 0; i < reorder_degree; i++) + portConnect(reorder_mux, "In" + (String) i, "ReorderIn", makeNetIndex(i, i+in_bits-1)); + portConnect(reorder_mux, "Out", "DeserializerIn"); + + addSubInstances(barrel_shift, 1.0); + addSubInstances(reorder_mux, 1.0); + addElectricalSubResults(barrel_shift, 1.0); + addElectricalSubResults(reorder_mux, 1.0); + getEventResult("ProcessBits")->addSubResult(barrel_shift->getEventResult("BarrelShift"), barrel_shift_name, 1.0); + getEventResult("ProcessBits")->addSubResult(reorder_mux->getEventResult("Mux"), reorder_mux_name, 1.0); + } + else if ((tuning_method == "FullThermal") || (tuning_method == "AthermalWithTrim")) + { + // If no bit reshuffling backend is present, then just connect deserializer up + portConnect(deserializer, "In", "In"); + portConnect(deserializer, "Out", "Out"); + portConnect(deserializer, "InCK", "LinkCK"); + } + else + { + ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown ring tuning method '" + tuning_method + "'!"); + } + + return; + } + + void OpticalLinkBackendRx::updateModel() + { + // Update everyone + Model::updateModel(); + // Update ring tuning power + getNddPowerResult("RingTuning")->setValue(getRingTuningPower()); + return; + } + + void OpticalLinkBackendRx::propagateTransitionInfo() + { + // Get parameters + const String& tuning_method = getParameter("RingTuningMethod");; + + // Get properties + + // Update the deserializer + if ((tuning_method == "ThermalWithBitReshuffle") || (tuning_method == "ElectricalAssistWithBitReshuffle")) + { + // Get generated properties + unsigned int reorder_degree = getGenProperties()->get("ReorderDegree"); + unsigned int shift_index_min = getGenProperties()->get("ShiftIndexMin"); + unsigned int shift_index_max = getGenProperties()->get("ShiftIndexMax"); + + // Reorder mux shift select bits + unsigned int reorder_sel_bits = (unsigned int)ceil(log2(reorder_degree)); + + // Create bit reorder muxes + const String& reorder_mux_name = "ReorderMux"; + ElectricalModel* reorder_mux = (ElectricalModel*) getSubInstance(reorder_mux_name); + for (unsigned int i = 0; i < reorder_degree; ++i) + propagatePortTransitionInfo(reorder_mux, "In" + (String) i, "In"); + // Set select transitions to be 0, since these are statically configured + for (unsigned int i = 0; i < reorder_sel_bits; ++i) + reorder_mux->getInputPort("Sel" + (String) i)->setTransitionInfo(TransitionInfo(0.5, 0.0, 0.5)); + reorder_mux->use(); + + // Update the deserializer + ElectricalModel* deserializer = (ElectricalModel*) getSubInstance("Deserializer"); + propagatePortTransitionInfo(deserializer, "In", reorder_mux, "Out"); + propagatePortTransitionInfo(deserializer, "InCK", "LinkCK"); + deserializer->use(); + + // Update barrel shifter + const String& barrel_shift_name = "BarrelShifter"; + ElectricalModel* barrel_shift = (ElectricalModel*) getSubInstance(barrel_shift_name); + propagatePortTransitionInfo(barrel_shift, "In", deserializer, "Out"); + // Set shift transitions to be very low (since it is affected by slow temperature time constants) + for (unsigned int i = shift_index_min; i <= shift_index_max; ++i) + barrel_shift->getInputPort("Shift" + (String) i)->setTransitionInfo(TransitionInfo(0.499, 0.001, 0.499)); + barrel_shift->use(); + + // Set output transition info + propagatePortTransitionInfo("Out", barrel_shift, "Out"); + } + else if ((tuning_method == "FullThermal") || (tuning_method == "AthermalWithTrim")) + { + // Update the deserializer + ElectricalModel* deserializer = (ElectricalModel*) getSubInstance("Deserializer"); + propagatePortTransitionInfo(deserializer, "In", "In"); + propagatePortTransitionInfo(deserializer, "InCK", "LinkCK"); + deserializer->use(); + + // Set output transition info + propagatePortTransitionInfo("Out", deserializer, "Out"); + } + else + { + ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown ring tuning method '" + tuning_method + "'!"); + } + + return; + } + + double OpticalLinkBackendRx::getRingTuningPower() + { + // Get properties + const String& tuning_method = getParameter("RingTuningMethod");; + unsigned int number_rings = getGenProperties()->get("InBits"); + + // Get tech model parameters + double R = getTechModel()->get("Ring->Radius"); + double n_g = getTechModel()->get("Ring->GroupIndex"); + double heating_efficiency = getTechModel()->get("Ring->HeatingEfficiency"); + // This can actually be derived if we know thermo-optic coefficient (delta n / delta T) + double tuning_efficiency = getTechModel()->get("Ring->TuningEfficiency"); + double sigma_r_local = getTechModel()->get("Ring->LocalVariationSigma"); + double sigma_r_systematic = getTechModel()->get("Ring->SystematicVariationSigma"); + double T_max = getTechModel()->get("Ring->TemperatureMax"); + double T_min = getTechModel()->get("Ring->TemperatureMin"); + double T = getTechModel()->get("Temperature"); + + // Get constants + double c = Constants::c; + double pi = Constants::pi; + + double tuning_power = 0.0; + + if (tuning_method == "ThermalWithBitReshuffle") + { + // When an electrical backend is present, rings only have to tune to the nearest channel + // This can be approximated as each ring tuning to something exactly 1 channel away + + // Setup calculations + double L = 2 * pi * R; // Optical length + double FSR = c / (n_g * L); // Free spectral range + double freq_sep = FSR / number_rings; // Channel separation + + // Calculate tuning power + tuning_power = number_rings * freq_sep / (tuning_efficiency * heating_efficiency); + } + else if (tuning_method == "ElectricalAssistWithBitReshuffle") + { + // Electrical assistance allows for a fraction of the tuning range to be + // covered electrically. This is most pronounced when the tuning range is small, + // such is the case when bit reshuffling is applied + + // Get electrically tunable range + double max_assist = getTechModel()->get("Ring->MaxElectricallyTunableFreq"); + + // Setup calculations + double L = 2 * pi * R; // Optical length + double FSR = c / (n_g * L); // Free spectral range + double freq_sep = FSR / number_rings; // Channel separation + double heating_range = std::max(0.0, freq_sep - max_assist); // The distance needed to bridge using heaters + + // Calculate tuning power, which is really only the power spent on heating since + // distance tuned electrically is pretty much free + tuning_power = number_rings * heating_range / (tuning_efficiency * heating_efficiency); + } + else if (tuning_method == "FullThermal") + { + // If there is no bit reshuffling backend, each ring must tune to an + // absolute channel frequency. Since we can only heat rings (and not cool), + // we can only red-shift (decrease frequency). Thus, a fabrication bias + // must be applied such that under any process and temperature corner, the + // ring resonance remains above channel resonance + // I'll use 3 sigmas of sigma_r_local and sigma_r_systematic, and bias against + // the full temperature range + double fabrication_bias_freq = 3.0 * sqrt(pow(sigma_r_local, 2) + pow(sigma_r_systematic, 2)) + + (T_max - T_min) * tuning_efficiency; + + // The local/systematic variations are 0 on average. Thus, the tuning distance can be calculated as + double tuning_distance = fabrication_bias_freq - (T - T_min) * tuning_efficiency; + + // Tuning power needed is just the number of rings * tuning distance / (tuning and heating efficiencies) + tuning_power = number_rings * tuning_distance / (tuning_efficiency * heating_efficiency); + } + else if (tuning_method == "AthermalWithTrim") + { + // Athermal! + tuning_power = 0; + } + else + { + ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown ring tuning method '" + tuning_method + "'!"); + } + + return tuning_power; + } + + unsigned int OpticalLinkBackendRx::getBitReorderDegree() + { + // Get properties + unsigned int number_rings = getGenProperties()->get("InBits"); + + // Get tech model parameters + double R = getTechModel()->get("Ring->Radius"); + double n_g = getTechModel()->get("Ring->GroupIndex"); + // This can actually be derived if we know thermo-optic coefficient (delta n / delta T) + double sigma_r_local = getTechModel()->get("Ring->LocalVariationSigma"); + + // Get constants + double c = Constants::c; + double pi = Constants::pi; + + // Calculates the degree of bit re-order multiplexing needed for bit-reshuffling backend + // Bit reshuffling tuning is largely unaffected by sigma_r_systematic. However, sigma_r_local + // Can potentially throw each ring to a channel several channels away. This just calculates + // the degree of bit reorder muxing needed to realign bits in the correct order + + // Setup calculations + double L = 2 * pi * R; // Optical length + double FSR = c / (n_g * L); // Free spectral range + double freq_sep = FSR / number_rings; // Channel separation + // Using 4 sigmas as the worst re-ordering case (must double to get both sides) + unsigned int worst_case_channels = (unsigned int)ceil(2.0 * 4.0 * sigma_r_local / freq_sep); + + return worst_case_channels; + } + +} // namespace DSENT + diff --git a/ext/dsent/model/optical/OpticalLinkBackendRx.h b/ext/dsent/model/optical/OpticalLinkBackendRx.h new file mode 100644 index 000000000..19f396664 --- /dev/null +++ b/ext/dsent/model/optical/OpticalLinkBackendRx.h @@ -0,0 +1,39 @@ +#ifndef __DSENT_MODEL_OPTICAL_OPTICALLINKBACKENDRX_H__ +#define __DSENT_MODEL_OPTICAL_OPTICALLINKBACKENDRX_H__ + +#include "util/CommonType.h" +#include "model/ElectricalModel.h" + +namespace DSENT +{ + class OpticalLinkBackendRx : public ElectricalModel + { + // An optical link backend rx contains everything needed for thermal + // tuning of rings, bit-reshuffling (if necessary), and deserialization (if necessary) + public: + OpticalLinkBackendRx(const String& instance_name_, const TechModel* tech_model_); + virtual ~OpticalLinkBackendRx(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void propagateTransitionInfo(); + + private: + // Calculate ring tuning power + double getRingTuningPower(); + // Calculate the degree of bit re-order muxing (for the bit-reshuffler) + unsigned int getBitReorderDegree(); + + }; // class OpticalLinkBackendRx +} // namespace DSENT + +#endif // __DSENT_MODEL_OPTICAL_OPTICALLINKBACKENDRX_H__ + diff --git a/ext/dsent/model/optical/OpticalLinkBackendTx.cc b/ext/dsent/model/optical/OpticalLinkBackendTx.cc new file mode 100644 index 000000000..18d86cfe7 --- /dev/null +++ b/ext/dsent/model/optical/OpticalLinkBackendTx.cc @@ -0,0 +1,355 @@ +#include "model/optical/OpticalLinkBackendTx.h" + +#include "util/Constants.h" +#include "model/PortInfo.h" +#include "model/TransitionInfo.h" +#include "model/EventInfo.h" +#include "model/electrical/MuxTreeSerializer.h" +#include "model/electrical/BarrelShifter.h" +#include "model/electrical/Multiplexer.h" +#include <cmath> + +namespace DSENT +{ + // TODO: Kind of don't like the way thermal tuning is written here. Maybe will switch + // to curve fitting the CICC paper, which uses results from a monte-carlo sim + + OpticalLinkBackendTx::OpticalLinkBackendTx(const String& instance_name_, const TechModel* tech_model_) + : ElectricalModel(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + OpticalLinkBackendTx::~OpticalLinkBackendTx() + {} + + void OpticalLinkBackendTx::initParameters() + { + addParameterName("InBits"); + addParameterName("CoreDataRate"); + addParameterName("LinkDataRate"); + addParameterName("RingTuningMethod"); + addParameterName("BitDuplicate"); + return; + } + + void OpticalLinkBackendTx::initProperties() + { + return; + } + + void OpticalLinkBackendTx::constructModel() + { + unsigned int in_bits = getParameter("InBits"); + double core_data_rate = getParameter("CoreDataRate"); + double link_data_rate = getParameter("LinkDataRate"); + const String& tuning_method = getParameter("RingTuningMethod");; + bool bit_duplicate = getParameter("BitDuplicate"); + + // Calculate serialization ratio + unsigned int serialization_ratio = (unsigned int) floor(link_data_rate / core_data_rate); + ASSERT(serialization_ratio == link_data_rate / core_data_rate, + "[Error] " + getInstanceName() + " -> Cannot have non-integer serialization ratios " + + "(" + (String) (core_data_rate / link_data_rate) + ")!"); + + // Calculate output width + ASSERT(floor((double) in_bits / serialization_ratio) == (double) in_bits / serialization_ratio, + "[Error] " + getInstanceName() + " -> Input width (" + (String) in_bits + ") " + + "must be a multiple of the serialization ratio (" + (String) serialization_ratio + ")!"); + unsigned int out_bits = in_bits / serialization_ratio; + + getGenProperties()->set("SerializationRatio", serialization_ratio); + getGenProperties()->set("OutBits", out_bits); + + // Create ports + createInputPort("In", makeNetIndex(0, in_bits-1)); + createInputPort("LinkCK"); + createOutputPort("Out", makeNetIndex(0, out_bits-1)); + + //Create energy, power, and area results + createElectricalResults(); + // Create ring heating power cost + addNddPowerResult(new AtomicResult("RingTuning")); + // Create process bits event + createElectricalEventResult("ProcessBits"); + getEventInfo("ProcessBits")->setTransitionInfo("LinkCK", TransitionInfo(0.0, (double) serialization_ratio / 2.0, 0.0)); + // Set conditions during idle state + getEventInfo("Idle")->setStaticTransitionInfos(); + getEventInfo("Idle")->setTransitionInfo("LinkCK", TransitionInfo(0.0, (double) serialization_ratio / 2.0, 0.0)); + + // Create serializer + const String& serializer_name = "Serializer"; + MuxTreeSerializer* serializer = new MuxTreeSerializer(serializer_name, getTechModel()); + serializer->setParameter("InBits", in_bits); + serializer->setParameter("InDataRate", core_data_rate); + serializer->setParameter("OutDataRate", link_data_rate); + serializer->setParameter("BitDuplicate", bit_duplicate); + serializer->construct(); + + addSubInstances(serializer, 1.0); + addElectricalSubResults(serializer, 1.0); + getEventResult("ProcessBits")->addSubResult(serializer->getEventResult("Serialize"), serializer_name, 1.0); + + if ((tuning_method == "ThermalWithBitReshuffle") || (tuning_method == "ElectricalAssistWithBitReshuffle")) + { + // If a bit reshuffling backend is present, create the reshuffling backend + unsigned int reorder_degree = getBitReorderDegree(); + + // Create intermediate nets + createNet("SerializerIn", makeNetIndex(0, in_bits-1)); + createNet("ReorderIn", makeNetIndex(0, out_bits+reorder_degree-1)); + assign("ReorderIn", makeNetIndex(out_bits, out_bits+reorder_degree-1), "ReorderIn", makeNetIndex(0, reorder_degree-1)); + + // Create barrelshifter + unsigned int shift_index_min = (unsigned int)ceil(log2(serialization_ratio)); + unsigned int shift_index_max = std::max(shift_index_min, (unsigned int) ceil(log2(in_bits)) - 1); + + // Remember some things + getGenProperties()->set("ReorderDegree", reorder_degree); + getGenProperties()->set("ShiftIndexMin", shift_index_min); + getGenProperties()->set("ShiftIndexMax", shift_index_max); + + const String& barrel_shift_name = "BarrelShifter"; + BarrelShifter* barrel_shift = new BarrelShifter(barrel_shift_name, getTechModel()); + barrel_shift->setParameter("NumberBits", in_bits); + barrel_shift->setParameter("ShiftIndexMax", shift_index_max); + barrel_shift->setParameter("ShiftIndexMin", shift_index_min); + barrel_shift->setParameter("BitDuplicate", bit_duplicate); + barrel_shift->construct(); + + // Create bit reorder muxes + const String& reorder_mux_name = "ReorderMux"; + Multiplexer* reorder_mux = new Multiplexer(reorder_mux_name, getTechModel()); + reorder_mux->setParameter("NumberBits", out_bits); + reorder_mux->setParameter("NumberInputs", reorder_degree); + reorder_mux->setParameter("BitDuplicate", bit_duplicate); + reorder_mux->construct(); + + // Connect barrelshifter + // TODO: Connect barrelshift shifts! + portConnect(barrel_shift, "In", "In"); + portConnect(barrel_shift, "Out", "SerializerIn"); + + // Connect serializer + portConnect(serializer, "In", "SerializerIn"); + portConnect(serializer, "Out", "ReorderIn", makeNetIndex(0, out_bits-1)); + portConnect(serializer, "OutCK", "LinkCK"); + + // Connect bit reorder muxes + // TODO: Connect re-order multiplex select signals! + for (unsigned int i = 0; i < reorder_degree; i++) + portConnect(reorder_mux, "In" + (String) i, "ReorderIn", makeNetIndex(i, i+out_bits-1)); + portConnect(reorder_mux, "Out", "Out"); + + addSubInstances(barrel_shift, 1.0); + addSubInstances(reorder_mux, 1.0); + addElectricalSubResults(barrel_shift, 1.0); + addElectricalSubResults(reorder_mux, 1.0); + getEventResult("ProcessBits")->addSubResult(barrel_shift->getEventResult("BarrelShift"), barrel_shift_name, 1.0); + getEventResult("ProcessBits")->addSubResult(reorder_mux->getEventResult("Mux"), reorder_mux_name, 1.0); // This happens multiple times + } + else if ((tuning_method == "FullThermal") || (tuning_method == "AthermalWithTrim")) + { + // If no bit reshuffling backend is present, then just connect serializer up + portConnect(serializer, "In", "In"); + portConnect(serializer, "Out", "Out"); + portConnect(serializer, "OutCK", "LinkCK"); + } + else + { + ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown ring tuning method '" + tuning_method + "'!"); + } + + return; + } + + void OpticalLinkBackendTx::updateModel() + { + // Update everyone + Model::updateModel(); + // Update ring tuning power + getNddPowerResult("RingTuning")->setValue(getRingTuningPower()); + return; + } + + void OpticalLinkBackendTx::propagateTransitionInfo() + { + // Get parameters + const String& tuning_method = getParameter("RingTuningMethod"); + + // Update the serializer + if ((tuning_method == "ThermalWithBitReshuffle") || (tuning_method == "ElectricalAssistWithBitReshuffle")) + { + // Get generated properties + unsigned int reorder_degree = getGenProperties()->get("ReorderDegree").toUInt(); + unsigned int shift_index_min = getGenProperties()->get("ShiftIndexMin").toUInt(); + unsigned int shift_index_max = getGenProperties()->get("ShiftIndexMax").toUInt(); + + // Update barrel shifter + const String& barrel_shift_name = "BarrelShifter"; + ElectricalModel* barrel_shift = (ElectricalModel*) getSubInstance(barrel_shift_name); + propagatePortTransitionInfo(barrel_shift, "In", "In"); + // Set shift transitions to be very low (since it is affected by slow temperature time constants) + for (unsigned int i = shift_index_min; i <= shift_index_max; ++i) + barrel_shift->getInputPort("Shift" + (String) i)->setTransitionInfo(TransitionInfo(0.499, 0.001, 0.499)); + barrel_shift->use(); + + // Set serializer transition info + ElectricalModel* serializer = (ElectricalModel*) getSubInstance("Serializer"); + propagatePortTransitionInfo(serializer, "In", barrel_shift, "Out"); + propagatePortTransitionInfo(serializer, "OutCK", "LinkCK"); + serializer->use(); + + // Reorder mux shift select bits + unsigned int reorder_sel_bits = (unsigned int)ceil(log2(reorder_degree)); + + // Reorder mux probabilities + const String& reorder_mux_name = "ReorderMux"; + ElectricalModel* reorder_mux = (ElectricalModel*) getSubInstance(reorder_mux_name); + for (unsigned int i = 0; i < reorder_degree; ++i) + propagatePortTransitionInfo(reorder_mux, "In" + (String) i, serializer, "Out"); + // Set select transitions to be 0, since these are statically configured + for (unsigned int i = 0; i < reorder_sel_bits; ++i) + reorder_mux->getInputPort("Sel" + (String) i)->setTransitionInfo(TransitionInfo(0.5, 0.0, 0.5)); + reorder_mux->use(); + + // Set output transition info + propagatePortTransitionInfo("Out", reorder_mux, "Out"); + } + else if ((tuning_method == "FullThermal") || (tuning_method == "AthermalWithTrim")) + { + // Set serializer transition info + ElectricalModel* serializer = (ElectricalModel*) getSubInstance("Serializer"); + propagatePortTransitionInfo(serializer, "In", "In"); + propagatePortTransitionInfo(serializer, "OutCK", "LinkCK"); + serializer->use(); + + // Set output transition info + propagatePortTransitionInfo("Out", serializer, "Out"); + } + + return; + } + + double OpticalLinkBackendTx::getRingTuningPower() + { + // Get properties + const String& tuning_method = getParameter("RingTuningMethod");; + unsigned int number_rings = getGenProperties()->get("OutBits"); + + // Get tech model parameters + double R = getTechModel()->get("Ring->Radius"); + double n_g = getTechModel()->get("Ring->GroupIndex"); + double heating_efficiency = getTechModel()->get("Ring->HeatingEfficiency"); + // This can actually be derived if we know thermo-optic coefficient (delta n / delta T) + double tuning_efficiency = getTechModel()->get("Ring->TuningEfficiency"); + double sigma_r_local = getTechModel()->get("Ring->LocalVariationSigma"); + double sigma_r_systematic = getTechModel()->get("Ring->SystematicVariationSigma"); + double T_max = getTechModel()->get("Ring->TemperatureMax"); + double T_min = getTechModel()->get("Ring->TemperatureMin"); + double T = getTechModel()->get("Temperature"); + + // Get constants + double c = Constants::c; + double pi = Constants::pi; + + double tuning_power = 0.0; + + if (tuning_method == "ThermalWithBitReshuffle") + { + // When an electrical backend is present, rings only have to tune to the nearest channel + // This can be approximated as each ring tuning to something exactly 1 channel away + + // Setup calculations + double L = 2 * pi * R; // Optical length + double FSR = c / (n_g * L); // Free spectral range + double freq_sep = FSR / number_rings; // Channel separation + + // Calculate tuning power + tuning_power = number_rings * freq_sep / (tuning_efficiency * heating_efficiency); + } + else if (tuning_method == "ElectricalAssistWithBitReshuffle") + { + // Electrical assistance allows for a fraction of the tuning range to be + // covered electrically. This is most pronounced when the tuning range is small, + // such is the case when bit reshuffling is applied. The electrically + // assisted part of it pretty much comes for free... + + // Get electrically tunable range + double max_assist = getTechModel()->get("Ring->MaxElectricallyTunableFreq"); + + // Setup calculations + double L = 2 * pi * R; // Optical length + double FSR = c / (n_g * L); // Free spectral range + double freq_sep = FSR / number_rings; // Channel separation + double heating_range = std::max(0.0, freq_sep - max_assist); // The distance needed to bridge using heaters + + // Calculate tuning power, which is really only the power spent on heating since + // distance tuned electrically is pretty much free + tuning_power = number_rings * heating_range / (tuning_efficiency * heating_efficiency); + } + else if (tuning_method == "FullThermal") + { + // If there is no bit reshuffling backend, each ring must tune to an + // absolute channel frequency. Since we can only heat rings (and not cool), + // we can only red-shift (decrease frequency). Thus, a fabrication bias + // must be applied such that under any process and temperature corner, the + // ring resonance remains above channel resonance + // I'll use 3 sigmas of sigma_r_local and sigma_r_systematic, and bias against + // the full temperature range + double fabrication_bias_freq = 3.0 * sqrt(pow(sigma_r_local, 2) + pow(sigma_r_systematic, 2)) + + (T_max - T_min) * tuning_efficiency; + + // The local/systematic variations are 0 on average. Thus, the tuning distance can be calculated as + double tuning_distance = fabrication_bias_freq - (T - T_min) * tuning_efficiency; + + // Tuning power needed is just the number of rings * tuning distance / (tuning and heating efficiencies) + tuning_power = number_rings * tuning_distance / (tuning_efficiency * heating_efficiency); + } + else if (tuning_method == "AthermalWithTrim") + { + // Athermal! Each ring's process variations are trimmed! Everything is free! + // Basically an ideal scenario + tuning_power = 0; + } + else + { + ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown ring tuning method '" + tuning_method + "'!"); + } + + return tuning_power; + } + + unsigned int OpticalLinkBackendTx::getBitReorderDegree() + { + // Get properties + unsigned int number_rings = getGenProperties()->get("OutBits"); + + // Get tech model parameters + double R = getTechModel()->get("Ring->Radius"); + double n_g = getTechModel()->get("Ring->GroupIndex"); + // This can actually be derived if we know thermo-optic coefficient (delta n / delta T) + double sigma_r_local = getTechModel()->get("Ring->LocalVariationSigma"); + + // Get constants + double c = Constants::c; + double pi = Constants::pi; + + // Calculates the degree of bit re-order multiplexing needed for bit-reshuffling backend + // Bit reshuffling tuning is largely unaffected by sigma_r_systematic. However, sigma_r_local + // Can potentially throw each ring to a channel several channels away. This just calculates + // the degree of bit reorder muxing needed to realign bits in the correct order + + // Setup calculations + double L = 2 * pi * R; // Optical length + double FSR = c / (n_g * L); // Free spectral range + double freq_sep = FSR / number_rings; // Channel separation + // Using 4 sigmas as the worst re-ordering case (must double to get both sides) + unsigned int worst_case_channels = (unsigned int)ceil(2.0 * 4.0 * sigma_r_local / freq_sep); + + return worst_case_channels; + } + +} // namespace DSENT + diff --git a/ext/dsent/model/optical/OpticalLinkBackendTx.h b/ext/dsent/model/optical/OpticalLinkBackendTx.h new file mode 100644 index 000000000..a3e596403 --- /dev/null +++ b/ext/dsent/model/optical/OpticalLinkBackendTx.h @@ -0,0 +1,39 @@ +#ifndef __DSENT_MODEL_OPTICAL_OPTICALLINKBACKENDTX_H__ +#define __DSENT_MODEL_OPTICAL_OPTICALLINKBACKENDTX_H__ + +#include "util/CommonType.h" +#include "model/ElectricalModel.h" + +namespace DSENT +{ + class OpticalLinkBackendTx : public ElectricalModel + { + // An optical link backend tx contains everything needed for thermal + // tuning of rings, bit-reshuffling (if necessary), and serialization (if necessary) + public: + OpticalLinkBackendTx(const String& instance_name_, const TechModel* tech_model_); + virtual ~OpticalLinkBackendTx(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void propagateTransitionInfo(); + + private: + // Calculate ring tuning power + double getRingTuningPower(); + // Calculate the degree of bit re-order muxing (for the bit-reshuffler) + unsigned int getBitReorderDegree(); + + }; // class OpticalLinkBackendTx +} // namespace DSENT + +#endif // __DSENT_MODEL_OPTICAL_OPTICALLINKBACKENDTX_H__ + diff --git a/ext/dsent/model/optical/OpticalTestModel.cc b/ext/dsent/model/optical/OpticalTestModel.cc new file mode 100644 index 000000000..c821c4841 --- /dev/null +++ b/ext/dsent/model/optical/OpticalTestModel.cc @@ -0,0 +1,121 @@ +#include "model/optical/OpticalTestModel.h" +#include "model/optical_graph/OpticalGraph.h" +#include "model/optical_graph/OpticalWaveguide.h" +#include "model/optical/RingModulator.h" +#include "model/optical/RingFilter.h" +#include "model/optical/RingDetector.h" +#include "model/optical/LaserSource.h" + +namespace DSENT +{ + OpticalTestModel::OpticalTestModel(const String& instance_name_, const TechModel* tech_model_) + : OpticalModel(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + OpticalTestModel::~OpticalTestModel() + {} + + void OpticalTestModel::initParameters() + { + return; + } + + void OpticalTestModel::initProperties() + { + return; + } + + void OpticalTestModel::constructModel() + { + unsigned int wavelengths = 64; + unsigned int number_readers = 1; + + createWaveguide("LaserToMod", makeWavelengthGroup(0, wavelengths-1)); + + // Create laser + LaserSource* laser = new LaserSource("Laser", getTechModel()); + laser->setParameter("OutStart", 0); + laser->setParameter("OutEnd", wavelengths-1); + laser->construct(); + + // Create modulator + RingModulator* modulator = new RingModulator("Modulator", getTechModel()); + modulator->setParameter("InStart", 0); + modulator->setParameter("InEnd", wavelengths-1); + modulator->setParameter("ModStart", 0); + modulator->setParameter("ModEnd", wavelengths-1); + modulator->construct(); + + for (unsigned int i = 0; i <= number_readers; ++i) + { + String n = (String) i; + createWaveguide("WaveguideDet-" + n, makeWavelengthGroup(0, wavelengths-1)); + } + + // Create a SWMR Configuration + for (unsigned int i = 0; i < number_readers; ++i) + { + String n = (String) i; + + // Create resonant ring detector + RingDetector* detector = new RingDetector("Detector-" + n, getTechModel()); + detector->setParameter("InStart", 0); + detector->setParameter("InEnd", wavelengths-1); + detector->setParameter("DetStart", 0); + detector->setParameter("DetEnd", wavelengths-1); + detector->setParameter("DropAll", "FALSE"); + detector->setParameter("SenseAmp", "TRUE"); + detector->construct(); + + opticalPortConnect(detector, "In", "WaveguideDet-" + n); + opticalPortConnect(detector, "Out", "WaveguideDet-" + (String) (i + 1)); + + addSubInstances(detector, 1.0); + } + + opticalPortConnect(laser, "Out", "LaserToMod"); + opticalPortConnect(modulator, "In", "LaserToMod"); + opticalPortConnect(modulator, "Out", "WaveguideDet-0"); + + addSubInstances(laser, 1.0); + addSubInstances(modulator, 1.0); + } + + void OpticalTestModel::updateModel() + { + double data_rate = 8e9; + double extinction_ratio = 5; + double insertion_loss = 3; + + Model* laser = getSubInstance("Laser"); + laser->update(); + + getWaveguide("LaserToMod")->setLoss(10); + + Model* modulator = getSubInstance("Modulator"); + modulator->setProperty("ExtinctionRatio", extinction_ratio); + modulator->setProperty("InsertionLoss", insertion_loss); + modulator->setProperty("DataRate", data_rate); + modulator->setProperty("P(In)", 0.5); + modulator->setProperty("Act(In)", 1.0); + modulator->update(); + + unsigned int number_readers = 1; + for (unsigned int i = 0; i < number_readers; ++i) + { + Model* detector = getSubInstance("Detector-" + (String) i); + detector->setProperty("ExtinctionRatio", extinction_ratio); + detector->setProperty("DataRate", data_rate); + detector->setProperty("P(In)", 0.5); + detector->setProperty("Act(In)", 1.0); + detector->update(); + } + + + } + +} // namespace DSENT + diff --git a/ext/dsent/model/optical/OpticalTestModel.h b/ext/dsent/model/optical/OpticalTestModel.h new file mode 100644 index 000000000..06a80e955 --- /dev/null +++ b/ext/dsent/model/optical/OpticalTestModel.h @@ -0,0 +1,30 @@ +#ifndef __DSENT_MODEL_OPTICAL_OPTICALTESTMODEL_H__ +#define __DSENT_MODEL_OPTICAL_OPTICALTESTMODEL_H__ + +#include "util/CommonType.h" +#include "model/OpticalModel.h" + +namespace DSENT +{ + class OpticalTestModel : public OpticalModel + { + public: + OpticalTestModel(const String& instance_name_, const TechModel* tech_model_); + virtual ~OpticalTestModel(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + + }; // class OpticalTestModel +} // namespace DSENT + +#endif // __DSENT_MODEL_OPTICAL_RINGLASERSOURCE_H__ + diff --git a/ext/dsent/model/optical/RingDetector.cc b/ext/dsent/model/optical/RingDetector.cc new file mode 100644 index 000000000..4baf2f68f --- /dev/null +++ b/ext/dsent/model/optical/RingDetector.cc @@ -0,0 +1,338 @@ +#include "model/optical/RingDetector.h" + +#include <cmath> + +#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/OpticalDetector.h" +#include "model/optical_graph/OpticalFilter.h" +#include "model/timing_graph/ElectricalDriver.h" +#include "model/timing_graph/ElectricalNet.h" + +namespace DSENT +{ + // TODOs for this model + // Add the other receiver topologies from [Georgas, CICC 2011] + // Split integ_time_ratio = SA integ time ratio + // Right now perfect clock gating is assumed...may not be what we want + + // Constants + const String RingDetector::INTEGRATINGSENSEAMP = "INTSA"; + + RingDetector::RingDetector(const String& instance_name_, const TechModel* tech_model_) + : OpticalModel(instance_name_, tech_model_), OpticalReceiver() + { + initParameters(); + initProperties(); + } + + RingDetector::~RingDetector() + {} + + void RingDetector::initParameters() + { + addParameterName("DataRate"); + addParameterName("InStart"); + addParameterName("InEnd"); + addParameterName("DetStart"); + addParameterName("DetEnd"); + addParameterName("DropAll"); + addParameterName("Topology"); + return; + } + + void RingDetector::initProperties() + { + return; + } + + void RingDetector::constructModel() + { + // Get parameters + WavelengthGroup in_wavelengths = makeWavelengthGroup(getParameter("InStart"), getParameter("InEnd")); + WavelengthGroup det_wavelengths = makeWavelengthGroup(getParameter("DetStart"), getParameter("DetEnd")); + int number_wavelengths = det_wavelengths.second - det_wavelengths.first + 1; + bool drop_all = getParameter("DropAll"); + const String& topology = getParameter("Topology"); + + // Set some generated properties + getGenProperties()->set("NumberWavelengths", number_wavelengths); + + // Create device area result + addAreaResult(new AtomicResult("Photonic")); + // Create electrical results + createElectricalAtomicResults(); + if (topology == INTEGRATINGSENSEAMP) addEventResult(new AtomicResult("Receive")); + else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology + ")!"); + + // Create optical ports + createOpticalInputPort( "In", in_wavelengths); + createOpticalOutputPort( "Out", in_wavelengths); + // Create the filter and modulator + createFilter( "RingFilter", in_wavelengths, drop_all, det_wavelengths); + createDetector( "RingDetector", det_wavelengths, this); + OpticalFilter* ring_filter = getFilter("RingFilter"); + OpticalDetector* ring_detector = getDetector("RingDetector"); + // Connect the filter and modulator + getWaveguide("In")->addDownstreamNode(ring_filter); + ring_filter->addDownstreamNode(getWaveguide("Out")); + ring_filter->setDropPort(ring_detector); + + // Create electrical ports + createOutputPort("Out", makeNetIndex(0, number_wavelengths-1)); + // Create net + createNet("OutVFO"); + // Create output driver + createDriver("OutDriver", false); + // Connect driver + getDriver("OutDriver")->addDownstreamNode(getNet("OutVFO")); + // Connect output + assignVirtualFanout("Out", "OutVFO"); + + // Precompute some technology values + precomputeTech(); + + return; + } + + void RingDetector::updateModel() + { + // Get some generated properties + unsigned int number_wavelengths = getGenProperties()->get("NumberWavelengths"); + + // Get tech model numbers + double ring_area = getTechModel()->get("Ring->Area"); + double thru_loss = getTechModel()->get("Ring->ThroughLoss"); + double drop_loss = getTechModel()->get("Ring->DropLoss"); + double pd_loss = getTechModel()->get("Photodetector->Loss"); + double pd_responsivity = getTechModel()->get("Photodetector->Responsivity"); + + // Design the receiver + designReceiver(); + + // Update losses + // Connect the filter and modulator + OpticalFilter* ring_filter = getFilter("RingFilter"); + OpticalDetector* ring_detector = getDetector("RingDetector"); + ring_filter->setLoss(thru_loss * number_wavelengths); + ring_filter->setDropLoss(drop_loss + thru_loss * number_wavelengths); + ring_detector->setLoss(pd_loss); + ring_detector->setResponsivity(pd_responsivity); + // Update device area + getAreaResult("Photonic")->setValue(ring_area * (number_wavelengths)); + + return; + } + + void RingDetector::useModel() + { + // Get parameters + const String& topology = getParameter("Topology"); + + // Get some generated properties + unsigned int number_wavelengths = getGenProperties()->get("NumberWavelengths"); + + // Get optical input transition info + const TransitionInfo& in_trans = getOpticalInputPort("In")->getTransitionInfo(); + + // Get tech models + double vdd = getTechModel()->get("Vdd"); + // Get caps + double unit_gate_cap = getTechModel()->get("Gate->MinWidth").toDouble() * getTechModel()->get("Gate->CapPerWidth").toDouble(); + double unit_drain_cap = getTechModel()->get("Gate->MinWidth").toDouble() * getTechModel()->get("Drain->CapPerWidth").toDouble(); + double inv_x1_gate_cap = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->A"); + double inv_x1_drain_cap = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->Y"); + + // Construct a simple sense-amp model + if(topology == INTEGRATINGSENSEAMP) + { + // Use ratios from the receiver published in [Georgas, ESSCIRC 2011] + // Note: + // The numbers in the paper (43fJ/b, 50 fJ/b in the cited work) is done with the clock buffer (there are 4 receivers), + // capacitive DAC, and extra output flops used in the physical layout, as the compared receiver is extremely conservative + // We simplified this model to not have the capacitive DAC, the clock buffer (since this is an individual receiver), or + // the extra output flops (since receiver structure is already a posedge flop functionally). + // Look for an upcoming paper [Georgas, JSSC 2012] (when it is published) for the power breakdown pie-chart for the receiver. + // This model only models the latch (sampler) and the dynamic to static (RS latch) part of the design, which is all you really + // need in the receiver. + + // Gate caps + double c_gate_sampler = unit_gate_cap * (4 * 2.0 + 2 * 1.0 + 2 * 3.0 + 2 * 5.0) + unit_gate_cap * (2 * 6.0 + 2 * 1.0) + inv_x1_gate_cap; + double c_gate_rslatch = unit_gate_cap * (4 * 1.0) + inv_x1_gate_cap; + // Drain caps + double c_drain_sampler = unit_drain_cap * (2 * 2.0 + 2 * 1.0 + 3 * 5.0 + 1 * 3.0) + inv_x1_drain_cap; + double c_drain_rslatch = unit_drain_cap * (2 * 6.0) + inv_x1_drain_cap; + // Sum up cap switched for the sampler + double c_sampler = c_gate_sampler + c_drain_sampler; + double c_rslatch = c_gate_rslatch + c_drain_rslatch; + // Average cap switched + // Sampler is differential, one side will always switch (R or S in the latch) regardless of probability + double avg_cap = c_sampler + c_rslatch * in_trans.getProbability0() * in_trans.getProbability1(); + + // 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 (curve fit with design) + double total_leakage = 0.5 * (unit_leak_0 + unit_leak_1) * 7.43; + + // Create results + getEventResult("Receive")->setValue(vdd * vdd * avg_cap * number_wavelengths); + getNddPowerResult("Leakage")->setValue(total_leakage * number_wavelengths); + + } + else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology + ")!"); + + return; + } + + void RingDetector::propagateTransitionInfo() + { + // Propagate probabilities from optical input to electrical output port + getOutputPort("Out")->setTransitionInfo(getOpticalInputPort("In")->getTransitionInfo()); + + return; + } + + void RingDetector::precomputeTech() + { + // Get parameters + const double data_rate = getParameter("DataRate"); + const String& topology = getParameter("Topology"); + + // Get tech model numbers + double pd_cap = getTechModel()->get("Photodetector->Cap"); + double parasitic_cap = getTechModel()->get("Photodetector->ParasiticCap"); + double apd = getTechModel()->get("Photodetector->AvalancheGain"); + double vdd = getTechModel()->get("Vdd"); + + // Constants shortcuts + double pi = Constants::pi; + double k = Constants::k; + double q = Constants::q; + double T = getTechModel()->get("Temperature"); + + if(topology == INTEGRATINGSENSEAMP) + { + // Get more tech parameters + double integ_time_ratio = getTechModel()->get("Receiver->Int->IntegrationTimeRatio"); + double BER = getTechModel()->get("SenseAmp->BER"); + double CMRR = getTechModel()->get("SenseAmp->CMRR"); + double offset_comp_bits = getTechModel()->get("SenseAmp->OffsetCompensationBits"); + double offset = getTechModel()->get("SenseAmp->OffsetRatio").toDouble() * vdd; + double supply_noise_rand = getTechModel()->get("SenseAmp->SupplyNoiseRandRatio").toDouble() * vdd; + double supply_noise_det = getTechModel()->get("SenseAmp->SupplyNoiseDetRatio").toDouble() * vdd; + double noise_margin = getTechModel()->get("SenseAmp->NoiseMargin"); + double jitter_ratio = getTechModel()->get("SenseAmp->JitterRatio"); + + // Approximate tao using FO4 + double unit_drain_cap = getTechModel()->get("Gate->MinWidth").toDouble() * getTechModel()->get("Drain->CapPerWidth").toDouble(); + double c_g = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->A"); + double c_d = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->Y"); + double r_o = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->DriveRes->Y"); + // Calculate sense amp tau from sense amp output loading + double tau = r_o * (c_g + c_d); + // Set output inverter drive strength + getDriver("OutDriver")->setOutputRes(r_o); + + // Calculate sense amp input cap based on schematic + double sense_amp_cap_in = unit_drain_cap * (2.0 + 3.0 + 5.0 + 1.0); + + // Residual offset + double v_residual = 3 * offset / pow(2, offset_comp_bits); + // Noise + double v_noise = supply_noise_rand * supply_noise_rand / (CMRR * CMRR); + // Sense amp voltage build-up minimum + double v_sense = vdd * exp(-(1 - integ_time_ratio) / (data_rate * tau)) + noise_margin + v_residual + supply_noise_det / CMRR; + // Sigmas corresponding to BER + double sigma = calcInvNormCdf(BER); + + //K_int is the time the bit is valid for evaluation + + // Total input cap load + double input_node_cap = sense_amp_cap_in + pd_cap + parasitic_cap; + double z_int = integ_time_ratio / (data_rate * input_node_cap); //should use K_int + + // Store precalculated values + m_quad_a_ = 1 - (sigma * sigma * jitter_ratio * jitter_ratio); + m_quad_b1_ = - 2 * pi / 2 * sigma * sigma * q * 0.7 * data_rate; + m_quad_b2_ = -2 * v_sense / (z_int * apd); + m_quad_c_ = 1 / (z_int * z_int) * (v_sense * v_sense - sigma * sigma * (k * T / input_node_cap + v_noise)); + } + else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology + ")!"); + + return; + } + + void RingDetector::designReceiver() + { + // Get some generated properties + unsigned int number_wavelengths = getGenProperties()->get("NumberWavelengths"); + + // Get relevant properties/parameters + const String& topology = getParameter("Topology"); + + // Construct a simple sense-amp model + if(topology == INTEGRATINGSENSEAMP) + { + // No really good way to estimate the area...can assume each receiver is the size of 40 inverters, which is + // about the right size for just the sense amp in the layout + double unit_area_active = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Area->Active"); + double unit_area_metal1 = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Area->Metal1Wire"); + getAreaResult("Active")->setValue(unit_area_active * 40 * number_wavelengths); + getAreaResult("Metal1Wire")->setValue(unit_area_metal1 * 40 * number_wavelengths); + } + else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology + ")!"); + + return; + } + + double RingDetector::getSensitivity(double ER_dB_) const + { + // Get parameters + const String& topology = getParameter("Topology"); + // Turn extinction ratio into a ratio from dB scale + double ER = pow(10, ER_dB_ / 10); + + // Initialize sensitivity + double sensitivity = 1e99; + // Construct a simple sense-amp model + if(topology == INTEGRATINGSENSEAMP) + { + // Scale photodetector shot noise using ER, add rest of noise source + double b = m_quad_b1_ * (1 + ER) / (2 * (ER - 1)) + m_quad_b2_; + + // Find sensitivity (-b + sqrt(b^2-4ac)) / 2a + sensitivity = ((-b + sqrt(b * b - 4 * m_quad_a_ * m_quad_c_)) / (2 * m_quad_a_)); + } + else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology + ")!"); + + return sensitivity; + } + + double RingDetector::calcInvNormCdf(double num_) + { + // 53 bit precision for double FP + unsigned int num_iterations = 20; + // Upperbound the step + double step = 20; + double out = step; + // Iteratively guess and check calculation + for (unsigned int i = 0; i < num_iterations; ++i) + { + double current = 0.5 * erfc(out / sqrt(2)); + if (current > num_) out += step; + else out -= step; + step = step * 0.5; + } + + return out; + } + +} // namespace DSENT + diff --git a/ext/dsent/model/optical/RingDetector.h b/ext/dsent/model/optical/RingDetector.h new file mode 100644 index 000000000..e18b2fe75 --- /dev/null +++ b/ext/dsent/model/optical/RingDetector.h @@ -0,0 +1,54 @@ +#ifndef __DSENT_MODEL_OPTICAL_RINGDETECTOR_H__ +#define __DSENT_MODEL_OPTICAL_RINGDETECTOR_H__ + +#include "util/CommonType.h" +#include "model/OpticalModel.h" +#include "model/optical_graph/OpticalReceiver.h" + +namespace DSENT +{ + class RingDetector : public OpticalModel, public OpticalReceiver + { + public: + // Receiver topolgy strings + static const String INTEGRATINGSENSEAMP; + + public: + RingDetector(const String& instance_name_, const TechModel* tech_model_); + virtual ~RingDetector(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + // Returns the sensitivity of the receiver given an extinction ratio + double getSensitivity(double ER_dB_) const; + + private: + // Precompute values based on tech parameters + void precomputeTech(); + // Design the receiver helper function + void designReceiver(); + // Calculates inverse normal cdf + double calcInvNormCdf(double num_); + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void useModel(); + virtual void propagateTransitionInfo(); + + private: + // Precomputed numbers + double m_quad_a_; + double m_quad_b1_; + double m_quad_b2_; + double m_quad_c_; + + }; // class RingDetector +} // namespace DSENT + +#endif // __DSENT_MODEL_OPTICAL_RINGDETECTOR_H__ + diff --git a/ext/dsent/model/optical/RingFilter.cc b/ext/dsent/model/optical/RingFilter.cc new file mode 100644 index 000000000..5f0bd5b40 --- /dev/null +++ b/ext/dsent/model/optical/RingFilter.cc @@ -0,0 +1,77 @@ +#include "model/optical/RingFilter.h" + +#include "model/optical_graph/OpticalWaveguide.h" +#include "model/optical_graph/OpticalFilter.h" + +namespace DSENT +{ + RingFilter::RingFilter(const String& instance_name_, const TechModel* tech_model_) + : OpticalModel(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + RingFilter::~RingFilter() + {} + + void RingFilter::initParameters() + { + addParameterName("InStart"); + addParameterName("InEnd"); + addParameterName("DropStart"); + addParameterName("DropEnd"); + addParameterName("DropAll", "TRUE"); + return; + } + + void RingFilter::initProperties() + { + return; + } + + void RingFilter::constructModel() + { + //TODO: Add tuning energy/ndd-power costs? + + // Create Area result + Result* area_result = new AtomicResult("Photonic"); + addAreaResult(area_result); + + // Get parameters + WavelengthGroup in_wavelengths = makeWavelengthGroup(getParameter("InStart"), getParameter("InEnd")); + WavelengthGroup drop_wavelengths = makeWavelengthGroup(getParameter("DropStart"), getParameter("DropEnd")); + bool drop_all = getParameter("DropAll"); + + // Create optical ports + createOpticalInputPort( "In", in_wavelengths); + createOpticalOutputPort( "Drop", drop_wavelengths); + createOpticalOutputPort( "Out", in_wavelengths); + // Create the filter + createFilter( "RingFilter", in_wavelengths, drop_all, drop_wavelengths); + OpticalFilter* ring_filter = getFilter("RingFilter"); + // Connect the filter + getWaveguide("In")->addDownstreamNode(ring_filter); + ring_filter->addDownstreamNode(getWaveguide("Out")); + ring_filter->setDropPort(getWaveguide("Drop")); + } + + void RingFilter::updateModel() + { + //TODO: Get numbers from tech model; + double ring_area = 200e-12; + double thru_loss = 1e-4; + double drop_loss = 1.0; + // Get parameters + WavelengthGroup drop_wavelengths = makeWavelengthGroup(getParameter("DropStart"), getParameter("DropEnd")); + int number_wavelengths = drop_wavelengths.second - drop_wavelengths.first + 1; + // Update losses + OpticalFilter* ring_filter = getFilter("RingFilter"); + ring_filter->setLoss(thru_loss * number_wavelengths); + ring_filter->setDropLoss(drop_loss + thru_loss * number_wavelengths); + // Update area + getAreaResult("Photonic")->setValue(ring_area * (number_wavelengths)); + } + +} // namespace DSENT + diff --git a/ext/dsent/model/optical/RingFilter.h b/ext/dsent/model/optical/RingFilter.h new file mode 100644 index 000000000..87fcb8c04 --- /dev/null +++ b/ext/dsent/model/optical/RingFilter.h @@ -0,0 +1,30 @@ +#ifndef __DSENT_MODEL_OPTICAL_RINGFILTER_H__ +#define __DSENT_MODEL_OPTICAL_RINGFILTER_H__ + +#include "util/CommonType.h" +#include "model/OpticalModel.h" + +namespace DSENT +{ + class RingFilter : public OpticalModel + { + public: + RingFilter(const String& instance_name_, const TechModel* tech_model_); + virtual ~RingFilter(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + + }; // class RingFilter +} // namespace DSENT + +#endif // __DSENT_MODEL_OPTICAL_RINGFILTER_H__ + 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 <cmath> + +#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 + diff --git a/ext/dsent/model/optical/RingModulator.h b/ext/dsent/model/optical/RingModulator.h new file mode 100644 index 000000000..bbfa7f4ee --- /dev/null +++ b/ext/dsent/model/optical/RingModulator.h @@ -0,0 +1,54 @@ +#ifndef __DSENT_MODEL_OPTICAL_RINGMODULATOR_H__ +#define __DSENT_MODEL_OPTICAL_RINGMODULATOR_H__ + +#include "util/CommonType.h" +#include "model/OpticalModel.h" +#include "model/optical_graph/OpticalTransmitter.h" + +namespace DSENT +{ + class RingModulator : public OpticalModel, public OpticalTransmitter + { + public: + RingModulator(const String& instance_name_, const TechModel* tech_model_); + virtual ~RingModulator(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + // Set the transmitter specifications, returns whether it is possible + // to build a modulator that met those specs + bool setTransmitterSpec(double IL_dB_, double ER_dB_); + // Returns power of the transmitter at a given utilization + double getPower(double util_) const; + + private: + // Precompute values based on tech parameters + void precomputeTech(); + // Design ring modulator driver + bool designModulator(double IL_dB_, double ER_dB_); + // Calculate modulator energy + double calcModulatorEnergy() const; + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void useModel(); + virtual void propagateTransitionInfo(); + + private: + // Some precomputed tech values + double m_precompute_V_bi_; + double m_precompute_x_d0_; + double m_precompute_C_j0_; + double m_precompute_Q_0_; + + + }; // class RingModulator +} // namespace DSENT + +#endif // __DSENT_MODEL_OPTICAL_RINGMODULATOR_H__ + diff --git a/ext/dsent/model/optical/SWMRLink.cc b/ext/dsent/model/optical/SWMRLink.cc new file mode 100644 index 000000000..56d2d70b3 --- /dev/null +++ b/ext/dsent/model/optical/SWMRLink.cc @@ -0,0 +1,309 @@ +#include "model/optical/SWMRLink.h" + +#include "model/PortInfo.h" +#include "model/TransitionInfo.h" +#include "model/EventInfo.h" +#include "model/optical_graph/OpticalGraph.h" +#include "model/optical_graph/OpticalWaveguide.h" +#include "model/optical/RingModulator.h" +#include "model/optical/RingFilter.h" +#include "model/optical/RingDetector.h" +#include "model/optical/LaserSource.h" +#include "model/optical/ThrottledLaserSource.h" + +namespace DSENT +{ + SWMRLink::SWMRLink(const String& instance_name_, const TechModel* tech_model_) + : OpticalModel(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + SWMRLink::~SWMRLink() + {} + + void SWMRLink::initParameters() + { + addParameterName("NumberReaders"); + addParameterName("NumberWavelengths"); + addParameterName("DataRate"); + addParameterName("LaserType"); + addParameterName("MaxReaders"); + addParameterName("MinReaders"); + addParameterName("OptimizeLoss", "TRUE"); + return; + } + + void SWMRLink::initProperties() + { + addPropertyName("Length"); + addPropertyName("OptUtil", 0.5); // default to 50% utilization (a new word 50% of the time) + addPropertyName("ExtinctionRatio", 6); // default properties + addPropertyName("InsertionLoss", 2); // default properties + return; + } + + void SWMRLink::constructModel() + { + // Get parameters + unsigned int number_wavelengths = getParameter("NumberWavelengths"); + unsigned int number_readers = getParameter("NumberReaders"); + unsigned int number_max_readers = std::min(number_readers, getParameter("MaxReaders").toUInt()); + unsigned int number_min_readers = std::min(number_max_readers, getParameter("MinReaders").toUInt()); + + // Create electrical ports + createInputPort("CK"); + createInputPort("In", makeNetIndex(0, number_wavelengths-1)); + for (unsigned int i = 0; i < number_readers; ++i) + createOutputPort("Out" + (String) i, makeNetIndex(0, number_wavelengths-1)); + + // Create Waveguides + // Temporarily assume its all on one waveguide + createWaveguide("LaserToMod", makeWavelengthGroup(0, number_wavelengths-1)); + for (unsigned int i = 0; i <= number_readers; ++i) + createWaveguide("WaveguideSegment[" + (String) i + "]", makeWavelengthGroup(0, number_wavelengths-1)); + + // Add area results + addAreaResult(new Result("Photonic")); + createElectricalResults(); + // Setup idle event + getEventInfo("Idle")->setStaticTransitionInfos(); + // Create a waveguide area result + addAreaResult(new AtomicResult("Waveguide")); + getAreaResult("Photonic")->addSubResult(getAreaResult("Waveguide"), "Waveguide", 1.0); + // Add results + addNddPowerResult(new Result("Laser")); + // Add event result + createElectricalEventResult("BroadcastFlit"); + + for (unsigned int i = number_min_readers; i <= number_max_readers; ++i) + createElectricalEventResult("MulticastFlit" + (String) i); + + buildLaser(); + buildModulator(); + buildDetectors(); + + return; + } + + void SWMRLink::updateModel() + { + // Get parameters + double data_rate = getParameter("DataRate"); + unsigned int number_readers = getParameter("NumberReaders"); + + // Get properties + double length = getProperty("Length"); + const String& extinction_ratio = getProperty("ExtinctionRatio"); + const String& insertion_loss = getProperty("InsertionLoss"); + const double opt_util = getProperty("OptUtil"); + + // Calculate loss for each waveguide segment + double segment_length = (double) length / number_readers; + double segment_loss = getTechModel()->get("Waveguide->LossPerMeter").toDouble() * segment_length; + // Set loss of each waveguide segment + for (unsigned int i = 0; i < number_readers; ++i) + getWaveguide("WaveguideSegment[" + (String) i + "]")->setLoss(segment_loss); + // Calculate waveguide area + double waveguide_area = length * getTechModel()->get("Waveguide->Pitch").toDouble(); + getAreaResult("Waveguide")->setValue(waveguide_area); + + // Update the laser + Model* laser = getSubInstance("Laser"); + laser->setProperty("LaserEventTime", 1.0 / data_rate); + laser->setProperty("OptUtil", opt_util); + laser->update(); + + // Update the modulator + Model* modulator = getSubInstance("Modulator"); + modulator->setProperty("ExtinctionRatio", extinction_ratio); + modulator->setProperty("InsertionLoss", insertion_loss); + modulator->update(); + + // Update all receivers + for (unsigned int i = 0; i < number_readers; ++i) + { + Model* detector = getSubInstance("Detector_" + (String) i); + detector->update(); + } + + return; + } + + void SWMRLink::propagateTransitionInfo() + { + // Get parameters + const String& laser_type = getParameter("LaserType"); + unsigned int number_readers = getParameter("NumberReaders"); + + // Set transition info for the modulator + OpticalModel* modulator = (OpticalModel*) getSubInstance("Modulator"); + propagatePortTransitionInfo(modulator, "In", "In"); + modulator->use(); + + // Modulator out transition info + const TransitionInfo& mod_out_transitions = modulator->getOpticalOutputPort("Out")->getTransitionInfo(); + + // Set transition info for all receivers + for (unsigned int i = 0; i < number_readers; ++i) + { + OpticalModel* detector = (OpticalModel*) getSubInstance("Detector_" + (String) i); + detector->getOpticalInputPort("In")->setTransitionInfo(mod_out_transitions); + detector->use(); + + // Propagate output transition info to output + propagatePortTransitionInfo("Out" + (String) i, detector, "Out"); + } + + // Set enable signals for the laser, if applicable + if (laser_type == "Throttled") + { + // Figure out how many cycles the laser needs to be on + double cycles = getInputPort("In")->getTransitionInfo().getFrequencyMultiplier(); + + OpticalModel* laser = (OpticalModel*) getSubInstance("Laser"); + laser->getInputPort("LaserEnable")->setTransitionInfo(TransitionInfo(0.0, 1.0, cycles - 1.0)); + laser->use(); + } + return; + } + + void SWMRLink::buildLaser() + { + // Get parameters + unsigned int number_wavelengths = getParameter("NumberWavelengths"); + unsigned int number_readers = getParameter("NumberReaders"); + unsigned int number_max_readers = std::min(number_readers, getParameter("MaxReaders").toUInt()); + unsigned int number_min_readers = std::min(number_max_readers, getParameter("MinReaders").toUInt()); + const String& laser_type = getParameter("LaserType"); + + // Create laser + OpticalModel* laser = NULL; + if (laser_type == "Throttled") + laser = new ThrottledLaserSource("Laser", getTechModel()); + else if (laser_type == "Standard") + laser = new LaserSource("Laser", getTechModel()); + else + ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown laser type '" + laser_type + "'!"); + + laser->setParameter("OutStart", 0); + laser->setParameter("OutEnd", number_wavelengths-1); + laser->setParameter("MaxDetectors", number_max_readers); + laser->setParameter("MinDetectors", number_min_readers); + laser->construct(); + + addSubInstances(laser, 1.0); + getAreaResult("Photonic")->addSubResult(laser->getAreaResult("Photonic"), "Laser", 1.0); + // Connect laser output port + opticalPortConnect(laser, "Out", "LaserToMod"); + + // Without laser gating, laser is pure NDD power + if (laser_type == "Standard") + getNddPowerResult("Laser")->addSubResult(laser->getNddPowerResult("Laser"), "Laser", 1.0); + // With laser power gating, laser is an event + else + { + // If laser is throttled, only pay for the amount needed to reach some number of readers + getEventResult("BroadcastFlit")->addSubResult(laser->getEventResult("Laser" + (String) number_max_readers), "Laser", 1.0); + for (unsigned int i = number_min_readers; i <= number_max_readers; ++i) + getEventResult("MulticastFlit" + (String) i)->addSubResult(laser->getEventResult("Laser" + (String) i), "Laser", 1.0); + } + + return; + } + + void SWMRLink::buildModulator() + { + // Get parameters + double data_rate = getParameter("DataRate"); + const String& optimize_loss = getParameter("OptimizeLoss"); + unsigned int number_wavelengths = getParameter("NumberWavelengths"); + unsigned int number_readers = getParameter("NumberReaders"); + unsigned int number_max_readers = std::min(number_readers, getParameter("MaxReaders").toUInt()); + unsigned int number_min_readers = std::min(number_max_readers, getParameter("MinReaders").toUInt()); + + // Create modulator + RingModulator* modulator = new RingModulator("Modulator", getTechModel()); + modulator->setParameter("DataRate", data_rate); + modulator->setParameter("InStart", 0); + modulator->setParameter("InEnd", number_wavelengths-1); + modulator->setParameter("ModStart", 0); + modulator->setParameter("ModEnd", number_wavelengths-1); + modulator->setParameter("OptimizeLoss", optimize_loss); + modulator->construct(); + addSubInstances(modulator, 1.0); + getAreaResult("Photonic")->addSubResult(modulator->getAreaResult("Photonic"), "Modulator", 1.0); + addElectricalSubResults(modulator, 1.0); + + // Connect electrical port + portConnect(modulator, "In", "In"); + // Connect modulator input, output port + opticalPortConnect(modulator, "In", "LaserToMod"); + opticalPortConnect(modulator, "Out", "WaveguideSegment[0]"); + + // Add modulator energy event for all broadcast events + getEventResult("BroadcastFlit")->addSubResult(modulator->getEventResult("Modulate"), "Modulator", 1.0); + for (unsigned int i = number_min_readers; i <= number_max_readers; ++i) + getEventResult("MulticastFlit" + (String) i)->addSubResult(modulator->getEventResult("Modulate"), "Modulator", 1.0); + + return; + } + + void SWMRLink::buildDetectors() + { + // Get parameters + double data_rate = getParameter("DataRate"); + unsigned int number_wavelengths = getParameter("NumberWavelengths"); + unsigned int number_readers = getParameter("NumberReaders"); + unsigned int number_max_readers = std::min(number_readers, getParameter("MaxReaders").toUInt()); + unsigned int number_min_readers = std::min(number_max_readers, getParameter("MinReaders").toUInt()); + + // Create a SWMR Configuration + for (unsigned int i = 0; i < number_readers; ++i) + { + String n = (String) i; + + // Create resonant ring detector + RingDetector* detector = new RingDetector("Detector_" + n, getTechModel()); + detector->setParameter("DataRate", data_rate); + detector->setParameter("InStart", 0); + detector->setParameter("InEnd", number_wavelengths-1); + detector->setParameter("DetStart", 0); + detector->setParameter("DetEnd", number_wavelengths-1); + detector->setParameter("DropAll", "FALSE"); + detector->setParameter("Topology", RingDetector::INTEGRATINGSENSEAMP); + detector->construct(); + addSubInstances(detector, 1.0); + getAreaResult("Photonic")->addSubResult(detector->getAreaResult("Photonic"), "Detector_" + n, 1.0); + addElectricalSubResults(detector, 1.0); + + // connect to electrical port + portConnect(detector, "Out", "Out" + (String) i); + // connect optical input, output port + opticalPortConnect(detector, "In", "WaveguideSegment[" + (String) i + "]"); + opticalPortConnect(detector, "Out", "WaveguideSegment[" + (String) (i + 1) + "]"); + } + + // Add an average receiver energy for all multicast events (and broadcast) + Result* broadcast_event = getEventResult("BroadcastFlit"); + for (unsigned int i = 0; i < number_readers; ++i) + { + const String detector_name = "Detector_" + (String) i; + broadcast_event->addSubResult(getSubInstance(detector_name)->getEventResult("Receive"), detector_name, 1.0); + } + for (unsigned int i = number_min_readers; i <= number_max_readers; ++i) + { + Result* multicast_event = getEventResult("MulticastFlit" + (String) i); + for (unsigned int j = 0; j < number_readers; ++j) + { + const String detector_name = "Detector_" + (String) j; + multicast_event->addSubResult(getSubInstance(detector_name)->getEventResult("Receive"), detector_name, (double) i / number_readers); + } + } + + return; + } + +} // namespace DSENT + diff --git a/ext/dsent/model/optical/SWMRLink.h b/ext/dsent/model/optical/SWMRLink.h new file mode 100644 index 000000000..a2618358c --- /dev/null +++ b/ext/dsent/model/optical/SWMRLink.h @@ -0,0 +1,38 @@ +#ifndef __DSENT_MODEL_OPTICAL_SWMRLINK_H__ +#define __DSENT_MODEL_OPTICAL_SWMRLINK_H__ + +#include "util/CommonType.h" +#include "model/OpticalModel.h" + +namespace DSENT +{ + class SWMRLink : public OpticalModel + { + // A SWMR Link consists of a laser, a modulator (the writer) and a variable + // number of readers + public: + SWMRLink(const String& instance_name_, const TechModel* tech_model_); + virtual ~SWMRLink(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void propagateTransitionInfo(); + + private: + void buildLaser(); + void buildModulator(); + void buildDetectors(); + + }; // class SWMRLink +} // namespace DSENT + +#endif // __DSENT_MODEL_OPTICAL_SWMRLINK_H__ + diff --git a/ext/dsent/model/optical/SWSRLink.cc b/ext/dsent/model/optical/SWSRLink.cc new file mode 100644 index 000000000..88973e392 --- /dev/null +++ b/ext/dsent/model/optical/SWSRLink.cc @@ -0,0 +1,328 @@ +#include "model/optical/SWSRLink.h" + +#include "model/ModelGen.h" +#include "model/PortInfo.h" +#include "model/TransitionInfo.h" +#include "model/EventInfo.h" +#include "model/optical_graph/OpticalGraph.h" +#include "model/optical_graph/OpticalWaveguide.h" +#include "model/optical/RingModulator.h" +#include "model/optical/RingFilter.h" +#include "model/optical/RingDetector.h" +#include "model/optical/LaserSource.h" +#include "model/optical/ThrottledLaserSource.h" + +namespace DSENT +{ + SWSRLink::SWSRLink(const String& instance_name_, const TechModel* tech_model_) + : OpticalModel(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + SWSRLink::~SWSRLink() + {} + + void SWSRLink::initParameters() + { + addParameterName("NumberBits"); + addParameterName("CoreDataRate"); + addParameterName("LinkDataRate"); + + addParameterName("LaserType"); + addParameterName("RingTuningMethod"); + addParameterName("OptimizeLoss", "TRUE"); + + return; + } + + void SWSRLink::initProperties() + { + addPropertyName("Length"); + addPropertyName("OptUtil", 0.5); // default to 50% utilization (a new word 50% of the time) + addPropertyName("ExtinctionRatio", 6); // default properties + addPropertyName("InsertionLoss", 2); // default properties + return; + } + + void SWSRLink::constructModel() + { + // Get parameters + unsigned int number_bits = getParameter("NumberBits"); + double core_data_rate = getParameter("CoreDataRate"); + double link_data_rate = getParameter("LinkDataRate"); + + // Get directly propagated parameters + const String& ring_tuning_method = getParameter("RingTuningMethod"); + + // Calculate number of wavelengths needed + unsigned int number_wavelengths = (unsigned int)((double) number_bits * core_data_rate / link_data_rate); + + // Set some generated properties + getGenProperties()->set("NumberWavelengths", number_wavelengths); + + // Create electrical ports + createInputPort("LinkCK"); + createInputPort("In", makeNetIndex(0, number_bits-1)); + createOutputPort("Out", makeNetIndex(0, number_bits-1)); + + // Create Waveguides + // Temporarily assume its all on one waveguide + createWaveguide("LaserToMod", makeWavelengthGroup(0, number_wavelengths-1)); + createWaveguide("ModToDetector", makeWavelengthGroup(0, number_wavelengths-1)); + + // Add area results + addAreaResult(new Result("Photonic")); + createElectricalResults(); + // Setup idle event + getEventInfo("Idle")->setStaticTransitionInfos(); + // Create a waveguide area result + addAreaResult(new AtomicResult("Waveguide")); + getAreaResult("Photonic")->addSubResult(getAreaResult("Waveguide"), "Waveguide", 1.0); + // Add results + addNddPowerResult(new Result("Laser")); + addNddPowerResult(new Result("RingTuning")); + // Add event result + createElectricalEventResult("Send"); + + // Create Tx, Rx backends + // Create Tx electrical backend + ElectricalModel* tx_backend = (ElectricalModel*) ModelGen::createModel("OpticalLinkBackendTx", "OpticalLinkBackendTx", getTechModel()); + tx_backend->setParameter("InBits", number_bits); + tx_backend->setParameter("CoreDataRate", core_data_rate); + tx_backend->setParameter("LinkDataRate", link_data_rate); + tx_backend->setParameter("RingTuningMethod", ring_tuning_method); + tx_backend->setParameter("BitDuplicate", "TRUE"); + tx_backend->construct(); + + // Create Rx electrical backend + ElectricalModel* rx_backend = (ElectricalModel*) ModelGen::createModel("OpticalLinkBackendRx", "OpticalLinkBackendRx", getTechModel()); + rx_backend->setParameter("OutBits", number_bits); + rx_backend->setParameter("CoreDataRate", core_data_rate); + rx_backend->setParameter("LinkDataRate", link_data_rate); + rx_backend->setParameter("RingTuningMethod", ring_tuning_method); + rx_backend->setParameter("BitDuplicate", "TRUE"); + rx_backend->construct(); + + // Connect ports + createNet("TxBackendToTx", makeNetIndex(0, number_wavelengths-1)); + createNet("RxToRxBackend", makeNetIndex(0, number_wavelengths-1)); + portConnect(tx_backend, "In", "In"); + portConnect(tx_backend, "Out", "TxBackendToTx"); + portConnect(tx_backend, "LinkCK", "LinkCK"); + portConnect(rx_backend, "In", "RxToRxBackend"); + portConnect(rx_backend, "Out", "Out"); + portConnect(rx_backend, "LinkCK", "LinkCK"); + + // Add instances + addSubInstances(tx_backend, 1.0); + addSubInstances(rx_backend, 1.0); + + // Add electrical results + addElectricalSubResults(tx_backend, 1.0); + addElectricalSubResults(rx_backend, 1.0); + + // Add tuning power result + getNddPowerResult("RingTuning")->addSubResult(tx_backend->getNddPowerResult("RingTuning"), "OpticalLinkBackendTx", 1.0); + getNddPowerResult("RingTuning")->addSubResult(rx_backend->getNddPowerResult("RingTuning"), "OpticalLinkBackendRx", 1.0); + + // Add event results + getEventInfo("Send")->setTransitionInfo("LinkCK", TransitionInfo(0.0, (double) link_data_rate / (core_data_rate * 2.0), 0.0)); + + getEventResult("Send")->addSubResult(tx_backend->getEventResult("ProcessBits"), "OpticalLinkBackendTx", 1.0); + getEventResult("Send")->addSubResult(rx_backend->getEventResult("ProcessBits"), "OpticalLinkBackendRx", 1.0); + + buildLaser(); + buildModulator(); + buildDetector(); + + return; + } + + void SWSRLink::updateModel() + { + // Get parameters + double link_data_rate = getParameter("LinkDataRate"); + + // Get properties + double length = getProperty("Length"); + const String& extinction_ratio = getProperty("ExtinctionRatio"); + const String& insertion_loss = getProperty("InsertionLoss"); + const double opt_util = getProperty("OptUtil"); + + // Calculate loss for waveguide + double waveguide_loss = getTechModel()->get("Waveguide->LossPerMeter").toDouble() * length; + // Set loss of the waveguide + getWaveguide("ModToDetector")->setLoss(waveguide_loss); + // Calculate waveguide area + double waveguide_area = length * getTechModel()->get("Waveguide->Pitch").toDouble(); + getAreaResult("Waveguide")->setValue(waveguide_area); + + // Update the laser + Model* laser = getSubInstance("Laser"); + laser->setProperty("LaserEventTime", 1.0 / link_data_rate); + laser->setProperty("OptUtil", opt_util); + laser->update(); + + // Update the modulator + Model* modulator = getSubInstance("Modulator"); + modulator->setProperty("ExtinctionRatio", extinction_ratio); + modulator->setProperty("InsertionLoss", insertion_loss); + modulator->update(); + + Model* detector = getSubInstance("Detector"); + detector->update(); + + Model* tx_backend = getSubInstance("OpticalLinkBackendTx"); + tx_backend->update(); + + Model* rx_backend = getSubInstance("OpticalLinkBackendRx"); + rx_backend->update(); + + return; + } + + void SWSRLink::propagateTransitionInfo() + { + // Get parameters + const String& laser_type = getParameter("LaserType"); + + // Propagate transition info to tx backend + OpticalModel* tx_backend = (OpticalModel*) getSubInstance("OpticalLinkBackendTx"); + propagatePortTransitionInfo(tx_backend, "In", "In"); + propagatePortTransitionInfo(tx_backend, "LinkCK", "LinkCK"); + tx_backend->use(); + + // Set transition info for the modulator + OpticalModel* modulator = (OpticalModel*) getSubInstance("Modulator"); + propagatePortTransitionInfo(modulator, "In", tx_backend, "Out"); + modulator->use(); + + // Modulator out transition info + const TransitionInfo& mod_out_transitions = modulator->getOpticalOutputPort("Out")->getTransitionInfo(); + + // Set transition info for the receiver + OpticalModel* detector = (OpticalModel*) getSubInstance("Detector"); + detector->getOpticalInputPort("In")->setTransitionInfo(mod_out_transitions); + detector->use(); + + // Propagate transition info to tx backend + OpticalModel* rx_backend = (OpticalModel*) getSubInstance("OpticalLinkBackendRx"); + propagatePortTransitionInfo(rx_backend, "In", detector, "Out"); + propagatePortTransitionInfo(rx_backend, "LinkCK", "LinkCK"); + rx_backend->use(); + + // Propagate output transition info to output + propagatePortTransitionInfo("Out", rx_backend, "Out"); + + // Set enable signals for the laser, if applicable + if (laser_type == "Throttled") + { + // Figure out how many cycles the laser needs to be on + double cycles = getInputPort("In")->getTransitionInfo().getFrequencyMultiplier(); + + OpticalModel* laser = (OpticalModel*) getSubInstance("Laser"); + laser->getInputPort("LaserEnable")->setTransitionInfo(TransitionInfo(0.0, 1.0, cycles - 1.0)); + laser->use(); + } + + + return; + } + + void SWSRLink::buildLaser() + { + // Get parameters + unsigned int number_wavelengths = getGenProperties()->get("NumberWavelengths"); + const String& laser_type = getParameter("LaserType"); + + // Create laser + OpticalModel* laser = NULL; + if (laser_type == "Throttled") laser = new ThrottledLaserSource("Laser", getTechModel()); + else if (laser_type == "Standard") laser = new LaserSource("Laser", getTechModel()); + else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown laser type '" + laser_type + "'!"); + + laser->setParameter("OutStart", 0); + laser->setParameter("OutEnd", number_wavelengths-1); + laser->setParameter("MaxDetectors", 1); + laser->setParameter("MinDetectors", 1); + laser->construct(); + + addSubInstances(laser, 1.0); + getAreaResult("Photonic")->addSubResult(laser->getAreaResult("Photonic"), "Laser", 1.0); + // Connect laser output port + opticalPortConnect(laser, "Out", "LaserToMod"); + + // Without laser gating, laser is pure NDD power + if (laser_type == "Standard") getNddPowerResult("Laser")->addSubResult(laser->getNddPowerResult("Laser"), "Laser", 1.0); + // With laser power gating, laser is an event + else getEventResult("Send")->addSubResult(laser->getEventResult("Laser1"), "Laser", 1.0); + + return; + } + + void SWSRLink::buildModulator() + { + // Get parameters + double link_data_rate = getParameter("LinkDataRate"); + const String& optimize_loss = getParameter("OptimizeLoss"); + unsigned int number_wavelengths = getGenProperties()->get("NumberWavelengths"); + + // Create modulator + RingModulator* modulator = new RingModulator("Modulator", getTechModel()); + modulator->setParameter("DataRate", link_data_rate); + modulator->setParameter("InStart", 0); + modulator->setParameter("InEnd", number_wavelengths-1); + modulator->setParameter("ModStart", 0); + modulator->setParameter("ModEnd", number_wavelengths-1); + modulator->setParameter("OptimizeLoss", optimize_loss); + modulator->construct(); + addSubInstances(modulator, 1.0); + getAreaResult("Photonic")->addSubResult(modulator->getAreaResult("Photonic"), "Modulator", 1.0); + addElectricalSubResults(modulator, 1.0); + + // Connect electrical port + portConnect(modulator, "In", "TxBackendToTx"); + // Connect modulator input, output port + opticalPortConnect(modulator, "In", "LaserToMod"); + opticalPortConnect(modulator, "Out", "ModToDetector"); + + // Add modulator energy event for send events + getEventResult("Send")->addSubResult(modulator->getEventResult("Modulate"), "Modulator", 1.0); + return; + } + + void SWSRLink::buildDetector() + { + // Get parameters + double link_data_rate = getParameter("LinkDataRate"); + unsigned int number_wavelengths = getGenProperties()->get("NumberWavelengths"); + + // Create resonant ring detector + RingDetector* detector = new RingDetector("Detector", getTechModel()); + detector->setParameter("DataRate", link_data_rate); + detector->setParameter("InStart", 0); + detector->setParameter("InEnd", number_wavelengths-1); + detector->setParameter("DetStart", 0); + detector->setParameter("DetEnd", number_wavelengths-1); + detector->setParameter("DropAll", "TRUE"); + detector->setParameter("Topology", RingDetector::INTEGRATINGSENSEAMP); + detector->construct(); + addSubInstances(detector, 1.0); + getAreaResult("Photonic")->addSubResult(detector->getAreaResult("Photonic"), "Detector", 1.0); + addElectricalSubResults(detector, 1.0); + + // connect to electrical port + portConnect(detector, "Out", "RxToRxBackend"); + // connect optical input, output port + opticalPortConnect(detector, "In", "ModToDetector"); + + // Add receiver energy + getEventResult("Send")->addSubResult(detector->getEventResult("Receive"), "Detector", 1.0); + + return; + } + +} // namespace DSENT + diff --git a/ext/dsent/model/optical/SWSRLink.h b/ext/dsent/model/optical/SWSRLink.h new file mode 100644 index 000000000..fd6ecca73 --- /dev/null +++ b/ext/dsent/model/optical/SWSRLink.h @@ -0,0 +1,38 @@ +#ifndef __DSENT_MODEL_OPTICAL_SWSRLINK_H__ +#define __DSENT_MODEL_OPTICAL_SWSRLINK_H__ + +#include "util/CommonType.h" +#include "model/OpticalModel.h" + +namespace DSENT +{ + class SWSRLink : public OpticalModel + { + // A SWSR Link consists of a laser, a modulator (the writer) and a variable + // number of readers + public: + SWSRLink(const String& instance_name_, const TechModel* tech_model_); + virtual ~SWSRLink(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void propagateTransitionInfo(); + + private: + void buildLaser(); + void buildModulator(); + void buildDetector(); + + }; // class SWSRLink +} // namespace DSENT + +#endif // __DSENT_MODEL_OPTICAL_SWSRLINK_H__ + diff --git a/ext/dsent/model/optical/ThrottledLaserSource.cc b/ext/dsent/model/optical/ThrottledLaserSource.cc new file mode 100644 index 000000000..e95188b77 --- /dev/null +++ b/ext/dsent/model/optical/ThrottledLaserSource.cc @@ -0,0 +1,137 @@ +#include "model/optical/ThrottledLaserSource.h" + +#include "model/PortInfo.h" +#include "model/TransitionInfo.h" +#include "model/EventInfo.h" +#include "model/optical_graph/OpticalWaveguide.h" +#include "model/optical_graph/OpticalWavelength.h" +#include "model/optical_graph/OpticalLaser.h" +#include "model/optical_graph/OpticalGraph.h" + +namespace DSENT +{ + ThrottledLaserSource::ThrottledLaserSource(const String& instance_name_, const TechModel* tech_model_) + : OpticalModel(instance_name_, tech_model_), m_wavelength_(NULL) + { + initParameters(); + initProperties(); + } + + ThrottledLaserSource::~ThrottledLaserSource() + { + if (m_wavelength_ != NULL) delete m_wavelength_; + } + + void ThrottledLaserSource::initParameters() + { + addParameterName("OutStart"); + addParameterName("OutEnd"); + addParameterName("MaxDetectors"); + addParameterName("MinDetectors"); + return; + } + + void ThrottledLaserSource::initProperties() + { + addPropertyName("OptUtil", 1.0); + addPropertyName("LaserEventTime"); + return; + } + + void ThrottledLaserSource::constructModel() + { + // Get parameters + WavelengthGroup laser_wavelengths = makeWavelengthGroup(getParameter("OutStart"), getParameter("OutEnd")); + unsigned int max_detectors = getParameter("MaxDetectors").toUInt(); + unsigned int min_detectors = getParameter("MinDetectors").toUInt(); + + // Create electrical input port for laser control + createInputPort( "LaserEnable"); + + // Create Area result + addAreaResult(new AtomicResult("Photonic")); + // Create event result for each detector number possibility + for (unsigned int i = min_detectors; i <= max_detectors; ++i) + { + createElectricalEventAtomicResult("Laser" + (String) i); + getEventInfo("Laser" + (String) i)->setTransitionInfo("LaserEnable", TransitionInfo(0.0, 1.0, 0.0)); + } + + // Create optical ports + createOpticalOutputPort( "Out", laser_wavelengths); + // Create the filter + createLaser( "Laser", laser_wavelengths); + OpticalLaser* laser = getLaser("Laser"); + // Connect the laser to the output + laser->addDownstreamNode(getWaveguide("Out")); + } + + void ThrottledLaserSource::updateModel() + { + // Get properties + double laser_efficiency = getTechModel()->get("Laser->CW->Efficiency").toDouble(); + double laser_area = getTechModel()->get("Laser->CW->Area").toDouble(); + double laser_diode_loss = getTechModel()->get("Laser->CW->LaserDiodeLoss"); + + // Get parameters + WavelengthGroup laser_wavelengths = makeWavelengthGroup(getParameter("OutStart"), getParameter("OutEnd")); + unsigned int number_wavelengths = laser_wavelengths.second - laser_wavelengths.first + 1; + // Update losses + OpticalLaser* laser = getLaser("Laser"); + laser->setLoss(laser_diode_loss); + laser->setEfficiency(laser_efficiency); + // Update area + getAreaResult("Photonic")->setValue(laser_area * number_wavelengths); + } + + void ThrottledLaserSource::evaluateModel() + { + // Get parameters + unsigned int max_detectors = getParameter("MaxDetectors"); + WavelengthGroup laser_wavelengths = makeWavelengthGroup(getParameter("OutStart"), getParameter("OutEnd")); + + // Get properties + double opt_util = getProperty("OptUtil"); + + // Create optical graph object + OpticalGraph* optical_graph = new OpticalGraph("LaserTrace", this); + // Ask optical graph object to perform power optimization + bool success = optical_graph->performPowerOpt(getLaser("Laser"), laser_wavelengths, max_detectors, opt_util); + if (!success) + { + Log::printLine(std::cerr, "[Warning] " + getInstanceName() + + " -> Wavelengths contains data paths with no possible modulator configurations!"); + } + + // Trace the wavelengths the laser is outputting to find the output + // power needed by the laser + if (m_wavelength_ != NULL) delete m_wavelength_; + m_wavelength_ = optical_graph->traceWavelength(laser_wavelengths, getLaser("Laser")); + + delete optical_graph; + } + + void ThrottledLaserSource::useModel() + { + // Get parameters + unsigned int max_detectors = getParameter("MaxDetectors"); + unsigned int min_detectors = getParameter("MinDetectors"); + + // Get properties + double laser_event_time = getProperty("LaserEventTime"); + // Get laser enable information + const TransitionInfo& enable_info = getInputPort("LaserEnable")->getTransitionInfo(); + + for (unsigned int i = min_detectors; i <= max_detectors; ++i) + { + // Calculate the power needed by the wavelength + double laser_power = m_wavelength_->getLaserPower(i); + // Calculate the laser event power by calculating the amount + // of time the laser is on + getEventResult("Laser" + (String) i)->setValue(laser_power * laser_event_time * + enable_info.getFrequencyMultiplier() * enable_info.getProbability1()); + } + } + +} // namespace DSENT + diff --git a/ext/dsent/model/optical/ThrottledLaserSource.h b/ext/dsent/model/optical/ThrottledLaserSource.h new file mode 100644 index 000000000..117465419 --- /dev/null +++ b/ext/dsent/model/optical/ThrottledLaserSource.h @@ -0,0 +1,40 @@ +#ifndef __DSENT_MODEL_OPTICAL_THROTTLEDLASERSOURCE_H__ +#define __DSENT_MODEL_OPTICAL_THROTTLEDLASERSOURCE_H__ + +#include "util/CommonType.h" +#include "model/OpticalModel.h" + +namespace DSENT +{ + class OpticalWavelength; + + // A laser source that outputs some number of wavelengths. This laser + // full on/off power gating, thus all power are event-based energies + class ThrottledLaserSource : public OpticalModel + { + public: + ThrottledLaserSource(const String& instance_name_, const TechModel* tech_model_); + virtual ~ThrottledLaserSource(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + + protected: + // Build the model + void constructModel(); + void updateModel(); + void evaluateModel(); + void useModel(); + + private: + // Data structure containing the wavelengths that this laser outputs + OpticalWavelength* m_wavelength_; + + }; // class ThrottledLaserSource +} // namespace DSENT + +#endif // __DSENT_MODEL_OPTICAL_THROTTLEDLASERSOURCE_H__ + |