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