summaryrefslogtreecommitdiff
path: root/ext/dsent/model/optical
diff options
context:
space:
mode:
Diffstat (limited to 'ext/dsent/model/optical')
-rw-r--r--ext/dsent/model/optical/GatedLaserSource.cc106
-rw-r--r--ext/dsent/model/optical/GatedLaserSource.h33
-rw-r--r--ext/dsent/model/optical/LaserSource.cc105
-rw-r--r--ext/dsent/model/optical/LaserSource.h33
-rw-r--r--ext/dsent/model/optical/OpticalLinkBackendRx.cc364
-rw-r--r--ext/dsent/model/optical/OpticalLinkBackendRx.h39
-rw-r--r--ext/dsent/model/optical/OpticalLinkBackendTx.cc355
-rw-r--r--ext/dsent/model/optical/OpticalLinkBackendTx.h39
-rw-r--r--ext/dsent/model/optical/OpticalTestModel.cc121
-rw-r--r--ext/dsent/model/optical/OpticalTestModel.h30
-rw-r--r--ext/dsent/model/optical/RingDetector.cc338
-rw-r--r--ext/dsent/model/optical/RingDetector.h54
-rw-r--r--ext/dsent/model/optical/RingFilter.cc77
-rw-r--r--ext/dsent/model/optical/RingFilter.h30
-rw-r--r--ext/dsent/model/optical/RingModulator.cc403
-rw-r--r--ext/dsent/model/optical/RingModulator.h54
-rw-r--r--ext/dsent/model/optical/SWMRLink.cc309
-rw-r--r--ext/dsent/model/optical/SWMRLink.h38
-rw-r--r--ext/dsent/model/optical/SWSRLink.cc328
-rw-r--r--ext/dsent/model/optical/SWSRLink.h38
-rw-r--r--ext/dsent/model/optical/ThrottledLaserSource.cc137
-rw-r--r--ext/dsent/model/optical/ThrottledLaserSource.h40
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__
+