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