OpticalLinkBackendRx.cc revision 10447:a465576671d4
1#include "model/optical/OpticalLinkBackendRx.h"
2
3#include "util/Constants.h"
4#include "model/PortInfo.h"
5#include "model/TransitionInfo.h"
6#include "model/EventInfo.h"
7#include "model/electrical/DemuxTreeDeserializer.h"
8#include "model/electrical/BarrelShifter.h"
9#include "model/electrical/Multiplexer.h"
10#include <cmath>
11
12namespace DSENT
13{
14    // TODO: Kind of don't like the way thermal tuning is written here. Maybe will switch
15    // to curve fitting the CICC paper, which uses results from a monte-carlo sim. Also, there is
16    // redundant code between this one and the tx one...
17
18    OpticalLinkBackendRx::OpticalLinkBackendRx(const String& instance_name_, const TechModel* tech_model_)
19        : ElectricalModel(instance_name_, tech_model_)
20    {
21        initParameters();
22        initProperties();
23    }
24
25    OpticalLinkBackendRx::~OpticalLinkBackendRx()
26    {}
27
28    void OpticalLinkBackendRx::initParameters()
29    {
30        addParameterName("OutBits");
31        addParameterName("CoreDataRate");
32        addParameterName("LinkDataRate");
33        addParameterName("RingTuningMethod");
34        addParameterName("BitDuplicate");
35        return;
36    }
37
38    void OpticalLinkBackendRx::initProperties()
39    {
40        return;
41    }
42
43    void OpticalLinkBackendRx::constructModel()
44    {
45        unsigned int out_bits = getParameter("OutBits");
46        double core_data_rate = getParameter("CoreDataRate");
47        double link_data_rate = getParameter("LinkDataRate");
48        const String& tuning_method = getParameter("RingTuningMethod");
49        bool bit_duplicate = getParameter("BitDuplicate");
50
51        // Calculate deserialization ratio
52        unsigned int deserialization_ratio = (unsigned int) floor(link_data_rate / core_data_rate);
53        ASSERT(deserialization_ratio == link_data_rate / core_data_rate,
54            "[Error] " + getInstanceName() + " -> Cannot have non-integer deserialization ratios!");
55        ASSERT((deserialization_ratio & (deserialization_ratio - 1)) == 0,
56            "[Error] " + getInstanceName() + " -> Deserialization ratio must be a power of 2");
57
58        // Calculate output width
59        unsigned int in_bits = out_bits / deserialization_ratio;
60        ASSERT(out_bits >= deserialization_ratio, "[Error] " + getInstanceName() +
61            " -> Output width must be >= deserialization ratio!");
62        ASSERT(floor((double) out_bits / deserialization_ratio) == in_bits,
63            "[Error] " + getInstanceName() + " -> Output width must be a multiple of the serialization ratio!");
64
65        getGenProperties()->set("DeserializationRatio", deserialization_ratio);
66        getGenProperties()->set("InBits", in_bits);
67
68        // Create ports
69        createInputPort("In", makeNetIndex(0, in_bits-1));
70        createInputPort("LinkCK");
71        createOutputPort("Out", makeNetIndex(0, out_bits-1));
72
73        //Create energy, power, and area results
74        createElectricalResults();
75        // Create ring heating power cost
76        addNddPowerResult(new AtomicResult("RingTuning"));
77        // Create process bits event
78        createElectricalEventResult("ProcessBits");
79        getEventInfo("ProcessBits")->setTransitionInfo("LinkCK", TransitionInfo(0.0, (double) deserialization_ratio / 2.0, 0.0));
80        // Set conditions during idle state
81        getEventInfo("Idle")->setStaticTransitionInfos();
82        getEventInfo("Idle")->setTransitionInfo("LinkCK", TransitionInfo(0.0, (double) deserialization_ratio / 2.0, 0.0));
83
84        // Create deserializer
85        const String& deserializer_name = "Deserializer";
86        DemuxTreeDeserializer* deserializer = new DemuxTreeDeserializer(deserializer_name, getTechModel());
87        deserializer->setParameter("OutBits", out_bits);
88        deserializer->setParameter("InDataRate", link_data_rate);
89        deserializer->setParameter("OutDataRate", core_data_rate);
90        deserializer->setParameter("BitDuplicate", bit_duplicate);
91        deserializer->construct();
92
93        addSubInstances(deserializer, 1.0);
94        addElectricalSubResults(deserializer, 1.0);
95        getEventResult("ProcessBits")->addSubResult(deserializer->getEventResult("Deserialize"), deserializer_name, 1.0);
96
97        if ((tuning_method == "ThermalWithBitReshuffle") || (tuning_method == "ElectricalAssistWithBitReshuffle"))
98        {
99            // If a bit reshuffling backend is present, create the reshuffling backend
100            unsigned int reorder_degree = getBitReorderDegree();
101
102            // Create intermediate nets
103            createNet("ReorderIn", makeNetIndex(0, in_bits+reorder_degree-1));
104            assign("ReorderIn", makeNetIndex(0, in_bits-1), "In");
105            assign("ReorderIn", makeNetIndex(in_bits, in_bits+reorder_degree-1), "ReorderIn", makeNetIndex(0, reorder_degree-1));
106            createNet("DeserializerIn", makeNetIndex(0, in_bits-1));
107            createNet("BarrelShiftIn", makeNetIndex(0, out_bits-1));
108
109            // Create bit reorder muxes
110            const String& reorder_mux_name = "ReorderMux";
111            Multiplexer* reorder_mux = new Multiplexer(reorder_mux_name, getTechModel());
112            reorder_mux->setParameter("NumberBits", in_bits);
113            reorder_mux->setParameter("NumberInputs", reorder_degree);
114            reorder_mux->setParameter("BitDuplicate", bit_duplicate);
115            reorder_mux->construct();
116
117            // Create barrelshifter
118            unsigned int shift_index_min = (unsigned int)ceil(log2(deserialization_ratio));
119            unsigned int shift_index_max = std::max(shift_index_min, (unsigned int) ceil(log2(out_bits)) - 1);
120
121            // Remember some things
122            getGenProperties()->set("ReorderDegree", reorder_degree);
123            getGenProperties()->set("ShiftIndexMin", shift_index_min);
124            getGenProperties()->set("ShiftIndexMax", shift_index_max);
125
126            const String& barrel_shift_name = "BarrelShifter";
127            BarrelShifter* barrel_shift = new BarrelShifter(barrel_shift_name, getTechModel());
128            barrel_shift->setParameter("NumberBits", out_bits);
129            barrel_shift->setParameter("ShiftIndexMax", shift_index_max);
130            barrel_shift->setParameter("ShiftIndexMin", shift_index_min);
131            barrel_shift->setParameter("BitDuplicate", bit_duplicate);
132            barrel_shift->construct();
133
134            // Connect serializer
135            portConnect(deserializer, "In", "DeserializerIn");
136            portConnect(deserializer, "Out", "BarrelShiftIn");
137            portConnect(deserializer, "InCK", "LinkCK");
138
139            // Connect barrelshifter
140            // TODO: Connect barrelshift shifts!
141            portConnect(barrel_shift, "In", "BarrelShiftIn");
142            portConnect(barrel_shift, "Out", "Out");
143
144            // Connect bit reorder muxes
145            // TODO: Connect re-order multiplex select signals!
146            for (unsigned int i = 0; i < reorder_degree; i++)
147                portConnect(reorder_mux, "In" + (String) i, "ReorderIn", makeNetIndex(i, i+in_bits-1));
148            portConnect(reorder_mux, "Out", "DeserializerIn");
149
150            addSubInstances(barrel_shift, 1.0);
151            addSubInstances(reorder_mux, 1.0);
152            addElectricalSubResults(barrel_shift, 1.0);
153            addElectricalSubResults(reorder_mux, 1.0);
154            getEventResult("ProcessBits")->addSubResult(barrel_shift->getEventResult("BarrelShift"), barrel_shift_name, 1.0);
155            getEventResult("ProcessBits")->addSubResult(reorder_mux->getEventResult("Mux"), reorder_mux_name, 1.0);
156        }
157        else if ((tuning_method == "FullThermal") || (tuning_method == "AthermalWithTrim"))
158        {
159            // If no bit reshuffling backend is present, then just connect deserializer up
160            portConnect(deserializer, "In", "In");
161            portConnect(deserializer, "Out", "Out");
162            portConnect(deserializer, "InCK", "LinkCK");
163        }
164        else
165        {
166            ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown ring tuning method '" + tuning_method + "'!");
167        }
168
169        return;
170    }
171
172    void OpticalLinkBackendRx::updateModel()
173    {
174        // Update everyone
175        Model::updateModel();
176        // Update ring tuning power
177        getNddPowerResult("RingTuning")->setValue(getRingTuningPower());
178        return;
179    }
180
181    void OpticalLinkBackendRx::propagateTransitionInfo()
182    {
183        // Get parameters
184        const String& tuning_method = getParameter("RingTuningMethod");;
185
186        // Get properties
187
188        // Update the deserializer
189        if ((tuning_method == "ThermalWithBitReshuffle") || (tuning_method == "ElectricalAssistWithBitReshuffle"))
190        {
191            // Get generated properties
192            unsigned int reorder_degree = getGenProperties()->get("ReorderDegree");
193            unsigned int shift_index_min = getGenProperties()->get("ShiftIndexMin");
194            unsigned int shift_index_max = getGenProperties()->get("ShiftIndexMax");
195
196            // Reorder mux shift select bits
197            unsigned int reorder_sel_bits = (unsigned int)ceil(log2(reorder_degree));
198
199            // Create bit reorder muxes
200            const String& reorder_mux_name = "ReorderMux";
201            ElectricalModel* reorder_mux = (ElectricalModel*) getSubInstance(reorder_mux_name);
202            for (unsigned int i = 0; i < reorder_degree; ++i)
203                propagatePortTransitionInfo(reorder_mux, "In" + (String) i, "In");
204            // Set select transitions to be 0, since these are statically configured
205            for (unsigned int i = 0; i < reorder_sel_bits; ++i)
206                reorder_mux->getInputPort("Sel" + (String) i)->setTransitionInfo(TransitionInfo(0.5, 0.0, 0.5));
207            reorder_mux->use();
208
209            // Update the deserializer
210            ElectricalModel* deserializer = (ElectricalModel*) getSubInstance("Deserializer");
211            propagatePortTransitionInfo(deserializer, "In", reorder_mux, "Out");
212            propagatePortTransitionInfo(deserializer, "InCK", "LinkCK");
213            deserializer->use();
214
215            // Update barrel shifter
216            const String& barrel_shift_name = "BarrelShifter";
217            ElectricalModel* barrel_shift = (ElectricalModel*) getSubInstance(barrel_shift_name);
218            propagatePortTransitionInfo(barrel_shift, "In", deserializer, "Out");
219            // Set shift transitions to be very low (since it is affected by slow temperature time constants)
220            for (unsigned int i = shift_index_min; i <= shift_index_max; ++i)
221                barrel_shift->getInputPort("Shift" + (String) i)->setTransitionInfo(TransitionInfo(0.499, 0.001, 0.499));
222            barrel_shift->use();
223
224            // Set output transition info
225            propagatePortTransitionInfo("Out", barrel_shift, "Out");
226        }
227        else if ((tuning_method == "FullThermal") || (tuning_method == "AthermalWithTrim"))
228        {
229            // Update the deserializer
230            ElectricalModel* deserializer = (ElectricalModel*) getSubInstance("Deserializer");
231            propagatePortTransitionInfo(deserializer, "In", "In");
232            propagatePortTransitionInfo(deserializer, "InCK", "LinkCK");
233            deserializer->use();
234
235            // Set output transition info
236            propagatePortTransitionInfo("Out", deserializer, "Out");
237        }
238        else
239        {
240            ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown ring tuning method '" + tuning_method + "'!");
241        }
242
243        return;
244    }
245
246    double OpticalLinkBackendRx::getRingTuningPower()
247    {
248        // Get properties
249        const String& tuning_method = getParameter("RingTuningMethod");;
250        unsigned int number_rings = getGenProperties()->get("InBits");
251
252        // Get tech model parameters
253        double R = getTechModel()->get("Ring->Radius");
254        double n_g = getTechModel()->get("Ring->GroupIndex");
255        double heating_efficiency = getTechModel()->get("Ring->HeatingEfficiency");
256        // This can actually be derived if we know thermo-optic coefficient (delta n / delta T)
257        double tuning_efficiency = getTechModel()->get("Ring->TuningEfficiency");
258        double sigma_r_local = getTechModel()->get("Ring->LocalVariationSigma");
259        double sigma_r_systematic = getTechModel()->get("Ring->SystematicVariationSigma");
260        double T_max = getTechModel()->get("Ring->TemperatureMax");
261        double T_min = getTechModel()->get("Ring->TemperatureMin");
262        double T = getTechModel()->get("Temperature");
263
264        // Get constants
265        double c = Constants::c;
266        double pi = Constants::pi;
267
268        double tuning_power = 0.0;
269
270        if (tuning_method == "ThermalWithBitReshuffle")
271        {
272            // When an electrical backend is present, rings only have to tune to the nearest channel
273            // This can be approximated as each ring tuning to something exactly 1 channel away
274
275            // Setup calculations
276            double L = 2 * pi * R;                  // Optical length
277            double FSR = c / (n_g * L);             // Free spectral range
278            double freq_sep = FSR / number_rings;   // Channel separation
279
280            // Calculate tuning power
281            tuning_power = number_rings * freq_sep / (tuning_efficiency * heating_efficiency);
282        }
283        else if (tuning_method == "ElectricalAssistWithBitReshuffle")
284        {
285            // Electrical assistance allows for a fraction of the tuning range to be
286            // covered electrically. This is most pronounced when the tuning range is small,
287            // such is the case when bit reshuffling is applied
288
289            // Get electrically tunable range
290            double max_assist = getTechModel()->get("Ring->MaxElectricallyTunableFreq");
291
292            // Setup calculations
293            double L = 2 * pi * R;                  // Optical length
294            double FSR = c / (n_g * L);             // Free spectral range
295            double freq_sep = FSR / number_rings;   // Channel separation
296            double heating_range = std::max(0.0, freq_sep - max_assist);  // The distance needed to bridge using heaters
297
298            // Calculate tuning power, which is really only the power spent on heating since
299            // distance tuned electrically is pretty much free
300            tuning_power = number_rings * heating_range / (tuning_efficiency * heating_efficiency);
301        }
302        else if (tuning_method == "FullThermal")
303        {
304            // If there is no bit reshuffling backend, each ring must tune to an
305            // absolute channel frequency. Since we can only heat rings (and not cool),
306            // we can only red-shift (decrease frequency). Thus, a fabrication bias
307            // must be applied such that under any process and temperature corner, the
308            // ring resonance remains above channel resonance
309            // I'll use 3 sigmas of sigma_r_local and sigma_r_systematic, and bias against
310            // the full temperature range
311            double fabrication_bias_freq = 3.0 * sqrt(pow(sigma_r_local, 2) + pow(sigma_r_systematic, 2)) +
312                (T_max - T_min) * tuning_efficiency;
313
314            // The local/systematic variations are 0 on average. Thus, the tuning distance can be calculated as
315            double tuning_distance = fabrication_bias_freq - (T - T_min) * tuning_efficiency;
316
317            // Tuning power needed is just the number of rings * tuning distance / (tuning and heating efficiencies)
318            tuning_power = number_rings * tuning_distance / (tuning_efficiency * heating_efficiency);
319        }
320        else if (tuning_method == "AthermalWithTrim")
321        {
322            // Athermal!
323            tuning_power = 0;
324        }
325        else
326        {
327            ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown ring tuning method '" + tuning_method + "'!");
328        }
329
330        return tuning_power;
331    }
332
333    unsigned int OpticalLinkBackendRx::getBitReorderDegree()
334    {
335        // Get properties
336        unsigned int number_rings = getGenProperties()->get("InBits");
337
338        // Get tech model parameters
339        double R = getTechModel()->get("Ring->Radius");
340        double n_g = getTechModel()->get("Ring->GroupIndex");
341        // This can actually be derived if we know thermo-optic coefficient (delta n / delta T)
342        double sigma_r_local = getTechModel()->get("Ring->LocalVariationSigma");
343
344        // Get constants
345        double c = Constants::c;
346        double pi = Constants::pi;
347
348        // Calculates the degree of bit re-order multiplexing needed for bit-reshuffling backend
349        // Bit reshuffling tuning is largely unaffected by sigma_r_systematic. However, sigma_r_local
350        // Can potentially throw each ring to a channel several channels away. This just calculates
351        // the degree of bit reorder muxing needed to realign bits in the correct order
352
353        // Setup calculations
354        double L = 2 * pi * R;                  // Optical length
355        double FSR = c / (n_g * L);             // Free spectral range
356        double freq_sep = FSR / number_rings;   // Channel separation
357        // Using 4 sigmas as the worst re-ordering case (must double to get both sides)
358        unsigned int worst_case_channels = (unsigned int)ceil(2.0 * 4.0 * sigma_r_local / freq_sep);
359
360        return worst_case_channels;
361    }
362
363} // namespace DSENT
364
365