From e8ed7b1d1b5bef31e9874f679a5797c2e00d06f1 Mon Sep 17 00:00:00 2001 From: Nilay Vaish Date: Sat, 11 Oct 2014 15:02:23 -0500 Subject: ext: add the source code for DSENT This patch adds a tool called DSENT to the ext/ directory. DSENT is a tool that models power and area for on-chip networks. The next patch adds a script for using the tool. --- ext/dsent/model/electrical/RepeatedLink.cc | 305 +++++++++++++++++++++++++++++ 1 file changed, 305 insertions(+) create mode 100644 ext/dsent/model/electrical/RepeatedLink.cc (limited to 'ext/dsent/model/electrical/RepeatedLink.cc') diff --git a/ext/dsent/model/electrical/RepeatedLink.cc b/ext/dsent/model/electrical/RepeatedLink.cc new file mode 100644 index 000000000..08a40e432 --- /dev/null +++ b/ext/dsent/model/electrical/RepeatedLink.cc @@ -0,0 +1,305 @@ +#include "model/electrical/RepeatedLink.h" + +#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/ElectricalTimingTree.h" +#include "model/timing_graph/ElectricalTimingNode.h" +#include "model/timing_graph/ElectricalNet.h" +#include "model/timing_graph/ElectricalDriver.h" +#include "model/timing_graph/ElectricalDelay.h" +#include "model/timing_graph/ElectricalLoad.h" + +namespace DSENT +{ + RepeatedLink::RepeatedLink(const String& instance_name_, const TechModel* tech_model_) + : ElectricalModel(instance_name_, tech_model_) + { + m_repeater_ = NULL; + m_repeater_load_ = NULL; + m_timing_tree_ = NULL; + + initParameters(); + initProperties(); + } + + RepeatedLink::~RepeatedLink() + { + delete m_repeater_; + delete m_repeater_load_; + delete m_timing_tree_; + } + + void RepeatedLink::initParameters() + { + addParameterName("NumberBits"); + addParameterName("WireLayer"); + addParameterName("WireWidthMultiplier", 1.0); + addParameterName("WireSpacingMultiplier", 1.0); + return; + } + + void RepeatedLink::initProperties() + { + addPropertyName("WireLength"); + addPropertyName("Delay"); + addPropertyName("IsKeepParity", "TRUE"); + return; + } + + RepeatedLink* RepeatedLink::clone() const + { + // TODO + return NULL; + } + + void RepeatedLink::constructModel() + { + // Get parameters + 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_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 area, power, and event results + createElectricalAtomicResults(); + createElectricalEventAtomicResult("Send"); + + // Create connections + // Since the length is not set yet, we only to virtual fan-in and virtual fan-out + createNet("InTmp"); + createNet("OutTmp"); + assignVirtualFanin("InTmp", "In"); + assignVirtualFanout("Out", "OutTmp"); + + // Build Electrical Connectivity + createLoad("In_Cap"); + createDelay("In_to_Out_delay"); + createDriver("Out_Ron", false); // Indicate this driver is not sizable + + ElectricalLoad* in_cap = getLoad("In_Cap"); + ElectricalDelay* in_to_out_delay = getDelay("In_to_Out_delay"); + ElectricalDriver* out_ron = getDriver("Out_Ron"); + + getNet("InTmp")->addDownstreamNode(in_cap); + in_cap->addDownstreamNode(in_to_out_delay); + in_to_out_delay->addDownstreamNode(out_ron); + out_ron->addDownstreamNode(getNet("OutTmp")); + + // Init a repeater and a load to mimic a segment of a repeated link + m_repeater_ = getTechModel()->getStdCellLib()->createStdCell("INV", "Repeater"); + m_repeater_->construct(); + m_repeater_load_ = new ElectricalLoad("RepeaterIn_Cap", this); + // Make path repeater_ -> repeater_load_ + // to catch the repeater's input/output cap and ensure only one inverter delay + // is added + m_repeater_->getNet("Y")->addDownstreamNode(m_repeater_load_); + // Init a timing object to calculate delay + m_timing_tree_ = new ElectricalTimingTree("RepeatedLink", this); + m_timing_tree_->performCritPathExtract(m_repeater_->getNet("A")); + return; + } + + void RepeatedLink::updateModel() + { + unsigned int number_bits = getParameter("NumberBits").toUInt(); + + // Get properties + double wire_length = getProperty("WireLength").toDouble(); + double required_delay = getProperty("Delay").toDouble(); + bool isKeepParity = getProperty("IsKeepParity").toBool(); + + ASSERT(wire_length >= 0, "[Error] " + getInstanceName() + + " -> Wire length must be >= 0!"); + ASSERT(required_delay >= 0, "[Error] " + getInstanceName() + + " -> Required delay must be >= 0!"); + + const String& wire_layer = getParameter("WireLayer"); + double wire_width = getGenProperties()->get("WireWidth").toDouble(); + double wire_spacing = getGenProperties()->get("WireSpacing").toDouble(); + + // Calculate the total wire cap and total wire res + double wire_cap_per_len = getGenProperties()->get("WireCapacitancePerLength").toDouble(); + double wire_res_per_len = getGenProperties()->get("WireResistancePerLength").toDouble(); + double total_wire_cap = wire_cap_per_len * wire_length; + double total_wire_res = wire_res_per_len * wire_length; + + m_repeater_->update(); + + unsigned int increment_segments = (isKeepParity)? 2:1; + unsigned int number_segments = increment_segments; + double delay; + m_repeater_->setMinDrivingStrength(); + m_repeater_->getNet("Y")->setDistributedCap(total_wire_cap / number_segments); + m_repeater_->getNet("Y")->setDistributedRes(total_wire_res / number_segments); + m_repeater_load_->setLoadCap(m_repeater_->getNet("A")->getTotalDownstreamCap()); + m_timing_tree_->performCritPathExtract(m_repeater_->getNet("A")); + delay = m_timing_tree_->calculateCritPathDelay(m_repeater_->getNet("A")) * number_segments; + + // If everything is 0, use number_segments min-sized repeater + if(wire_length != 0) + { + // Set the initial number of segments based on isKeepParity + double last_min_size_delay = 0; + unsigned int iteration = 0; + + // First set the repeater to the minimum driving strength + last_min_size_delay = delay; + + Log::printLine(getInstanceName() + " -> Beginning Repeater Insertion"); + + while(required_delay < delay) + { + Log::printLine(getInstanceName() + " -> Repeater Insertion Iteration " + (String)iteration + + ": Required delay = " + (String)required_delay + + ", Delay = " + (String)delay + + ", Slack = " + (String)(required_delay - delay) + + ", Number of repeaters = " + (String)number_segments); + + // Size up if timing is not met + while(required_delay < delay) + { + if(m_repeater_->hasMaxDrivingStrength()) + { + break; + } + m_repeater_->increaseDrivingStrength(); + m_repeater_load_->setLoadCap(m_repeater_->getNet("A")->getTotalDownstreamCap()); + m_timing_tree_->performCritPathExtract(m_repeater_->getNet("A")); + delay = m_timing_tree_->calculateCritPathDelay(m_repeater_->getNet("A")) * number_segments; + + iteration++; + Log::printLine(getInstanceName() + " -> Slack: " + (String)(required_delay - delay)); + } + // Increase number of segments if timing is not met + if(required_delay < delay) + { + number_segments += increment_segments; + m_repeater_->setMinDrivingStrength(); + m_repeater_->getNet("Y")->setDistributedCap(total_wire_cap / number_segments); + m_repeater_->getNet("Y")->setDistributedRes(total_wire_res / number_segments); + m_repeater_load_->setLoadCap(m_repeater_->getNet("A")->getTotalDownstreamCap()); + m_timing_tree_->performCritPathExtract(m_repeater_->getNet("A")); + delay = m_timing_tree_->calculateCritPathDelay(m_repeater_->getNet("A")) * number_segments; + + // Abort if adding more min sized repeaters does not decrease the delay + if(delay > last_min_size_delay) + { + break; + } + last_min_size_delay = delay; + } + } + Log::printLine(getInstanceName() + " -> Repeater Insertion Ended after Iteration: " + (String)iteration + + ": Required delay = " + (String)required_delay + + ", Delay = " + (String)delay + + ", Slack = " + (String)(required_delay - delay) + + ", Number of repeaters = " + (String)number_segments); + + // Print a warning if the timing is not met + if(required_delay < delay) + { + const String& warning_msg = "[Warning] " + getInstanceName() + " -> Timing not met" + + ": Required delay = " + (String)required_delay + + ", Delay = " + (String)delay + + ", Slack = " + (String)(required_delay - delay) + + ", Number of repeaters = " + (String)number_segments; + Log::printLine(std::cerr, warning_msg); + } + } + + // Update electrical interfaces + getLoad("In_Cap")->setLoadCap(m_repeater_->getNet("A")->getTotalDownstreamCap()); + getDelay("In_to_Out_delay")->setDelay(delay); + getDriver("Out_Ron")->setOutputRes(m_repeater_->getDriver("Y_Ron")->getOutputRes() + (total_wire_res / number_segments)); + + getGenProperties()->set("NumberSegments", number_segments); + + // Update area, power results + resetElectricalAtomicResults(); + addElecticalAtomicResultValues(m_repeater_, number_segments * number_bits); + double wire_area = wire_length * (wire_width + wire_spacing) * number_bits; + addElecticalWireAtomicResultValue(wire_layer, wire_area); + + return; + } + + void RepeatedLink::useModel() + { + // Update the transition information for the modeled repeater + // 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); + m_repeater_->getInputPort("A")->setTransitionInfo(mod_trans_In); + m_repeater_->use(); + + // Get parameters + unsigned int number_bits = getParameter("NumberBits").toUInt(); + unsigned int number_segments = getGenProperties()->get("NumberSegments").toUInt(); + + // Propagate the transition information + propagateTransitionInfo(); + + // Update leakage power + double power = 0.0; + power += m_repeater_->getNddPowerResult("Leakage")->calculateSum() * number_segments * number_bits; + getNddPowerResult("Leakage")->setValue(power); + + // Update event result + double energy = 0.0; + energy += m_repeater_->getEventResult("INV")->calculateSum() * number_segments * number_bits; + getEventResult("Send")->setValue(energy); + + return; + } + + void RepeatedLink::propagateTransitionInfo() + { + unsigned int number_segments = getGenProperties()->get("NumberSegments"); + + if((number_segments % 2) == 0) + { + propagatePortTransitionInfo("Out", "In"); + } + else + { + const TransitionInfo& trans_In = getInputPort("In")->getTransitionInfo(); + TransitionInfo trans_Out(trans_In.getNumberTransitions11(), trans_In.getNumberTransitions01(), trans_In.getNumberTransitions00()); + getOutputPort("Out")->setTransitionInfo(trans_Out); + } + return; + } + +} // namespace DSENT + -- cgit v1.2.3