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