summaryrefslogtreecommitdiff
path: root/ext/dsent/model/electrical/RepeatedLink.cc
diff options
context:
space:
mode:
Diffstat (limited to 'ext/dsent/model/electrical/RepeatedLink.cc')
-rw-r--r--ext/dsent/model/electrical/RepeatedLink.cc305
1 files changed, 305 insertions, 0 deletions
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
+