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