1 /* Copyright (c) 2012 Massachusetts Institute of Technology
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:
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
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
22 #include "model/optical/RingDetector.h"
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"
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
46 const String
RingDetector::INTEGRATINGSENSEAMP
= "INTSA";
48 RingDetector::RingDetector(const String
& instance_name_
, const TechModel
* tech_model_
)
49 : OpticalModel(instance_name_
, tech_model_
), OpticalReceiver()
55 RingDetector::~RingDetector()
58 void RingDetector::initParameters()
60 addParameterName("DataRate");
61 addParameterName("InStart");
62 addParameterName("InEnd");
63 addParameterName("DetStart");
64 addParameterName("DetEnd");
65 addParameterName("DropAll");
66 addParameterName("Topology");
70 void RingDetector::initProperties()
75 void RingDetector::constructModel()
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");
84 // Set some generated properties
85 getGenProperties()->set("NumberWavelengths", number_wavelengths
);
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
+ ")!");
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
);
107 // Create electrical ports
108 createOutputPort("Out", makeNetIndex(0, number_wavelengths
-1));
111 // Create output driver
112 createDriver("OutDriver", false);
114 getDriver("OutDriver")->addDownstreamNode(getNet("OutVFO"));
116 assignVirtualFanout("Out", "OutVFO");
118 // Precompute some technology values
124 void RingDetector::updateModel()
126 // Get some generated properties
127 unsigned int number_wavelengths
= getGenProperties()->get("NumberWavelengths");
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");
136 // Design the receiver
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
));
153 void RingDetector::useModel()
156 const String
& topology
= getParameter("Topology");
158 // Get some generated properties
159 unsigned int number_wavelengths
= getGenProperties()->get("NumberWavelengths");
161 // Get optical input transition info
162 const TransitionInfo
& in_trans
= getOpticalInputPort("In")->getTransitionInfo();
165 double vdd
= getTechModel()->get("Vdd");
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");
172 // Construct a simple sense-amp model
173 if(topology
== INTEGRATINGSENSEAMP
)
175 // Use ratios from the receiver published in [Georgas, ESSCIRC 2011]
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.
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
;
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();
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");
202 // Approximate leakage (curve fit with design)
203 double total_leakage
= 0.5 * (unit_leak_0
+ unit_leak_1
) * 7.43;
206 getEventResult("Receive")->setValue(vdd
* vdd
* avg_cap
* number_wavelengths
);
207 getNddPowerResult("Leakage")->setValue(total_leakage
* number_wavelengths
);
210 else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology
+ ")!");
215 void RingDetector::propagateTransitionInfo()
217 // Propagate probabilities from optical input to electrical output port
218 getOutputPort("Out")->setTransitionInfo(getOpticalInputPort("In")->getTransitionInfo());
223 void RingDetector::precomputeTech()
226 const double data_rate
= getParameter("DataRate");
227 const String
& topology
= getParameter("Topology");
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");
235 // Constants shortcuts
236 double pi
= Constants::pi
;
237 double k
= Constants::k
;
238 double q
= Constants::q
;
239 double T
= getTechModel()->get("Temperature");
241 if(topology
== INTEGRATINGSENSEAMP
)
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");
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
);
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);
268 double v_residual
= 3 * offset
/ pow(2, offset_comp_bits
);
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
);
276 //K_int is the time the bit is valid for evaluation
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
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
));
288 else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology
+ ")!");
293 void RingDetector::designReceiver()
295 // Get some generated properties
296 unsigned int number_wavelengths
= getGenProperties()->get("NumberWavelengths");
298 // Get relevant properties/parameters
299 const String
& topology
= getParameter("Topology");
301 // Construct a simple sense-amp model
302 if(topology
== INTEGRATINGSENSEAMP
)
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
);
311 else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology
+ ")!");
316 double RingDetector::getSensitivity(double ER_dB_
) const
319 const String
& topology
= getParameter("Topology");
320 // Turn extinction ratio into a ratio from dB scale
321 double ER
= pow(10, ER_dB_
/ 10);
323 // Initialize sensitivity
324 double sensitivity
= 1e99
;
325 // Construct a simple sense-amp model
326 if(topology
== INTEGRATINGSENSEAMP
)
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_
;
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_
));
334 else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology
+ ")!");
339 double RingDetector::calcInvNormCdf(double num_
)
341 // 53 bit precision for double FP
342 unsigned int num_iterations
= 20;
343 // Upperbound the step
346 // Iteratively guess and check calculation
347 for (unsigned int i
= 0; i
< num_iterations
; ++i
)
349 double current
= 0.5 * erfc(out
/ sqrt(2));
350 if (current
> num_
) out
+= step
;