summaryrefslogtreecommitdiff
path: root/ext/dsent/model/electrical/BroadcastHTree.cc
diff options
context:
space:
mode:
Diffstat (limited to 'ext/dsent/model/electrical/BroadcastHTree.cc')
-rw-r--r--ext/dsent/model/electrical/BroadcastHTree.cc400
1 files changed, 400 insertions, 0 deletions
diff --git a/ext/dsent/model/electrical/BroadcastHTree.cc b/ext/dsent/model/electrical/BroadcastHTree.cc
new file mode 100644
index 000000000..efac128e7
--- /dev/null
+++ b/ext/dsent/model/electrical/BroadcastHTree.cc
@@ -0,0 +1,400 @@
+#include "model/electrical/BroadcastHTree.h"
+
+#include <cmath>
+#include <vector>
+
+#include "model/PortInfo.h"
+#include "model/EventInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/std_cells/StdCellLib.h"
+#include "model/std_cells/StdCell.h"
+#include "model/timing_graph/ElectricalLoad.h"
+#include "model/timing_graph/ElectricalDelay.h"
+#include "model/timing_graph/ElectricalDriver.h"
+#include "model/timing_graph/ElectricalTimingTree.h"
+#include "model/timing_graph/ElectricalNet.h"
+
+namespace DSENT
+{
+ using std::pow;
+ using std::vector;
+
+ BroadcastHTree::BroadcastHTree(const String& instance_name_, const TechModel* tech_model_)
+ : ElectricalModel(instance_name_, tech_model_)
+ {
+ initParameters();
+ initProperties();
+
+ m_leaf_load_ = NULL;
+ m_leaf_head_driver_ = NULL;
+ m_leaf_head_load_ = NULL;
+ }
+
+ BroadcastHTree::~BroadcastHTree()
+ {
+ clearPtrVector<StdCell>(&m_repeaters_);
+ clearPtrVector<ElectricalLoad>(&m_repeater_loads_);
+ clearPtrVector<ElectricalTimingTree>(&m_timing_trees_);
+ clearPtrVector<StdCell>(&m_leaf_drivers_);
+ delete m_leaf_load_;
+ delete m_leaf_head_driver_;
+ delete m_leaf_head_load_;
+ }
+
+ void BroadcastHTree::initParameters()
+ {
+ addParameterName("NumberLevels");
+ addParameterName("NumberBits");
+ addParameterName("WireLayer");
+ addParameterName("WireWidthMultiplier", 1.0);
+ addParameterName("WireSpacingMultiplier", 1.0);
+ return;
+ }
+
+ void BroadcastHTree::initProperties()
+ {
+ addPropertyName("SitePitch");
+ addPropertyName("TotalLoadCapPerBit");
+ return;
+ }
+
+ BroadcastHTree* BroadcastHTree::clone() const
+ {
+ // TODO
+ return NULL;
+ }
+
+ void BroadcastHTree::constructModel()
+ {
+ // Get parameters
+ unsigned int number_levels = getParameter("NumberLevels").toUInt();
+ unsigned int number_bits = getParameter("NumberBits").toUInt();
+ const String& wire_layer = getParameter("WireLayer");
+ double wire_width_multiplier = getParameter("WireWidthMultiplier").toDouble();
+ double wire_spacing_multiplier = getParameter("WireSpacingMultiplier").toDouble();
+
+ ASSERT(number_levels > 0, "[Error] " + getInstanceName() +
+ " -> Number of levels must be > 0!");
+ ASSERT(number_bits > 0, "[Error] " + getInstanceName() +
+ " -> Number of bits must be > 0!");
+ ASSERT(getTechModel()->isWireLayerExist(wire_layer), "[Error] " + getInstanceName() +
+ " -> Wire layer does not exist!");
+ ASSERT(wire_width_multiplier >= 1.0, "[Error] " + getInstanceName() +
+ " -> Wire width multiplier must be >= 1.0!");
+ ASSERT(wire_spacing_multiplier >= 1.0, "[Error] " + getInstanceName() +
+ " -> Wire spacing multiplier must be >= 1.0!");
+
+ double wire_min_width = getTechModel()->get("Wire->" + wire_layer + "->MinWidth").toDouble();
+ double wire_min_spacing = getTechModel()->get("Wire->" + wire_layer + "->MinSpacing").toDouble();
+
+ double wire_width = wire_min_width * wire_width_multiplier;
+ double wire_spacing = wire_min_spacing * wire_spacing_multiplier;
+
+ double wire_cap_per_len = getTechModel()->calculateWireCapacitance(wire_layer, wire_width, wire_spacing, 1.0);
+ double wire_res_per_len = getTechModel()->calculateWireResistance(wire_layer, wire_width, 1.0);
+
+ getGenProperties()->set("WireWidth", wire_width);
+ getGenProperties()->set("WireSpacing", wire_spacing);
+ getGenProperties()->set("WireCapacitancePerLength", wire_cap_per_len);
+ getGenProperties()->set("WireResistancePerLength", wire_res_per_len);
+
+ // Create ports
+ createInputPort("In", makeNetIndex(0, number_bits-1));
+ createOutputPort("Out", makeNetIndex(0, number_bits-1));
+
+ // Create connections
+ createNet("InTmp");
+ createNet("OutTmp");
+ assignVirtualFanin("InTmp", "In");
+ assignVirtualFanout("Out", "OutTmp");
+
+ createLoad("In_Cap");
+ createDelay("In_to_Out_delay");
+
+ ElectricalLoad* in_cap = getLoad("In_Cap");
+ ElectricalDelay* in_to_out_delay = getDelay("In_to_Out_delay");
+
+ getNet("InTmp")->addDownstreamNode(in_cap);
+ in_cap->addDownstreamNode(in_to_out_delay);
+
+ // Init
+ for(unsigned int i = 0; i < number_levels; ++i)
+ {
+ StdCell* repeater = getTechModel()->getStdCellLib()->createStdCell("INV", "Repeater" + (String)i);
+ ElectricalLoad* repeater_load = new ElectricalLoad("RepeaterIn_Cap" + (String)i, this);
+ ElectricalTimingTree* timing_tree = new ElectricalTimingTree("RepeatedLink" + (String)i, this);
+
+ repeater->construct();
+ repeater->getNet("Y")->addDownstreamNode(repeater_load);
+ m_repeaters_.push_back(repeater);
+ m_repeater_loads_.push_back(repeater_load);
+ m_timing_trees_.push_back(timing_tree);
+ }
+
+ // Create area, power, and event results
+ createElectricalAtomicResults();
+ createElectricalEventResult("Send");
+ addEventResult(new AtomicResult("DriveLoad"));
+ addEventResult(new AtomicResult("DriveTree"));
+
+ getEventResult("Send")->addSubResult(getEventResult("DriveLoad"), "Self", 1.0);
+ getEventResult("Send")->addSubResult(getEventResult("DriveTree"), "Self", 1.0);
+ return;
+ }
+
+ void BroadcastHTree::updateModel()
+ {
+ // Get properties
+ double site_pitch = getProperty("SitePitch").toDouble();
+ double total_load_cap_per_bit = getProperty("TotalLoadCapPerBit").toDouble();
+
+ ASSERT(site_pitch > 0, "[Error] " + getInstanceName() +
+ " -> Site pitch must be > 0!");
+ ASSERT(total_load_cap_per_bit >= 0.0, "[Error] " + getInstanceName() +
+ " -> Total load capacitance per bit must be >= 0!");
+
+ // Get parameters
+ unsigned int number_levels = getParameter("NumberLevels");
+ unsigned int number_bits = getParameter("NumberBits");
+
+ const String& wire_layer = getParameter("WireLayer");
+ double wire_width = getGenProperties()->get("WireWidth").toDouble();
+ double wire_spacing = getGenProperties()->get("WireSpacing").toDouble();
+ double wire_cap_per_len = getGenProperties()->get("WireCapacitancePerLength").toDouble();
+ double wire_res_per_len = getGenProperties()->get("WireResistancePerLength").toDouble();
+
+ double leaf_load_cap = total_load_cap_per_bit / pow(2.0, (double)(number_levels-1));
+
+ vector<double> wire_caps(number_levels, 0.0);
+ vector<double> wire_ress(number_levels, 0.0);
+ double wire_length = site_pitch / 2.0;
+ for(unsigned int i = 0; i < number_levels; ++i)
+ {
+ wire_caps[i] = wire_cap_per_len * wire_length;
+ wire_ress[i] = wire_res_per_len * wire_length;
+ wire_length /= 2.0;
+ }
+
+ // Start sizing each stage of repeaters for a transition times. TODO: Find a heuristic about
+ // how the transition time is done...place and route tools make this user-specified
+ double required_transition = 40e-12;
+ m_number_segments_.resize(number_levels, 1);
+ for(unsigned int i = 0; i < number_levels; ++i)
+ {
+ Log::printLine(getInstanceName() + " -> Beginning Repeater Insertion " + (String)i);
+
+ double transition;
+ unsigned int iteration = 0;
+ m_repeaters_[i]->setMinDrivingStrength();
+ m_repeaters_[i]->getNet("Y")->setDistributedCap(wire_caps[i] / m_number_segments_[i]);
+ m_repeaters_[i]->getNet("Y")->setDistributedRes(wire_ress[i] / m_number_segments_[i]);
+ m_repeater_loads_[i]->setLoadCap(m_repeaters_[i]->getNet("A")->getTotalDownstreamCap());
+
+ transition = m_timing_trees_[i]->calculateNodeTransition(m_repeaters_[i]->getNet("Y"));
+
+ while(required_transition < transition)
+ {
+ Log::printLine(getInstanceName() + " -> Repeater Insertion Iteration " + (String)iteration +
+ ": Required transition = " + (String)required_transition +
+ ", Transition = " + (String)transition +
+ ", Slack = " + (String)(required_transition - transition) +
+ ", Number of repeaters = " + (String)m_number_segments_[i]);
+
+ // Size up if transition is not met
+ while(required_transition < transition)
+ {
+ if(m_repeaters_[i]->hasMaxDrivingStrength())
+ {
+ break;
+ }
+ m_repeaters_[i]->increaseDrivingStrength();
+ m_repeater_loads_[i]->setLoadCap(m_repeaters_[i]->getNet("A")->getTotalDownstreamCap());
+ transition = m_timing_trees_[i]->calculateNodeTransition(m_repeaters_[i]->getNet("Y"));
+
+ iteration++;
+ Log::printLine(getInstanceName() + " -> Slack: " + (String)(required_transition - transition));
+ }
+ // Increase number of segments if thansition is not met
+ if(required_transition < transition)
+ {
+ m_number_segments_[i]++;
+ m_repeaters_[i]->setMinDrivingStrength();
+ m_repeaters_[i]->getNet("Y")->setDistributedCap(wire_caps[i] / m_number_segments_[i]);
+ m_repeaters_[i]->getNet("Y")->setDistributedRes(wire_ress[i] / m_number_segments_[i]);
+ m_repeater_loads_[i]->setLoadCap(m_repeaters_[i]->getNet("A")->getTotalDownstreamCap());
+ transition = m_timing_trees_[i]->calculateNodeTransition(m_repeaters_[i]->getNet("Y"));
+ }
+ }
+ Log::printLine(getInstanceName() + " -> Repeater Insertion " + (String)i + " Ended after Iteration: " + (String)iteration +
+ ": Required transition = " + (String)required_transition +
+ ", Transition = " + (String)transition +
+ ", Slack = " + (String)(required_transition - transition) +
+ ", Number of repeaters = " + (String)m_number_segments_[i]);
+ }
+
+ // Insert inverters to ensure the transition time at the leaf
+ int min_driving_strength_idx = m_repeaters_[number_levels-1]->getDrivingStrengthIdx();
+
+ // Remove everything and rebuild again
+ clearPtrVector<StdCell>(&m_leaf_drivers_);
+ delete m_leaf_load_;
+ delete m_leaf_head_driver_;
+ delete m_leaf_head_load_;
+
+ m_leaf_head_driver_ = getTechModel()->getStdCellLib()->createStdCell("INV", "LeafHeadDriver");
+ m_leaf_head_driver_->construct();
+ m_leaf_head_driver_->setDrivingStrengthIdx(min_driving_strength_idx);
+
+ m_leaf_head_load_ = new ElectricalLoad("LeafHead_Cap", this);
+ m_leaf_head_driver_->getNet("Y")->addDownstreamNode(m_leaf_head_load_);
+
+ m_leaf_load_ = new ElectricalLoad("Leaf_Cap", this);
+ m_leaf_load_->setLoadCap(leaf_load_cap);
+
+ StdCell* inv = getTechModel()->getStdCellLib()->createStdCell("INV", "LeafDriver0");
+ inv->construct();
+ inv->getNet("Y")->addDownstreamNode(m_leaf_load_);
+ inv->setDrivingStrengthIdx(min_driving_strength_idx);
+ m_leaf_drivers_.push_back(inv);
+
+ m_leaf_head_load_->setLoadCap(m_leaf_drivers_[0]->getNet("A")->getTotalDownstreamCap());
+
+ // Start inserting the buffers
+ ElectricalTimingTree t2("LeafHead", m_leaf_head_driver_);
+ int curr_driver = 0;
+ unsigned int iteration = 0;
+ while(true)
+ {
+ ElectricalTimingTree t("LeafDriver", m_leaf_drivers_[curr_driver]);
+ double transition = t.calculateNodeTransition(m_leaf_drivers_[curr_driver]->getNet("Y"));
+ Log::printLine(getInstanceName() + " -> Buffer Insertion : " + (String)iteration +
+ ": Required transition = " + (String)required_transition +
+ ", Transition = " + (String)transition +
+ ", Slack = " + (String)(required_transition - transition) +
+ ", Number of buffers = " + (String)(curr_driver+1));
+
+ // Size up the inverter at curr_driver so that it could drive the next stage
+ while(required_transition < transition)
+ {
+ if(m_leaf_drivers_[curr_driver]->hasMaxDrivingStrength())
+ {
+ const String& warning_msg = "[Warning] " + getInstanceName() + " -> Transition not met" +
+ ": Required transition = " + (String)required_transition +
+ ", Transition = " + (String)transition +
+ ", Slack = " + (String)(required_transition - transition);
+ Log::printLine(std::cerr, warning_msg);
+ break;
+ }
+ m_leaf_drivers_[curr_driver]->increaseDrivingStrength();
+ transition = t.calculateNodeTransition(m_leaf_drivers_[curr_driver]->getNet("Y"));
+ iteration++;
+ }
+ // Add an additional inverter if the transition for the first stage does not meet the required transition
+ m_leaf_head_load_->setLoadCap(m_leaf_drivers_[curr_driver]->getNet("A")->getTotalDownstreamCap());
+ transition = t2.calculateNodeTransition(m_leaf_head_driver_->getNet("Y"));
+ if(required_transition < transition)
+ {
+ inv = getTechModel()->getStdCellLib()->createStdCell("INV", "LeafDriver" + (String)(curr_driver+1));
+ inv->construct();
+ inv->getNet("Y")->addDownstreamNode(m_leaf_drivers_[curr_driver]->getNet("A"));
+ inv->setDrivingStrengthIdx(min_driving_strength_idx);
+ m_leaf_drivers_.push_back(inv);
+ curr_driver++;
+ }
+ else
+ {
+ Log::printLine(getInstanceName() + " -> Buffer Insertion Ended after Iteration: " + (String)iteration +
+ ", Number of buffers = " + (String)(curr_driver+1));
+ break;
+ }
+ }
+
+
+ // Update electrical interfaces
+ getLoad("In_Cap")->setLoadCap(m_repeaters_[0]->getNet("A")->getTotalDownstreamCap());
+ // TODO
+ getDelay("In_to_Out_delay")->setDelay(0.0);
+
+ // Reset all the atomic results to 0 before start updating new results
+ resetElectricalAtomicResults();
+
+ // Update area, power results
+ double wire_area = 0.0;
+ wire_length = site_pitch / 2.0;
+ unsigned int number_branches = 1;
+ for(unsigned int i = 0; i < number_levels; ++i)
+ {
+ wire_area += wire_length * (wire_width + wire_spacing) * number_branches * number_bits;
+ addElecticalAtomicResultValues(m_repeaters_[i], m_number_segments_[i] * number_branches * number_bits);
+ wire_length /= 2.0;
+ number_branches *= 2;
+ }
+ number_branches = (unsigned int)pow(2.0, (double)number_levels-1);
+ addElecticalAtomicResultValues(m_leaf_head_driver_, number_branches * number_bits);
+ for(unsigned int i = 0; i < m_leaf_drivers_.size(); ++i)
+ {
+ addElecticalAtomicResultValues(m_leaf_drivers_[i], number_branches * number_bits);
+ }
+ addElecticalWireAtomicResultValue(wire_layer, wire_area);
+
+ return;
+ }
+
+ void BroadcastHTree::useModel()
+ {
+ unsigned int number_bits = getParameter("NumberBits").toUInt();
+ unsigned int number_levels = getParameter("NumberLevels").toUInt();
+
+ // Update the transition information for the modeled repeaters
+ // Since we only modeled one repeater. So the transition information for 0->0 and 1->1
+ // is averaged out
+ const TransitionInfo& trans_In = getInputPort("In")->getTransitionInfo();
+ double average_static_transition = (trans_In.getNumberTransitions00() + trans_In.getNumberTransitions11()) / 2.0;
+ TransitionInfo mod_trans_In(average_static_transition, trans_In.getNumberTransitions01(), average_static_transition);
+
+ // Propagate the transition information
+ propagateTransitionInfo();
+
+ // Update leakage and event
+ double energy = 0.0;
+ double power = 0.0;
+ unsigned int number_branches = 1;
+ for(unsigned int i = 0; i < number_levels; ++i)
+ {
+ assignPortTransitionInfo(m_repeaters_[i], "A", mod_trans_In);
+ m_repeaters_[i]->use();
+ power += m_repeaters_[i]->getNddPowerResult("Leakage")->calculateSum() * m_number_segments_[i] * number_branches;
+ energy += m_repeaters_[i]->getEventResult("INV")->calculateSum() * m_number_segments_[i] * number_branches;
+ number_branches *= 2;
+ }
+ energy *= number_bits;
+ getEventResult("DriveTree")->setValue(energy);
+
+ energy = 0.0;
+ assignPortTransitionInfo(m_leaf_head_driver_, "A", mod_trans_In);
+ m_leaf_head_driver_->use();
+ number_branches = (unsigned int)pow(2.0, (double)number_levels-1);
+ power += m_leaf_head_driver_->getNddPowerResult("Leakage")->calculateSum() * number_branches;
+ energy += m_leaf_head_driver_->getEventResult("INV")->calculateSum() * number_branches;
+ for(unsigned int i = 0; i < m_leaf_drivers_.size(); ++i)
+ {
+ assignPortTransitionInfo(m_leaf_drivers_[i], "A", mod_trans_In);
+ m_leaf_drivers_[i]->use();
+ power += m_leaf_drivers_[i]->getNddPowerResult("Leakage")->calculateSum() * number_branches;
+ energy += m_leaf_drivers_[i]->getEventResult("INV")->calculateSum() * number_branches;
+ }
+ power *= number_bits;
+ energy *= number_bits;
+ getEventResult("DriveLoad")->setValue(energy);
+ getNddPowerResult("Leakage")->setValue(power);
+
+ return;
+ }
+
+ void BroadcastHTree::propagateTransitionInfo()
+ {
+ propagatePortTransitionInfo("Out", "In");
+ return;
+ }
+} // namespace DSENT
+