OpticalLinkBackendRx.cc revision 10447
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