1/* Copyright (c) 2012 Massachusetts Institute of Technology 2 * 3 * Permission is hereby granted, free of charge, to any person obtaining a copy 4 * of this software and associated documentation files (the "Software"), to deal 5 * in the Software without restriction, including without limitation the rights 6 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 * copies of the Software, and to permit persons to whom the Software is 8 * furnished to do so, subject to the following conditions: 9 * 10 * The above copyright notice and this permission notice shall be included in 11 * all copies or substantial portions of the Software. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 * THE SOFTWARE. 20 */ 21 22#include "model/optical/RingDetector.h" 23 24#include <cmath> 25 26#include "util/Constants.h" 27#include "model/PortInfo.h" 28#include "model/TransitionInfo.h" 29#include "model/EventInfo.h" 30#include "model/std_cells/StdCell.h" 31#include "model/std_cells/StdCellLib.h" 32#include "model/optical_graph/OpticalWaveguide.h" 33#include "model/optical_graph/OpticalDetector.h" 34#include "model/optical_graph/OpticalFilter.h" 35#include "model/timing_graph/ElectricalDriver.h" 36#include "model/timing_graph/ElectricalNet.h" 37 38namespace DSENT 39{ 40 // TODOs for this model 41 // Add the other receiver topologies from [Georgas, CICC 2011] 42 // Split integ_time_ratio = SA integ time ratio 43 // Right now perfect clock gating is assumed...may not be what we want 44 45 // Constants 46 const String RingDetector::INTEGRATINGSENSEAMP = "INTSA"; 47 48 RingDetector::RingDetector(const String& instance_name_, const TechModel* tech_model_) 49 : OpticalModel(instance_name_, tech_model_), OpticalReceiver() 50 { 51 initParameters(); 52 initProperties(); 53 } 54 55 RingDetector::~RingDetector() 56 {} 57 58 void RingDetector::initParameters() 59 { 60 addParameterName("DataRate"); 61 addParameterName("InStart"); 62 addParameterName("InEnd"); 63 addParameterName("DetStart"); 64 addParameterName("DetEnd"); 65 addParameterName("DropAll"); 66 addParameterName("Topology"); 67 return; 68 } 69 70 void RingDetector::initProperties() 71 { 72 return; 73 } 74 75 void RingDetector::constructModel() 76 { 77 // Get parameters 78 WavelengthGroup in_wavelengths = makeWavelengthGroup(getParameter("InStart"), getParameter("InEnd")); 79 WavelengthGroup det_wavelengths = makeWavelengthGroup(getParameter("DetStart"), getParameter("DetEnd")); 80 int number_wavelengths = det_wavelengths.second - det_wavelengths.first + 1; 81 bool drop_all = getParameter("DropAll"); 82 const String& topology = getParameter("Topology"); 83 84 // Set some generated properties 85 getGenProperties()->set("NumberWavelengths", number_wavelengths); 86 87 // Create device area result 88 addAreaResult(new AtomicResult("Photonic")); 89 // Create electrical results 90 createElectricalAtomicResults(); 91 if (topology == INTEGRATINGSENSEAMP) addEventResult(new AtomicResult("Receive")); 92 else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology + ")!"); 93 94 // Create optical ports 95 createOpticalInputPort( "In", in_wavelengths); 96 createOpticalOutputPort( "Out", in_wavelengths); 97 // Create the filter and modulator 98 createFilter( "RingFilter", in_wavelengths, drop_all, det_wavelengths); 99 createDetector( "RingDetector", det_wavelengths, this); 100 OpticalFilter* ring_filter = getFilter("RingFilter"); 101 OpticalDetector* ring_detector = getDetector("RingDetector"); 102 // Connect the filter and modulator 103 getWaveguide("In")->addDownstreamNode(ring_filter); 104 ring_filter->addDownstreamNode(getWaveguide("Out")); 105 ring_filter->setDropPort(ring_detector); 106 107 // Create electrical ports 108 createOutputPort("Out", makeNetIndex(0, number_wavelengths-1)); 109 // Create net 110 createNet("OutVFO"); 111 // Create output driver 112 createDriver("OutDriver", false); 113 // Connect driver 114 getDriver("OutDriver")->addDownstreamNode(getNet("OutVFO")); 115 // Connect output 116 assignVirtualFanout("Out", "OutVFO"); 117 118 // Precompute some technology values 119 precomputeTech(); 120 121 return; 122 } 123 124 void RingDetector::updateModel() 125 { 126 // Get some generated properties 127 unsigned int number_wavelengths = getGenProperties()->get("NumberWavelengths"); 128 129 // Get tech model numbers 130 double ring_area = getTechModel()->get("Ring->Area"); 131 double thru_loss = getTechModel()->get("Ring->ThroughLoss"); 132 double drop_loss = getTechModel()->get("Ring->DropLoss"); 133 double pd_loss = getTechModel()->get("Photodetector->Loss"); 134 double pd_responsivity = getTechModel()->get("Photodetector->Responsivity"); 135 136 // Design the receiver 137 designReceiver(); 138 139 // Update losses 140 // Connect the filter and modulator 141 OpticalFilter* ring_filter = getFilter("RingFilter"); 142 OpticalDetector* ring_detector = getDetector("RingDetector"); 143 ring_filter->setLoss(thru_loss * number_wavelengths); 144 ring_filter->setDropLoss(drop_loss + thru_loss * number_wavelengths); 145 ring_detector->setLoss(pd_loss); 146 ring_detector->setResponsivity(pd_responsivity); 147 // Update device area 148 getAreaResult("Photonic")->setValue(ring_area * (number_wavelengths)); 149 150 return; 151 } 152 153 void RingDetector::useModel() 154 { 155 // Get parameters 156 const String& topology = getParameter("Topology"); 157 158 // Get some generated properties 159 unsigned int number_wavelengths = getGenProperties()->get("NumberWavelengths"); 160 161 // Get optical input transition info 162 const TransitionInfo& in_trans = getOpticalInputPort("In")->getTransitionInfo(); 163 164 // Get tech models 165 double vdd = getTechModel()->get("Vdd"); 166 // Get caps 167 double unit_gate_cap = getTechModel()->get("Gate->MinWidth").toDouble() * getTechModel()->get("Gate->CapPerWidth").toDouble(); 168 double unit_drain_cap = getTechModel()->get("Gate->MinWidth").toDouble() * getTechModel()->get("Drain->CapPerWidth").toDouble(); 169 double inv_x1_gate_cap = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->A"); 170 double inv_x1_drain_cap = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->Y"); 171 172 // Construct a simple sense-amp model 173 if(topology == INTEGRATINGSENSEAMP) 174 { 175 // Use ratios from the receiver published in [Georgas, ESSCIRC 2011] 176 // Note: 177 // The numbers in the paper (43fJ/b, 50 fJ/b in the cited work) is done with the clock buffer (there are 4 receivers), 178 // capacitive DAC, and extra output flops used in the physical layout, as the compared receiver is extremely conservative 179 // We simplified this model to not have the capacitive DAC, the clock buffer (since this is an individual receiver), or 180 // the extra output flops (since receiver structure is already a posedge flop functionally). 181 // Look for an upcoming paper [Georgas, JSSC 2012] (when it is published) for the power breakdown pie-chart for the receiver. 182 // This model only models the latch (sampler) and the dynamic to static (RS latch) part of the design, which is all you really 183 // need in the receiver. 184 185 // Gate caps 186 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; 187 double c_gate_rslatch = unit_gate_cap * (4 * 1.0) + inv_x1_gate_cap; 188 // Drain caps 189 double c_drain_sampler = unit_drain_cap * (2 * 2.0 + 2 * 1.0 + 3 * 5.0 + 1 * 3.0) + inv_x1_drain_cap; 190 double c_drain_rslatch = unit_drain_cap * (2 * 6.0) + inv_x1_drain_cap; 191 // Sum up cap switched for the sampler 192 double c_sampler = c_gate_sampler + c_drain_sampler; 193 double c_rslatch = c_gate_rslatch + c_drain_rslatch; 194 // Average cap switched 195 // Sampler is differential, one side will always switch (R or S in the latch) regardless of probability 196 double avg_cap = c_sampler + c_rslatch * in_trans.getProbability0() * in_trans.getProbability1(); 197 198 // Get parameters corresponding to a unit-inverter 199 double unit_leak_0 = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Leakage->!A"); 200 double unit_leak_1 = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Leakage->A"); 201 202 // Approximate leakage (curve fit with design) 203 double total_leakage = 0.5 * (unit_leak_0 + unit_leak_1) * 7.43; 204 205 // Create results 206 getEventResult("Receive")->setValue(vdd * vdd * avg_cap * number_wavelengths); 207 getNddPowerResult("Leakage")->setValue(total_leakage * number_wavelengths); 208 209 } 210 else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology + ")!"); 211 212 return; 213 } 214 215 void RingDetector::propagateTransitionInfo() 216 { 217 // Propagate probabilities from optical input to electrical output port 218 getOutputPort("Out")->setTransitionInfo(getOpticalInputPort("In")->getTransitionInfo()); 219 220 return; 221 } 222 223 void RingDetector::precomputeTech() 224 { 225 // Get parameters 226 const double data_rate = getParameter("DataRate"); 227 const String& topology = getParameter("Topology"); 228 229 // Get tech model numbers 230 double pd_cap = getTechModel()->get("Photodetector->Cap"); 231 double parasitic_cap = getTechModel()->get("Photodetector->ParasiticCap"); 232 double apd = getTechModel()->get("Photodetector->AvalancheGain"); 233 double vdd = getTechModel()->get("Vdd"); 234 235 // Constants shortcuts 236 double pi = Constants::pi; 237 double k = Constants::k; 238 double q = Constants::q; 239 double T = getTechModel()->get("Temperature"); 240 241 if(topology == INTEGRATINGSENSEAMP) 242 { 243 // Get more tech parameters 244 double integ_time_ratio = getTechModel()->get("Receiver->Int->IntegrationTimeRatio"); 245 double BER = getTechModel()->get("SenseAmp->BER"); 246 double CMRR = getTechModel()->get("SenseAmp->CMRR"); 247 double offset_comp_bits = getTechModel()->get("SenseAmp->OffsetCompensationBits"); 248 double offset = getTechModel()->get("SenseAmp->OffsetRatio").toDouble() * vdd; 249 double supply_noise_rand = getTechModel()->get("SenseAmp->SupplyNoiseRandRatio").toDouble() * vdd; 250 double supply_noise_det = getTechModel()->get("SenseAmp->SupplyNoiseDetRatio").toDouble() * vdd; 251 double noise_margin = getTechModel()->get("SenseAmp->NoiseMargin"); 252 double jitter_ratio = getTechModel()->get("SenseAmp->JitterRatio"); 253 254 // Approximate tao using FO4 255 double unit_drain_cap = getTechModel()->get("Gate->MinWidth").toDouble() * getTechModel()->get("Drain->CapPerWidth").toDouble(); 256 double c_g = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->A"); 257 double c_d = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->Y"); 258 double r_o = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->DriveRes->Y"); 259 // Calculate sense amp tau from sense amp output loading 260 double tau = r_o * (c_g + c_d); 261 // Set output inverter drive strength 262 getDriver("OutDriver")->setOutputRes(r_o); 263 264 // Calculate sense amp input cap based on schematic 265 double sense_amp_cap_in = unit_drain_cap * (2.0 + 3.0 + 5.0 + 1.0); 266 267 // Residual offset 268 double v_residual = 3 * offset / pow(2, offset_comp_bits); 269 // Noise 270 double v_noise = supply_noise_rand * supply_noise_rand / (CMRR * CMRR); 271 // Sense amp voltage build-up minimum 272 double v_sense = vdd * exp(-(1 - integ_time_ratio) / (data_rate * tau)) + noise_margin + v_residual + supply_noise_det / CMRR; 273 // Sigmas corresponding to BER 274 double sigma = calcInvNormCdf(BER); 275 276 //K_int is the time the bit is valid for evaluation 277 278 // Total input cap load 279 double input_node_cap = sense_amp_cap_in + pd_cap + parasitic_cap; 280 double z_int = integ_time_ratio / (data_rate * input_node_cap); //should use K_int 281 282 // Store precalculated values 283 m_quad_a_ = 1 - (sigma * sigma * jitter_ratio * jitter_ratio); 284 m_quad_b1_ = - 2 * pi / 2 * sigma * sigma * q * 0.7 * data_rate; 285 m_quad_b2_ = -2 * v_sense / (z_int * apd); 286 m_quad_c_ = 1 / (z_int * z_int) * (v_sense * v_sense - sigma * sigma * (k * T / input_node_cap + v_noise)); 287 } 288 else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology + ")!"); 289 290 return; 291 } 292 293 void RingDetector::designReceiver() 294 { 295 // Get some generated properties 296 unsigned int number_wavelengths = getGenProperties()->get("NumberWavelengths"); 297 298 // Get relevant properties/parameters 299 const String& topology = getParameter("Topology"); 300 301 // Construct a simple sense-amp model 302 if(topology == INTEGRATINGSENSEAMP) 303 { 304 // No really good way to estimate the area...can assume each receiver is the size of 40 inverters, which is 305 // about the right size for just the sense amp in the layout 306 double unit_area_active = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Area->Active"); 307 double unit_area_metal1 = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Area->Metal1Wire"); 308 getAreaResult("Active")->setValue(unit_area_active * 40 * number_wavelengths); 309 getAreaResult("Metal1Wire")->setValue(unit_area_metal1 * 40 * number_wavelengths); 310 } 311 else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology + ")!"); 312 313 return; 314 } 315 316 double RingDetector::getSensitivity(double ER_dB_) const 317 { 318 // Get parameters 319 const String& topology = getParameter("Topology"); 320 // Turn extinction ratio into a ratio from dB scale 321 double ER = pow(10, ER_dB_ / 10); 322 323 // Initialize sensitivity 324 double sensitivity = 1e99; 325 // Construct a simple sense-amp model 326 if(topology == INTEGRATINGSENSEAMP) 327 { 328 // Scale photodetector shot noise using ER, add rest of noise source 329 double b = m_quad_b1_ * (1 + ER) / (2 * (ER - 1)) + m_quad_b2_; 330 331 // Find sensitivity (-b + sqrt(b^2-4ac)) / 2a 332 sensitivity = ((-b + sqrt(b * b - 4 * m_quad_a_ * m_quad_c_)) / (2 * m_quad_a_)); 333 } 334 else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology + ")!"); 335 336 return sensitivity; 337 } 338 339 double RingDetector::calcInvNormCdf(double num_) 340 { 341 // 53 bit precision for double FP 342 unsigned int num_iterations = 20; 343 // Upperbound the step 344 double step = 20; 345 double out = step; 346 // Iteratively guess and check calculation 347 for (unsigned int i = 0; i < num_iterations; ++i) 348 { 349 double current = 0.5 * erfc(out / sqrt(2)); 350 if (current > num_) out += step; 351 else out -= step; 352 step = step * 0.5; 353 } 354 355 return out; 356 } 357 358} // namespace DSENT 359 360