diff options
author | Nilay Vaish <nilay@cs.wisc.edu> | 2014-10-11 15:02:23 -0500 |
---|---|---|
committer | Nilay Vaish <nilay@cs.wisc.edu> | 2014-10-11 15:02:23 -0500 |
commit | e8ed7b1d1b5bef31e9874f679a5797c2e00d06f1 (patch) | |
tree | 421c9c50377aa664958685914f5504c4c019e21f /ext/dsent/model/optical/RingDetector.cc | |
parent | a098fad174d8559037602b248b8e6f7f46bfebbb (diff) | |
download | gem5-e8ed7b1d1b5bef31e9874f679a5797c2e00d06f1.tar.xz |
ext: add the source code for DSENT
This patch adds a tool called DSENT to the ext/ directory. DSENT
is a tool that models power and area for on-chip networks. The next
patch adds a script for using the tool.
Diffstat (limited to 'ext/dsent/model/optical/RingDetector.cc')
-rw-r--r-- | ext/dsent/model/optical/RingDetector.cc | 338 |
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 + |