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