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/electrical/RepeatedLink.h" 23 24#include "model/PortInfo.h" 25#include "model/EventInfo.h" 26#include "model/TransitionInfo.h" 27#include "model/std_cells/StdCellLib.h" 28#include "model/std_cells/StdCell.h" 29#include "model/timing_graph/ElectricalTimingTree.h" 30#include "model/timing_graph/ElectricalTimingNode.h" 31#include "model/timing_graph/ElectricalNet.h" 32#include "model/timing_graph/ElectricalDriver.h" 33#include "model/timing_graph/ElectricalDelay.h" 34#include "model/timing_graph/ElectricalLoad.h" 35 36namespace DSENT 37{ 38 RepeatedLink::RepeatedLink(const String& instance_name_, const TechModel* tech_model_) 39 : ElectricalModel(instance_name_, tech_model_) 40 { 41 m_repeater_ = NULL; 42 m_repeater_load_ = NULL; 43 m_timing_tree_ = NULL; 44 45 initParameters(); 46 initProperties(); 47 } 48 49 RepeatedLink::~RepeatedLink() 50 { 51 delete m_repeater_; 52 delete m_repeater_load_; 53 delete m_timing_tree_; 54 } 55 56 void RepeatedLink::initParameters() 57 { 58 addParameterName("NumberBits"); 59 addParameterName("WireLayer"); 60 addParameterName("WireWidthMultiplier", 1.0); 61 addParameterName("WireSpacingMultiplier", 1.0); 62 return; 63 } 64 65 void RepeatedLink::initProperties() 66 { 67 addPropertyName("WireLength"); 68 addPropertyName("Delay"); 69 addPropertyName("IsKeepParity", "TRUE"); 70 return; 71 } 72 73 RepeatedLink* RepeatedLink::clone() const 74 { 75 // TODO 76 return NULL; 77 } 78 79 void RepeatedLink::constructModel() 80 { 81 // Get parameters 82 unsigned int number_bits = getParameter("NumberBits").toUInt(); 83 const String& wire_layer = getParameter("WireLayer"); 84 double wire_width_multiplier = getParameter("WireWidthMultiplier").toDouble(); 85 double wire_spacing_multiplier = getParameter("WireSpacingMultiplier").toDouble(); 86 87 ASSERT(number_bits > 0, "[Error] " + getInstanceName() + 88 " -> Number of bits must be > 0!"); 89 ASSERT(getTechModel()->isWireLayerExist(wire_layer), "[Error] " + getInstanceName() + 90 " -> Wire layer does not exist!"); 91 ASSERT(wire_width_multiplier >= 1.0, "[Error] " + getInstanceName() + 92 " -> Wire width multiplier must be >= 1.0!"); 93 ASSERT(wire_spacing_multiplier >= 1.0, "[Error] " + getInstanceName() + 94 " -> Wire spacing multiplier must be >= 1.0!"); 95 96 double wire_min_width = getTechModel()->get("Wire->" + wire_layer + "->MinWidth").toDouble(); 97 double wire_min_spacing = getTechModel()->get("Wire->" + wire_layer + "->MinSpacing").toDouble(); 98 99 double wire_width = wire_min_width * wire_width_multiplier; 100 double wire_spacing = wire_min_spacing * wire_spacing_multiplier; 101 102 double wire_cap_per_len = getTechModel()->calculateWireCapacitance(wire_layer, wire_width, wire_spacing, 1.0); 103 double wire_res_per_len = getTechModel()->calculateWireResistance(wire_layer, wire_width, 1.0); 104 105 getGenProperties()->set("WireWidth", wire_width); 106 getGenProperties()->set("WireSpacing", wire_spacing); 107 getGenProperties()->set("WireCapacitancePerLength", wire_cap_per_len); 108 getGenProperties()->set("WireResistancePerLength", wire_res_per_len); 109 110 // Create ports 111 createInputPort("In", makeNetIndex(0, number_bits-1)); 112 createOutputPort("Out", makeNetIndex(0, number_bits-1)); 113 114 // Create area, power, and event results 115 createElectricalAtomicResults(); 116 createElectricalEventAtomicResult("Send"); 117 118 // Create connections 119 // Since the length is not set yet, we only to virtual fan-in and virtual fan-out 120 createNet("InTmp"); 121 createNet("OutTmp"); 122 assignVirtualFanin("InTmp", "In"); 123 assignVirtualFanout("Out", "OutTmp"); 124 125 // Build Electrical Connectivity 126 createLoad("In_Cap"); 127 createDelay("In_to_Out_delay"); 128 createDriver("Out_Ron", false); // Indicate this driver is not sizable 129 130 ElectricalLoad* in_cap = getLoad("In_Cap"); 131 ElectricalDelay* in_to_out_delay = getDelay("In_to_Out_delay"); 132 ElectricalDriver* out_ron = getDriver("Out_Ron"); 133 134 getNet("InTmp")->addDownstreamNode(in_cap); 135 in_cap->addDownstreamNode(in_to_out_delay); 136 in_to_out_delay->addDownstreamNode(out_ron); 137 out_ron->addDownstreamNode(getNet("OutTmp")); 138 139 // Init a repeater and a load to mimic a segment of a repeated link 140 m_repeater_ = getTechModel()->getStdCellLib()->createStdCell("INV", "Repeater"); 141 m_repeater_->construct(); 142 m_repeater_load_ = new ElectricalLoad("RepeaterIn_Cap", this); 143 // Make path repeater_ -> repeater_load_ 144 // to catch the repeater's input/output cap and ensure only one inverter delay 145 // is added 146 m_repeater_->getNet("Y")->addDownstreamNode(m_repeater_load_); 147 // Init a timing object to calculate delay 148 m_timing_tree_ = new ElectricalTimingTree("RepeatedLink", this); 149 m_timing_tree_->performCritPathExtract(m_repeater_->getNet("A")); 150 return; 151 } 152 153 void RepeatedLink::updateModel() 154 { 155 unsigned int number_bits = getParameter("NumberBits").toUInt(); 156 157 // Get properties 158 double wire_length = getProperty("WireLength").toDouble(); 159 double required_delay = getProperty("Delay").toDouble(); 160 bool isKeepParity = getProperty("IsKeepParity").toBool(); 161 162 ASSERT(wire_length >= 0, "[Error] " + getInstanceName() + 163 " -> Wire length must be >= 0!"); 164 ASSERT(required_delay >= 0, "[Error] " + getInstanceName() + 165 " -> Required delay must be >= 0!"); 166 167 const String& wire_layer = getParameter("WireLayer"); 168 double wire_width = getGenProperties()->get("WireWidth").toDouble(); 169 double wire_spacing = getGenProperties()->get("WireSpacing").toDouble(); 170 171 // Calculate the total wire cap and total wire res 172 double wire_cap_per_len = getGenProperties()->get("WireCapacitancePerLength").toDouble(); 173 double wire_res_per_len = getGenProperties()->get("WireResistancePerLength").toDouble(); 174 double total_wire_cap = wire_cap_per_len * wire_length; 175 double total_wire_res = wire_res_per_len * wire_length; 176 177 m_repeater_->update(); 178 179 unsigned int increment_segments = (isKeepParity)? 2:1; 180 unsigned int number_segments = increment_segments; 181 double delay; 182 m_repeater_->setMinDrivingStrength(); 183 m_repeater_->getNet("Y")->setDistributedCap(total_wire_cap / number_segments); 184 m_repeater_->getNet("Y")->setDistributedRes(total_wire_res / number_segments); 185 m_repeater_load_->setLoadCap(m_repeater_->getNet("A")->getTotalDownstreamCap()); 186 m_timing_tree_->performCritPathExtract(m_repeater_->getNet("A")); 187 delay = m_timing_tree_->calculateCritPathDelay(m_repeater_->getNet("A")) * number_segments; 188 189 // If everything is 0, use number_segments min-sized repeater 190 if(wire_length != 0) 191 { 192 // Set the initial number of segments based on isKeepParity 193 double last_min_size_delay = 0; 194 unsigned int iteration = 0; 195 196 // First set the repeater to the minimum driving strength 197 last_min_size_delay = delay; 198 199 Log::printLine(getInstanceName() + " -> Beginning Repeater Insertion"); 200 201 while(required_delay < delay) 202 { 203 Log::printLine(getInstanceName() + " -> Repeater Insertion Iteration " + (String)iteration + 204 ": Required delay = " + (String)required_delay + 205 ", Delay = " + (String)delay + 206 ", Slack = " + (String)(required_delay - delay) + 207 ", Number of repeaters = " + (String)number_segments); 208 209 // Size up if timing is not met 210 while(required_delay < delay) 211 { 212 if(m_repeater_->hasMaxDrivingStrength()) 213 { 214 break; 215 } 216 m_repeater_->increaseDrivingStrength(); 217 m_repeater_load_->setLoadCap(m_repeater_->getNet("A")->getTotalDownstreamCap()); 218 m_timing_tree_->performCritPathExtract(m_repeater_->getNet("A")); 219 delay = m_timing_tree_->calculateCritPathDelay(m_repeater_->getNet("A")) * number_segments; 220 221 iteration++; 222 Log::printLine(getInstanceName() + " -> Slack: " + (String)(required_delay - delay)); 223 } 224 // Increase number of segments if timing is not met 225 if(required_delay < delay) 226 { 227 number_segments += increment_segments; 228 m_repeater_->setMinDrivingStrength(); 229 m_repeater_->getNet("Y")->setDistributedCap(total_wire_cap / number_segments); 230 m_repeater_->getNet("Y")->setDistributedRes(total_wire_res / number_segments); 231 m_repeater_load_->setLoadCap(m_repeater_->getNet("A")->getTotalDownstreamCap()); 232 m_timing_tree_->performCritPathExtract(m_repeater_->getNet("A")); 233 delay = m_timing_tree_->calculateCritPathDelay(m_repeater_->getNet("A")) * number_segments; 234 235 // Abort if adding more min sized repeaters does not decrease the delay 236 if(delay > last_min_size_delay) 237 { 238 break; 239 } 240 last_min_size_delay = delay; 241 } 242 } 243 Log::printLine(getInstanceName() + " -> Repeater Insertion Ended after Iteration: " + (String)iteration + 244 ": Required delay = " + (String)required_delay + 245 ", Delay = " + (String)delay + 246 ", Slack = " + (String)(required_delay - delay) + 247 ", Number of repeaters = " + (String)number_segments); 248 249 // Print a warning if the timing is not met 250 if(required_delay < delay) 251 { 252 const String& warning_msg = "[Warning] " + getInstanceName() + " -> Timing not met" + 253 ": Required delay = " + (String)required_delay + 254 ", Delay = " + (String)delay + 255 ", Slack = " + (String)(required_delay - delay) + 256 ", Number of repeaters = " + (String)number_segments; 257 Log::printLine(std::cerr, warning_msg); 258 } 259 } 260 261 // Update electrical interfaces 262 getLoad("In_Cap")->setLoadCap(m_repeater_->getNet("A")->getTotalDownstreamCap()); 263 getDelay("In_to_Out_delay")->setDelay(delay); 264 getDriver("Out_Ron")->setOutputRes(m_repeater_->getDriver("Y_Ron")->getOutputRes() + (total_wire_res / number_segments)); 265 266 getGenProperties()->set("NumberSegments", number_segments); 267 268 // Update area, power results 269 resetElectricalAtomicResults(); 270 addElecticalAtomicResultValues(m_repeater_, number_segments * number_bits); 271 double wire_area = wire_length * (wire_width + wire_spacing) * number_bits; 272 addElecticalWireAtomicResultValue(wire_layer, wire_area); 273 274 return; 275 } 276 277 void RepeatedLink::useModel() 278 { 279 // Update the transition information for the modeled repeater 280 // Since we only modeled one repeater. So the transition information for 0->0 and 1->1 281 // is averaged out 282 const TransitionInfo& trans_In = getInputPort("In")->getTransitionInfo(); 283 double average_static_transition = (trans_In.getNumberTransitions00() + trans_In.getNumberTransitions11()) / 2.0; 284 TransitionInfo mod_trans_In(average_static_transition, trans_In.getNumberTransitions01(), average_static_transition); 285 m_repeater_->getInputPort("A")->setTransitionInfo(mod_trans_In); 286 m_repeater_->use(); 287 288 // Get parameters 289 unsigned int number_bits = getParameter("NumberBits").toUInt(); 290 unsigned int number_segments = getGenProperties()->get("NumberSegments").toUInt(); 291 292 // Propagate the transition information 293 propagateTransitionInfo(); 294 295 // Update leakage power 296 double power = 0.0; 297 power += m_repeater_->getNddPowerResult("Leakage")->calculateSum() * number_segments * number_bits; 298 getNddPowerResult("Leakage")->setValue(power); 299 300 // Update event result 301 double energy = 0.0; 302 energy += m_repeater_->getEventResult("INV")->calculateSum() * number_segments * number_bits; 303 getEventResult("Send")->setValue(energy); 304 305 return; 306 } 307 308 void RepeatedLink::propagateTransitionInfo() 309 { 310 unsigned int number_segments = getGenProperties()->get("NumberSegments"); 311 312 if((number_segments % 2) == 0) 313 { 314 propagatePortTransitionInfo("Out", "In"); 315 } 316 else 317 { 318 const TransitionInfo& trans_In = getInputPort("In")->getTransitionInfo(); 319 TransitionInfo trans_Out(trans_In.getNumberTransitions11(), trans_In.getNumberTransitions01(), trans_In.getNumberTransitions00()); 320 getOutputPort("Out")->setTransitionInfo(trans_Out); 321 } 322 return; 323 } 324 325} // namespace DSENT 326 327