summaryrefslogtreecommitdiff
path: root/ext/dsent/model/optical/RingDetector.cc
diff options
context:
space:
mode:
Diffstat (limited to 'ext/dsent/model/optical/RingDetector.cc')
-rw-r--r--ext/dsent/model/optical/RingDetector.cc338
1 files changed, 338 insertions, 0 deletions
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
+