1 /* Copyright (c) 2012 Massachusetts Institute of Technology
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:
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
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
22 #include "model/electrical/RepeatedLink.h"
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"
38 RepeatedLink::RepeatedLink(const String
& instance_name_
, const TechModel
* tech_model_
)
39 : ElectricalModel(instance_name_
, tech_model_
)
42 m_repeater_load_
= NULL
;
43 m_timing_tree_
= NULL
;
49 RepeatedLink::~RepeatedLink()
52 delete m_repeater_load_
;
53 delete m_timing_tree_
;
56 void RepeatedLink::initParameters()
58 addParameterName("NumberBits");
59 addParameterName("WireLayer");
60 addParameterName("WireWidthMultiplier", 1.0);
61 addParameterName("WireSpacingMultiplier", 1.0);
65 void RepeatedLink::initProperties()
67 addPropertyName("WireLength");
68 addPropertyName("Delay");
69 addPropertyName("IsKeepParity", "TRUE");
73 RepeatedLink
* RepeatedLink::clone() const
79 void RepeatedLink::constructModel()
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();
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!");
96 double wire_min_width
= getTechModel()->get("Wire->" + wire_layer
+ "->MinWidth").toDouble();
97 double wire_min_spacing
= getTechModel()->get("Wire->" + wire_layer
+ "->MinSpacing").toDouble();
99 double wire_width
= wire_min_width
* wire_width_multiplier
;
100 double wire_spacing
= wire_min_spacing
* wire_spacing_multiplier
;
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);
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
);
111 createInputPort("In", makeNetIndex(0, number_bits
-1));
112 createOutputPort("Out", makeNetIndex(0, number_bits
-1));
114 // Create area, power, and event results
115 createElectricalAtomicResults();
116 createElectricalEventAtomicResult("Send");
118 // Create connections
119 // Since the length is not set yet, we only to virtual fan-in and virtual fan-out
122 assignVirtualFanin("InTmp", "In");
123 assignVirtualFanout("Out", "OutTmp");
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
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");
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"));
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
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"));
153 void RepeatedLink::updateModel()
155 unsigned int number_bits
= getParameter("NumberBits").toUInt();
158 double wire_length
= getProperty("WireLength").toDouble();
159 double required_delay
= getProperty("Delay").toDouble();
160 bool isKeepParity
= getProperty("IsKeepParity").toBool();
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!");
167 const String
& wire_layer
= getParameter("WireLayer");
168 double wire_width
= getGenProperties()->get("WireWidth").toDouble();
169 double wire_spacing
= getGenProperties()->get("WireSpacing").toDouble();
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
;
177 m_repeater_
->update();
179 unsigned int increment_segments
= (isKeepParity
)? 2:1;
180 unsigned int number_segments
= increment_segments
;
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
;
189 // If everything is 0, use number_segments min-sized repeater
192 // Set the initial number of segments based on isKeepParity
193 double last_min_size_delay
= 0;
194 unsigned int iteration
= 0;
196 // First set the repeater to the minimum driving strength
197 last_min_size_delay
= delay
;
199 Log::printLine(getInstanceName() + " -> Beginning Repeater Insertion");
201 while(required_delay
< delay
)
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
);
209 // Size up if timing is not met
210 while(required_delay
< delay
)
212 if(m_repeater_
->hasMaxDrivingStrength())
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
;
222 Log::printLine(getInstanceName() + " -> Slack: " + (String
)(required_delay
- delay
));
224 // Increase number of segments if timing is not met
225 if(required_delay
< delay
)
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
;
235 // Abort if adding more min sized repeaters does not decrease the delay
236 if(delay
> last_min_size_delay
)
240 last_min_size_delay
= delay
;
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
);
249 // Print a warning if the timing is not met
250 if(required_delay
< delay
)
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
);
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
));
266 getGenProperties()->set("NumberSegments", number_segments
);
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
);
277 void RepeatedLink::useModel()
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
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
);
289 unsigned int number_bits
= getParameter("NumberBits").toUInt();
290 unsigned int number_segments
= getGenProperties()->get("NumberSegments").toUInt();
292 // Propagate the transition information
293 propagateTransitionInfo();
295 // Update leakage power
297 power
+= m_repeater_
->getNddPowerResult("Leakage")->calculateSum() * number_segments
* number_bits
;
298 getNddPowerResult("Leakage")->setValue(power
);
300 // Update event result
302 energy
+= m_repeater_
->getEventResult("INV")->calculateSum() * number_segments
* number_bits
;
303 getEventResult("Send")->setValue(energy
);
308 void RepeatedLink::propagateTransitionInfo()
310 unsigned int number_segments
= getGenProperties()->get("NumberSegments");
312 if((number_segments
% 2) == 0)
314 propagatePortTransitionInfo("Out", "In");
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
);