sim, kvm: make KvmVM a System parameter
[gem5.git] / ext / dsent / model / optical / RingDetector.cc
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
38 namespace 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