BroadcastHTree.cc revision 10447:a465576671d4
1#include "model/electrical/BroadcastHTree.h"
2
3#include <cmath>
4#include <vector>
5
6#include "model/PortInfo.h"
7#include "model/EventInfo.h"
8#include "model/TransitionInfo.h"
9#include "model/std_cells/StdCellLib.h"
10#include "model/std_cells/StdCell.h"
11#include "model/timing_graph/ElectricalLoad.h"
12#include "model/timing_graph/ElectricalDelay.h"
13#include "model/timing_graph/ElectricalDriver.h"
14#include "model/timing_graph/ElectricalTimingTree.h"
15#include "model/timing_graph/ElectricalNet.h"
16
17namespace DSENT
18{
19    using std::pow;
20    using std::vector;
21
22    BroadcastHTree::BroadcastHTree(const String& instance_name_, const TechModel* tech_model_)
23        : ElectricalModel(instance_name_, tech_model_)
24    {
25        initParameters();
26        initProperties();
27
28        m_leaf_load_ = NULL;
29        m_leaf_head_driver_ = NULL;
30        m_leaf_head_load_ = NULL;
31    }
32
33    BroadcastHTree::~BroadcastHTree()
34    {
35        clearPtrVector<StdCell>(&m_repeaters_);
36        clearPtrVector<ElectricalLoad>(&m_repeater_loads_);
37        clearPtrVector<ElectricalTimingTree>(&m_timing_trees_);
38        clearPtrVector<StdCell>(&m_leaf_drivers_);
39        delete m_leaf_load_;
40        delete m_leaf_head_driver_;
41        delete m_leaf_head_load_;
42    }
43
44    void BroadcastHTree::initParameters()
45    {
46        addParameterName("NumberLevels");
47        addParameterName("NumberBits");
48        addParameterName("WireLayer");
49        addParameterName("WireWidthMultiplier", 1.0);
50        addParameterName("WireSpacingMultiplier", 1.0);
51        return;
52    }
53
54    void BroadcastHTree::initProperties()
55    {
56        addPropertyName("SitePitch");
57        addPropertyName("TotalLoadCapPerBit");
58        return;
59    }
60
61    BroadcastHTree* BroadcastHTree::clone() const
62    {
63        // TODO
64        return NULL;
65    }
66
67    void BroadcastHTree::constructModel()
68    {
69        // Get parameters
70        unsigned int number_levels = getParameter("NumberLevels").toUInt();
71        unsigned int number_bits = getParameter("NumberBits").toUInt();
72        const String& wire_layer = getParameter("WireLayer");
73        double wire_width_multiplier = getParameter("WireWidthMultiplier").toDouble();
74        double wire_spacing_multiplier = getParameter("WireSpacingMultiplier").toDouble();
75
76        ASSERT(number_levels > 0, "[Error] " + getInstanceName() +
77                " -> Number of levels must be > 0!");
78        ASSERT(number_bits > 0, "[Error] " + getInstanceName() +
79                " -> Number of bits must be > 0!");
80        ASSERT(getTechModel()->isWireLayerExist(wire_layer), "[Error] " + getInstanceName() +
81                " -> Wire layer does not exist!");
82        ASSERT(wire_width_multiplier >= 1.0, "[Error] " + getInstanceName() +
83                " -> Wire width multiplier must be >= 1.0!");
84        ASSERT(wire_spacing_multiplier >= 1.0, "[Error] " + getInstanceName() +
85                " -> Wire spacing multiplier must be >= 1.0!");
86
87        double wire_min_width = getTechModel()->get("Wire->" + wire_layer + "->MinWidth").toDouble();
88        double wire_min_spacing = getTechModel()->get("Wire->" + wire_layer + "->MinSpacing").toDouble();
89
90        double wire_width = wire_min_width * wire_width_multiplier;
91        double wire_spacing = wire_min_spacing * wire_spacing_multiplier;
92
93        double wire_cap_per_len = getTechModel()->calculateWireCapacitance(wire_layer, wire_width, wire_spacing, 1.0);
94        double wire_res_per_len = getTechModel()->calculateWireResistance(wire_layer, wire_width, 1.0);
95
96        getGenProperties()->set("WireWidth", wire_width);
97        getGenProperties()->set("WireSpacing", wire_spacing);
98        getGenProperties()->set("WireCapacitancePerLength", wire_cap_per_len);
99        getGenProperties()->set("WireResistancePerLength", wire_res_per_len);
100
101        // Create ports
102        createInputPort("In", makeNetIndex(0, number_bits-1));
103        createOutputPort("Out", makeNetIndex(0, number_bits-1));
104
105        // Create connections
106        createNet("InTmp");
107        createNet("OutTmp");
108        assignVirtualFanin("InTmp", "In");
109        assignVirtualFanout("Out", "OutTmp");
110
111        createLoad("In_Cap");
112        createDelay("In_to_Out_delay");
113
114        ElectricalLoad* in_cap = getLoad("In_Cap");
115        ElectricalDelay* in_to_out_delay = getDelay("In_to_Out_delay");
116
117        getNet("InTmp")->addDownstreamNode(in_cap);
118        in_cap->addDownstreamNode(in_to_out_delay);
119
120        // Init
121        for(unsigned int i = 0; i < number_levels; ++i)
122        {
123            StdCell* repeater = getTechModel()->getStdCellLib()->createStdCell("INV", "Repeater" + (String)i);
124            ElectricalLoad* repeater_load = new ElectricalLoad("RepeaterIn_Cap" + (String)i, this);
125            ElectricalTimingTree* timing_tree = new ElectricalTimingTree("RepeatedLink" + (String)i, this);
126
127            repeater->construct();
128            repeater->getNet("Y")->addDownstreamNode(repeater_load);
129            m_repeaters_.push_back(repeater);
130            m_repeater_loads_.push_back(repeater_load);
131            m_timing_trees_.push_back(timing_tree);
132        }
133
134        // Create area, power, and event results
135        createElectricalAtomicResults();
136        createElectricalEventResult("Send");
137        addEventResult(new AtomicResult("DriveLoad"));
138        addEventResult(new AtomicResult("DriveTree"));
139
140        getEventResult("Send")->addSubResult(getEventResult("DriveLoad"), "Self", 1.0);
141        getEventResult("Send")->addSubResult(getEventResult("DriveTree"), "Self", 1.0);
142        return;
143    }
144
145    void BroadcastHTree::updateModel()
146    {
147        // Get properties
148        double site_pitch = getProperty("SitePitch").toDouble();
149        double total_load_cap_per_bit = getProperty("TotalLoadCapPerBit").toDouble();
150
151        ASSERT(site_pitch > 0, "[Error] " + getInstanceName() +
152                " -> Site pitch must be > 0!");
153        ASSERT(total_load_cap_per_bit >= 0.0, "[Error] " + getInstanceName() +
154                " -> Total load capacitance per bit must be >= 0!");
155
156        // Get parameters
157        unsigned int number_levels = getParameter("NumberLevels");
158        unsigned int number_bits = getParameter("NumberBits");
159
160        const String& wire_layer = getParameter("WireLayer");
161        double wire_width = getGenProperties()->get("WireWidth").toDouble();
162        double wire_spacing = getGenProperties()->get("WireSpacing").toDouble();
163        double wire_cap_per_len = getGenProperties()->get("WireCapacitancePerLength").toDouble();
164        double wire_res_per_len = getGenProperties()->get("WireResistancePerLength").toDouble();
165
166        double leaf_load_cap = total_load_cap_per_bit / pow(2.0, (double)(number_levels-1));
167
168        vector<double> wire_caps(number_levels, 0.0);
169        vector<double> wire_ress(number_levels, 0.0);
170        double wire_length = site_pitch / 2.0;
171        for(unsigned int i = 0; i < number_levels; ++i)
172        {
173            wire_caps[i] = wire_cap_per_len * wire_length;
174            wire_ress[i] = wire_res_per_len * wire_length;
175            wire_length /= 2.0;
176        }
177
178        // Start sizing each stage of repeaters for a transition times. TODO: Find a heuristic about
179        // how the transition time is done...place and route tools make this user-specified
180        double required_transition = 40e-12;
181        m_number_segments_.resize(number_levels, 1);
182        for(unsigned int i = 0; i < number_levels; ++i)
183        {
184            Log::printLine(getInstanceName() + " -> Beginning Repeater Insertion " + (String)i);
185
186            double transition;
187            unsigned int iteration = 0;
188            m_repeaters_[i]->setMinDrivingStrength();
189            m_repeaters_[i]->getNet("Y")->setDistributedCap(wire_caps[i] / m_number_segments_[i]);
190            m_repeaters_[i]->getNet("Y")->setDistributedRes(wire_ress[i] / m_number_segments_[i]);
191            m_repeater_loads_[i]->setLoadCap(m_repeaters_[i]->getNet("A")->getTotalDownstreamCap());
192
193            transition = m_timing_trees_[i]->calculateNodeTransition(m_repeaters_[i]->getNet("Y"));
194
195            while(required_transition < transition)
196            {
197                Log::printLine(getInstanceName() + " -> Repeater Insertion Iteration " + (String)iteration +
198                        ": Required transition = " + (String)required_transition +
199                        ", Transition = " + (String)transition +
200                        ", Slack = " + (String)(required_transition - transition) +
201                        ", Number of repeaters = " + (String)m_number_segments_[i]);
202
203                // Size up if transition is not met
204                while(required_transition < transition)
205                {
206                    if(m_repeaters_[i]->hasMaxDrivingStrength())
207                    {
208                        break;
209                    }
210                    m_repeaters_[i]->increaseDrivingStrength();
211                    m_repeater_loads_[i]->setLoadCap(m_repeaters_[i]->getNet("A")->getTotalDownstreamCap());
212                    transition = m_timing_trees_[i]->calculateNodeTransition(m_repeaters_[i]->getNet("Y"));
213
214                    iteration++;
215                    Log::printLine(getInstanceName() + " -> Slack: " + (String)(required_transition - transition));
216                }
217                // Increase number of segments if thansition is not met
218                if(required_transition < transition)
219                {
220                    m_number_segments_[i]++;
221                    m_repeaters_[i]->setMinDrivingStrength();
222                    m_repeaters_[i]->getNet("Y")->setDistributedCap(wire_caps[i] / m_number_segments_[i]);
223                    m_repeaters_[i]->getNet("Y")->setDistributedRes(wire_ress[i] / m_number_segments_[i]);
224                    m_repeater_loads_[i]->setLoadCap(m_repeaters_[i]->getNet("A")->getTotalDownstreamCap());
225                    transition = m_timing_trees_[i]->calculateNodeTransition(m_repeaters_[i]->getNet("Y"));
226                }
227            }
228            Log::printLine(getInstanceName() + " -> Repeater Insertion " + (String)i + " Ended after Iteration: " + (String)iteration +
229                    ": Required transition = " + (String)required_transition +
230                    ", Transition = " + (String)transition +
231                    ", Slack = " + (String)(required_transition - transition) +
232                    ", Number of repeaters = " + (String)m_number_segments_[i]);
233        }
234
235        // Insert inverters to ensure the transition time at the leaf
236        int min_driving_strength_idx = m_repeaters_[number_levels-1]->getDrivingStrengthIdx();
237
238        // Remove everything and rebuild again
239        clearPtrVector<StdCell>(&m_leaf_drivers_);
240        delete m_leaf_load_;
241        delete m_leaf_head_driver_;
242        delete m_leaf_head_load_;
243
244        m_leaf_head_driver_ = getTechModel()->getStdCellLib()->createStdCell("INV", "LeafHeadDriver");
245        m_leaf_head_driver_->construct();
246        m_leaf_head_driver_->setDrivingStrengthIdx(min_driving_strength_idx);
247
248        m_leaf_head_load_ = new ElectricalLoad("LeafHead_Cap", this);
249        m_leaf_head_driver_->getNet("Y")->addDownstreamNode(m_leaf_head_load_);
250
251        m_leaf_load_ = new ElectricalLoad("Leaf_Cap", this);
252        m_leaf_load_->setLoadCap(leaf_load_cap);
253
254        StdCell* inv = getTechModel()->getStdCellLib()->createStdCell("INV", "LeafDriver0");
255        inv->construct();
256        inv->getNet("Y")->addDownstreamNode(m_leaf_load_);
257        inv->setDrivingStrengthIdx(min_driving_strength_idx);
258        m_leaf_drivers_.push_back(inv);
259
260        m_leaf_head_load_->setLoadCap(m_leaf_drivers_[0]->getNet("A")->getTotalDownstreamCap());
261
262        // Start inserting the buffers
263        ElectricalTimingTree t2("LeafHead", m_leaf_head_driver_);
264        int curr_driver = 0;
265        unsigned int iteration = 0;
266        while(true)
267        {
268            ElectricalTimingTree t("LeafDriver", m_leaf_drivers_[curr_driver]);
269            double transition = t.calculateNodeTransition(m_leaf_drivers_[curr_driver]->getNet("Y"));
270            Log::printLine(getInstanceName() + " -> Buffer Insertion : " + (String)iteration +
271                    ": Required transition = " + (String)required_transition +
272                    ", Transition = " + (String)transition +
273                    ", Slack = " + (String)(required_transition - transition) +
274                    ", Number of buffers = " + (String)(curr_driver+1));
275
276            // Size up the inverter at curr_driver so that it could drive the next stage
277            while(required_transition < transition)
278            {
279                if(m_leaf_drivers_[curr_driver]->hasMaxDrivingStrength())
280                {
281                    const String& warning_msg = "[Warning] " + getInstanceName() + " -> Transition not met" +
282                        ": Required transition = " + (String)required_transition +
283                        ", Transition = " + (String)transition +
284                        ", Slack = " + (String)(required_transition - transition);
285                    Log::printLine(std::cerr, warning_msg);
286                    break;
287                }
288                m_leaf_drivers_[curr_driver]->increaseDrivingStrength();
289                transition = t.calculateNodeTransition(m_leaf_drivers_[curr_driver]->getNet("Y"));
290                iteration++;
291            }
292            // Add an additional inverter if the transition for the first stage does not meet the required transition
293            m_leaf_head_load_->setLoadCap(m_leaf_drivers_[curr_driver]->getNet("A")->getTotalDownstreamCap());
294            transition = t2.calculateNodeTransition(m_leaf_head_driver_->getNet("Y"));
295            if(required_transition < transition)
296            {
297                inv = getTechModel()->getStdCellLib()->createStdCell("INV", "LeafDriver" + (String)(curr_driver+1));
298                inv->construct();
299                inv->getNet("Y")->addDownstreamNode(m_leaf_drivers_[curr_driver]->getNet("A"));
300                inv->setDrivingStrengthIdx(min_driving_strength_idx);
301                m_leaf_drivers_.push_back(inv);
302                curr_driver++;
303            }
304            else
305            {
306                Log::printLine(getInstanceName() + " -> Buffer Insertion Ended after Iteration: " + (String)iteration +
307                        ", Number of buffers = " + (String)(curr_driver+1));
308                break;
309            }
310        }
311
312
313        // Update electrical interfaces
314        getLoad("In_Cap")->setLoadCap(m_repeaters_[0]->getNet("A")->getTotalDownstreamCap());
315        // TODO
316        getDelay("In_to_Out_delay")->setDelay(0.0);
317
318        // Reset all the atomic results to 0 before start updating new results
319        resetElectricalAtomicResults();
320
321        // Update area, power results
322        double wire_area = 0.0;
323        wire_length = site_pitch / 2.0;
324        unsigned int number_branches = 1;
325        for(unsigned int i = 0; i < number_levels; ++i)
326        {
327            wire_area += wire_length * (wire_width + wire_spacing) * number_branches * number_bits;
328            addElecticalAtomicResultValues(m_repeaters_[i], m_number_segments_[i] * number_branches * number_bits);
329            wire_length /= 2.0;
330            number_branches *= 2;
331        }
332        number_branches = (unsigned int)pow(2.0, (double)number_levels-1);
333        addElecticalAtomicResultValues(m_leaf_head_driver_, number_branches * number_bits);
334        for(unsigned int i = 0; i < m_leaf_drivers_.size(); ++i)
335        {
336            addElecticalAtomicResultValues(m_leaf_drivers_[i], number_branches * number_bits);
337        }
338        addElecticalWireAtomicResultValue(wire_layer, wire_area);
339
340        return;
341    }
342
343    void BroadcastHTree::useModel()
344    {
345        unsigned int number_bits = getParameter("NumberBits").toUInt();
346        unsigned int number_levels = getParameter("NumberLevels").toUInt();
347
348        // Update the transition information for the modeled repeaters
349        // Since we only modeled one repeater. So the transition information for 0->0 and 1->1
350        // is averaged out
351        const TransitionInfo& trans_In = getInputPort("In")->getTransitionInfo();
352        double average_static_transition = (trans_In.getNumberTransitions00() + trans_In.getNumberTransitions11()) / 2.0;
353        TransitionInfo mod_trans_In(average_static_transition, trans_In.getNumberTransitions01(), average_static_transition);
354
355        // Propagate the transition information
356        propagateTransitionInfo();
357
358        // Update leakage and event
359        double energy = 0.0;
360        double power = 0.0;
361        unsigned int number_branches = 1;
362        for(unsigned int i = 0; i < number_levels; ++i)
363        {
364            assignPortTransitionInfo(m_repeaters_[i], "A", mod_trans_In);
365            m_repeaters_[i]->use();
366            power += m_repeaters_[i]->getNddPowerResult("Leakage")->calculateSum() * m_number_segments_[i] * number_branches;
367            energy += m_repeaters_[i]->getEventResult("INV")->calculateSum() * m_number_segments_[i] * number_branches;
368            number_branches *= 2;
369        }
370        energy *= number_bits;
371        getEventResult("DriveTree")->setValue(energy);
372
373        energy = 0.0;
374        assignPortTransitionInfo(m_leaf_head_driver_, "A", mod_trans_In);
375        m_leaf_head_driver_->use();
376        number_branches = (unsigned int)pow(2.0, (double)number_levels-1);
377        power += m_leaf_head_driver_->getNddPowerResult("Leakage")->calculateSum() * number_branches;
378        energy += m_leaf_head_driver_->getEventResult("INV")->calculateSum() * number_branches;
379        for(unsigned int i = 0; i < m_leaf_drivers_.size(); ++i)
380        {
381            assignPortTransitionInfo(m_leaf_drivers_[i], "A", mod_trans_In);
382            m_leaf_drivers_[i]->use();
383            power += m_leaf_drivers_[i]->getNddPowerResult("Leakage")->calculateSum() * number_branches;
384            energy += m_leaf_drivers_[i]->getEventResult("INV")->calculateSum() * number_branches;
385        }
386        power *= number_bits;
387        energy *= number_bits;
388        getEventResult("DriveLoad")->setValue(energy);
389        getNddPowerResult("Leakage")->setValue(power);
390
391        return;
392    }
393
394    void BroadcastHTree::propagateTransitionInfo()
395    {
396        propagatePortTransitionInfo("Out", "In");
397        return;
398    }
399} // namespace DSENT
400
401