summaryrefslogtreecommitdiff
path: root/ext/dsent/model/electrical
diff options
context:
space:
mode:
Diffstat (limited to 'ext/dsent/model/electrical')
-rw-r--r--ext/dsent/model/electrical/BarrelShifter.cc241
-rw-r--r--ext/dsent/model/electrical/BarrelShifter.h34
-rw-r--r--ext/dsent/model/electrical/BroadcastHTree.cc400
-rw-r--r--ext/dsent/model/electrical/BroadcastHTree.h54
-rw-r--r--ext/dsent/model/electrical/DFFRAM.cc321
-rw-r--r--ext/dsent/model/electrical/DFFRAM.h33
-rw-r--r--ext/dsent/model/electrical/Decoder.cc235
-rw-r--r--ext/dsent/model/electrical/Decoder.h33
-rw-r--r--ext/dsent/model/electrical/DemuxTreeDeserializer.cc378
-rw-r--r--ext/dsent/model/electrical/DemuxTreeDeserializer.h33
-rw-r--r--ext/dsent/model/electrical/MatrixArbiter.cc434
-rw-r--r--ext/dsent/model/electrical/MatrixArbiter.h33
-rw-r--r--ext/dsent/model/electrical/Multiplexer.cc347
-rw-r--r--ext/dsent/model/electrical/Multiplexer.h34
-rw-r--r--ext/dsent/model/electrical/MultiplexerCrossbar.cc214
-rw-r--r--ext/dsent/model/electrical/MultiplexerCrossbar.h38
-rw-r--r--ext/dsent/model/electrical/MuxTreeSerializer.cc226
-rw-r--r--ext/dsent/model/electrical/MuxTreeSerializer.h33
-rw-r--r--ext/dsent/model/electrical/OR.cc239
-rw-r--r--ext/dsent/model/electrical/OR.h36
-rw-r--r--ext/dsent/model/electrical/RepeatedLink.cc305
-rw-r--r--ext/dsent/model/electrical/RepeatedLink.h44
-rw-r--r--ext/dsent/model/electrical/RippleAdder.cc106
-rw-r--r--ext/dsent/model/electrical/RippleAdder.h30
-rw-r--r--ext/dsent/model/electrical/SeparableAllocator.cc270
-rw-r--r--ext/dsent/model/electrical/SeparableAllocator.h33
-rw-r--r--ext/dsent/model/electrical/TestModel.cc218
-rw-r--r--ext/dsent/model/electrical/TestModel.h32
-rw-r--r--ext/dsent/model/electrical/router/Router.cc536
-rw-r--r--ext/dsent/model/electrical/router/Router.h46
-rw-r--r--ext/dsent/model/electrical/router/RouterInputPort.cc201
-rw-r--r--ext/dsent/model/electrical/router/RouterInputPort.h33
-rw-r--r--ext/dsent/model/electrical/router/RouterSwitchAllocator.cc199
-rw-r--r--ext/dsent/model/electrical/router/RouterSwitchAllocator.h33
34 files changed, 5482 insertions, 0 deletions
diff --git a/ext/dsent/model/electrical/BarrelShifter.cc b/ext/dsent/model/electrical/BarrelShifter.cc
new file mode 100644
index 000000000..b951fc566
--- /dev/null
+++ b/ext/dsent/model/electrical/BarrelShifter.cc
@@ -0,0 +1,241 @@
+#include "model/electrical/BarrelShifter.h"
+#include "model/electrical/Multiplexer.h"
+
+#include <cmath>
+
+#include "model/PortInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/EventInfo.h"
+#include "model/timing_graph/ElectricalDriverMultiplier.h"
+#include "model/timing_graph/ElectricalNet.h"
+#include "model/std_cells/StdCell.h"
+#include "model/std_cells/StdCellLib.h"
+
+namespace DSENT
+{
+ BarrelShifter::BarrelShifter(const String& instance_name_, const TechModel* tech_model_)
+ : ElectricalModel(instance_name_, tech_model_)
+ {
+ initParameters();
+ initProperties();
+ }
+
+ BarrelShifter::~BarrelShifter()
+ {}
+
+ void BarrelShifter::initParameters()
+ {
+ addParameterName("NumberBits");
+ addParameterName("ShiftIndexMin");
+ addParameterName("ShiftIndexMax");
+ addParameterName("BitDuplicate", "TRUE");
+ return;
+ }
+
+ void BarrelShifter::initProperties()
+ {
+ return;
+ }
+
+ BarrelShifter* BarrelShifter::clone() const
+ {
+ return NULL;
+ }
+
+ void BarrelShifter::constructModel()
+ {
+ // Get parameters
+ unsigned int number_bits = getParameter("NumberBits");
+ unsigned int number_shift_bits = (unsigned int)ceil(log2((double) number_bits));
+ unsigned int shift_index_min = getParameter("ShiftIndexMin");
+ unsigned int shift_index_max = getParameter("ShiftIndexMax");
+ bool bit_duplicate = (bool) getParameter("BitDuplicate");
+
+ ASSERT(number_bits > 0, "[Error] " + getInstanceName() + " -> Number of bits must be > 0!");
+ // No need to check these if there arent any shifts
+ if (number_shift_bits > 0)
+ {
+ ASSERT(shift_index_min <= number_shift_bits,
+ "[Error] " + getInstanceName() + " -> Min shift index must be >= 0 and <= " +
+ "the total number of shift bits!");
+ ASSERT(shift_index_max >= shift_index_min && shift_index_max <= number_shift_bits,
+ "[Error] " + getInstanceName() + " -> Max shift index must be >= minimum shift index and <= " +
+ "the total number of shift bits!");
+ }
+
+ //Construct electrical ports
+ //Create each input port
+ createInputPort( "In", makeNetIndex(0, number_bits-1));
+ //Create output
+ createOutputPort( "Out", makeNetIndex(0, number_bits-1));
+
+ //Create shift ports (which only exists if there is something to shift)
+ if (shift_index_min != number_shift_bits)
+ for (unsigned int i = shift_index_min; i <= shift_index_max; ++i)
+ createInputPort( "Shift" + (String) i);
+
+ //Create energy, power, and area results
+ createElectricalResults();
+ createElectricalEventResult("BarrelShift");
+ //Set conditions during idle event
+ getEventInfo("Idle")->setStaticTransitionInfos();
+
+ //If the input is only 1-bit, connect input to output and be done
+ if (number_shift_bits == 0 || (shift_index_min == number_shift_bits))
+ assign("Out", "In");
+ else
+ {
+ for (unsigned int i = shift_index_min; i <= shift_index_max; ++i)
+ {
+ //Create internally buffered shift select signals
+ createNet("Shift_b" + (String) i);
+ createNet("Shift_i" + (String) i);
+ }
+
+ // Create shift and shifted signals
+ for (unsigned int i = shift_index_min; i <= shift_index_max; ++i)
+ {
+ unsigned int current_shifts = (unsigned int)pow(2, i);
+ const String& n = (String) current_shifts;
+ //Instantiate and connect intermediate nets. In a barrel-shifter, the nets do
+ //all the "shifting" and the muxes just select which to take
+ createNet("R_" + n, makeNetIndex(0, number_bits-1)); //wire R_n[number_bits-1:0]
+ createNet("RS_" + n, makeNetIndex(0, number_bits-1)); //wire RS_n[number_bits-1:0]
+
+ //Implements the shifts
+ //assign RS_n[number_bits-1:number_bits-current_shifts] = R_n[current_shifts-1:0];
+ assign("RS_" + n, makeNetIndex(number_bits-current_shifts, number_bits-1),
+ "R_" + n, makeNetIndex(0, current_shifts-1));
+ //assign RS_n[number_bits-current_shifts-1:0] = R_n[current_shifts:number_bits-1];
+ assign("RS_" + n, makeNetIndex(0, number_bits-current_shifts-1),
+ "R_" + n, makeNetIndex(current_shifts, number_bits-1));
+ }
+
+ const String& n_max = (String) pow(2, shift_index_max+1);
+ const String& n_min = (String) pow(2, shift_index_min);
+ // Create the R_(max) net
+ createNet("R_" + n_max, makeNetIndex(0, number_bits-1));
+ // Set R_1 to be the input
+ assign("R_" + n_min, "In");
+ // Set R_(max) to be the output
+ assign("Out", "R_" + n_max, makeNetIndex(0, number_bits-1));
+
+ for (unsigned int i = shift_index_min; i <= shift_index_max; ++i)
+ {
+ unsigned int current_shifts = (unsigned int)pow(2, i);
+ const String& n = (String) current_shifts;
+ const String& n_next = (String) (current_shifts * 2);
+
+ const String& buf_inv_0_name = "ShiftBufInv0_" + (String) n;
+ const String& buf_inv_1_name = "ShiftBufInv1_" + (String) n;
+ // Create shift buffer inverters
+ StdCell* buf_inv_0 = getTechModel()->getStdCellLib()->createStdCell("INV", buf_inv_0_name);
+ buf_inv_0->construct();
+ StdCell* buf_inv_1 = getTechModel()->getStdCellLib()->createStdCell("INV", buf_inv_1_name);
+ buf_inv_1->construct();
+
+ // Connect up shift buffer inverters
+ portConnect(buf_inv_0, "A", "Shift" + (String) i);
+ portConnect(buf_inv_0, "Y", "Shift_b" + (String) i);
+ portConnect(buf_inv_1, "A", "Shift_b" + (String) i);
+ portConnect(buf_inv_1, "Y", "Shift_i" + (String) i);
+
+ // Add area, power, and event results for inverters
+ addSubInstances(buf_inv_0, 1.0);
+ addSubInstances(buf_inv_1, 1.0);
+ addElectricalSubResults(buf_inv_0, 1.0);
+ addElectricalSubResults(buf_inv_1, 1.0);
+ getEventResult("BarrelShift")->addSubResult(buf_inv_0->getEventResult("INV"), buf_inv_0_name, 1.0);
+ getEventResult("BarrelShift")->addSubResult(buf_inv_1->getEventResult("INV"), buf_inv_1_name, 1.0);
+
+ //Instantiate 2:1 multiplexers, one for each shift bit.
+ const String& mux_name = "SRL" + n;
+ Multiplexer* mux = new Multiplexer(mux_name, getTechModel());
+ mux->setParameter("NumberInputs", 2);
+ mux->setParameter("NumberBits", number_bits);
+ mux->setParameter("BitDuplicate", bit_duplicate);
+ mux->construct();
+
+ //Just have to connect the In0 and In1 inputs of the mux to the
+ //non-shifted and shifted intermediate signals, respectively.
+ portConnect(mux, "In0", "R_" + n);
+ portConnect(mux, "In1", "RS_" + n);
+ //Selector connects to the shift signal for that index
+ portConnect(mux, "Sel0", "Shift_i" + (String) i);
+ //Connect mux output
+ portConnect(mux, "Out", "R_" + n_next);
+
+ //Add area, power, and event results for each mux
+ addSubInstances(mux, 1.0);
+ addElectricalSubResults(mux, 1.0);
+ getEventResult("BarrelShift")->addSubResult(mux->getEventResult("Mux"), mux_name, 1.0);
+ }
+ }
+ return;
+ }
+
+ void BarrelShifter::propagateTransitionInfo()
+ {
+ // The only thing can be updated are the input probabilities...so we will update them
+ unsigned int number_bits = (unsigned int) getParameter("NumberBits");
+ unsigned int number_shift_bits = (unsigned int) ceil(log2((double) number_bits));
+ unsigned int shift_index_min = getParameter("ShiftIndexMin");
+ unsigned int shift_index_max = getParameter("ShiftIndexMax");
+
+ // Keep track of the multiplexer of the last stage
+ ElectricalModel* last_mux = NULL;
+ // We only need to update stuff if we are not shifting by exact multiples
+ // of number of input bits
+ if (shift_index_min < number_shift_bits)
+ {
+ for (unsigned int i = shift_index_min; i <= shift_index_max; ++i)
+ {
+ unsigned int current_shifts = (unsigned int)pow(2, i);
+ String n = (String) current_shifts;
+
+ // Set the
+ const String& buf_inv_0_name = "ShiftBufInv0_" + (String) n;
+ const String& buf_inv_1_name = "ShiftBufInv1_" + (String) n;
+ const String& mux_name = "SRL" + n;
+
+ // Set the transition infos for the inverter buffers
+ ElectricalModel* buf_inv_0 = (ElectricalModel*) getSubInstance(buf_inv_0_name);
+ propagatePortTransitionInfo(buf_inv_0, "A", "Shift" + (String) i);
+ buf_inv_0->use();
+
+ ElectricalModel* buf_inv_1 = (ElectricalModel*) getSubInstance(buf_inv_1_name);
+ propagatePortTransitionInfo(buf_inv_1, "A", buf_inv_0, "Y");
+ buf_inv_1->use();
+
+ // Set the transition infos for the shift multiplexers
+ ElectricalModel* mux = (ElectricalModel*) getSubInstance(mux_name);
+ propagatePortTransitionInfo(mux, "Sel0", buf_inv_1, "Y");
+ if (last_mux == NULL)
+ {
+ propagatePortTransitionInfo(mux, "In0", "In");
+ propagatePortTransitionInfo(mux, "In1", "In");
+ }
+ else
+ {
+ propagatePortTransitionInfo(mux, "In0", last_mux, "Out");
+ propagatePortTransitionInfo(mux, "In1", last_mux, "Out");
+ }
+ mux->use();
+
+ // Set this to be the last mux visted
+ last_mux = mux;
+ }
+ }
+
+ // If there isn't anything to shift
+ if (last_mux == NULL)
+ propagatePortTransitionInfo("Out", "In");
+ // Take the transition info of the last mux
+ else
+ propagatePortTransitionInfo("Out", last_mux, "Out");
+
+ return;
+ }
+
+} // namespace DSENT
+
diff --git a/ext/dsent/model/electrical/BarrelShifter.h b/ext/dsent/model/electrical/BarrelShifter.h
new file mode 100644
index 000000000..e26ca9e91
--- /dev/null
+++ b/ext/dsent/model/electrical/BarrelShifter.h
@@ -0,0 +1,34 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_BARRELSHIFTER_H__
+#define __DSENT_MODEL_ELECTRICAL_BARRELSHIFTER_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+ // A model on N-bit barrel-shifter. Shifts to the right by X
+ class BarrelShifter : public ElectricalModel
+ {
+ public:
+ BarrelShifter(const String& instance_name_, const TechModel* tech_model_);
+ virtual ~BarrelShifter();
+
+ public:
+ // Set a list of properties' name needed to construct model
+ void initParameters();
+ // Set a list of properties' name needed to construct model
+ void initProperties();
+
+ // Clone and return a new instance
+ virtual BarrelShifter* clone() const;
+
+ protected:
+ // Build the model
+ virtual void constructModel();
+ virtual void propagateTransitionInfo();
+
+ }; // class BarrelShifter
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_MULTIPLEXER_H__
+
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
+
diff --git a/ext/dsent/model/electrical/BroadcastHTree.h b/ext/dsent/model/electrical/BroadcastHTree.h
new file mode 100644
index 000000000..f2c8d407b
--- /dev/null
+++ b/ext/dsent/model/electrical/BroadcastHTree.h
@@ -0,0 +1,54 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_BROADCAST_HTREE_H__
+#define __DSENT_MODEL_ELECTRICAL_BROADCAST_HTREE_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+#include <vector>
+
+namespace DSENT
+{
+ using std::vector;
+
+ class StdCell;
+ class ElectricalLoad;
+ class ElectricalTimingTree;
+
+ class BroadcastHTree : public ElectricalModel
+ {
+ public:
+ BroadcastHTree(const String& instance_name_, const TechModel* tech_model_);
+ virtual ~BroadcastHTree();
+
+ public:
+ // Set a list of properties' name needed to construct model
+ void initParameters();
+ // Set a list of properties' name needed to construct model
+ void initProperties();
+
+ // Clone and return a new instance
+ virtual BroadcastHTree* clone() const;
+
+ protected:
+ // Build the model
+ virtual void constructModel();
+ virtual void updateModel();
+ virtual void useModel();
+ virtual void propagateTransitionInfo();
+
+ private:
+ vector<StdCell*> m_repeaters_;
+ vector<ElectricalLoad*> m_repeater_loads_;
+ vector<ElectricalTimingTree*> m_timing_trees_;
+ vector<unsigned int> m_number_segments_;
+
+ vector<StdCell*> m_leaf_drivers_;
+ ElectricalLoad* m_leaf_load_;
+ StdCell* m_leaf_head_driver_;
+ ElectricalLoad* m_leaf_head_load_;
+
+ }; // class BroadcastHTree
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_BROADCAST_HTREE_H__
+
diff --git a/ext/dsent/model/electrical/DFFRAM.cc b/ext/dsent/model/electrical/DFFRAM.cc
new file mode 100644
index 000000000..604aead2f
--- /dev/null
+++ b/ext/dsent/model/electrical/DFFRAM.cc
@@ -0,0 +1,321 @@
+#include "model/electrical/DFFRAM.h"
+
+#include <cmath>
+
+#include "model/PortInfo.h"
+#include "model/EventInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/timing_graph/ElectricalDriverMultiplier.h"
+#include "model/timing_graph/ElectricalNet.h"
+#include "model/std_cells/StdCell.h"
+#include "model/std_cells/StdCellLib.h"
+#include "model/electrical/Decoder.h"
+#include "model/electrical/Multiplexer.h"
+
+namespace DSENT
+{
+ using std::ceil;
+
+ DFFRAM::DFFRAM(const String& instance_name_, const TechModel* tech_model_)
+ : ElectricalModel(instance_name_, tech_model_)
+ {
+ initParameters();
+ initProperties();
+ }
+
+ DFFRAM::~DFFRAM()
+ {}
+
+ void DFFRAM::initParameters()
+ {
+ addParameterName("NumberEntries");
+ addParameterName("NumberBits");
+ return;
+ }
+
+ void DFFRAM::initProperties()
+ {
+ return;
+ }
+
+ DFFRAM* DFFRAM::clone() const
+ {
+ // TODO
+ return NULL;
+ }
+
+ void DFFRAM::constructModel()
+ {
+ // Get parameters
+ unsigned int number_bits = getParameter("NumberBits").toUInt();
+ unsigned int number_entries = getParameter("NumberEntries").toUInt();
+
+ ASSERT(number_bits > 0, "[Error] " + getInstanceName() +
+ " -> Number of bits must be > 0!");
+ ASSERT(number_entries > 0, "[Error] " + getInstanceName() +
+ " -> Number of entries must be > 0!");
+
+ unsigned int number_addr_bits = (unsigned int)ceil(log2(number_entries));
+
+ // Create ports
+ createInputPort("In", makeNetIndex(0, number_bits-1));
+ for(unsigned int i = 0; i < number_addr_bits; ++i)
+ {
+ createInputPort("WRAddr" + (String)i);
+ createInputPort("RDAddr" + (String)i);
+ }
+ createInputPort("WE");
+ createInputPort("CK");
+ createOutputPort("Out", makeNetIndex(0, number_bits-1));
+
+ // Create energy, power, and area results
+ createElectricalResults();
+ getEventInfo("Idle")->setStaticTransitionInfos();
+ getEventInfo("Idle")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
+ getEventInfo("Idle")->setTransitionInfo("WE", TransitionInfo(1.0, 0.0, 0.0));
+
+ createElectricalEventResult("Read");
+ getEventInfo("Read")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
+ getEventInfo("Read")->setTransitionInfo("WE", TransitionInfo(1.0, 0.0, 0.0));
+ for(unsigned int i = 0; i < number_addr_bits; ++i)
+ {
+ getEventInfo("Read")->setTransitionInfo("WRAddr" + (String)i, TransitionInfo(0.5, 0.0, 0.5));
+ }
+ createElectricalEventResult("Write");
+ getEventInfo("Write")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
+ getEventInfo("Write")->setTransitionInfo("WE", TransitionInfo(0.0, 0.0, 1.0));
+ for(unsigned int i = 0; i < number_addr_bits; ++i)
+ {
+ getEventInfo("Write")->setTransitionInfo("RDAddr" + (String)i, TransitionInfo(0.5, 0.0, 0.5));
+ }
+
+ // Init components - DFF array, Dec, Mux
+ vector<String> dff_names(number_entries, "");
+ vector<StdCell*> dffs(number_entries, NULL);
+ for(unsigned int i = 0; i < number_entries; ++i)
+ {
+ dff_names[i] = "DFF_" + (String)i;
+ dffs[i] = getTechModel()->getStdCellLib()->createStdCell("DFFQ", dff_names[i]);
+ dffs[i]->construct();
+ }
+
+ const String& dec_name = "Dec";
+ Decoder* dec = new Decoder(dec_name, getTechModel());
+ dec->setParameter("NumberOutputs", number_entries);
+ dec->construct();
+
+ const String& mux_name = "Mux";
+ Multiplexer* mux = new Multiplexer(mux_name, getTechModel());
+ mux->setParameter("NumberInputs", number_entries);
+ mux->setParameter("NumberBits", 1);
+ mux->setParameter("BitDuplicate", "TRUE");
+ mux->construct();
+
+ // Init components - CK & WE
+ const String& nand2cg0_name = "NAND2_CKGate0";
+ StdCell* nand2cg0 = getTechModel()->getStdCellLib()->createStdCell("NAND2", nand2cg0_name);
+ nand2cg0->construct();
+ const String& invcg0_name = "INV_CKGate0";
+ StdCell* invcg0 = getTechModel()->getStdCellLib()->createStdCell("INV", invcg0_name);
+ invcg0->construct();
+
+ // Init components - (CK & WE) & DecOut[i]
+ vector<String> nand2cg1_names(number_entries, "");
+ vector<StdCell*> nand2cg1s(number_entries, NULL);
+ vector<String> invcg1_names(number_entries, "");
+ vector<StdCell*> invcg1s(number_entries, NULL);
+ for(unsigned int i = 0; i < number_entries; ++i)
+ {
+ nand2cg1_names[i] = "NAND2_CKGate1_" + (String)i;
+ nand2cg1s[i] = getTechModel()->getStdCellLib()->createStdCell("NAND2", nand2cg1_names[i]);
+ nand2cg1s[i]->construct();
+
+ invcg1_names[i] = "INV_CKGate1_" + (String)i;
+ invcg1s[i] = getTechModel()->getStdCellLib()->createStdCell("INV", invcg1_names[i]);
+ invcg1s[i]->construct();
+ }
+
+ // Connect Decoder
+ for(unsigned int i = 0; i < number_addr_bits; ++i)
+ {
+ portConnect(dec, "Addr" + (String)i, "WRAddr" + (String)i);
+ }
+ for(unsigned int i = 0; i < number_entries; ++i)
+ {
+ createNet("Dec_Out" + (String)i);
+ portConnect(dec, "Out" + (String)i, "Dec_Out" + (String)i);
+ }
+
+ // Connect CKGate0 - CK, WE
+ createNet("NAND2_CKGate0_Out");
+ createNet("CKGate0_Out");
+ portConnect(nand2cg0, "A", "CK");
+ portConnect(nand2cg0, "B", "WE");
+ portConnect(nand2cg0, "Y", "NAND2_CKGate0_Out");
+ portConnect(invcg0, "A", "NAND2_CKGate0_Out");
+ portConnect(invcg0, "Y", "CKGate0_Out");
+
+ // Connect CKGate1 - CKGate0, Dec_Out
+ for(unsigned int i = 0; i < number_entries; ++i)
+ {
+ createNet("NAND2_CKGate1_Outs" + (String)i);
+ createNet("CKGate1_Outs" + (String)i);
+ portConnect(nand2cg1s[i], "A", "CKGate0_Out");
+ portConnect(nand2cg1s[i], "B", "Dec_Out" + (String)i);
+ portConnect(nand2cg1s[i], "Y", "NAND2_CKGate1_Outs" + (String)i);
+ portConnect(invcg1s[i], "A", "NAND2_CKGate1_Outs" + (String)i);
+ portConnect(invcg1s[i], "Y", "CKGate1_Outs" + (String)i);
+ }
+
+ // Connect DFF array
+ for(unsigned int i = 0; i < number_entries; ++i)
+ {
+ createNet("DFF_Out" + (String)i);
+ for(unsigned int n = 0; n < number_bits; ++n)
+ {
+ portConnect(dffs[i], "D", "In", makeNetIndex(n));
+ portConnect(dffs[i], "CK", "CKGate1_Outs" + (String)i);
+ }
+ portConnect(dffs[i], "Q", "DFF_Out" + (String)i);
+ }
+
+ // Connect Multiplexer
+ createNet("Mux_Out");
+ for(unsigned int i = 0; i < number_entries; ++i)
+ {
+ portConnect(mux, "In" + (String)i, "DFF_Out" + (String)i);
+ }
+ for(unsigned int i = 0; i < number_addr_bits; ++i)
+ {
+ portConnect(mux, "Sel" + (String)i, "RDAddr" + (String)i);
+ }
+ portConnect(mux, "Out", "Mux_Out");
+
+ // Use driver multiplier to connect Mux_Out to Out
+ createDriverMultiplier("OutMult");
+ ElectricalDriverMultiplier* drive_mult = getDriverMultiplier("OutMult");
+ getNet("Mux_Out")->addDownstreamNode(drive_mult);
+ for(unsigned int n = 0; n < number_bits; ++n)
+ {
+ drive_mult->addDownstreamNode(getNet("Out", makeNetIndex(n)));
+ }
+
+ // Add area and power results
+ for(unsigned int i = 0; i < number_entries; ++i)
+ {
+ addSubInstances(dffs[i], number_bits);
+ addElectricalSubResults(dffs[i], number_bits);
+ }
+
+ addSubInstances(dec, 1.0);
+ addElectricalSubResults(dec, 1.0);
+
+ addSubInstances(mux, number_bits);
+ addElectricalSubResults(mux, number_bits);
+
+ addSubInstances(nand2cg0, 1.0);
+ addElectricalSubResults(nand2cg0, 1.0);
+
+ addSubInstances(invcg0, 1);
+ addElectricalSubResults(invcg0, 1.0);
+
+ for(unsigned int i = 0; i < number_entries; ++i)
+ {
+ addSubInstances(nand2cg1s[i], 1);
+ addElectricalSubResults(nand2cg1s[i], 1.0);
+
+ addSubInstances(invcg1s[i], 1);
+ addElectricalSubResults(invcg1s[i], 1.0);
+ }
+
+ // Add write event
+ Result* write_event = getEventResult("Write");
+ write_event->addSubResult(nand2cg0->getEventResult("NAND2"), nand2cg0_name, 1.0);
+ write_event->addSubResult(invcg0->getEventResult("INV"), invcg0_name, 1.0);
+ write_event->addSubResult(dec->getEventResult("Decode"), dec_name, 1.0);
+ for(unsigned int i = 0; i < number_entries; ++i)
+ {
+ write_event->addSubResult(nand2cg1s[i]->getEventResult("NAND2"), nand2cg1_names[i], 1.0);
+ write_event->addSubResult(invcg1s[i]->getEventResult("INV"), invcg1_names[i], 1.0);
+ write_event->addSubResult(dffs[i]->getEventResult("DFFD"), dff_names[i], number_bits);
+ write_event->addSubResult(dffs[i]->getEventResult("DFFQ"), dff_names[i], number_bits);
+ write_event->addSubResult(dffs[i]->getEventResult("CK"), dff_names[i], number_bits);
+ }
+
+ // Add read event
+ Result* read_event = getEventResult("Read");
+ //for(unsigned int i = 0; i < number_entries; ++i)
+ //{
+ // read_event->addSubResult(dffs[i]->getEventResult("DFFQ"), dff_names[i], number_bits);
+ //}
+ read_event->addSubResult(mux->getEventResult("Mux"), mux_name, number_bits);
+
+ return;
+ }
+
+ void DFFRAM::propagateTransitionInfo()
+ {
+ // Update probability
+ unsigned int number_entries = (unsigned int)getParameter("NumberEntries");
+ unsigned int number_addr_bits = (unsigned int)ceil(log2(number_entries));
+
+ // Update decoder
+ ElectricalModel* dec = (ElectricalModel*)getSubInstance("Dec");
+ for(unsigned int i = 0; i < number_addr_bits; ++i)
+ {
+ propagatePortTransitionInfo(dec, "Addr" + (String)i, "WRAddr" + (String)i);
+ }
+ dec->use();
+
+ // Update CKGate0 nands + invs
+ ElectricalModel* nand2cg0 = (ElectricalModel*)getSubInstance("NAND2_CKGate0");
+ propagatePortTransitionInfo(nand2cg0, "A", "CK");
+ propagatePortTransitionInfo(nand2cg0, "B", "WE");
+ nand2cg0->use();
+ ElectricalModel* invcg0 = (ElectricalModel*)getSubInstance("INV_CKGate0");
+ propagatePortTransitionInfo(invcg0, "A", nand2cg0, "Y");
+ invcg0->use();
+
+ // Update CKGate1 nands + invs
+ vector<ElectricalModel*> nand2cg1s(number_entries, NULL);
+ vector<ElectricalModel*> invcg1s(number_entries, NULL);
+ for(unsigned int i = 0; i < number_entries; ++i)
+ {
+ nand2cg1s[i] = (ElectricalModel*)getSubInstance("NAND2_CKGate1_" + (String)i);
+ propagatePortTransitionInfo(nand2cg1s[i], "A", invcg0, "Y");
+ propagatePortTransitionInfo(nand2cg1s[i], "B", dec, "Out" + (String)i);
+ nand2cg1s[i]->use();
+
+ invcg1s[i] = (ElectricalModel*)getSubInstance("INV_CKGate1_" + (String)i);
+ propagatePortTransitionInfo(invcg1s[i], "A", nand2cg1s[i], "Y");
+ invcg1s[i]->use();
+ }
+
+ // Update DFF
+ vector<ElectricalModel*> dffs(number_entries, NULL);
+ for(unsigned int i = 0; i < number_entries; ++i)
+ {
+ dffs[i] = (ElectricalModel*)getSubInstance("DFF_" + (String)i);
+ propagatePortTransitionInfo(dffs[i], "D", "In");
+ propagatePortTransitionInfo(dffs[i], "CK", invcg1s[i], "Y");
+ dffs[i]->use();
+ }
+
+ // Update Mux
+ ElectricalModel* mux = (ElectricalModel*)getSubInstance("Mux");
+ for(unsigned int i = 0; i < number_entries; ++i)
+ {
+ propagatePortTransitionInfo(mux, "In" + (String)i, dffs[i], "Q");
+ }
+ for(unsigned int i = 0; i < number_addr_bits; ++i)
+ {
+ propagatePortTransitionInfo(mux, "Sel" + (String)i, "RDAddr" + (String)i);
+ }
+ mux->use();
+
+ // Set output probability
+ getOutputPort("Out")->setTransitionInfo(mux->getOutputPort("Out")->getTransitionInfo());
+ return;
+ }
+} // namespace DSENT
+
diff --git a/ext/dsent/model/electrical/DFFRAM.h b/ext/dsent/model/electrical/DFFRAM.h
new file mode 100644
index 000000000..0e7626ecd
--- /dev/null
+++ b/ext/dsent/model/electrical/DFFRAM.h
@@ -0,0 +1,33 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_DFFRAM_H__
+#define __DSENT_MODEL_ELECTRICAL_DFFRAM_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+ class DFFRAM : public ElectricalModel
+ {
+ public:
+ DFFRAM(const String& instance_name_, const TechModel* tech_model_);
+ virtual ~DFFRAM();
+
+ public:
+ // Set a list of properties' name needed to construct model
+ void initParameters();
+ // Set a list of properties' name needed to construct model
+ void initProperties();
+
+ // Clone and return a new instance
+ virtual DFFRAM* clone() const;
+
+ protected:
+ // Build the model
+ virtual void constructModel();
+ virtual void propagateTransitionInfo();
+
+ }; // class DFFRAM
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_BUFFER_H__
+
diff --git a/ext/dsent/model/electrical/Decoder.cc b/ext/dsent/model/electrical/Decoder.cc
new file mode 100644
index 000000000..7629bf8b2
--- /dev/null
+++ b/ext/dsent/model/electrical/Decoder.cc
@@ -0,0 +1,235 @@
+#include "model/electrical/Decoder.h"
+
+#include <cmath>
+
+#include "model/PortInfo.h"
+#include "model/EventInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/std_cells/StdCellLib.h"
+#include "model/std_cells/StdCell.h"
+
+namespace DSENT
+{
+ using std::ceil;
+
+ Decoder::Decoder(const String& instance_name_, const TechModel* tech_model_)
+ : ElectricalModel(instance_name_, tech_model_)
+ {
+ initParameters();
+ initProperties();
+ }
+
+ Decoder::~Decoder()
+ {}
+
+ void Decoder::initParameters()
+ {
+ addParameterName("NumberOutputs");
+ }
+
+ void Decoder::initProperties()
+ {
+ return;
+ }
+
+ Decoder* Decoder::clone() const
+ {
+ // TODO
+ return NULL;
+ }
+
+ void Decoder::constructModel()
+ {
+ // Get parameters
+ unsigned int number_outputs = getParameter("NumberOutputs").toUInt();
+
+ ASSERT(number_outputs > 0, "[Error] " + getInstanceName() + " -> Number of outputs must be > 0!");
+
+ unsigned int number_addr_bits = (unsigned int)ceil(log2(number_outputs));
+
+ // Create ports
+ for(unsigned int i = 0; i < number_addr_bits; ++i)
+ {
+ createInputPort("Addr" + (String)i);
+ }
+ for(unsigned int i = 0; i < number_outputs; ++i)
+ {
+ createOutputPort("Out" + (String)i);
+ }
+
+ // Create energy, power, and area results
+ createElectricalResults();
+ createElectricalEventResult("Decode");
+ Result* decode_event = getEventResult("Decode");
+
+ getEventInfo("Idle")->setStaticTransitionInfos();
+
+ if(number_addr_bits == 0)
+ {
+ // Do not need a decoder
+ }
+ else if(number_addr_bits == 1)
+ {
+ const String& inv0_name = "Inv0";
+
+ StdCell* inv0 = getTechModel()->getStdCellLib()->createStdCell("INV", inv0_name);
+ inv0->construct();
+
+ // Connect inputs and outputs
+ portConnect(inv0, "A", "Addr0");
+ portConnect(inv0, "Y", "Out0");
+ assign("Out1", "Addr0");
+
+ // Add area, power, and event results
+ addSubInstances(inv0, 1.0);
+ addElectricalSubResults(inv0, 1.0);
+ decode_event->addSubResult(inv0->getEventResult("INV"), inv0_name, 1.0);
+ }
+ else
+ {
+ unsigned int number_addr_bits_0 = (unsigned int)ceil((double)number_addr_bits / 2.0);
+ unsigned int number_addr_bits_1 = (unsigned int)floor((double)number_addr_bits / 2.0);
+
+ unsigned int number_outputs_0 = (unsigned int)pow(2.0, number_addr_bits_0);
+ unsigned int number_outputs_1 = (unsigned int)ceil((double)number_outputs / (double)number_outputs_0);
+
+ const String& dec0_name = "Dec_way0";
+ const String& dec1_name = "Dec_way1";
+ vector<String> nand2_names(number_outputs, "");
+ vector<String> inv_names(number_outputs, "");
+ for(unsigned int i = 0; i < number_outputs; ++i)
+ {
+ nand2_names[i] = "NAND2_" + (String)i;
+ inv_names[i] = "INV_" + (String)i;
+ }
+
+ Decoder* dec0 = new Decoder(dec0_name, getTechModel());
+ dec0->setParameter("NumberOutputs", number_outputs_0);
+ dec0->construct();
+
+ Decoder* dec1 = new Decoder(dec1_name, getTechModel());
+ dec1->setParameter("NumberOutputs", number_outputs_1);
+ dec1->construct();
+
+ vector<StdCell*> nand2s(number_outputs, NULL);
+ vector<StdCell*> invs(number_outputs, NULL);
+ for(unsigned int i = 0; i < number_outputs; ++i)
+ {
+ nand2s[i] = getTechModel()->getStdCellLib()->createStdCell("NAND2", nand2_names[i]);
+ nand2s[i]->construct();
+ invs[i] = getTechModel()->getStdCellLib()->createStdCell("INV", inv_names[i]);
+ invs[i]->construct();
+ }
+
+ // Connect inputs and outputs
+ for(unsigned int i = 0; i < number_addr_bits_0; ++i)
+ {
+ portConnect(dec0, "Addr" + (String)i, "Addr" + (String)i);
+ }
+ for(unsigned int i = 0; i < number_addr_bits_1; ++i)
+ {
+ portConnect(dec1, "Addr" + (String)i, "Addr" + (String)(i + number_addr_bits_0));
+ }
+ for(unsigned int i = 0; i < number_outputs_0; ++i)
+ {
+ createNet("way0Out" + (String)i);
+ portConnect(dec0, "Out" + (String)i, "way0Out" + (String)i);
+ }
+ for(unsigned int i = 0; i < number_outputs_1; ++i)
+ {
+ createNet("way1Out" + (String)i);
+ portConnect(dec1, "Out" + (String)i, "way1Out" + (String)i);
+ }
+
+ for(unsigned int i = 0; i < number_outputs; ++i)
+ {
+ createNet("nand" + (String)i + "Out");
+ portConnect(nand2s[i], "A", "way0Out" + (String)(i%number_outputs_0));
+ portConnect(nand2s[i], "B", "way1Out" + (String)((unsigned int)floor(i/number_outputs_0)));
+ portConnect(nand2s[i], "Y", "nand" + (String)i + "Out");
+ portConnect(invs[i], "A", "nand" + (String)i + "Out");
+ portConnect(invs[i], "Y", "Out" + (String)i);
+ }
+
+ // Add area, power, and event results
+ addSubInstances(dec0, 1.0);
+ addElectricalSubResults(dec0, 1.0);
+ decode_event->addSubResult(dec0->getEventResult("Decode"), dec0_name, 1.0);
+ addSubInstances(dec1, 1.0);
+ addElectricalSubResults(dec1, 1.0);
+ decode_event->addSubResult(dec1->getEventResult("Decode"), dec1_name, 1.0);
+ for(unsigned int i = 0; i < number_outputs; ++i)
+ {
+ addSubInstances(nand2s[i], 1.0);
+ addElectricalSubResults(nand2s[i], 1.0);
+ decode_event->addSubResult(nand2s[i]->getEventResult("NAND2"), nand2_names[i], 1.0);
+
+ addSubInstances(invs[i], 1.0);
+ addElectricalSubResults(invs[i], 1.0);
+ decode_event->addSubResult(invs[i]->getEventResult("INV"), inv_names[i], 1.0);
+ }
+ }
+ return;
+ }
+
+ void Decoder::propagateTransitionInfo()
+ {
+ // The only thing can be updated are the input probabilities
+ unsigned int number_outputs = getParameter("NumberOutputs").toUInt();
+
+ unsigned int number_addr_bits = (unsigned int)ceil(log2(number_outputs));
+
+ if(number_addr_bits == 0)
+ {
+ // Do not need a decoder
+ }
+ else if(number_addr_bits == 1)
+ {
+ ElectricalModel* inv0 = (ElectricalModel*)getSubInstance("Inv0");
+ propagatePortTransitionInfo(inv0, "A", "Addr0");
+ inv0->use();
+
+ // Since # addr bits is 1, the output 0 is directly connected
+ propagatePortTransitionInfo("Out0", inv0, "Y");
+ propagatePortTransitionInfo("Out1", "Addr0");
+ }
+ else
+ {
+ unsigned int number_addr_bits_0 = (unsigned int)ceil((double)number_addr_bits / 2.0);
+ unsigned int number_addr_bits_1 = (unsigned int)floor((double)number_addr_bits / 2.0);
+
+ unsigned int number_outputs_0 = (unsigned int)pow(2.0, number_addr_bits_0);
+
+ // Update decoders with probabilities
+ ElectricalModel* dec0 = (ElectricalModel*)getSubInstance("Dec_way0");
+ for(unsigned int i = 0; i < number_addr_bits_0; ++i)
+ {
+ propagatePortTransitionInfo(dec0, "Addr" + (String)i, "Addr" + (String)i);
+ }
+ dec0->use();
+ ElectricalModel* dec1 = (ElectricalModel*)getSubInstance("Dec_way1");
+ for(unsigned int i = 0; i < number_addr_bits_1; ++i)
+ {
+ propagatePortTransitionInfo(dec1, "Addr" + (String)i, "Addr" + (String)(i + number_addr_bits_0));
+ }
+ dec1->use();
+
+ for(unsigned int i = 0; i < number_outputs; ++i)
+ {
+ ElectricalModel* nand2 = (ElectricalModel*)getSubInstance("NAND2_" + (String)i);
+ propagatePortTransitionInfo(nand2, "A", dec0, "Out" + (String)(i%number_outputs_0));
+ propagatePortTransitionInfo(nand2, "B", dec1, "Out" + (String)((unsigned int)floor(i/number_outputs_0)));
+ nand2->use();
+
+ ElectricalModel* inv = (ElectricalModel*)getSubInstance("INV_" + (String)i);
+ propagatePortTransitionInfo(inv, "A", nand2, "Y");
+ inv->use();
+
+ propagatePortTransitionInfo("Out" + (String)i, inv, "Y");
+ }
+ }
+ return;
+ }
+
+} // namespace DSENT
+
diff --git a/ext/dsent/model/electrical/Decoder.h b/ext/dsent/model/electrical/Decoder.h
new file mode 100644
index 000000000..3c09fc4ef
--- /dev/null
+++ b/ext/dsent/model/electrical/Decoder.h
@@ -0,0 +1,33 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_DECODER_H__
+#define __DSENT_MODEL_ELECTRICAL_DECODER_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+ class Decoder : public ElectricalModel
+ {
+ public:
+ Decoder(const String& instance_name_, const TechModel* tech_model_);
+ virtual ~Decoder();
+
+ public:
+ // Set a list of properties' name needed to construct model
+ void initParameters();
+ // Set a list of properties' name needed to construct model
+ void initProperties();
+
+ // Clone and return a new instance
+ virtual Decoder* clone() const;
+
+ protected:
+ // Build the model
+ virtual void constructModel();
+ virtual void propagateTransitionInfo();
+
+ }; // class Decoder
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_DECODER_H__
+
diff --git a/ext/dsent/model/electrical/DemuxTreeDeserializer.cc b/ext/dsent/model/electrical/DemuxTreeDeserializer.cc
new file mode 100644
index 000000000..4d74e8db2
--- /dev/null
+++ b/ext/dsent/model/electrical/DemuxTreeDeserializer.cc
@@ -0,0 +1,378 @@
+#include "model/electrical/DemuxTreeDeserializer.h"
+
+#include <cmath>
+
+#include "model/PortInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/EventInfo.h"
+#include "model/std_cells/StdCellLib.h"
+#include "model/std_cells/StdCell.h"
+#include "model/electrical/Multiplexer.h"
+#include "model/timing_graph/ElectricalNet.h"
+
+namespace DSENT
+{
+ using std::ceil;
+
+ DemuxTreeDeserializer::DemuxTreeDeserializer(const String& instance_name_, const TechModel* tech_model_)
+ : ElectricalModel(instance_name_, tech_model_)
+ {
+ initParameters();
+ initProperties();
+ }
+
+ DemuxTreeDeserializer::~DemuxTreeDeserializer()
+ {}
+
+ void DemuxTreeDeserializer::initParameters()
+ {
+ addParameterName("InDataRate");
+ addParameterName("OutDataRate");
+ addParameterName("OutBits"); //Output width will just be output width / serialization ratio
+ addParameterName("BitDuplicate", "TRUE");
+ return;
+ }
+
+ void DemuxTreeDeserializer::initProperties()
+ {
+ return;
+ }
+
+ DemuxTreeDeserializer* DemuxTreeDeserializer::clone() const
+ {
+ // TODO
+ return NULL;
+ }
+
+ void DemuxTreeDeserializer::constructModel()
+ {
+
+ // Get parameters
+ double in_data_rate = getParameter("InDataRate");
+ double out_data_rate = getParameter("OutDataRate");
+ unsigned int out_bits = getParameter("OutBits");
+ bool bit_duplicate = getParameter("BitDuplicate");
+
+ // Calculate deserialization ratio
+ unsigned int deserialization_ratio = (unsigned int) floor(in_data_rate / out_data_rate);
+ ASSERT(deserialization_ratio == in_data_rate / out_data_rate,
+ "[Error] " + getInstanceName() + " -> Cannot have non-integer deserialization ratios!");
+ ASSERT((deserialization_ratio & (deserialization_ratio - 1)) == 0,
+ "[Error] " + getInstanceName() + " -> Deserialization ratio must be a power of 2");
+
+ // Calculate output width
+ unsigned int input_bits = out_bits / deserialization_ratio;
+ ASSERT(out_bits >= deserialization_ratio, "[Error] " + getInstanceName() +
+ " -> Output width must be >= deserialization ratio!");
+ ASSERT(floor((double) out_bits / deserialization_ratio) == input_bits,
+ "[Error] " + getInstanceName() + " -> Output width must be a multiple of the serialization ratio!");
+
+ // Store calculated numbers
+ getGenProperties()->set("DeserializationRatio", deserialization_ratio);
+ getGenProperties()->set("InputBits", input_bits);
+
+ // Create ports
+ createInputPort("In", makeNetIndex(0, input_bits-1));
+ createInputPort("InCK");
+ createOutputPort("Out", makeNetIndex(0, out_bits-1));
+
+ //Create energy, power, and area results
+ createElectricalResults();
+ createElectricalEventResult("Deserialize");
+ getEventInfo("Deserialize")->setTransitionInfo("InCK", TransitionInfo(0.0, (double) deserialization_ratio / 2.0, 0.0));
+ // Set conditions during idle state
+ getEventInfo("Idle")->setStaticTransitionInfos();
+ getEventInfo("Idle")->setTransitionInfo("InCK", TransitionInfo(0.0, (double) deserialization_ratio / 2.0, 0.0));
+
+ // Mark InCK as a false path (since timing tool will do strange stuff due to all the clock divides and stuff)
+ getNet("InCK")->setFalsePath(true);
+
+ // Create deserializer
+ if (deserialization_ratio == 1)
+ {
+ // No need to do anything, hohoho
+ assign("Out", "In");
+ }
+ else if (input_bits == 1)
+ {
+ //-----------------------------------------------------------------
+ // Create 2:1 demux deserializer
+ //-----------------------------------------------------------------
+ const String& des_dff_way0_name = "DesDFFWay0";
+ const String& des_dff_way1_name = "DesDFFWay1";
+ const String& des_latch_name = "DesLatch";
+ const String& ck_dff_name = "CKDFF";
+ const String& ck_inv_name = "CKINV";
+ const String& out_way0_name = "OutWay0";
+ const String& out_way1_name = "OutWay1";
+ const String& mid_way0_name = "MidWay0";
+ const String& ck_div2_name = "CK_div2";
+ const String& ck_div2_b_name = "CK_div2_b";
+
+ // Create nets
+ createNet(out_way0_name);
+ createNet(out_way1_name);
+ createNet(mid_way0_name);
+ createNet(ck_div2_name);
+ createNet(ck_div2_b_name);
+
+ // Create the dffs and latch needed on both ways
+ StdCell* des_dff_way0 = getTechModel()->getStdCellLib()->createStdCell("DFFQ", des_dff_way0_name);
+ des_dff_way0->construct();
+ StdCell* des_dff_way1 = getTechModel()->getStdCellLib()->createStdCell("DFFQ", des_dff_way1_name);
+ des_dff_way1->construct();
+ StdCell* des_latch = getTechModel()->getStdCellLib()->createStdCell("LATQ", des_latch_name);
+ des_latch->construct();
+
+ // Create clk divide circuit
+ StdCell* ck_dff = getTechModel()->getStdCellLib()->createStdCell("DFFQ", ck_dff_name);
+ ck_dff->construct();
+ StdCell* ck_inv = getTechModel()->getStdCellLib()->createStdCell("INV", ck_inv_name);
+ ck_inv->construct();
+
+ // Connect ports
+ portConnect(des_dff_way0, "CK", "InCK");
+ portConnect(des_dff_way0, "D", mid_way0_name);
+ portConnect(des_dff_way0, "Q", out_way0_name);
+ portConnect(des_latch, "G", "InCK");
+ portConnect(des_latch, "D", "In");
+ portConnect(des_latch, "Q", mid_way0_name);
+ portConnect(des_dff_way1, "CK", "InCK");
+ portConnect(des_dff_way1, "D", "In");
+ portConnect(des_dff_way1, "Q", out_way1_name);
+ portConnect(ck_dff, "CK", "InCK");
+ portConnect(ck_dff, "D", ck_div2_b_name);
+ portConnect(ck_dff, "Q", ck_div2_name);
+ portConnect(ck_inv, "A", ck_div2_name);
+ portConnect(ck_inv, "Y", ck_div2_b_name);
+
+ // Add sub instances
+ addSubInstances(des_dff_way0, 1.0);
+ addElectricalSubResults(des_dff_way0, 1.0);
+ addSubInstances(des_dff_way1, 1.0);
+ addElectricalSubResults(des_dff_way1, 1.0);
+ addSubInstances(des_latch, 1.0);
+ addElectricalSubResults(des_latch, 1.0);
+ addSubInstances(ck_dff, 1.0);
+ addElectricalSubResults(ck_dff, 1.0);
+ addSubInstances(ck_inv, 1.0);
+ addElectricalSubResults(ck_inv, 1.0);
+
+ Result* deserialize = getEventResult("Deserialize");
+ deserialize->addSubResult(des_dff_way0->getEventResult("CK"), des_dff_way0_name, 1.0);
+ deserialize->addSubResult(des_dff_way0->getEventResult("DFFD"), des_dff_way0_name, 1.0);
+ deserialize->addSubResult(des_dff_way0->getEventResult("DFFQ"), des_dff_way0_name, 1.0);
+ deserialize->addSubResult(des_dff_way1->getEventResult("CK"), des_dff_way1_name, 1.0);
+ deserialize->addSubResult(des_dff_way1->getEventResult("DFFD"), des_dff_way1_name, 1.0);
+ deserialize->addSubResult(des_dff_way1->getEventResult("DFFQ"), des_dff_way1_name, 1.0);
+ deserialize->addSubResult(des_latch->getEventResult("G"), des_latch_name, 1.0);
+ deserialize->addSubResult(des_latch->getEventResult("LATD"), des_latch_name, 1.0);
+ deserialize->addSubResult(des_latch->getEventResult("LATQ"), des_latch_name, 1.0);
+ deserialize->addSubResult(ck_dff->getEventResult("CK"), ck_dff_name, 1.0);
+ deserialize->addSubResult(ck_dff->getEventResult("DFFD"), ck_dff_name, 1.0);
+ deserialize->addSubResult(ck_dff->getEventResult("DFFQ"), ck_dff_name, 1.0);
+ deserialize->addSubResult(ck_inv->getEventResult("INV"), ck_inv_name, 1.0);
+ //-----------------------------------------------------------------
+
+ //-----------------------------------------------------------------
+ // Create Sub-deserializers
+ //-----------------------------------------------------------------
+ // Create sub-deserializers
+ const String& demux_way0_name = "DemuxTree_way0_" + (String) deserialization_ratio + "_to_1";
+ const String& demux_way1_name = "DemuxTree_way1_" + (String) deserialization_ratio + "_to_1";
+
+ DemuxTreeDeserializer* demux_way0 = new DemuxTreeDeserializer(demux_way0_name, getTechModel());
+ demux_way0->setParameter("InDataRate", in_data_rate / 2.0);
+ demux_way0->setParameter("OutDataRate", out_data_rate);
+ demux_way0->setParameter("OutBits", out_bits / 2);
+ demux_way0->setParameter("BitDuplicate", "TRUE");
+ demux_way0->construct();
+
+ DemuxTreeDeserializer* demux_way1 = new DemuxTreeDeserializer(demux_way1_name, getTechModel());
+ demux_way1->setParameter("InDataRate", in_data_rate / 2.0);
+ demux_way1->setParameter("OutDataRate", out_data_rate);
+ demux_way1->setParameter("OutBits", out_bits / 2);
+ demux_way1->setParameter("BitDuplicate", "TRUE");
+ demux_way1->construct();
+
+ // Connect ports
+ portConnect(demux_way0, "In", out_way0_name);
+ portConnect(demux_way0, "InCK", ck_div2_name);
+ portConnect(demux_way0, "Out", "Out", makeNetIndex(0, out_bits/2-1));
+
+ portConnect(demux_way1, "In", out_way1_name);
+ portConnect(demux_way1, "InCK", ck_div2_name);
+ portConnect(demux_way1, "Out", "Out", makeNetIndex(out_bits/2, out_bits-1));
+
+ // Add subinstances and area results
+ addSubInstances(demux_way0, 1.0);
+ addElectricalSubResults(demux_way0, 1.0);
+ addSubInstances(demux_way1, 1.0);
+ addElectricalSubResults(demux_way1, 1.0);
+
+ deserialize->addSubResult(demux_way0->getEventResult("Deserialize"), demux_way0_name, 1.0);
+ deserialize->addSubResult(demux_way1->getEventResult("Deserialize"), demux_way1_name, 1.0);
+ //-----------------------------------------------------------------
+
+ }
+ else if (bit_duplicate)
+ {
+ const String& demux_name = "DemuxTree_" + (String) deserialization_ratio + "_to_1";
+
+ DemuxTreeDeserializer* des_bit = new DemuxTreeDeserializer(demux_name, getTechModel());
+ des_bit->setParameter("InDataRate", in_data_rate);
+ des_bit->setParameter("OutDataRate", out_data_rate);
+ des_bit->setParameter("OutBits", deserialization_ratio);
+ des_bit->setParameter("BitDuplicate", "TRUE");
+ des_bit->construct();
+
+ // Create VFI and VFO nets
+ createNet("InVFI");
+ createNet("OutVFO", makeNetIndex(0, deserialization_ratio-1));
+
+ // Connect ports
+ portConnect(des_bit, "In", "InVFI");
+ portConnect(des_bit, "Out", "OutVFO");
+
+ // Do VFI and VFO
+ assignVirtualFanin("InVFI", "In");
+ for (unsigned int i = 0; i < input_bits; ++i)
+ {
+ portConnect(des_bit, "InCK", "InCK");
+ for (unsigned int j = 0; j < deserialization_ratio; ++j)
+ assignVirtualFanout("Out", makeNetIndex(i*deserialization_ratio + j), "OutVFO", makeNetIndex(j));
+ }
+ // Add subinstances and area results
+ addSubInstances(des_bit, input_bits);
+ addElectricalSubResults(des_bit, input_bits);
+ getEventResult("Deserialize")->addSubResult(des_bit->getEventResult("Deserialize"), demux_name, input_bits);
+ }
+ else
+ {
+ //Instantiate a bunch of 1 input bit deserializers
+ for (unsigned int i = 0; i < input_bits; ++i)
+ {
+ const String& demux_name = "DemuxTree_" + (String) deserialization_ratio + "_to_1_bit" + (String) i;
+
+ DemuxTreeDeserializer* des_bit = new DemuxTreeDeserializer(demux_name, getTechModel());
+ des_bit->setParameter("InDataRate", in_data_rate);
+ des_bit->setParameter("OutDataRate", out_data_rate);
+ des_bit->setParameter("OutBits", deserialization_ratio);
+ des_bit->setParameter("BitDuplicate", "TRUE");
+ des_bit->construct();
+
+ portConnect(des_bit, "In", "In", makeNetIndex(i));
+ portConnect(des_bit, "InCK", "InCK");
+ portConnect(des_bit, "Out", "Out", makeNetIndex(i*deserialization_ratio, (i+1)*deserialization_ratio-1));
+
+ addSubInstances(des_bit, 1.0);
+ addElectricalSubResults(des_bit, 1.0);
+ getEventResult("Deserialize")->addSubResult(des_bit->getEventResult("Deserialize"), demux_name, 1.0);
+ }
+ }
+
+ return;
+ }
+
+ void DemuxTreeDeserializer::propagateTransitionInfo()
+ {
+ // Get parameters
+ bool bit_duplicate = getParameter("BitDuplicate");
+ // Get generated properties
+ unsigned int deserialization_ratio = getGenProperties()->get("DeserializationRatio");
+ unsigned int input_bits = getGenProperties()->get("InputBits");
+
+ // Calculate output transitions and activities
+ if (deserialization_ratio == 1)
+ {
+ // If no deserialization, then just propagate input transition info to output port
+ propagatePortTransitionInfo("Out", "In");
+ }
+ else if (input_bits == 1)
+ {
+ const String& des_dff_way0_name = "DesDFFWay0";
+ const String& des_dff_way1_name = "DesDFFWay1";
+ const String& des_latch_name = "DesLatch";
+ const String& ck_dff_name = "CKDFF";
+ const String& ck_inv_name = "CKINV";
+
+ // Sub-deserializer names
+ const String& demux_way0_name = "DemuxTree_way0_" + (String) deserialization_ratio + "_to_1";
+ const String& demux_way1_name = "DemuxTree_way1_" + (String) deserialization_ratio + "_to_1";
+
+ // Update transition info for deserialization registers/latches
+ ElectricalModel* des_latch = (ElectricalModel*) getSubInstance(des_latch_name);
+ propagatePortTransitionInfo(des_latch, "G", "InCK");
+ propagatePortTransitionInfo(des_latch, "D", "In");
+ des_latch->use();
+
+ ElectricalModel* des_dff_way0 = (ElectricalModel*) getSubInstance(des_dff_way0_name);
+ propagatePortTransitionInfo(des_dff_way0, "CK", "InCK");
+ propagatePortTransitionInfo(des_dff_way0, "D", des_latch, "Q");
+ des_dff_way0->use();
+
+ ElectricalModel* des_dff_way1 = (ElectricalModel*) getSubInstance(des_dff_way1_name);
+ propagatePortTransitionInfo(des_dff_way1, "CK", "InCK");
+ propagatePortTransitionInfo(des_dff_way1, "D", "In");
+ des_dff_way1->use();
+
+ // Get input transitions of input clock
+ double P01_CK = getInputPort("InCK")->getTransitionInfo().getNumberTransitions01();
+ // Update transition info for clk division DFF
+ ElectricalModel* ck_dff = (ElectricalModel*) getSubInstance(ck_dff_name);
+ propagatePortTransitionInfo(ck_dff, "CK", "InCK");
+ // Since it is a clock divider, P01 is D and Q are simply half the P01 of D and Q of
+ // the input clock
+ if (P01_CK != 0) ck_dff->getInputPort("D")->setTransitionInfo(TransitionInfo(0.0, P01_CK * 0.5, 0.0));
+ else ck_dff->getInputPort("D")->setTransitionInfo(TransitionInfo(0.5, 0.0, 0.5));
+
+ ck_dff->use();
+ // Update transition info of clk divided inverter
+ ElectricalModel* ck_inv = (ElectricalModel*) getSubInstance(ck_inv_name);
+ propagatePortTransitionInfo(ck_inv, "A", ck_dff, "Q");
+ ck_inv->use();
+
+ // Update transition info for next demux stages
+ ElectricalModel* demux_way0 = (ElectricalModel*) getSubInstance(demux_way0_name);
+ propagatePortTransitionInfo(demux_way0, "In", des_dff_way0, "Q");
+ propagatePortTransitionInfo(demux_way0, "InCK", ck_dff, "Q");
+ demux_way0->use();
+ ElectricalModel* demux_way1 = (ElectricalModel*) getSubInstance(demux_way1_name);
+ propagatePortTransitionInfo(demux_way1, "In", des_dff_way1, "Q");
+ propagatePortTransitionInfo(demux_way1, "InCK", ck_dff, "Q");
+ demux_way1->use();
+
+ propagatePortTransitionInfo("Out", demux_way0, "Out");
+ }
+ else if (bit_duplicate)
+ {
+ // Propagate transition info
+ const String& demux_name = "DemuxTree_" + (String) deserialization_ratio + "_to_1";
+ ElectricalModel* demux = (ElectricalModel*) getSubInstance(demux_name);
+ propagatePortTransitionInfo(demux, "In", "In");
+ propagatePortTransitionInfo(demux, "InCK", "InCK");
+ demux->use();
+
+ propagatePortTransitionInfo("Out", demux, "Out");
+ }
+ else
+ {
+ // Set output probability to be average that of probabilties of each output bit
+ // Update all 1 bit deserializers
+ for (unsigned int i = 0; i < input_bits; ++i)
+ {
+ const String& demux_name = "DemuxTree_" + (String) deserialization_ratio + "_to_1_bit" + (String) i;
+ ElectricalModel* demux_bit = (ElectricalModel*) getSubInstance(demux_name);
+ propagatePortTransitionInfo(demux_bit, "In", "In");
+ propagatePortTransitionInfo(demux_bit, "InCK", "InCK");
+ demux_bit->use();
+
+ propagatePortTransitionInfo("Out", demux_bit, "Out");
+ }
+ }
+
+ return;
+ }
+
+} // namespace DSENT
+
diff --git a/ext/dsent/model/electrical/DemuxTreeDeserializer.h b/ext/dsent/model/electrical/DemuxTreeDeserializer.h
new file mode 100644
index 000000000..216614193
--- /dev/null
+++ b/ext/dsent/model/electrical/DemuxTreeDeserializer.h
@@ -0,0 +1,33 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_MULTIPHASEDESERIALIZER_H__
+#define __DSENT_MODEL_ELECTRICAL_MULTIPHASEDESERIALIZER_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+ class DemuxTreeDeserializer : public ElectricalModel
+ {
+ public:
+ DemuxTreeDeserializer(const String& instance_name_, const TechModel* tech_model_);
+ virtual ~DemuxTreeDeserializer();
+
+ public:
+ // Set a list of properties' name needed to construct model
+ void initParameters();
+ // Set a list of properties' name needed to construct model
+ void initProperties();
+
+ // Clone and return a new instance
+ virtual DemuxTreeDeserializer* clone() const;
+
+ protected:
+ // Build the model
+ virtual void constructModel();
+ virtual void propagateTransitionInfo();
+
+ }; // class DemuxTreeDeserializer
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_MULTIPHASEDESERIALIZER_H__
+
diff --git a/ext/dsent/model/electrical/MatrixArbiter.cc b/ext/dsent/model/electrical/MatrixArbiter.cc
new file mode 100644
index 000000000..7f72abd63
--- /dev/null
+++ b/ext/dsent/model/electrical/MatrixArbiter.cc
@@ -0,0 +1,434 @@
+#include "model/electrical/MatrixArbiter.h"
+
+#include <cmath>
+#include <vector>
+
+#include "model/PortInfo.h"
+#include "model/EventInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/ModelGen.h"
+#include "model/std_cells/StdCell.h"
+#include "model/std_cells/StdCellLib.h"
+
+namespace DSENT
+{
+ using std::abs;
+ using std::vector;
+
+ MatrixArbiter::MatrixArbiter(const String& instance_name_, const TechModel* tech_model_)
+ : ElectricalModel(instance_name_, tech_model_)
+ {
+ initParameters();
+ initProperties();
+ }
+
+ MatrixArbiter::~MatrixArbiter()
+ {}
+
+ void MatrixArbiter::initParameters()
+ {
+ addParameterName("NumberRequests");
+ return;
+ }
+
+ void MatrixArbiter::initProperties()
+ {
+ return;
+ }
+
+ MatrixArbiter* MatrixArbiter::clone() const
+ {
+ // TODO
+ return NULL;
+ }
+
+ void MatrixArbiter::constructModel()
+ {
+ // Get parameters
+ unsigned int number_requests = getParameter("NumberRequests").toUInt();
+
+ ASSERT(number_requests > 0, "[Error] " + getInstanceName() +
+ " -> Number of requests must be > 0!");
+
+ // Connect ports
+ createInputPort("CK");
+ for(unsigned int i = 0; i < number_requests; ++i)
+ {
+ createInputPort("Request" + (String)i);
+ createOutputPort("Grant" + (String)i);
+ }
+
+ // Create area, power, event results
+ createElectricalResults();
+ getEventInfo("Idle")->setStaticTransitionInfos();
+ getEventInfo("Idle")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
+// for(unsigned int i = 0; i <= number_requests; ++i)
+// {
+// // Create arbitrate event with i requests
+// createElectricalEventResult("Arbitrate" + (String)i);
+// EventInfo* event_info = getEventInfo("Arbitrate" + (String)i);
+// event_info->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
+//
+// for(unsigned int j = 0; j < i; ++j)
+// {
+// event_info->setTransitionInfo("Request" + (String)j, TransitionInfo(0.0, 0.0, 1.0));
+// }
+// for(unsigned int j = i; j < number_requests; ++j)
+// {
+// event_info->setTransitionInfo("Request" + (String)j, TransitionInfo(1.0, 0.0, 0.0));
+//
+// }
+// //double P_0 = (double)(number_requests - i) / (double)(number_requests);
+// //double P_1 = (double)(i) / (double)(number_requests);
+// //TransitionInfo trans(P_0 * P_0, P_0 * P_1, P_1 * P_1);
+//
+// //for(unsigned int j = 0; j < number_requests; ++j)
+// //{
+// // event_info->setTransitionInfo("Request" + (String)j, trans);
+// //}
+// }
+ createElectricalEventResult("Arbitrate");
+ getEventInfo("Arbitrate")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
+ for(unsigned int i = 0; i < number_requests; ++i)
+ {
+ getEventInfo("Arbitrate")->setTransitionInfo("Request" + (String)i, TransitionInfo(0.25, 0.25, 0.25));
+ }
+
+ if(number_requests == 1)
+ {
+ assign("Grant0", "Request0");
+ }
+ else
+ {
+ // Init components
+ vector<String> g_inv_names(number_requests, "");
+ vector<StdCell*> g_invs(number_requests, NULL);
+ vector<String> g_and2_names(number_requests, "");
+ vector<StdCell*> g_and2s(number_requests, NULL);
+ for(unsigned int i = 0; i < number_requests; ++i)
+ {
+ g_inv_names[i] = "G_INV" + (String)i;
+ g_and2_names[i] = "G_AND2" + (String)i;
+ g_invs[i] = getTechModel()->getStdCellLib()->createStdCell("INV", g_inv_names[i]);
+ g_invs[i]->construct();
+ g_and2s[i] = getTechModel()->getStdCellLib()->createStdCell("AND2", g_and2_names[i]);
+ g_and2s[i]->construct();
+ }
+
+ unsigned int number_states = (number_requests - 1) * number_requests / 2;
+
+ vector<String> w_or2_names(number_states, "");
+ vector<StdCell*> w_or2s(number_states, NULL);
+ vector<String> w_and2_names(number_states, "");
+ vector<StdCell*> w_and2s(number_states, NULL);
+ vector<String> w_inv_names(number_states, "");
+ vector<StdCell*> w_invs(number_states, NULL);
+ vector<String> w_dff_names(number_states, "");
+ vector<StdCell*> w_dffs(number_states, NULL);
+ vector<String> dis_and2_names(number_states * 2, "");
+ vector<StdCell*> dis_and2s(number_states * 2, NULL);
+ vector<String> dis_inv_names(number_states, "");
+ vector<StdCell*> dis_invs(number_states, NULL);
+ unsigned int state_count = 0;
+ for(unsigned int i = 0; i < number_requests; ++i)
+ {
+ for(unsigned int j = i + 1; j < number_requests; ++j)
+ {
+ w_or2_names[state_count] = String::format("W_OR2_%d_%d", i, j);
+ w_and2_names[state_count] = String::format("W_AND2_%d_%d", i, j);
+ w_inv_names[state_count] = String::format("W_INV_%d_%d", i, j);
+ w_dff_names[state_count] = String::format("W_DFF_%d_%d", i, j);
+ w_or2s[state_count] = getTechModel()->getStdCellLib()->createStdCell("OR2", w_or2_names[state_count]);
+ w_or2s[state_count]->construct();
+ w_and2s[state_count] = getTechModel()->getStdCellLib()->createStdCell("AND2", w_and2_names[state_count]);
+ w_and2s[state_count]->construct();
+ w_invs[state_count] = getTechModel()->getStdCellLib()->createStdCell("INV", w_inv_names[state_count]);
+ w_invs[state_count]->construct();
+ w_dffs[state_count] = getTechModel()->getStdCellLib()->createStdCell("DFFQ", w_dff_names[state_count]);
+ w_dffs[state_count]->construct();
+
+ dis_inv_names[state_count] = String::format("Dis_INV_%d_%d", i, j);
+ dis_and2_names[state_count] = String::format("Dis_AND2_%d_%d", i, j);
+ dis_and2_names[state_count + number_states] = String::format("Dis_AND2_%d_%d", j, i);
+ dis_invs[state_count] = getTechModel()->getStdCellLib()->createStdCell("INV", dis_inv_names[state_count]);
+ dis_invs[state_count]->construct();
+ dis_and2s[state_count] = getTechModel()->getStdCellLib()->createStdCell("AND2", dis_and2_names[state_count]);
+ dis_and2s[state_count]->construct();
+ dis_and2s[state_count + number_states] = getTechModel()->getStdCellLib()->createStdCell("AND2", dis_and2_names[state_count + number_states]);
+ dis_and2s[state_count + number_states]->construct();
+ state_count++;
+ }
+ }
+
+ vector<String> dis_or_names(number_requests, "");
+ vector<ElectricalModel*> dis_ors(number_requests, NULL);
+ for(unsigned int i = 0; i < number_requests; ++i)
+ {
+ dis_or_names[i] = "Dis_OR" + (String)i;
+ dis_ors[i] = (ElectricalModel*)ModelGen::createModel("OR", dis_or_names[i], getTechModel());
+ dis_ors[i]->setParameter("NumberInputs", number_requests-1);
+ dis_ors[i]->setParameter("NumberBits", 1);
+ dis_ors[i]->construct();
+ }
+
+ state_count = 0;
+ for(unsigned int i = 0; i < number_requests; ++i)
+ {
+ createNet("Dis_OR_Out" + (String)i);
+ createNet("G_INV_Out" + (String)i);
+ portConnect(g_invs[i], "A", "Dis_OR_Out" + (String)i);
+ portConnect(g_invs[i], "Y", "G_INV_Out" + (String)i);
+ portConnect(g_and2s[i], "A", "Request" + (String)i);
+ portConnect(g_and2s[i], "B", "G_INV_Out" + (String)i);
+ portConnect(g_and2s[i], "Y", "Grant" + (String)i);
+
+ for(unsigned int j = i + 1; j < number_requests; ++j)
+ {
+ createNet(String::format("W_INV_Out_%d_%d", i, j));
+ createNet(String::format("W_OR2_Out_%d_%d", i, j));
+ createNet(String::format("W_AND2_Out_%d_%d", i, j));
+ createNet(String::format("W_DFF_Out_%d_%d", i, j));
+ portConnect(w_invs[state_count], "A", "Grant" + (String)i);
+ portConnect(w_invs[state_count], "Y", String::format("W_INV_Out_%d_%d", i, j));
+ portConnect(w_or2s[state_count], "A", String::format("W_DFF_Out_%d_%d", i, j));
+ portConnect(w_or2s[state_count], "B", "Grant" + (String)j);
+ portConnect(w_or2s[state_count], "Y", String::format("W_OR2_Out_%d_%d", i, j));
+ portConnect(w_and2s[state_count], "A", String::format("W_OR2_Out_%d_%d", i, j));
+ portConnect(w_and2s[state_count], "B", String::format("W_INV_Out_%d_%d", i, j));
+ portConnect(w_and2s[state_count], "Y", String::format("W_AND2_Out_%d_%d", i, j));
+ portConnect(w_dffs[state_count], "D", String::format("W_AND2_Out_%d_%d", i, j));
+ portConnect(w_dffs[state_count], "CK", "CK");
+ portConnect(w_dffs[state_count], "Q", String::format("W_DFF_Out_%d_%d", i, j));
+
+ createNet(String::format("Dis_AND2_Out_%d_%d", i, j));
+ createNet(String::format("Dis_AND2_Out_%d_%d", j, i));
+ createNet(String::format("Dis_INV_Out_%d_%d", j, i));
+ portConnect(dis_and2s[state_count], "A", "Request" + (String)i);
+ portConnect(dis_and2s[state_count], "B", String::format("W_DFF_Out_%d_%d", i, j));
+ portConnect(dis_and2s[state_count], "Y", String::format("Dis_AND2_Out_%d_%d", i, j));
+
+ portConnect(dis_invs[state_count], "A", String::format("W_DFF_Out_%d_%d", i, j));
+ portConnect(dis_invs[state_count], "Y", String::format("Dis_INV_Out_%d_%d", j, i));
+ portConnect(dis_and2s[state_count + number_states], "A", "Request" + (String)j);
+ portConnect(dis_and2s[state_count + number_states], "B", String::format("Dis_INV_Out_%d_%d", j, i));
+ portConnect(dis_and2s[state_count + number_states], "Y", String::format("Dis_AND2_Out_%d_%d", j, i));
+
+ state_count++;
+ }
+ }
+ for(unsigned int i = 0; i < number_requests; ++i)
+ {
+ unsigned int k = 0;
+ for(unsigned int j = 0; j < number_requests; ++j)
+ {
+ if(i != j)
+ {
+ portConnect(dis_ors[i], "In" + (String)k, String::format("Dis_AND2_Out_%d_%d", j, i));
+ k++;
+ }
+ }
+ portConnect(dis_ors[i], "Out", "Dis_OR_Out" + (String)i);
+ }
+
+ // Add instances
+ for(unsigned int i = 0; i < number_requests; ++i)
+ {
+ addSubInstances(g_invs[i], 1.0);
+ addElectricalSubResults(g_invs[i], 1.0);
+ addSubInstances(g_and2s[i], 1.0);
+ addElectricalSubResults(g_and2s[i], 1.0);
+ addSubInstances(dis_ors[i], 1.0);
+ addElectricalSubResults(dis_ors[i], 1.0);
+ }
+ for(unsigned int i = 0; i < number_states; ++i)
+ {
+ addSubInstances(w_or2s[i], 1.0);
+ addElectricalSubResults(w_or2s[i], 1.0);
+ addSubInstances(w_and2s[i], 1.0);
+ addElectricalSubResults(w_and2s[i], 1.0);
+ addSubInstances(w_invs[i], 1.0);
+ addElectricalSubResults(w_invs[i], 1.0);
+ addSubInstances(w_dffs[i], 1.0);
+ addElectricalSubResults(w_dffs[i], 1.0);
+ addSubInstances(dis_and2s[i], 1.0);
+ addElectricalSubResults(dis_and2s[i], 1.0);
+ addSubInstances(dis_and2s[i + number_states], 1.0);
+ addElectricalSubResults(dis_and2s[i + number_states], 1.0);
+ addSubInstances(dis_invs[i], 1.0);
+ addElectricalSubResults(dis_invs[i], 1.0);
+ }
+
+ // Update event
+ //for(unsigned int i = 0; i <= number_requests; ++i)
+ //{
+ //Result* arb_event = getEventResult("Arbitrate" + (String)i);
+ Result* arb_event = getEventResult("Arbitrate");
+ for(unsigned int j = 0; j < number_requests; ++j)
+ {
+ arb_event->addSubResult(g_invs[j]->getEventResult("INV"), g_inv_names[j], 1.0);
+ arb_event->addSubResult(g_and2s[j]->getEventResult("AND2"), g_and2_names[j], 1.0);
+ arb_event->addSubResult(dis_ors[j]->getEventResult("OR"), dis_or_names[j], 1.0);
+ }
+ for(unsigned int j = 0; j < number_states; ++j)
+ {
+ arb_event->addSubResult(w_or2s[j]->getEventResult("OR2"), w_or2_names[j], 1.0);
+ arb_event->addSubResult(w_and2s[j]->getEventResult("AND2"), w_and2_names[j], 1.0);
+ arb_event->addSubResult(w_invs[j]->getEventResult("INV"), w_inv_names[j], 1.0);
+ arb_event->addSubResult(w_dffs[j]->getEventResult("DFFD"), w_dff_names[j], 1.0);
+ arb_event->addSubResult(w_dffs[j]->getEventResult("DFFQ"), w_dff_names[j], 1.0);
+ arb_event->addSubResult(w_dffs[j]->getEventResult("CK"), w_dff_names[j], 1.0);
+ arb_event->addSubResult(dis_and2s[j]->getEventResult("AND2"), dis_and2_names[j], 1.0);
+ arb_event->addSubResult(dis_and2s[j + number_states]->getEventResult("AND2"), dis_and2_names[j + number_states], 1.0);
+ arb_event->addSubResult(dis_invs[j]->getEventResult("INV"), dis_inv_names[j], 1.0);
+ }
+ //}
+ }
+ return;
+ }
+
+ void MatrixArbiter::propagateTransitionInfo()
+ {
+ // Get parameters
+ unsigned int number_requests = getParameter("NumberRequests").toUInt();
+
+ if(number_requests == 1)
+ {
+ propagatePortTransitionInfo("Grant0", "Request0");
+ }
+ else
+ {
+ unsigned int number_states = (number_requests - 1) * number_requests / 2;
+
+ vector<ElectricalModel*> g_and2s(number_requests, NULL);
+ vector<ElectricalModel*> g_invs(number_requests, NULL);
+ vector<ElectricalModel*> w_invs(number_states, NULL);
+ vector<ElectricalModel*> w_or2s(number_states, NULL);
+ vector<ElectricalModel*> w_and2s(number_states, NULL);
+ vector<ElectricalModel*> w_dffs(number_states, NULL);
+ vector<ElectricalModel*> dis_invs(number_states, NULL);
+ vector<ElectricalModel*> dis_and2s(number_requests * number_requests, NULL);
+ vector<ElectricalModel*> dis_ors(number_requests, NULL);
+ for(unsigned int i = 0; i < number_requests; ++i)
+ {
+ g_and2s[i] = (ElectricalModel*)getSubInstance("G_AND2" + (String)i);
+ g_invs[i] = (ElectricalModel*)getSubInstance("G_INV" + (String)i);
+ dis_ors[i] = (ElectricalModel*)getSubInstance("Dis_OR" + (String)i);
+ }
+ unsigned int state_count = 0;
+ for(unsigned int i = 0; i < number_requests; ++i)
+ {
+ for(unsigned int j = i + 1; j < number_requests; ++j)
+ {
+ w_invs[state_count] = (ElectricalModel*)getSubInstance(String::format("W_INV_%d_%d", i, j));
+ w_or2s[state_count] = (ElectricalModel*)getSubInstance(String::format("W_OR2_%d_%d", i, j));
+ w_and2s[state_count] = (ElectricalModel*)getSubInstance(String::format("W_AND2_%d_%d", i, j));
+ w_dffs[state_count] = (ElectricalModel*)getSubInstance(String::format("W_DFF_%d_%d", i, j));
+ dis_invs[state_count] = (ElectricalModel*)getSubInstance(String::format("Dis_INV_%d_%d", i, j));
+ dis_and2s[i * number_requests + j] = (ElectricalModel*)getSubInstance(String::format("Dis_AND2_%d_%d", i, j));
+ dis_and2s[j * number_requests + i] = (ElectricalModel*)getSubInstance(String::format("Dis_AND2_%d_%d", j, i));
+
+ w_dffs[state_count]->getInputPort("D")->setTransitionInfo(TransitionInfo(0.5, 0.0, 0.5));
+ propagatePortTransitionInfo(w_dffs[state_count], "CK", "CK");
+ w_dffs[state_count]->use();
+
+ state_count++;
+ }
+ }
+
+ unsigned int iteration = 1;
+ unsigned int max_number_iterations = 10;
+ //vector<TransitionInfo> trans_vector(number_states, TransitionInfo(0.0, 0.0, 1.0));
+ //vector<double> total_P_vector(number_states, 0.0);
+ while(iteration < max_number_iterations)
+ {
+// for(unsigned int i = 0; i < number_states; ++i)
+// {
+// w_dffs[i]->getInputPort("D")->setTransitionInfo(trans_vector[i]);
+// propagatePortTransitionInfo(w_dffs[i], "CK", "CK");
+// w_dffs[i]->use();
+// }
+ state_count = 0;
+ for(unsigned int i = 0; i < number_requests; ++i)
+ {
+ for(unsigned int j = i + 1; j < number_requests; ++j)
+ {
+ propagatePortTransitionInfo(dis_and2s[i * number_requests + j], "A", "Request" + (String)i);
+ propagatePortTransitionInfo(dis_and2s[i * number_requests + j], "B", w_dffs[state_count], "Q");
+ dis_and2s[i * number_requests + j]->use();
+ propagatePortTransitionInfo(dis_invs[state_count], "A", w_dffs[state_count], "Q");
+ dis_invs[state_count]->use();
+ propagatePortTransitionInfo(dis_and2s[j * number_requests + i], "A", "Request" + (String)j);
+ propagatePortTransitionInfo(dis_and2s[j * number_requests + i], "B", dis_invs[state_count], "Y");
+ dis_and2s[j * number_requests + i]->use();
+
+ state_count++;
+ }
+ }
+ for(unsigned int i = 0; i < number_requests; ++i)
+ {
+ unsigned int k = 0;
+ for(unsigned int j = 0; j < number_requests; ++j)
+ {
+ if(i != j)
+ {
+ propagatePortTransitionInfo(dis_ors[i], "In" + (String)k, dis_and2s[j * number_requests + i], "Y");
+ k++;
+ }
+ }
+ dis_ors[i]->use();
+ }
+ for(unsigned int i = 0; i < number_requests; ++i)
+ {
+ propagatePortTransitionInfo(g_invs[i], "A", dis_ors[i], "Out");
+ g_invs[i]->use();
+ propagatePortTransitionInfo(g_and2s[i], "A", "Request" + (String)i);
+ propagatePortTransitionInfo(g_and2s[i], "B", g_invs[i], "Y");
+ g_and2s[i]->use();
+ }
+ state_count = 0;
+ for(unsigned int i = 0; i < number_requests; ++i)
+ {
+ for(unsigned int j = i + 1; j < number_requests; ++j)
+ {
+ propagatePortTransitionInfo(w_invs[state_count], "A", g_and2s[i], "Y");
+ w_invs[state_count]->use();
+ propagatePortTransitionInfo(w_or2s[state_count], "A", w_dffs[state_count], "Q");
+ propagatePortTransitionInfo(w_or2s[state_count], "B", g_and2s[j], "Y");
+ w_or2s[state_count]->use();
+ propagatePortTransitionInfo(w_and2s[state_count], "A", w_or2s[state_count], "Y");
+ propagatePortTransitionInfo(w_and2s[state_count], "B", w_invs[state_count], "Y");
+ w_and2s[state_count]->use();
+ propagatePortTransitionInfo(w_dffs[state_count], "D", w_and2s[state_count], "Y");
+ propagatePortTransitionInfo(w_dffs[state_count], "CK", "CK");
+ w_dffs[state_count]->use();
+ state_count++;
+ }
+ }
+
+// for(unsigned int i = 0; i < number_states; ++i)
+// {
+// const TransitionInfo& new_trans = w_dffs[i]->getOutputPort("Q")->getTransitionInfo();
+// total_P_vector[i] += new_trans.getProbability1();
+// trans_vector[i] = TransitionInfo((1.0 - total_P_vector[i] / iteration) * (1.0 - total_P_vector[i] / iteration),
+// (1.0 - total_P_vector[i] / iteration) * (total_P_vector[i] / iteration),
+// (total_P_vector[i] / iteration) * (total_P_vector[i] / iteration));
+// }
+//
+// for(unsigned int i = 0; i < number_requests; ++i)
+// {
+// g_and2s[i]->getOutputPort("Y")->getTransitionInfo().print(cout);
+// }
+// cout << endl;
+ iteration++;
+ }
+
+ for(unsigned int i = 0; i < number_requests; ++i)
+ {
+ propagatePortTransitionInfo("Grant" + (String)i, g_and2s[i], "Y");
+ }
+ }
+
+ return;
+ }
+} // namespace DSENT
+
diff --git a/ext/dsent/model/electrical/MatrixArbiter.h b/ext/dsent/model/electrical/MatrixArbiter.h
new file mode 100644
index 000000000..59a6786ab
--- /dev/null
+++ b/ext/dsent/model/electrical/MatrixArbiter.h
@@ -0,0 +1,33 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_MATRIX_ARBITER_H__
+#define __DSENT_MODEL_ELECTRICAL_MATRIX_ARBITER_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+ class MatrixArbiter : public ElectricalModel
+ {
+ public:
+ MatrixArbiter(const String& instance_name_, const TechModel* tech_model_);
+ virtual ~MatrixArbiter();
+
+ public:
+ // Set a list of properties' name needed to construct model
+ void initParameters();
+ // Set a list of properties' name needed to construct model
+ void initProperties();
+
+ // Clone and return a new instance
+ virtual MatrixArbiter* clone() const;
+
+ protected:
+ // Build the model
+ virtual void constructModel();
+ virtual void propagateTransitionInfo();
+
+ }; // class MatrixArbiter
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_MATRIX_ARBITER_H__
+
diff --git a/ext/dsent/model/electrical/Multiplexer.cc b/ext/dsent/model/electrical/Multiplexer.cc
new file mode 100644
index 000000000..f51f43b4c
--- /dev/null
+++ b/ext/dsent/model/electrical/Multiplexer.cc
@@ -0,0 +1,347 @@
+#include "model/electrical/Multiplexer.h"
+
+#include <cmath>
+
+#include "model/PortInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/EventInfo.h"
+#include "model/timing_graph/ElectricalDriverMultiplier.h"
+#include "model/timing_graph/ElectricalNet.h"
+#include "model/std_cells/StdCell.h"
+#include "model/std_cells/StdCellLib.h"
+
+namespace DSENT
+{
+ Multiplexer::Multiplexer(const String& instance_name_, const TechModel* tech_model_)
+ : ElectricalModel(instance_name_, tech_model_)
+ {
+ initParameters();
+ initProperties();
+ }
+
+ Multiplexer::~Multiplexer()
+ {}
+
+ void Multiplexer::initParameters()
+ {
+ addParameterName("NumberInputs");
+ addParameterName("NumberBits");
+ addParameterName("BitDuplicate", "TRUE");
+ addParameterName("IsTopLevel", "TRUE");
+ return;
+ }
+
+ void Multiplexer::initProperties()
+ {
+ return;
+ }
+
+ Multiplexer* Multiplexer::clone() const
+ {
+ return NULL;
+ }
+
+ void Multiplexer::constructModel()
+ {
+ // Get parameters
+ unsigned int number_bits = (unsigned int) getParameter("NumberBits");
+ unsigned int number_inputs = (unsigned int) getParameter("NumberInputs");
+ unsigned int number_selects = (unsigned int) ceil(log2((double) number_inputs));
+ bool bit_duplicate = (bool) getParameter("BitDuplicate");
+ bool is_top_level = getParameter("IsTopLevel").toBool();
+
+ ASSERT(number_inputs > 0, "[Error] " + getInstanceName() + " -> Number of inputs must be > 0!");
+ ASSERT(number_bits > 0, "[Error] " + getInstanceName() + " -> Number of bits must be > 0!");
+
+ //Construct electrical ports and nets
+ //Create each input port
+ for(unsigned int i = 0; i < number_inputs; ++i)
+ createInputPort( "In" + (String) i, makeNetIndex(0, number_bits-1));
+ //Create select signals
+ for(unsigned int i = 0; i < number_selects; ++i)
+ {
+ createInputPort( "Sel" + (String)i);
+ }
+ //Create output
+ createOutputPort( "Out", makeNetIndex(0, number_bits-1));
+
+ //Create energy, power, and area results
+ createElectricalResults();
+ getEventInfo("Idle")->setStaticTransitionInfos();
+ createElectricalEventResult("Mux");
+
+ //Number of inputs on the 0 side
+ unsigned int inputs_0 = (unsigned int) ceil((double) number_inputs / 2.0);
+ unsigned int selects_0 = (unsigned int) ceil(log2((double) inputs_0));
+ //Number of inputs on the 1 side
+ unsigned int inputs_1 = (unsigned int) floor((double) number_inputs / 2.0);
+ unsigned int selects_1 = (unsigned int) ceil(log2((double) inputs_1));
+
+ //Depending on whether we want to create a 1-bit instance and have it multiplied
+ //up by number of bits or actually instantiate number_bits of 1-bit instances.
+ //Recursively instantiates smaller multiplexers
+ if (bit_duplicate || number_bits == 1)
+ {
+ //If it is just a 1-input multiplexer, just connect output to input and be done
+ if (number_inputs == 1)
+ {
+ assign("Out", "In0");
+ }
+ else
+ {
+ //If it is more than 1 input, instantiate two sub multiplexers (Mux_way0 and Mux_way1)
+ //and create a final 2:1 mux (muxf) to select between them
+ String mux0_name = "Mux_way0";
+ String mux1_name = "Mux_way1";
+ String muxf_name = "Mux2_i" + (String)number_inputs;
+
+ Multiplexer* mux0 = new Multiplexer(mux0_name, getTechModel());
+ mux0->setParameter("NumberInputs", inputs_0);
+ mux0->setParameter("NumberBits", 1);
+ mux0->setParameter("BitDuplicate", "TRUE");
+ mux0->setParameter("IsTopLevel", "FALSE");
+ mux0->construct();
+
+ Multiplexer* mux1 = new Multiplexer(mux1_name, getTechModel());
+ mux1->setParameter("NumberInputs", inputs_1);
+ mux1->setParameter("NumberBits", 1);
+ mux1->setParameter("BitDuplicate", "TRUE");
+ mux1->setParameter("IsTopLevel", "FALSE");
+ mux1->construct();
+
+ StdCell* muxf = getTechModel()->getStdCellLib()->createStdCell("MUX2", muxf_name);
+ muxf->construct();
+
+ // TODO hack
+ // create selector driver at the top level
+ if(is_top_level)
+ {
+ for(unsigned int i = 0; i < number_selects; ++i)
+ {
+ StdCell* selinv0 = getTechModel()->getStdCellLib()->createStdCell("INV", String::format("Sel%dInv0", i));
+ StdCell* selinv1 = getTechModel()->getStdCellLib()->createStdCell("INV", String::format("Sel%dInv1", i));
+ selinv0->construct();
+ selinv1->construct();
+
+ addSubInstances(selinv0, 1.0);
+ addElectricalSubResults(selinv0, 1.0);
+ addSubInstances(selinv1, 1.0);
+ addElectricalSubResults(selinv1, 1.0);
+ getEventResult("Mux")->addSubResult(selinv0->getEventResult("INV"), String::format("Sel%dInv0", i), 1.0);
+ getEventResult("Mux")->addSubResult(selinv1->getEventResult("INV"), String::format("Sel%dInv1", i), 1.0);
+ }
+ }
+
+ //Create outputs of way0 and way1 multiplexers with final mux
+ createNet("way0Out");
+ createNet("way1Out");
+ portConnect(mux0, "Out", "way0Out");
+ portConnect(mux1, "Out", "way1Out");
+ portConnect(muxf, "A", "way0Out");
+ portConnect(muxf, "B", "way1Out");
+
+ // TODO hack
+ // Connect selector bits
+ if(is_top_level)
+ {
+ for(unsigned int i = 0; i < number_selects; ++i)
+ {
+ ElectricalModel* selinv0 = (ElectricalModel*)getSubInstance(String::format("Sel%dInv0", i));
+ ElectricalModel* selinv1 = (ElectricalModel*)getSubInstance(String::format("Sel%dInv1", i));
+ createNet("SelInv" + (String)i);
+ createNet("SelBuf" + (String)i);
+ portConnect(selinv0, "A", "Sel" + (String)i);
+ portConnect(selinv0, "Y", "SelInv" + (String)i);
+ portConnect(selinv1, "A", "SelInv" + (String)i);
+ portConnect(selinv1, "Y", "SelBuf" + (String)i);
+ }
+ }
+ //Connect inputs to the sub multiplexers.
+ //Note that multiple inputs are connected to the mux0 and mux1 input and the
+ //selector signals are connected multiple times. This is just so that everything
+ //is loaded appropriately since bit duplication is applied
+ for (unsigned int n = 0; n < number_bits; ++n)
+ {
+ //Connect inputs
+ for (unsigned int i = 0; i < inputs_0; ++i)
+ portConnect(mux0, "In" + (String) i, "In" + (String) i, makeNetIndex(n));
+ for (unsigned int i = 0; i < inputs_1; ++i)
+ portConnect(mux1, "In" + (String) i, "In" + (String) (i + inputs_0), makeNetIndex(n));
+ // TODO hack
+ if(is_top_level)
+ {
+ //Connect selector bits
+ for (unsigned int i = 0; i < selects_0; ++i)
+ portConnect(mux0, "Sel" + (String)i, "SelBuf" + (String)i);
+ for (unsigned int i = 0; i < selects_1; ++i)
+ portConnect(mux1, "Sel" + (String)i, "SelBuf" + (String)i);
+ portConnect(muxf, "S0", "SelBuf" + (String)(number_selects - 1));
+ }
+ else
+ {
+ //Connect selector bits
+ for (unsigned int i = 0; i < selects_0; ++i)
+ portConnect(mux0, "Sel" + (String)i, "Sel" + (String)i);
+ for (unsigned int i = 0; i < selects_1; ++i)
+ portConnect(mux1, "Sel" + (String)i, "Sel" + (String)i);
+ portConnect(muxf, "S0", "Sel" + (String)(number_selects - 1));
+ }
+ }
+
+ //Connect final mux to outputs
+ //Because we use bit duplication and so there is only only one multiplexer
+ //instance, we must use driver multiplier to drive each output appropriately
+ if (number_bits == 1)
+ portConnect(muxf, "Y", "Out");
+ else
+ {
+ createNet("OutTemp");
+ createDriverMultiplier("OutMult");
+ ElectricalDriverMultiplier* drive_mult = getDriverMultiplier("OutMult");
+ portConnect(muxf, "Y", "OutTemp");
+ getNet("OutTemp")->addDownstreamNode(drive_mult);
+ for (unsigned int n = 0; n < number_bits; ++n)
+ drive_mult->addDownstreamNode(getNet("Out", makeNetIndex(n)));
+ }
+
+ //Add area, power, and event results for each mux
+ addSubInstances(mux0, number_bits);
+ addElectricalSubResults(mux0, number_bits);
+ addSubInstances(mux1, number_bits);
+ addElectricalSubResults(mux1, number_bits);
+ addSubInstances(muxf, number_bits);
+ addElectricalSubResults(muxf, number_bits);
+ getEventResult("Mux")->addSubResult(mux0->getEventResult("Mux"), mux0_name, number_bits);
+ getEventResult("Mux")->addSubResult(mux1->getEventResult("Mux"), mux1_name, number_bits);
+ getEventResult("Mux")->addSubResult(muxf->getEventResult("MUX2"), muxf_name, number_bits);
+
+ }
+
+ }
+ else
+ {
+ //Instantiate a bunch of 1-bit multiplexers
+ for (unsigned int n = 0; n < number_bits; ++n)
+ {
+ String mux_name = "Mux_bit" + (String) n;
+
+ Multiplexer* mux = new Multiplexer(mux_name, getTechModel());
+ mux->setParameter("NumberInputs", number_inputs);
+ mux->setParameter("NumberBits", 1);
+ mux->setParameter("BitDuplicate", "TRUE");
+ mux->construct();
+
+ // Connect inputs
+ for (unsigned int i = 0; i < number_inputs; ++i)
+ portConnect(mux, "In" + (String) i, "In" + (String) i, makeNetIndex(n));
+ for(unsigned int i = 0; i < number_selects; ++i)
+ portConnect(mux, "Sel" + (String)i, "Sel" + (String)i);
+ portConnect(mux, "Out", "Out", makeNetIndex(n));
+
+ //Add area, power, and event results for each mux
+ addSubInstances(mux, 1.0);
+ addElectricalSubResults(mux, 1.0);
+ getEventResult("Mux")->addSubResult(mux->getEventResult("Mux"), mux_name, 1.0);
+ }
+ }
+
+ return;
+ }
+
+ void Multiplexer::propagateTransitionInfo()
+ {
+ // The only thing can be updated are the input probabilities...so we will update them
+ unsigned int number_bits = (unsigned int) getParameter("NumberBits");
+ unsigned int number_inputs = (unsigned int) getParameter("NumberInputs");
+ unsigned int number_selects = (unsigned int) ceil(log2((double) number_inputs));
+ bool bit_duplicate = (bool) getParameter("BitDuplicate");
+ bool is_top_level = getParameter("IsTopLevel").toBool();
+
+ //Number of inputs on the 0 side
+ unsigned int inputs_0 = (unsigned int) ceil((double) number_inputs / 2.0);
+ unsigned int selects_0 = (unsigned int) ceil(log2((double) inputs_0));
+
+ //Number of inputs on the 1 side
+ unsigned int inputs_1 = (unsigned int) floor((double) number_inputs / 2.0);
+ unsigned int selects_1 = (unsigned int) ceil(log2((double) inputs_1));
+
+ if (bit_duplicate || number_bits == 1)
+ {
+ if (number_inputs == 1)
+ {
+ //If theres only 1 input, output transition = input transition
+ propagatePortTransitionInfo("Out", "In0");
+ }
+ else
+ {
+ // Update sub muxes with appropriate probabilities
+ ElectricalModel* mux0 = (ElectricalModel*)getSubInstance("Mux_way0");
+ for(unsigned int i = 0; i < inputs_0; ++i)
+ {
+ propagatePortTransitionInfo(mux0, "In" + (String)i, "In" + (String)i);
+ }
+ for(unsigned int i = 0; i < selects_0; ++i)
+ {
+ propagatePortTransitionInfo(mux0, "Sel" + (String)i, "Sel" + (String)i);
+ }
+ mux0->use();
+ ElectricalModel* mux1 = (ElectricalModel*)getSubInstance("Mux_way1");
+ for(unsigned int i = 0; i < inputs_1; ++i)
+ {
+ propagatePortTransitionInfo(mux1, "In" + (String)i, "In" + (String)(i + inputs_0));
+ }
+ for(unsigned int i = 0; i < selects_1; ++i)
+ {
+ propagatePortTransitionInfo(mux1, "Sel" + (String)i, "Sel" + (String)i);
+ }
+ mux1->use();
+ ElectricalModel* muxf = (ElectricalModel*)getSubInstance("Mux2_i" + (String)number_inputs);
+ propagatePortTransitionInfo(muxf, "A", mux0, "Out");
+ propagatePortTransitionInfo(muxf, "B", mux1, "Out");
+ propagatePortTransitionInfo(muxf, "S0", "Sel" + (String)(number_selects-1));
+ muxf->use();
+
+ // TODO hack
+ if(is_top_level)
+ {
+ for(unsigned int i = 0; i < number_selects; ++i)
+ {
+ ElectricalModel* selinv0 = (ElectricalModel*)getSubInstance(String::format("Sel%dInv0", i));
+ ElectricalModel* selinv1 = (ElectricalModel*)getSubInstance(String::format("Sel%dInv1", i));
+ propagatePortTransitionInfo(selinv0, "A", "Sel" + (String)i);
+ selinv0->use();
+ propagatePortTransitionInfo(selinv1, "A", selinv0, "Y");
+ selinv1->use();
+ }
+ }
+
+ // Set output transition
+ propagatePortTransitionInfo("Out", muxf, "Y");
+ }
+ }
+ else
+ {
+ // Go through each bit and set the appropriate probability
+ for (unsigned int n = 0; n < number_bits; ++n)
+ {
+ ElectricalModel* mux_bit = (ElectricalModel*)getSubInstance("Mux_bit" + (String) n);
+ for(unsigned int i = 0; i < number_inputs; ++i)
+ {
+ propagatePortTransitionInfo(mux_bit, "In" + (String)i, "In" + (String)i);
+ }
+ for(unsigned int i = 0; i < number_selects; ++i)
+ {
+ propagatePortTransitionInfo(mux_bit, "Sel" + (String)i, "Sel" + (String)i);
+ }
+ mux_bit->use();
+ }
+
+ // Set output probability to be average that of probabilties of each output bit
+ ElectricalModel* mux_bit = (ElectricalModel*)getSubInstance("Mux_bit0");
+ propagatePortTransitionInfo("Out", mux_bit, "Out");
+ }
+ return;
+ }
+
+} // namespace DSENT
+
diff --git a/ext/dsent/model/electrical/Multiplexer.h b/ext/dsent/model/electrical/Multiplexer.h
new file mode 100644
index 000000000..845798b18
--- /dev/null
+++ b/ext/dsent/model/electrical/Multiplexer.h
@@ -0,0 +1,34 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_MULTIPLEXER_H__
+#define __DSENT_MODEL_ELECTRICAL_MULTIPLEXER_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+ // A model of an N-to-1 multiplexer
+ class Multiplexer : public ElectricalModel
+ {
+ public:
+ Multiplexer(const String& instance_name_, const TechModel* tech_model_);
+ virtual ~Multiplexer();
+
+ public:
+ // Set a list of properties' name needed to construct model
+ void initParameters();
+ // Set a list of properties' name needed to construct model
+ void initProperties();
+
+ // Clone and return a new instance
+ virtual Multiplexer* clone() const;
+
+ protected:
+ // Build the model
+ virtual void constructModel();
+ virtual void propagateTransitionInfo();
+
+ }; // class Multiplexer
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_MULTIPLEXER_H__
+
diff --git a/ext/dsent/model/electrical/MultiplexerCrossbar.cc b/ext/dsent/model/electrical/MultiplexerCrossbar.cc
new file mode 100644
index 000000000..7400d5ed2
--- /dev/null
+++ b/ext/dsent/model/electrical/MultiplexerCrossbar.cc
@@ -0,0 +1,214 @@
+#include "model/electrical/MultiplexerCrossbar.h"
+
+#include <vector>
+#include <cmath>
+
+#include "model/PortInfo.h"
+#include "model/EventInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/timing_graph/ElectricalNet.h"
+#include "model/electrical/Multiplexer.h"
+
+namespace DSENT
+{
+ using std::ceil;
+ using std::vector;
+
+ MultiplexerCrossbar::MultiplexerCrossbar(const String& instance_name_, const TechModel* tech_model_)
+ : ElectricalModel(instance_name_, tech_model_)
+ {
+ initParameters();
+ initProperties();
+ }
+
+ MultiplexerCrossbar::~MultiplexerCrossbar()
+ {}
+
+ void MultiplexerCrossbar::initParameters()
+ {
+ addParameterName("NumberInputs");
+ addParameterName("NumberOutputs");
+ addParameterName("NumberBits");
+ addParameterName("BitDuplicate", "TRUE");
+ return;
+ }
+
+ void MultiplexerCrossbar::initProperties()
+ {
+ return;
+ }
+
+ MultiplexerCrossbar* MultiplexerCrossbar::clone() const
+ {
+ // TODO
+ return NULL;
+ }
+
+ void MultiplexerCrossbar::constructModel()
+ {
+ // Get Parameters
+ unsigned int number_inputs = getParameter("NumberInputs").toUInt();
+ unsigned int number_outputs = getParameter("NumberOutputs").toUInt();
+ unsigned int number_bits = getParameter("NumberBits").toUInt();
+ bool bit_duplicate = getParameter("BitDuplicate").toBool();
+
+ ASSERT(number_inputs > 0, "[Error] " + getInstanceName() + " -> Number of inputs must be > 0!");
+ ASSERT(number_outputs > 0, "[Error] " + getInstanceName() + " -> Number of outputs must be > 0!");
+ ASSERT(number_bits > 0, "[Error] " + getInstanceName() + " -> Number of bits must be > 0!");
+
+ unsigned int number_selects = (unsigned int)ceil(log2((double)number_inputs));
+ getGenProperties()->set("NumberSelectsPerPort", number_selects);
+
+ // Construct electrical ports and nets
+ // Create input ports
+ for(unsigned int i = 0; i < number_inputs; ++i)
+ {
+ createInputPort("In" + (String)i, makeNetIndex(0, number_bits-1));
+ }
+ // Create select signals
+ for(unsigned int i = 0; i < number_outputs; ++i)
+ {
+ for(unsigned int j = 0; j < number_selects; ++j)
+ {
+ createInputPort(String::format("Sel%d_%d", i, j));
+ }
+ }
+ // Create output ports
+ for(unsigned int i = 0; i < number_outputs; ++i)
+ {
+ createOutputPort("Out" + (String)i, makeNetIndex(0, number_bits-1));
+ }
+
+ // Create energy, power, and area results
+ addAreaResult(new AtomicResult("CrossbarWire"));
+ addAreaResult(new AtomicResult("CrossbarFill"));
+ createElectricalResults();
+ getEventInfo("Idle")->setStaticTransitionInfos();
+ createElectricalEventResult("Multicast0");
+ getEventInfo("Multicast0")->setStaticTransitionInfos();
+ for(unsigned int i = 1; i <= number_outputs; ++i)
+ {
+ createElectricalEventResult("Multicast" + (String)i);
+ EventInfo* event_info = getEventInfo("Multicast" + (String)i);
+ // Assuming that In0 is sending to Out0, Out1, ..., Outi
+ // and other input ports are static
+ for(unsigned int j = 1; j < number_inputs; ++j)
+ {
+ event_info->setStaticTransitionInfo("In" + (String)j);
+ }
+ for(unsigned int j = i; j < number_outputs; ++j)
+ {
+ for(unsigned int k = 0; k < number_selects; ++k)
+ {
+ event_info->setStaticTransitionInfo(String::format("Sel%d_%d", j, k));
+ }
+ }
+ }
+ createElectricalEventResult("Crossbar");
+
+ // Initiate multiplexers
+ vector<String> mux_names(number_outputs, "");
+ vector<Multiplexer*> muxs(number_outputs, NULL);
+ for(unsigned int i = 0; i < number_outputs; ++i)
+ {
+ mux_names[i] = "Mux" + (String)i;
+ muxs[i] = new Multiplexer(mux_names[i], getTechModel());
+ muxs[i]->setParameter("NumberInputs", number_inputs);
+ muxs[i]->setParameter("NumberBits", number_bits);
+ muxs[i]->setParameter("BitDuplicate", bit_duplicate);
+ muxs[i]->construct();
+ }
+
+ // Connect inputs and outputs to multiplexers
+ for(unsigned int i = 0; i < number_outputs; ++i)
+ {
+ // Connect inputs
+ for(unsigned int j = 0; j < number_inputs; ++j)
+ {
+ portConnect(muxs[i], "In" + (String)j, "In" + (String)j, makeNetIndex(0, number_bits-1));
+ }
+
+ // Connect select signals
+ for(unsigned int j = 0; j < number_selects; ++j)
+ {
+ portConnect(muxs[i], "Sel" + (String)j, String::format("Sel%d_%d", i, j));
+ }
+
+ // Connect outputs
+ portConnect(muxs[i], "Out", "Out" + (String)i, makeNetIndex(0, number_bits-1));
+ }
+
+ // Add area, power, and event results for each mux
+ for(unsigned int i = 0; i < number_outputs; ++i)
+ {
+ addSubInstances(muxs[i], 1.0);
+ addElectricalSubResults(muxs[i], 1.0);
+ for(unsigned int j = 0; j <= number_outputs; ++j)
+ {
+ getEventResult("Multicast" + (String)j)->addSubResult(muxs[i]->getEventResult("Mux"), mux_names[i], 1.0);
+ }
+ getEventResult("Crossbar")->addSubResult(muxs[i]->getEventResult("Mux"), mux_names[i], 1.0);
+ }
+
+ // Estimate wiring area
+ const String& crossbar_wire_layer = "Intermediate";
+ addElectricalWireSubResult(crossbar_wire_layer, getAreaResult("CrossbarWire"), "Self", 1.0);
+ double wire_width = getTechModel()->get("Wire->" + crossbar_wire_layer + "->MinWidth").toDouble();
+ double wire_spacing = getTechModel()->get("Wire->" + crossbar_wire_layer + "->MinSpacing").toDouble();
+ double wire_pitch = wire_width + wire_spacing;
+ double wire_area = (number_bits * number_inputs * wire_pitch) * (number_bits * number_outputs * wire_pitch);
+ getAreaResult("CrossbarWire")->setValue(wire_area);
+
+ // Add filler area
+ getAreaResult("Active")->addSubResult(getAreaResult("CrossbarFill"), "Self", 1.0);
+ return;
+ }
+
+ void MultiplexerCrossbar::updateModel()
+ {
+ // Update all sub instances
+ Model::updateModel();
+
+ // Update filler area
+ // Total Active area = max(stdcell active area, wiring area);
+ double wire_area = getAreaResult("CrossbarWire")->calculateSum();
+ double active_area = getAreaResult("Active")->calculateSum();
+ double fill_area = 0.0;
+ if(active_area < wire_area)
+ {
+ fill_area = wire_area - active_area;
+ }
+ getAreaResult("CrossbarFill")->setValue(fill_area);
+ return;
+ }
+
+ void MultiplexerCrossbar::propagateTransitionInfo()
+ {
+ // The only thing can be updated are the input probabilities
+ const unsigned int number_inputs = getParameter("NumberInputs").toUInt();
+ const unsigned int number_outputs = getParameter("NumberOutputs").toUInt();
+
+ const unsigned int number_selects = getGenProperties()->get("NumberSelectsPerPort").toUInt();
+
+ for(unsigned int i = 0; i < number_outputs; ++i)
+ {
+ ElectricalModel* muxi = (ElectricalModel*)getSubInstance("Mux" + (String)i);
+ for(unsigned int j = 0; j < number_inputs; ++j)
+ {
+ propagatePortTransitionInfo(muxi, "In" + (String)j, "In" + (String)j);
+ }
+ for(unsigned int j = 0; j < number_selects; ++j)
+ {
+ propagatePortTransitionInfo(muxi, "Sel" + (String)j, String::format("Sel%d_%d", i, j));
+ }
+ muxi->use();
+
+ // Set output probability
+ propagatePortTransitionInfo("Out" + (String)i, muxi, "Out");
+ }
+
+ return;
+ }
+
+} // namespace DSENT
+
diff --git a/ext/dsent/model/electrical/MultiplexerCrossbar.h b/ext/dsent/model/electrical/MultiplexerCrossbar.h
new file mode 100644
index 000000000..e7f092061
--- /dev/null
+++ b/ext/dsent/model/electrical/MultiplexerCrossbar.h
@@ -0,0 +1,38 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_MULTIPLEXER_CROSSBAR_H__
+#define __DSENT_MODEL_ELECTRICAL_MULTIPLEXER_CROSSBAR_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+ // A model for a NxM W-bit multiplexer-based crossbar
+ class MultiplexerCrossbar : public ElectricalModel
+ {
+ public:
+ MultiplexerCrossbar(const String& instance_name_, const TechModel* tech_model_);
+ virtual ~MultiplexerCrossbar();
+
+ public:
+ // Set a list of paramerters' name needed to construct model
+ void initParameters();
+ // Set a list of peroperties' name needed to construct model
+ void initProperties();
+
+ // Clone and return a new instance
+ virtual MultiplexerCrossbar* clone() const;
+
+ protected:
+ // Build the model
+ virtual void constructModel();
+ virtual void updateModel();
+ virtual void propagateTransitionInfo();
+
+ private:
+ // Disable copy constructor
+ MultiplexerCrossbar(const MultiplexerCrossbar& crossbar_);
+ }; // class MultiplexerCrossbar
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_MULTIPLEXER_CROSSBAR_H__
+
diff --git a/ext/dsent/model/electrical/MuxTreeSerializer.cc b/ext/dsent/model/electrical/MuxTreeSerializer.cc
new file mode 100644
index 000000000..8f3b92122
--- /dev/null
+++ b/ext/dsent/model/electrical/MuxTreeSerializer.cc
@@ -0,0 +1,226 @@
+#include "model/electrical/MuxTreeSerializer.h"
+
+#include <cmath>
+
+#include "model/PortInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/EventInfo.h"
+#include "model/std_cells/StdCellLib.h"
+#include "model/std_cells/StdCell.h"
+#include "model/electrical/Multiplexer.h"
+#include "model/timing_graph/ElectricalNet.h"
+
+namespace DSENT
+{
+ using std::ceil;
+
+ MuxTreeSerializer::MuxTreeSerializer(const String& instance_name_, const TechModel* tech_model_)
+ : ElectricalModel(instance_name_, tech_model_)
+ {
+ initParameters();
+ initProperties();
+ }
+
+ MuxTreeSerializer::~MuxTreeSerializer()
+ {}
+
+ void MuxTreeSerializer::initParameters()
+ {
+ addParameterName("InDataRate");
+ addParameterName("OutDataRate");
+ addParameterName("InBits"); //Output width will just be input width / serialization ratio
+ }
+
+ void MuxTreeSerializer::initProperties()
+ {
+ return;
+ }
+
+ MuxTreeSerializer* MuxTreeSerializer::clone() const
+ {
+ // TODO
+ return NULL;
+ }
+
+ void MuxTreeSerializer::constructModel()
+ {
+ // Get parameters
+ double in_data_rate = getParameter("InDataRate").toDouble();
+ double out_data_rate = getParameter("OutDataRate").toDouble();
+ unsigned int in_bits = getParameter("InBits").toUInt();
+
+ // Calculate serialization ratio
+ unsigned int serialization_ratio = (unsigned int) floor(out_data_rate / in_data_rate);
+ ASSERT(serialization_ratio == out_data_rate / in_data_rate,
+ "[Error] " + getInstanceName() + " -> Cannot have non-integer serialization ratios " +
+ "(" + (String) (in_data_rate / out_data_rate) + ")!");
+
+ // Calculate output width
+ ASSERT(floor((double) in_bits / serialization_ratio) == (double) in_bits / serialization_ratio,
+ "[Error] " + getInstanceName() + " -> Input width (" + (String) in_bits + ") " +
+ "must be a multiple of the serialization ratio (" + (String) serialization_ratio + ")!");
+ unsigned int output_bits = in_bits / serialization_ratio;
+
+ // Calculate the number of multiplexer stages
+ unsigned int number_stages = (unsigned int)ceil(log2((double) serialization_ratio));
+
+ // Store calculated values
+ getGenProperties()->set("SerializationRatio", serialization_ratio);
+ getGenProperties()->set("OutputBits", output_bits);
+ getGenProperties()->set("NumberStages", number_stages);
+
+ // Create ports
+ createInputPort("In", makeNetIndex(0, in_bits-1));
+ createInputPort("OutCK");
+ createOutputPort("Out", makeNetIndex(0, output_bits-1));
+
+ //Create energy, power, and area results
+ createElectricalResults();
+ createElectricalEventResult("Serialize");
+ getEventInfo("Serialize")->setTransitionInfo("OutCK", TransitionInfo(0.0, (double) serialization_ratio / 2.0, 0.0));
+ //Set conditions during idle state
+ getEventInfo("Idle")->setStaticTransitionInfos();
+ getEventInfo("Idle")->setTransitionInfo("OutCK", TransitionInfo(0.0, (double) serialization_ratio / 2.0, 0.0));
+
+ // Mark OutCK as a false path (since timing tool will do strange stuff due to all the clock divides and stuff)
+ getNet("OutCK")->setFalsePath(true);
+
+ // Create mux-tree instance
+ if (serialization_ratio == 1)
+ {
+ // No need to do anything, hohoho
+ assign("Out", "In");
+ }
+ else
+ {
+ // Create multiplexer
+ String mux_tree_name = "MuxTree";
+ ElectricalModel* mux_tree = new Multiplexer(mux_tree_name, getTechModel());
+ mux_tree->setParameter("NumberInputs", serialization_ratio);
+ mux_tree->setParameter("NumberBits", output_bits);
+ mux_tree->setParameter("BitDuplicate", "TRUE");
+ mux_tree->construct();
+ // Create nets
+ if (number_stages > 1)
+ createNet("MuxSel_b", makeNetIndex(0, number_stages-2));
+ createNet("MuxSel", makeNetIndex(0, number_stages-1));
+ assign("MuxSel", makeNetIndex(number_stages-1), "OutCK");
+ // Create reindexed net (to help out with indexing)
+ createNet("InTmp", makeNetIndex(0, in_bits-1));
+ for (unsigned int i = 0; i < serialization_ratio; ++i)
+ for (unsigned int j = 0; j < output_bits; ++j)
+ assign("InTmp", makeNetIndex(i*output_bits+j), "In", makeNetIndex(j*serialization_ratio+i));
+
+ // Connect ports
+ for (unsigned int i = 0; i < serialization_ratio; ++i)
+ portConnect(mux_tree, "In" + (String) i, "InTmp", makeNetIndex(i*output_bits, (i+1)*output_bits-1));
+
+ for (unsigned int i = 0; i < number_stages; ++i)
+ portConnect(mux_tree, "Sel" + (String) i, "MuxSel", makeNetIndex(i));
+ portConnect(mux_tree, "Out", "Out");
+
+ // Add subinstance and events
+ addSubInstances(mux_tree, 1.0);
+ addElectricalSubResults(mux_tree, 1.0);
+ // Add serialize event/power
+ getEventResult("Serialize")->addSubResult(mux_tree->getEventResult("Mux"), mux_tree_name, 1.0);
+
+ // Create clock dividers (assumes power of 2...), don't need divider for fastest output stage
+ for (unsigned int i = 0; i < number_stages - 1; ++i)
+ {
+ // Clk dividing registers
+ const String& clk_div_dff_name = "ClkDivDFF_" + (String) i;
+ StdCell* clk_div_dff = getTechModel()->getStdCellLib()->createStdCell("DFFQ", clk_div_dff_name);
+ clk_div_dff->construct();
+ portConnect(clk_div_dff, "D", "MuxSel_b", makeNetIndex(i));
+ portConnect(clk_div_dff, "Q", "MuxSel", makeNetIndex(i));
+ portConnect(clk_div_dff, "CK", "MuxSel", makeNetIndex(i+1));
+ addSubInstances(clk_div_dff, 1.0);
+ addElectricalSubResults(clk_div_dff, 1.0);
+
+ // Inversions
+ const String& clk_div_inv_name = "ClkDivINV_" + (String) i;
+ StdCell* clk_div_inv = getTechModel()->getStdCellLib()->createStdCell("INV", clk_div_inv_name);
+ clk_div_inv->construct();
+ portConnect(clk_div_inv, "A", "MuxSel", makeNetIndex(i));
+ portConnect(clk_div_inv, "Y", "MuxSel_b", makeNetIndex(i));
+ addSubInstances(clk_div_inv, 1.0);
+ addElectricalSubResults(clk_div_inv, 1.0);
+
+ getEventResult("Serialize")->addSubResult(clk_div_dff->getEventResult("CK"), clk_div_dff_name, 1.0);
+ getEventResult("Serialize")->addSubResult(clk_div_dff->getEventResult("DFFD"), clk_div_dff_name, 1.0);
+ getEventResult("Serialize")->addSubResult(clk_div_dff->getEventResult("DFFQ"), clk_div_dff_name, 1.0);
+ getEventResult("Serialize")->addSubResult(clk_div_inv->getEventResult("INV"), clk_div_inv_name, 1.0);
+ }
+ }
+
+ return;
+ }
+
+ void MuxTreeSerializer::propagateTransitionInfo()
+ {
+ // Get some generated properties
+ const unsigned int serialization_ratio = getGenProperties()->get("SerializationRatio");
+ const unsigned int number_stages = getGenProperties()->get("NumberStages");
+
+ // Set transition info of the mux tree and clock divide DFF
+ if (serialization_ratio == 1)
+ {
+ // If no serialization, then just propagate input transition info to output port
+ propagatePortTransitionInfo("Out", "In");
+ }
+ else
+ {
+
+ // Propagate transition probabilities to the mux tree
+ ElectricalModel* mux_tree = (ElectricalModel*) getSubInstance("MuxTree");
+ // All input ports of the mux have the same probability
+ for (unsigned int i = 0; i < serialization_ratio; ++i)
+ propagatePortTransitionInfo(mux_tree, "In" + (String) i, "In");
+ // Connect last stage of the mux
+ propagatePortTransitionInfo(mux_tree, "Sel" + (String) (number_stages - 1), "OutCK");
+ // Keep track of the last clock divider
+ ElectricalModel* last_clk_div_dff = NULL;
+ // Find P01 of OutCK
+ double last_P01_CK = getInputPort("OutCK")->getTransitionInfo().getNumberTransitions01();
+ // Start from the last stage (since it is the stage with no clock division)
+ for (unsigned int i = 0; i < number_stages - 1; ++i)
+ {
+ const String& clk_div_dff_name = "ClkDivDFF_" + (String) (number_stages - i - 2);
+ const String& clk_div_inv_name = "ClkDivINV_" + (String) (number_stages - i - 2);
+
+ ElectricalModel* clk_div_dff = (ElectricalModel*) getSubInstance(clk_div_dff_name);
+ if (last_clk_div_dff == NULL)
+ propagatePortTransitionInfo(clk_div_dff, "CK", "OutCK");
+ else
+ propagatePortTransitionInfo(clk_div_dff, "CK", last_clk_div_dff, "Q");
+ // Since it is a clock divider, P01 is D and Q are simply half the P01 of D and Q of
+ // the input clock
+ if (last_P01_CK != 0) clk_div_dff->getInputPort("D")->setTransitionInfo(TransitionInfo(0.0, last_P01_CK * 0.5, 0.0));
+ else clk_div_dff->getInputPort("D")->setTransitionInfo(TransitionInfo(0.5, 0.0, 0.5));
+
+ clk_div_dff->use();
+
+ ElectricalModel* clk_div_inv = (ElectricalModel*) getSubInstance(clk_div_inv_name);
+ propagatePortTransitionInfo(clk_div_inv, "A", clk_div_dff, "Q");
+ clk_div_inv->use();
+
+ // Connect select port of the mux
+ propagatePortTransitionInfo(mux_tree, "Sel" + (String) (number_stages - i - 2), clk_div_dff, "Q");
+
+ // Clk divide by 2;
+ last_P01_CK = last_P01_CK * 0.5;
+ // Remember the last clk div DFF
+ last_clk_div_dff = clk_div_dff;
+ }
+
+ mux_tree->use();
+ // Set output transition info to be the output transition info of the mux tree
+ propagatePortTransitionInfo("Out", mux_tree, "Out");
+ }
+
+ return;
+ }
+
+} // namespace DSENT
+
diff --git a/ext/dsent/model/electrical/MuxTreeSerializer.h b/ext/dsent/model/electrical/MuxTreeSerializer.h
new file mode 100644
index 000000000..f56cccc4f
--- /dev/null
+++ b/ext/dsent/model/electrical/MuxTreeSerializer.h
@@ -0,0 +1,33 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_MUXTREESERIALIZER_H__
+#define __DSENT_MODEL_ELECTRICAL_MUXTREESERIALIZER_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+ class MuxTreeSerializer : public ElectricalModel
+ {
+ public:
+ MuxTreeSerializer(const String& instance_name_, const TechModel* tech_model_);
+ virtual ~MuxTreeSerializer();
+
+ public:
+ // Set a list of properties' name needed to construct model
+ void initParameters();
+ // Set a list of properties' name needed to construct model
+ void initProperties();
+
+ // Clone and return a new instance
+ virtual MuxTreeSerializer* clone() const;
+
+ protected:
+ // Build the model
+ virtual void constructModel();
+ virtual void propagateTransitionInfo();
+
+ }; // class MuxTreeSerializer
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_MUXTREESERIALIZER_H__
+
diff --git a/ext/dsent/model/electrical/OR.cc b/ext/dsent/model/electrical/OR.cc
new file mode 100644
index 000000000..d948ff086
--- /dev/null
+++ b/ext/dsent/model/electrical/OR.cc
@@ -0,0 +1,239 @@
+#include "model/electrical/OR.h"
+
+#include <cmath>
+
+#include "model/PortInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/EventInfo.h"
+#include "model/std_cells/StdCellLib.h"
+#include "model/std_cells/StdCell.h"
+#include "model/timing_graph/ElectricalNet.h"
+
+namespace DSENT
+{
+ using std::ceil;
+ using std::floor;
+
+ OR::OR(const String& instance_name_, const TechModel* tech_model_)
+ : ElectricalModel(instance_name_, tech_model_)
+ {
+ initParameters();
+ initProperties();
+ }
+
+ OR::~OR()
+ {}
+
+ void OR::initParameters()
+ {
+ addParameterName("NumberInputs");
+ addParameterName("NumberBits");
+ addParameterName("BitDuplicate", "TRUE");
+ return;
+ }
+
+ void OR::initProperties()
+ {
+ return;
+ }
+
+ OR* OR::clone() const
+ {
+ // TODO
+ return NULL;
+ }
+
+ void OR::constructModel()
+ {
+ // Get parameter
+ unsigned int number_inputs = getParameter("NumberInputs").toUInt();
+ unsigned int number_bits = getParameter("NumberBits").toUInt();
+ bool bit_duplicate = getParameter("BitDuplicate").toBool();
+
+ ASSERT(number_inputs > 0, "[Error] " + getInstanceName() +
+ " -> Number of inputs must be > 0!");
+ ASSERT(number_bits > 0, "[Error] " + getInstanceName() +
+ " -> Number of bits must be > 0!");
+
+
+ // Init ports
+ for(unsigned int i = 0; i < number_inputs; ++i)
+ {
+ createInputPort("In" + (String)i, makeNetIndex(0, number_bits-1));
+ }
+ createOutputPort("Out", makeNetIndex(0, number_bits-1));
+
+ // Number of inputs on the 0 side
+ unsigned int or0_number_inputs = (unsigned int)ceil((double)number_inputs / 2.0);
+ // Number of inputs on the 1 side
+ unsigned int or1_number_inputs = (unsigned int)floor((double)number_inputs / 2.0);
+
+ // Create area, power, and event results
+ createElectricalResults();
+ createElectricalEventResult("OR");
+
+ getEventInfo("Idle")->setStaticTransitionInfos();
+
+ //Depending on whether we want to create a 1-bit instance and have it multiplied
+ //up by number of bits or actually instantiate number_bits of 1-bit instances.
+ //Recursively instantiates smaller ors
+ if(bit_duplicate || number_bits == 1)
+ {
+ // If it is just a 1-input or, just connect output to input
+ if(number_inputs == 1)
+ {
+ assign("Out", "In0");
+ }
+ else
+ {
+ // If it is more than 1 input, instantiate two sub ors (OR_way0 and OR_way1)
+ // and create a final OR2 to OR them
+ const String& or0_name = "OR_way0";
+ const String& or1_name = "OR_way1";
+ const String& orf_name = "OR2_i" + (String)number_inputs;
+
+ OR* or0 = new OR(or0_name, getTechModel());
+ or0->setParameter("NumberInputs", or0_number_inputs);
+ or0->setParameter("NumberBits", 1);
+ or0->setParameter("BitDuplicate", "TRUE");
+ or0->construct();
+
+ OR* or1 = new OR(or1_name, getTechModel());
+ or1->setParameter("NumberInputs", or1_number_inputs);
+ or1->setParameter("NumberBits", 1);
+ or1->setParameter("BitDuplicate", "TRUE");
+ or1->construct();
+
+ StdCell* orf = getTechModel()->getStdCellLib()->createStdCell("OR2", orf_name);
+ orf->construct();
+
+ // Create outputs of way0 and way1 ors with final or
+ createNet("way0_Out");
+ createNet("way1_Out");
+ portConnect(or0, "Out", "way0_Out");
+ portConnect(or1, "Out", "way1_Out");
+ portConnect(orf, "A", "way0_Out");
+ portConnect(orf, "B", "way1_Out");
+
+ // Connect inputs to the sub ors.
+ for(unsigned int i = 0; i < or0_number_inputs; ++i)
+ {
+ createNet("way0_In" + (String)i);
+ portConnect(or0, "In" + (String)i, "way0_In" + (String)i);
+ assignVirtualFanin("way0_In" + (String)i, "In" + (String)i);
+ }
+ for(unsigned int i = 0; i < or1_number_inputs; ++i)
+ {
+ createNet("way1_In" + (String)i);
+ portConnect(or1, "In" + (String)i, "way1_In" + (String)i);
+ assignVirtualFanin("way1_In" + (String)i, "In" + (String)(i + or0_number_inputs));
+ }
+
+ // Connect outputs
+ createNet("OR2_Out");
+ portConnect(orf, "Y", "OR2_Out");
+ assignVirtualFanout("Out", "OR2_Out");
+
+ addSubInstances(or0, number_bits);
+ addElectricalSubResults(or0, number_bits);
+ addSubInstances(or1, number_bits);
+ addElectricalSubResults(or1, number_bits);
+ addSubInstances(orf, number_bits);
+ addElectricalSubResults(orf, number_bits);
+
+ Result* or_event = getEventResult("OR");
+ or_event->addSubResult(or0->getEventResult("OR"), or0_name, number_bits);
+ or_event->addSubResult(or1->getEventResult("OR"), or1_name, number_bits);
+ or_event->addSubResult(orf->getEventResult("OR2"), orf_name, number_bits);
+
+ }
+ }
+ else
+ {
+ // Init a bunch of 1-bit ors
+ Result* or_event = getEventResult("OR");
+ for(unsigned int n = 0; n < number_bits; ++n)
+ {
+ const String& or_name = "OR_bit" + (String)n;
+
+ OR* ors = new OR(or_name, getTechModel());
+ ors->setParameter("NumberInputs", number_inputs);
+ ors->setParameter("NumberBits", 1);
+ ors->setParameter("BitDuplicate", "TRUE");
+ ors->construct();
+
+ for(unsigned int i = 0; i < number_inputs; ++i)
+ {
+ portConnect(ors, "In" + (String)i, "In" + (String)i, makeNetIndex(n));
+ }
+ portConnect(ors, "Out", "Out", makeNetIndex(n));
+
+ addSubInstances(ors, 1.0);
+ addElectricalSubResults(ors, 1.0);
+ or_event->addSubResult(ors->getEventResult("OR"), or_name, 1.0);
+ }
+ }
+ return;
+ }
+
+ void OR::propagateTransitionInfo()
+ {
+ // Get parameters
+ unsigned int number_inputs = getParameter("NumberInputs").toUInt();
+ unsigned int number_bits = getParameter("NumberBits").toUInt();
+ bool bit_duplicate = getParameter("BitDuplicate").toBool();
+
+ // Number of inputs on 0 side
+ unsigned int or0_number_inputs = (unsigned int)ceil((double)number_inputs / 2.0);
+ unsigned int or1_number_inputs = (unsigned int)floor((double)number_inputs / 2.0);
+
+ if(bit_duplicate || number_bits == 1)
+ {
+ if(number_inputs == 1)
+ {
+ propagatePortTransitionInfo("Out", "In0");
+ }
+ else
+ {
+ ElectricalModel* or0 = (ElectricalModel*)getSubInstance("OR_way0");
+ for(unsigned int i = 0; i < or0_number_inputs; ++i)
+ {
+ propagatePortTransitionInfo(or0, "In" + (String)i, "In" + (String)i);
+ }
+ or0->use();
+
+ ElectricalModel* or1 = (ElectricalModel*)getSubInstance("OR_way1");
+ for(unsigned int i = 0; i < or1_number_inputs; ++i)
+ {
+ propagatePortTransitionInfo(or1, "In" + (String)i, "In" + (String)i);
+ }
+ or1->use();
+
+ ElectricalModel* orf = (ElectricalModel*)getSubInstance("OR2_i" + (String)number_inputs);
+ propagatePortTransitionInfo(orf, "A", or0, "Out");
+ propagatePortTransitionInfo(orf, "B", or1, "Out");
+ orf->use();
+
+ // Set output probability
+ propagatePortTransitionInfo("Out", orf, "Y");
+ }
+ }
+ else
+ {
+ for(unsigned int n = 0; n < number_bits; ++n)
+ {
+ ElectricalModel* or_bit = (ElectricalModel*)getSubInstance("OR_bit" + (String)n);
+ for(unsigned int i = 0; i < number_inputs; ++i)
+ {
+ propagatePortTransitionInfo(or_bit, "In" + (String)i, "In" + (String)i);
+ }
+ or_bit->use();
+ }
+
+ ElectricalModel* or_bit = (ElectricalModel*)getSubInstance("OR_bit0");
+ propagatePortTransitionInfo("Out", or_bit, "Out");
+ }
+ return;
+ }
+} // namespace DSENT
+
diff --git a/ext/dsent/model/electrical/OR.h b/ext/dsent/model/electrical/OR.h
new file mode 100644
index 000000000..b8304799c
--- /dev/null
+++ b/ext/dsent/model/electrical/OR.h
@@ -0,0 +1,36 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_OR_H__
+#define __DSENT_MODEL_ELECTRICAL_OR_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+ /**
+ * \brief A class that implements a n-input OR gate
+ */
+ class OR : public ElectricalModel
+ {
+ public:
+ OR(const String& instance_name_, const TechModel* tech_model_);
+ virtual ~OR();
+
+ public:
+ // Set a list of properties' name needed to construct model
+ void initParameters();
+ // Set a list of properties' name needed to construct model
+ void initProperties();
+
+ // Clone and return a new instance
+ virtual OR* clone() const;
+
+ protected:
+ // Build the model
+ virtual void constructModel();
+ virtual void propagateTransitionInfo();
+
+ }; // class OR
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_OR_H__
+
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
+
diff --git a/ext/dsent/model/electrical/RepeatedLink.h b/ext/dsent/model/electrical/RepeatedLink.h
new file mode 100644
index 000000000..1cd8e3412
--- /dev/null
+++ b/ext/dsent/model/electrical/RepeatedLink.h
@@ -0,0 +1,44 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_REPEATED_LINK_H__
+#define __DSENT_MODEL_ELECTRICAL_REPEATED_LINK_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+ class StdCell;
+ class ElectricalLoad;
+ class ElectricalTimingTree;
+
+ class RepeatedLink : public ElectricalModel
+ {
+ public:
+ RepeatedLink(const String& instance_name_, const TechModel* tech_model_);
+ virtual ~RepeatedLink();
+
+ public:
+ // Set a list of properties' name needed to construct model
+ void initParameters();
+ // Set a list of properties' name needed to construct model
+ void initProperties();
+
+ // Clone and return a new instance
+ virtual RepeatedLink* clone() const;
+
+ protected:
+ // Build the model
+ virtual void constructModel();
+ virtual void updateModel();
+ virtual void useModel();
+ virtual void propagateTransitionInfo();
+
+ private:
+ // Use a repeater and a load to mimic a segment of the repeated link
+ StdCell* m_repeater_;
+ ElectricalLoad* m_repeater_load_;
+ ElectricalTimingTree* m_timing_tree_;
+ }; // class RepeatedLink
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_REPEATED_LINK_H__
+
diff --git a/ext/dsent/model/electrical/RippleAdder.cc b/ext/dsent/model/electrical/RippleAdder.cc
new file mode 100644
index 000000000..779cd4798
--- /dev/null
+++ b/ext/dsent/model/electrical/RippleAdder.cc
@@ -0,0 +1,106 @@
+#include "model/electrical/RippleAdder.h"
+
+#include <cmath>
+
+#include "model/PortInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/EventInfo.h"
+#include "model/std_cells/StdCell.h"
+#include "model/std_cells/StdCellLib.h"
+
+namespace DSENT
+{
+ RippleAdder::RippleAdder(const String& instance_name_, const TechModel* tech_model_)
+ : ElectricalModel(instance_name_, tech_model_)
+ {
+ initParameters();
+ initProperties();
+ }
+
+ RippleAdder::~RippleAdder()
+ {}
+
+ void RippleAdder::initParameters()
+ {
+ addParameterName("NumberBits");
+ return;
+ }
+
+ void RippleAdder::initProperties()
+ {
+ return;
+ }
+
+ void RippleAdder::constructModel()
+ {
+ // Get properties
+ unsigned int number_bits = (unsigned int) getParameter("NumberBits");
+
+ //Construct electrical ports and nets
+ createInputPort("CI");
+ createOutputPort("CO");
+ for(unsigned int i = 0; i < number_bits; ++i)
+ {
+ createInputPort("A" + String(i));
+ createInputPort("B" + String(i));
+ createOutputPort("S" + String(i));
+ createNet("C" + String(i));
+ }
+ createNet("C" + String(number_bits));
+
+ //Create energy, power, and area results
+ createElectricalResults();
+ getEventInfo("Idle")->setStaticTransitionInfos();
+ createElectricalEventResult("Add");
+ Result* add_event = getEventResult("Add");
+
+ // Connect all nets
+ assign("C0", "CI");
+ assign("CO", "C" + String(number_bits));
+ for (unsigned int i = 0; i < number_bits; ++i)
+ {
+ String n = (String) i;
+ StdCell* adder = getTechModel()->getStdCellLib()->createStdCell("ADDF", "ADDF_" + n);
+ adder->construct();
+
+ //Build electrical connectivity
+ portConnect(adder, "A", "A" + String(i));
+ portConnect(adder, "B", "B" + String(i));
+ portConnect(adder, "CI", "C" + String(i));
+ portConnect(adder, "S", "S" + String(i));
+ portConnect(adder, "CO", "C" + String(i + 1));
+
+ //Add ADDF instance, leakage power, energy, and add event results
+ addSubInstances(adder, 1.0);
+ addElectricalSubResults(adder, 1.0);
+ add_event->addSubResult(adder->getEventResult("ADDF"), "ADDF_" + n, 1.0);
+ }
+
+ return;
+ }
+
+ void RippleAdder::propagateTransitionInfo()
+ {
+ unsigned int number_bits = getParameter("NumberBits").toUInt();
+
+ TransitionInfo current_trans_CI = getInputPort("CI")->getTransitionInfo();
+ for(unsigned int i = 0; i < number_bits; ++i)
+ {
+ ElectricalModel* adder = (ElectricalModel*)getSubInstance("ADDF_" + String(i));
+
+ // Propagate input transition info
+ propagatePortTransitionInfo(adder, "A", "A" + String(i));
+ propagatePortTransitionInfo(adder, "B", "B" + String(i));
+ assignPortTransitionInfo(adder, "CI", current_trans_CI);
+ adder->use();
+
+ // Assign output transition info
+ propagatePortTransitionInfo("S" + String(i), adder, "S");
+ current_trans_CI = adder->getOutputPort("CO")->getTransitionInfo();
+ }
+ getOutputPort("CO")->setTransitionInfo(current_trans_CI);
+ return;
+ }
+
+} // namespace DSENT
+
diff --git a/ext/dsent/model/electrical/RippleAdder.h b/ext/dsent/model/electrical/RippleAdder.h
new file mode 100644
index 000000000..6f5f71072
--- /dev/null
+++ b/ext/dsent/model/electrical/RippleAdder.h
@@ -0,0 +1,30 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_RIPPLE_ADDER_H__
+#define __DSENT_MODEL_ELECTRICAL_RIPPLE_ADDER_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+ class RippleAdder : public ElectricalModel
+ {
+ public:
+ RippleAdder(const String& instance_name_, const TechModel* tech_model_);
+ virtual ~RippleAdder();
+
+ public:
+ // Set a list of properties' name needed to construct model
+ void initParameters();
+ // Set a list of properties' name needed to construct model
+ void initProperties();
+
+ protected:
+ // Build the model
+ virtual void constructModel();
+ virtual void propagateTransitionInfo();
+
+ }; // class RippleAdder
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_TESTMODEL_H__
+
diff --git a/ext/dsent/model/electrical/SeparableAllocator.cc b/ext/dsent/model/electrical/SeparableAllocator.cc
new file mode 100644
index 000000000..e0965cbe9
--- /dev/null
+++ b/ext/dsent/model/electrical/SeparableAllocator.cc
@@ -0,0 +1,270 @@
+#include "model/electrical/SeparableAllocator.h"
+
+#include "model/ModelGen.h"
+#include "model/timing_graph/ElectricalNet.h"
+
+namespace DSENT
+{
+ SeparableAllocator::SeparableAllocator(const String& instance_name_, const TechModel* tech_model_)
+ : ElectricalModel(instance_name_, tech_model_)
+ {
+ initParameters();
+ initProperties();
+ }
+
+ SeparableAllocator::~SeparableAllocator()
+ {}
+
+ void SeparableAllocator::initParameters()
+ {
+ addParameterName("NumberRequesters");
+ addParameterName("NumberResources");
+ addParameterName("IsRequesterFirst", true);
+ addParameterName("Stage1->ArbiterModel");
+ addParameterName("Stage2->ArbiterModel");
+ return;
+ }
+
+ void SeparableAllocator::initProperties()
+ {
+ addPropertyName("P(Request)");
+ addPropertyName("Act(Request)");
+ addPropertyName("P(CK)");
+ addPropertyName("Act(CK)");
+ return;
+ }
+
+ SeparableAllocator* SeparableAllocator::clone() const
+ {
+ // TODO
+ return NULL;
+ }
+
+ void SeparableAllocator::constructModel()
+ {
+ // Get parameters
+ unsigned int number_requesters = getParameter("NumberRequesters").toUInt();
+ unsigned int number_resources = getParameter("NumberResources").toUInt();
+ bool is_requester_first = getParameter("IsRequesterFirst").toBool();
+ const String& stage1_arbiter_model = getParameter("Stage1->ArbiterModel");
+ const String& stage2_arbiter_model = getParameter("Stage2->ArbiterModel");
+
+ ASSERT(number_requesters > 0, "[Error] " + getInstanceName() +
+ " -> Number of requesters must be > 0!");
+ ASSERT(number_resources > 0, "[Error] " + getInstanceName() +
+ " -> Number of resources must be > 0!");
+
+ // Create area, power, and event results
+ createElectricalResults();
+ addEventResult(new Result("Allocate"));
+
+ // Create ports
+ createInputPort("CK");
+ for(unsigned int i = 0; i < number_requesters; ++i)
+ {
+ createInputPort("Request" + (String)i, makeNetIndex(0, number_resources-1));
+ createOutputPort("Grant" + (String)i, makeNetIndex(0, number_resources-1));
+ }
+
+ // If is_requester_first is set, requests from the same requester will be arbitrate
+ // on stage 1
+ if(is_requester_first)
+ {
+ // Init stage 1 arbiters
+ for(unsigned int i = 0; i < number_requesters; ++i)
+ {
+ ElectricalModel* arb = (ElectricalModel*)ModelGen::createModel(stage1_arbiter_model, "Stage1Arb" + (String)i, getTechModel());
+ arb->setParameter("NumberRequests", number_resources);
+ arb->construct();
+
+ addSubInstances(arb, 1.0);
+ addElectricalSubResults(arb, 1.0);
+
+ getEventResult("Allocate")->addSubResult(arb->getEventResult("Arbitrate"), arb->getInstanceName(), 1.0);
+
+ createNet("Stage1Arb_In" + (String)i, makeNetIndex(0, number_resources-1));
+ createNet("Stage1Arb_Out" + (String)i, makeNetIndex(0, number_resources-1));
+
+ portConnect(arb, "CK", "CK");
+ assign("Stage1Arb_In" + (String)i, "Request" + (String)i);
+ for(unsigned int j = 0; j < number_resources; ++j)
+ {
+ portConnect(arb, "Request" + (String)j, "Stage1Arb_In" + (String)i, makeNetIndex(j));
+ portConnect(arb, "Grant" + (String)j, "Stage1Arb_Out" + (String)i, makeNetIndex(j));
+ }
+ }
+
+ // Init stage 2 arbiters
+ for(unsigned int i = 0; i < number_resources; ++i)
+ {
+ ElectricalModel* arb = (ElectricalModel*)ModelGen::createModel(stage2_arbiter_model, "Stage2Arb" + (String)i, getTechModel());
+ arb->setParameter("NumberRequests", number_requesters);
+ arb->construct();
+
+ addSubInstances(arb, 1.0);
+ addElectricalSubResults(arb, 1.0);
+
+ getEventResult("Allocate")->addSubResult(arb->getEventResult("Arbitrate"), arb->getInstanceName(), 1.0);
+
+ createNet("Stage2Arb_In" + (String)i, makeNetIndex(0, number_requesters-1));
+ createNet("Stage2Arb_Out" + (String)i, makeNetIndex(0, number_requesters-1));
+
+ portConnect(arb, "CK", "CK");
+ for(unsigned int j = 0; j < number_requesters; ++j)
+ {
+ assign("Stage2Arb_In" + (String)i, makeNetIndex(j), "Stage1Arb_Out" + (String)j, makeNetIndex(i));
+ portConnect(arb, "Request" + (String)j, "Stage2Arb_In" + (String)i, makeNetIndex(j));
+ portConnect(arb, "Grant" + (String)j, "Stage2Arb_Out" + (String)i, makeNetIndex(j));
+ assign("Grant" + (String)j, makeNetIndex(i), "Stage2Arb_Out" + (String)i, makeNetIndex(j));
+ }
+ }
+ }
+ else
+ {
+ // Init stage 1 arbiters
+ for(unsigned int i = 0; i < number_resources; ++i)
+ {
+ ElectricalModel* arb = (ElectricalModel*)ModelGen::createModel(stage1_arbiter_model, "Stage1Arb" + (String)i, getTechModel());
+ arb->setParameter("NumberRequests", number_requesters);
+ arb->construct();
+
+ addSubInstances(arb, 1.0);
+ addElectricalSubResults(arb, 1.0);
+
+ getEventResult("Allocate")->addSubResult(arb->getEventResult("Arbitrate"), arb->getInstanceName(), 1.0);
+
+ createNet("Stage1Arb_In" + (String)i, makeNetIndex(0, number_requesters-1));
+ createNet("Stage1Arb_Out" + (String)i, makeNetIndex(0, number_requesters-1));
+
+ portConnect(arb, "CK", "CK");
+ for(unsigned int j = 0; j < number_requesters; ++j)
+ {
+ assign("Stage1Arb_In" + (String)i, makeNetIndex(j), "Request" + (String)j, makeNetIndex(i));
+ portConnect(arb, "Request" + (String)j, "Stage1Arb_In" + (String)i, makeNetIndex(j));
+ portConnect(arb, "Grant" + (String)j, "Stage1Arb_Out" + (String)i, makeNetIndex(j));
+ }
+ }
+
+ // Init stage 2 arbiters
+ for(unsigned int i = 0; i < number_requesters; ++i)
+ {
+ ElectricalModel* arb = (ElectricalModel*)ModelGen::createModel(stage2_arbiter_model, "Stage2Arb" + (String)i, getTechModel());
+ arb->setParameter("NumberRequests", number_requesters);
+ arb->construct();
+
+ addSubInstances(arb, 1.0);
+ addElectricalSubResults(arb, 1.0);
+
+ getEventResult("Allocate")->addSubResult(arb->getEventResult("Arbitrate"), arb->getInstanceName(), 1.0);
+
+ createNet("Stage2Arb_In" + (String)i, makeNetIndex(0, number_resources-1));
+ createNet("Stage2Arb_Out" + (String)i, makeNetIndex(0, number_resources-1));
+
+ portConnect(arb, "CK", "CK");
+ for(unsigned int j = 0; j < number_resources; ++j)
+ {
+ assign("Stage2Arb_In" + (String)i, makeNetIndex(j), "Stage1Arb_Out" + (String)j, makeNetIndex(i));
+ portConnect(arb, "Request" + (String)j, "Stage2Arb_In", makeNetIndex(j));
+ portConnect(arb, "Grant" + (String)j, "Stage2Arb_Out", makeNetIndex(j));
+ }
+ assign("Grant" + (String)i, "Stage2Arb_Out" + (String)i);
+ }
+ }
+ return;
+ }
+
+ void SeparableAllocator::updateModel()
+ {
+ // Get parameters
+ unsigned int number_requesters = getParameter("NumberRequesters").toUInt();
+ unsigned int number_resources = getParameter("NumberResources").toUInt();
+ bool is_requester_first = getParameter("IsRequesterFirst").toBool();
+
+ // Get probabilities from inputs
+ const String& P_request = getProperty("P(Request)");
+ const String& act_request = getProperty("Act(Request)");
+ const String& P_CK = getProperty("P(CK)");
+ const String& act_CK = getProperty("Act(CK)");
+
+ const vector<double>& P_request_vector = LibUtil::castStringVector<double>(P_request.split("[,]"));
+ const vector<double>& act_request_vector = LibUtil::castStringVector<double>(act_request.split("[,]"));
+
+ ASSERT(P_request_vector.size() == (number_requesters * number_resources), "[Error] " + getInstanceName() +
+ " -> Expecting " + (String)(number_requesters * number_resources) +
+ " request probabilities, but got " + P_request);
+ ASSERT(act_request_vector.size() == (number_requesters * number_resources), "[Error] " + getInstanceName() +
+ " -> Expecting " + (String)(number_requesters * number_resources) +
+ " request actvities multiplier, but got " + act_request);
+
+ vector<double> P_int_request_vector(number_requesters * number_resources, 0.0);
+ vector<double> act_int_request_vector(number_requesters * number_resources, 0.0);
+ vector<double> P_out_request_vector(number_requesters * number_resources, 0.0);
+ vector<double> act_out_request_vector(number_requesters * number_resources, 0.0);
+ if(is_requester_first)
+ {
+ // Update stage1 arbiter
+ for(unsigned int i = 0; i < number_requesters; ++i)
+ {
+ vector<double> P_arb_request_vector(number_resources, 0.0);
+ vector<double> act_arb_request_vector(number_resources, 0.0);
+ for(unsigned int j = 0; j < number_resources; ++j)
+ {
+ P_arb_request_vector[j] = P_request_vector[i * number_resources + j];
+ act_arb_request_vector[j] = act_request_vector[i * number_resources + j];
+ }
+
+ Model* arb = getSubInstance("Stage1Arb" + (String)i);
+ arb->setProperty("P(Request)", LibUtil::vectorToString(P_arb_request_vector));
+ arb->setProperty("Act(Request)", LibUtil::vectorToString(act_arb_request_vector));
+ arb->setProperty("P(CK)", P_CK);
+ arb->setProperty("Act(CK)", act_CK);
+ arb->update();
+
+ const vector<double>& P_arb_out_request_vector = LibUtil::castStringVector<double>(arb->getGenProperties()->get("P(Grant)").split("[,]"));
+ const vector<double>& act_arb_out_request_vector = LibUtil::castStringVector<double>(arb->getGenProperties()->get("Act(Grant)").split("[,]"));
+ for(unsigned int j = 0; j < number_resources; ++j)
+ {
+ P_int_request_vector[i * number_resources + j] = P_arb_out_request_vector[j];
+ act_int_request_vector[i * number_resources + j] = act_arb_out_request_vector[j];
+ }
+ }
+ // Update stage2 arbiter
+ for(unsigned int i = 0; i < number_resources; ++i)
+ {
+ vector<double> P_arb_request_vector(number_requesters, 0.0);
+ vector<double> act_arb_request_vector(number_requesters, 0.0);
+ for(unsigned int j = 0; j < number_requesters; ++j)
+ {
+ P_arb_request_vector[j] = P_int_request_vector[j * number_resources + i];
+ act_arb_request_vector[j] = act_int_request_vector[j * number_resources + i];
+ }
+
+ Model* arb = getSubInstance("Stage2Arb" + (String)i);
+ arb->setProperty("P(Request)", LibUtil::vectorToString(P_arb_request_vector));
+ arb->setProperty("Act(Request)", LibUtil::vectorToString(act_arb_request_vector));
+ arb->setProperty("P(CK)", P_CK);
+ arb->setProperty("Act(CK)", act_CK);
+ arb->update();
+
+ const vector<double>& P_arb_out_request_vector = LibUtil::castStringVector<double>(arb->getGenProperties()->get("P(Grant)").split("[,]"));
+ const vector<double>& act_arb_out_request_vector = LibUtil::castStringVector<double>(arb->getGenProperties()->get("Act(Grant)").split("[,]"));
+ for(unsigned int j = 0; j < number_requesters; ++j)
+ {
+ P_out_request_vector[j * number_resources + i] = P_arb_out_request_vector[j];
+ act_out_request_vector[j * number_resources + i] = act_arb_out_request_vector[j];
+ }
+ }
+ }
+ else
+ {
+
+ }
+
+ // Update output probabilities
+ getGenProperties()->set("P(Grant)", LibUtil::vectorToString(P_out_request_vector));
+ getGenProperties()->set("Act(Grant)", LibUtil::vectorToString(act_out_request_vector));
+
+ return;
+ }
+} // namespace DSENT
+
diff --git a/ext/dsent/model/electrical/SeparableAllocator.h b/ext/dsent/model/electrical/SeparableAllocator.h
new file mode 100644
index 000000000..21519bf38
--- /dev/null
+++ b/ext/dsent/model/electrical/SeparableAllocator.h
@@ -0,0 +1,33 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_SEPARABLE_ALLOCATOR_H__
+#define __DSENT_MODEL_ELECTRICAL_SEPARABLE_ALLOCATOR_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+ class SeparableAllocator : public ElectricalModel
+ {
+ public:
+ SeparableAllocator(const String& instance_name_, const TechModel* tech_model_);
+ virtual ~SeparableAllocator();
+
+ public:
+ // Set a list of properties' name needed to construct model
+ void initParameters();
+ // Set a list of properties' name needed to construct model
+ void initProperties();
+
+ // Clone and return a new instance
+ virtual SeparableAllocator* clone() const;
+
+ protected:
+ // Build the model
+ virtual void constructModel();
+ virtual void updateModel();
+
+ }; // class SeparableAllocator
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_SEPARABLE_ALLOCATOR_H__
+
diff --git a/ext/dsent/model/electrical/TestModel.cc b/ext/dsent/model/electrical/TestModel.cc
new file mode 100644
index 000000000..24f1fab43
--- /dev/null
+++ b/ext/dsent/model/electrical/TestModel.cc
@@ -0,0 +1,218 @@
+#include "model/electrical/TestModel.h"
+
+#include <cmath>
+
+#include "model/std_cells/StdCell.h"
+#include "model/std_cells/StdCellLib.h"
+#include "model/electrical/RippleAdder.h"
+#include "model/electrical/Multiplexer.h"
+#include "model/timing_graph/ElectricalNet.h"
+#include "model/timing_graph/ElectricalDriver.h"
+#include "model/timing_graph/ElectricalLoad.h"
+#include "model/timing_graph/ElectricalTimingTree.h"
+
+namespace DSENT
+{
+ TestModel::TestModel(const String& instance_name_, const TechModel* tech_model_)
+ : ElectricalModel(instance_name_, tech_model_)
+ {
+ initProperties();
+ }
+
+ TestModel::~TestModel()
+ {}
+
+ void TestModel::initProperties()
+ {
+ return;
+ }
+
+ TestModel* TestModel::clone() const
+ {
+ return NULL;
+ }
+
+ void TestModel::constructModel()
+ {
+ unsigned int num_bits = 64;
+ unsigned int mux_bits = 1;
+
+ // Create the instance
+ createNet("CK");
+ createNet("CI");
+ getNet("CI")->setDistributedCap(100e-15);
+ getNet("CI")->setDistributedRes(10);
+ createNet("CO");
+ createNet("A", makeNetIndex(0, num_bits - 1));
+ createNet("B", makeNetIndex(0, num_bits - 1));
+ createNet("S", makeNetIndex(0, num_bits - 1));
+
+ StdCell* ci_reg = getTechModel()->getStdCellLib()->createStdCell("DFFQ", "DFFQ-CI");
+ ci_reg->setProperty("P(D)", 0.5);
+ ci_reg->setProperty("P(CK)", 0.5);
+ ci_reg->construct();
+ portConnect(ci_reg, "Q", "CI");
+ portConnect(ci_reg, "CK", "CK");
+ //ci_reg->connect("Q", getNet("CI"));
+ //ci_reg->connect("CK", getNet("CK"));
+ addSubInstances(ci_reg, 1.0);
+
+ StdCell* co_reg = getTechModel()->getStdCellLib()->createStdCell("DFFQ", "DFFQ-CO");
+ co_reg->setProperty("P(D)", 0.5);
+ co_reg->setProperty("P(CK)", 0.5);
+ co_reg->construct();
+ portConnect(co_reg, "D", "CO");
+ portConnect(co_reg, "CK", "CK");
+ //co_reg->connect("D", getNet("CO"));
+ //co_reg->connect("CK", getNet("CK"));
+ addSubInstances(co_reg, 1.0);
+
+ for (unsigned int i = 0; i < num_bits; i++)
+ {
+ StdCell* a_reg = getTechModel()->getStdCellLib()->createStdCell("DFFQ", "DFFQ-A[" + (String) i + "]");
+ a_reg->setProperty("P(D)", 0.5);
+ a_reg->setProperty("P(CK)", 0.5);
+ a_reg->construct();
+ portConnect(a_reg, "Q", "A", makeNetIndex(i));
+ portConnect(a_reg, "CK", "CK");
+ //a_reg->connect("Q", getNet("A[" + (String) i + "]"));
+ //a_reg->connect("CK", getNet("CK"));
+ addSubInstances(a_reg, 1.0);
+
+ StdCell* b_reg = getTechModel()->getStdCellLib()->createStdCell("DFFQ", "DFFQ-B[" + (String) i + "]");
+ b_reg->setProperty("P(D)", 0.5);
+ b_reg->setProperty("P(CK)", 0.5);
+ b_reg->construct();
+ portConnect(b_reg, "Q", "B", makeNetIndex(i));
+ portConnect(b_reg, "CK", "CK");
+ //b_reg->connect("Q", getNet("B[" + (String) i + "]"));
+ //b_reg->connect("CK", getNet("CK"));
+ addSubInstances(b_reg, 1.0);
+
+ StdCell* s_reg = getTechModel()->getStdCellLib()->createStdCell("DFFQ", "DFFQ-S[" + (String) i + "]");
+ s_reg->setProperty("P(D)", 0.5);
+ s_reg->setProperty("P(CK)", 0.5);
+ s_reg->construct();
+ portConnect(s_reg, "D", "S", makeNetIndex(i));
+ portConnect(s_reg, "CK", "CK");
+ //s_reg->connect("D", getNet("A[" + (String) i + "]"));
+ //s_reg->connect("CK", getNet("CK"));
+ addSubInstances(s_reg, 1.0);
+ }
+
+
+ //Create some adders!
+
+ ElectricalModel* ripple_adder = new RippleAdder("Adder_1", getTechModel());
+ ripple_adder->setParameter("NumberBits", num_bits);
+ ripple_adder->setProperty("P(A)", 0.5);
+ ripple_adder->setProperty("P(B)", 0.5);
+ ripple_adder->setProperty("P(CI)", 0.5);
+
+ ripple_adder->construct();
+ addSubInstances(ripple_adder, 1.0);
+ portConnect(ripple_adder, "CI", "CI");
+ portConnect(ripple_adder, "CO", "CO");
+ portConnect(ripple_adder, "A", "A");
+ portConnect(ripple_adder, "B", "B");
+ portConnect(ripple_adder, "S", "S");
+
+ ElectricalModel* multiplexer = new Multiplexer("Mux_1", getTechModel());
+ multiplexer->setParameter("NumberInputs", 2);
+ multiplexer->setParameter("NumberBits", mux_bits);
+ multiplexer->setParameter("BitDuplicate", "FALSE");
+ //multiplexer->setProperty("P(In)", "[0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5]");
+ //multiplexer->setProperty("P(Sel)", "[0.5, 0.5, 0.5]");
+ //multiplexer->setProperty("Act(In)", "[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]");
+ //multiplexer->setProperty("Act(Sel)", "[2.0, 4.0, 8.0]");
+ multiplexer->setProperty("P(In)", "[0.5, 0.5]");
+ multiplexer->setProperty("P(Sel)", "[0.5]");
+ multiplexer->setProperty("Act(In)", "[1.0, 1.0]");
+ multiplexer->setProperty("Act(Sel)", "[1.0]");
+ multiplexer->construct();
+
+ createNet("In0", makeNetIndex(0, mux_bits-1));
+ createNet("In1", makeNetIndex(0, mux_bits-1));
+ createNet("In2", makeNetIndex(0, mux_bits-1));
+ createNet("In3", makeNetIndex(0, mux_bits-1));
+ createNet("In4", makeNetIndex(0, mux_bits-1));
+ createNet("Out", makeNetIndex(0, mux_bits-1));
+
+ portConnect(multiplexer, "In0", "In0");
+ portConnect(multiplexer, "In1", "In1");
+ //portConnect(multiplexer, "In2", "In2");
+ //portConnect(multiplexer, "In3", "In3");
+ //portConnect(multiplexer, "In4", "In4");
+ portConnect(multiplexer, "Out", "Out");
+
+ for (unsigned int i = 0; i < mux_bits; ++i)
+ {
+ String n = (String) i;
+
+ createLoad("OutLoad[" + n + "]");
+ getLoad("OutLoad[" + n + "]")->setLoadCap(100e-15);
+
+ getNet("Out", makeNetIndex(i))->addDownstreamNode(getLoad("OutLoad[" + n + "]"));
+ }
+ createNet("Sel", makeNetIndex(0, 2));
+ assign("Sel", makeNetIndex(0), "CK");
+ assign("Sel", makeNetIndex(1), "CK");
+ assign("Sel", makeNetIndex(2), "CK");
+
+ //portConnect(multiplexer, "Sel", "Sel");
+
+ addSubInstances(multiplexer, 1.0);
+
+ //ElectricalTimingAbstract* abstract = new ElectricalTimingAbstract("HAHAHA", getTechModel(), ripple_adder);
+ //abstract->buildAbstract();
+
+ return;
+ }
+
+ void TestModel::updateModel()
+ {
+ Model::updateModel();
+
+ //ElectricalTimingTree* t = new ElectricalTimingTree("Add", this);
+ //t->performTimingOpt(getNet("CK"), 4.21300e-8);
+ //t->performTimingOpt(getNet("CK"), 1e-9);
+ //delete t;
+
+ ElectricalTimingTree* t2 = new ElectricalTimingTree("Mux", this);
+ t2->performTimingOpt(getNet("In1", makeNetIndex(0)), 500e-12);
+ delete t2;
+
+
+ }
+
+ void TestModel::evaluateModel()
+ {
+ Model::evaluateModel();
+
+ //ripple_adder->getNddPowerResult("LeakagePower")->print("RippleAdder->Leakage", 10, cout);
+ getSubInstance("Adder_1")->getNddPowerResult("Leakage")->print("RippleAdder->Leakage", 0, cout);
+ //ripple_adder->getAreaResult("TotalArea")->print("RippleAdder->TotalArea", 10, cout);
+ getSubInstance("Adder_1")->getAreaResult("Active")->print("RippleAdder->ActiveArea", 0, cout);
+ //ripple_adder->getEventResult("AddEvent")->print("RippleAdder->AddEvent", 10, cout);
+ getSubInstance("Adder_1")->getEventResult("Add")->print("RippleAdder->Add", 0, cout);
+
+ getSubInstance("Mux_1")->getNddPowerResult("Leakage")->print("Multiplexer->Leakage", 0, cout);
+ getSubInstance("Mux_1")->getAreaResult("Active")->print("Multiplexer->ActiveArea", 0, cout);
+ getSubInstance("Mux_1")->getEventResult("Mux")->print("Multiplexer->MuxEvent", 0, cout);
+ cout << "Multiplexer->P(Out) = " << getSubInstance("Mux_1")->getGenProperties()->get("P(Out)") << endl;
+
+ getSubInstance("DFFQ-CI")->getNddPowerResult("Leakage")->print("DFFQ-CI->Leakage", 0, cout);
+ getSubInstance("DFFQ-CI")->getAreaResult("Active")->print("DFFQ-CI->ActiveArea", 0, cout);
+ getSubInstance("DFFQ-CI")->getEventResult("DFF")->print("DFFQ-CI->DFF", 0, cout);
+ getSubInstance("DFFQ-CI")->getEventResult("CK")->print("DFFQ-CI->CK", 0, cout);
+
+ //ripple_adder->getNddPowerResult("LeakagePower")->print("RippleAdder->Leakage", 10, cout);
+ getSubInstance("Adder_1")->getNddPowerResult("Leakage")->print("RippleAdder->Leakage", 0, cout);
+ //ripple_adder->getAreaResult("TotalArea")->print("RippleAdder->TotalArea", 10, cout);
+ getSubInstance("Adder_1")->getAreaResult("Active")->print("RippleAdder->ActiveArea", 0, cout);
+ //ripple_adder->getEventResult("AddEvent")->print("RippleAdder->AddEvent", 10, cout);
+ getSubInstance("Adder_1")->getEventResult("Add")->print("RippleAdder->AddEvent", 0, cout);
+ }
+
+} // namespace DSENT
+
diff --git a/ext/dsent/model/electrical/TestModel.h b/ext/dsent/model/electrical/TestModel.h
new file mode 100644
index 000000000..5e07ea30c
--- /dev/null
+++ b/ext/dsent/model/electrical/TestModel.h
@@ -0,0 +1,32 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_TESTMODEL_H__
+#define __DSENT_MODEL_ELECTRICAL_TESTMODEL_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+ class TestModel : public ElectricalModel
+ {
+ public:
+ TestModel(const String& instance_name_, const TechModel* tech_model_);
+ virtual ~TestModel();
+
+ public:
+ // Set a list of properties' name needed to construct model
+ void initProperties();
+
+ // Clone and return a new instance
+ virtual TestModel* clone() const;
+
+ protected:
+ // Build the model
+ void constructModel();
+ void updateModel();
+ void evaluateModel();
+
+ }; // class TestModel
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_TESTMODEL_H__
+
diff --git a/ext/dsent/model/electrical/router/Router.cc b/ext/dsent/model/electrical/router/Router.cc
new file mode 100644
index 000000000..c079bd1d5
--- /dev/null
+++ b/ext/dsent/model/electrical/router/Router.cc
@@ -0,0 +1,536 @@
+#include "model/electrical/router/Router.h"
+
+#include <cmath>
+#include <vector>
+
+#include "model/PortInfo.h"
+#include "model/EventInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/ModelGen.h"
+#include "model/std_cells/StdCellLib.h"
+#include "model/std_cells/StdCell.h"
+#include "model/electrical/router/RouterInputPort.h"
+#include "model/electrical/router/RouterSwitchAllocator.h"
+#include "model/timing_graph/ElectricalNet.h"
+
+namespace DSENT
+{
+ using std::sqrt;
+ using std::vector;
+
+ using LibUtil::castStringVector;
+ using LibUtil::vectorToString;
+
+ Router::Router(const String& instance_name_, const TechModel* tech_model_)
+ : ElectricalModel(instance_name_, tech_model_)
+ {
+ initParameters();
+ initProperties();
+ }
+
+ Router::~Router()
+ {}
+
+ void Router::initParameters()
+ {
+ addParameterName("NumberInputPorts");
+ addParameterName("NumberOutputPorts");
+ addParameterName("NumberBitsPerFlit");
+ addParameterName("NumberVirtualNetworks");
+ addParameterName("NumberVirtualChannelsPerVirtualNetwork");
+ addParameterName("NumberBuffersPerVirtualChannel");
+ // Spec for input port
+ addParameterName("InputPort->BufferModel");
+ // Spec for crossbar
+ addParameterName("CrossbarModel");
+ // Spec for switch allocator
+ addParameterName("SwitchAllocator->ArbiterModel");
+ // Spec for clock tree
+ addParameterName("ClockTreeModel");
+ addParameterName("ClockTree->NumberLevels");
+ addParameterName("ClockTree->WireLayer");
+ addParameterName("ClockTree->WireWidthMultiplier");
+ addParameterName("ClockTree->WireSpacingMultiplier", 3.0);
+ return;
+ }
+
+ void Router::initProperties()
+ {
+ return;
+ }
+
+ Router* Router::clone() const
+ {
+ // TODO
+ return NULL;
+ }
+
+ void Router::constructModel()
+ {
+ // Get parameters
+ unsigned int number_input_ports = getParameter("NumberInputPorts").toUInt();
+ unsigned int number_output_ports = getParameter("NumberOutputPorts").toUInt();
+ unsigned int number_bits_per_flit = getParameter("NumberBitsPerFlit").toUInt();
+
+ ASSERT(number_input_ports > 0, "[Error] " + getInstanceName() +
+ " -> Number of input ports must be > 0!");
+ ASSERT(number_output_ports > 0, "[Error] " + getInstanceName() +
+ " -> Number of output ports must be > 0!");
+ ASSERT(number_bits_per_flit > 0, "[Error] " + getInstanceName() +
+ " -> Number of bits per buffer must be > 0!");
+
+ // Create ports
+ createInputPort("CK");
+ for(unsigned int i = 0; i < number_input_ports; ++i)
+ {
+ createInputPort("FlitIn" + (String)i, makeNetIndex(0, number_bits_per_flit-1));
+ }
+ for(unsigned int i = 0; i < number_output_ports; ++i)
+ {
+ createOutputPort("FlitOut" + (String)i, makeNetIndex(0, number_bits_per_flit-1));
+ }
+
+ // Create area, power, event results
+ createElectricalResults();
+ getEventInfo("Idle")->setStaticTransitionInfos();
+ getEventInfo("Idle")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
+
+ createElectricalEventResult("ReadBuffer");
+ getEventInfo("ReadBuffer")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
+ createElectricalEventResult("WriteBuffer");
+ getEventInfo("WriteBuffer")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
+ for(unsigned int i = 1; i <= number_output_ports; ++i)
+ {
+ createElectricalEventResult("TraverseCrossbar->Multicast" + (String)i);
+ getEventInfo("TraverseCrossbar->Multicast" + (String)i)->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
+ }
+ createElectricalEventResult("ArbitrateSwitch->ArbitrateStage1");
+ createElectricalEventResult("ArbitrateSwitch->ArbitrateStage2");
+ createElectricalEventResult("DistributeClock");
+ getEventInfo("DistributeClock")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
+
+ // Create intermediate nets
+ createNet("PipelineReg0_In");
+ createNet("PipelineReg0_Out");
+ createNet("PipelineReg1_In");
+ createNet("PipelineReg1_Out");
+ for(unsigned int i = 0; i < number_output_ports; ++i)
+ {
+ createNet("PipelineReg2_In" + (String)i);
+ createNet("PipelineReg2_Out" + (String)i);
+ }
+
+ createRouterInputPort();
+ createSwitchAllocator();
+ createVirtualChannelAllocator();
+ createCrossbar();
+ createClockTree();
+ createPipelineReg();
+
+ // Get generated numbers
+ unsigned int number_crossbar_selects = getGenProperties()->get("Crossbar->NumberSelects");
+
+ // Add write buffer event
+ getEventResult("WriteBuffer")->addSubResult(getSubInstance("PipelineReg0")->getEventResult("DFFD"), "PipelineReg0", number_bits_per_flit);
+ getEventResult("WriteBuffer")->addSubResult(getSubInstance("PipelineReg0")->getEventResult("DFFQ"), "PipelineReg0", number_bits_per_flit);
+ getEventResult("WriteBuffer")->addSubResult(getSubInstance("PipelineReg0")->getEventResult("CK"), "PipelineReg0", number_bits_per_flit);
+ getEventResult("WriteBuffer")->addSubResult(getSubInstance("InputPort")->getEventResult("WriteBuffer"), "InputPort", 1.0);
+
+ // Add read buffer event
+ getEventResult("ReadBuffer")->addSubResult(getSubInstance("InputPort")->getEventResult("ReadBuffer"), "InputPort", 1.0);
+ getEventResult("ReadBuffer")->addSubResult(getSubInstance("PipelineReg1")->getEventResult("DFFD"), "PipelineReg1", number_bits_per_flit);
+ getEventResult("ReadBuffer")->addSubResult(getSubInstance("PipelineReg1")->getEventResult("DFFQ"), "PipelineReg1", number_bits_per_flit);
+ getEventResult("ReadBuffer")->addSubResult(getSubInstance("PipelineReg1")->getEventResult("CK"), "PipelineReg1", number_bits_per_flit);
+
+ // Add crossbar traversal event
+ for(unsigned int i = 1; i <= number_output_ports; ++i)
+ {
+ Result* traverse_crossbar_event = getEventResult("TraverseCrossbar->Multicast" + (String)i);
+ traverse_crossbar_event->addSubResult(getSubInstance("Crossbar_Sel_DFF")->getEventResult("DFFD"), "Crossbar_Sel_DFF", number_crossbar_selects);
+ traverse_crossbar_event->addSubResult(getSubInstance("Crossbar_Sel_DFF")->getEventResult("DFFQ"), "Crossbar_Sel_DFF", number_crossbar_selects);
+ traverse_crossbar_event->addSubResult(getSubInstance("Crossbar_Sel_DFF")->getEventResult("CK"), "Crossbar_Sel_DFF", number_crossbar_selects);
+ traverse_crossbar_event->addSubResult(getSubInstance("Crossbar")->getEventResult("Multicast" + (String)i), "Crossbar", 1.0);
+ for(unsigned int j = 0; j < i; ++j)
+ {
+ traverse_crossbar_event->addSubResult(getSubInstance("PipelineReg2_" + (String)j)->getEventResult("DFFD"), "PipelineReg2_" + (String)j, number_bits_per_flit);
+ traverse_crossbar_event->addSubResult(getSubInstance("PipelineReg2_" + (String)j)->getEventResult("DFFQ"), "PipelineReg2_" + (String)j, number_bits_per_flit);
+ traverse_crossbar_event->addSubResult(getSubInstance("PipelineReg2_" + (String)j)->getEventResult("CK"), "PipelineReg2_" + (String)j, number_bits_per_flit);
+ }
+ }
+
+ // Add stage1 allocator arbitrate
+ Result* arb_sw_stage1_event = getEventResult("ArbitrateSwitch->ArbitrateStage1");
+ arb_sw_stage1_event->addSubResult(getSubInstance("SwitchAllocator")->getEventResult("ArbitrateStage1"), "SwitchAllocator", 1.0);
+
+ // Add stage2 allocator arbitrate
+ Result* arb_sw_stage2_event = getEventResult("ArbitrateSwitch->ArbitrateStage2");
+ arb_sw_stage2_event->addSubResult(getSubInstance("SwitchAllocator")->getEventResult("ArbitrateStage2"), "SwitchAllocator", 1.0);
+
+ // Add CK event
+ getEventResult("DistributeClock")->addSubResult(getSubInstance("ClockTree")->getEventResult("Send"), "ClockTree", 1.0);
+ return;
+ }
+
+ void Router::updateModel()
+ {
+ // Get parameters
+ unsigned int number_output_ports = getParameter("NumberOutputPorts").toUInt();
+
+ // Update other components
+ getSubInstance("PipelineReg0")->update();
+ getSubInstance("InputPort")->update();
+ getSubInstance("PipelineReg1")->update();
+ getSubInstance("Crossbar_Sel_DFF")->update();
+ getSubInstance("Crossbar")->update();
+ for(unsigned int i = 0; i < number_output_ports; ++i)
+ {
+ getSubInstance("PipelineReg2_" + (String)i)->update();
+ }
+ getSubInstance("SwitchAllocator")->update();
+
+ // Update clock tree
+ double total_clock_tree_cap = getNet("CK")->getTotalDownstreamCap();
+ double router_area = getAreaResult("Active")->calculateSum();
+ Model* clock_tree = getSubInstance("ClockTree");
+ clock_tree->setProperty("SitePitch", sqrt(router_area));
+ clock_tree->setProperty("TotalLoadCapPerBit", total_clock_tree_cap);
+ clock_tree->update();
+
+ return;
+ }
+
+ void Router::propagateTransitionInfo()
+ {
+ // Update probability
+ unsigned int number_output_ports = getParameter("NumberOutputPorts");
+
+ // Current event
+ const String& current_event = getGenProperties()->get("UseModelEvent");
+
+ ElectricalModel* pipeline_reg0 = (ElectricalModel*)getSubInstance("PipelineReg0");
+ propagatePortTransitionInfo(pipeline_reg0, "D", "FlitIn0");
+ propagatePortTransitionInfo(pipeline_reg0, "CK", "CK");
+ pipeline_reg0->use();
+
+ ElectricalModel* input_port = (ElectricalModel*)getSubInstance("InputPort");
+ propagatePortTransitionInfo(input_port, "FlitIn", pipeline_reg0, "Q");
+ propagatePortTransitionInfo(input_port, "CK", "CK");
+ input_port->getGenProperties()->set("UseModelEvent", "ReadWrite");
+ input_port->use();
+
+ ElectricalModel* pipeline_reg1 = (ElectricalModel*)getSubInstance("PipelineReg1");
+ propagatePortTransitionInfo(pipeline_reg1, "D", "FlitIn0");
+ propagatePortTransitionInfo(pipeline_reg1, "CK", "CK");
+ pipeline_reg1->use();
+
+ ElectricalModel* crossbar_sel_dff = (ElectricalModel*)getSubInstance("Crossbar_Sel_DFF");
+ assignPortTransitionInfo(crossbar_sel_dff, "D", TransitionInfo());
+ propagatePortTransitionInfo(crossbar_sel_dff, "CK", "CK");
+ crossbar_sel_dff->use();
+
+ ElectricalModel* crossbar = (ElectricalModel*)getSubInstance("Crossbar");
+ bool is_crossbar_event = false;
+ for(unsigned int i = 1; i <= number_output_ports; ++i)
+ {
+ if(current_event == ("TraverseCrossbar->Multicast" + (String)i))
+ {
+ is_crossbar_event = true;
+ // Assume the flit is sent from port 0 to port 0~i-1
+ // Apply default transition info
+ crossbar->applyTransitionInfo("Multicast" + (String)i);
+ // Overwrite transition info
+ propagatePortTransitionInfo(crossbar, "In0", "FlitIn0");
+ break;
+ }
+ }
+ if(is_crossbar_event == false)
+ {
+ crossbar->applyTransitionInfo("Multicast1");
+ propagatePortTransitionInfo(crossbar, "In0", "FlitIn0");
+ }
+ crossbar->use();
+
+ vector<ElectricalModel*> pipeline_reg2s(number_output_ports, NULL);
+ for(unsigned int i = 0; i < number_output_ports; ++i)
+ {
+ pipeline_reg2s[i] = (ElectricalModel*)getSubInstance("PipelineReg2_" + (String)i);
+ propagatePortTransitionInfo(pipeline_reg2s[i], "D", "FlitIn0");
+ propagatePortTransitionInfo(pipeline_reg2s[i], "CK", "CK");
+ pipeline_reg2s[i]->use();
+ }
+
+ ElectricalModel* sw_allocator = (ElectricalModel*)getSubInstance("SwitchAllocator");
+ if(current_event == "ArbitrateSwitch->ArbitrateStage1")
+ {
+ sw_allocator->applyTransitionInfo("ArbitrateStage1");
+ }
+ else if(current_event == "ArbitrateSwitch->ArbitrateStage2")
+ {
+ sw_allocator->applyTransitionInfo("ArbitrateStage2");
+ }
+ else
+ {
+ sw_allocator->applyTransitionInfo("Idle");
+ }
+ sw_allocator->use();
+
+ ElectricalModel* clock_tree = (ElectricalModel*)getSubInstance("ClockTree");
+ propagatePortTransitionInfo(clock_tree, "In", "CK");
+ clock_tree->use();
+ return;
+ }
+
+ void Router::createRouterInputPort()
+ {
+ // Get parameters
+ unsigned int number_input_ports = getParameter("NumberInputPorts").toUInt();
+ unsigned int number_vns = getParameter("NumberVirtualNetworks").toUInt();
+ const String& number_vcs_per_vn = getParameter("NumberVirtualChannelsPerVirtualNetwork");
+ const String& number_bufs_per_vc = getParameter("NumberBuffersPerVirtualChannel");
+ unsigned int number_bits_per_flit = getParameter("NumberBitsPerFlit").toUInt();
+ const String& buffer_model = getParameter("InputPort->BufferModel");
+
+ // Init input port model
+ const String& input_port_name = "InputPort";
+ RouterInputPort* input_port = new RouterInputPort(input_port_name, getTechModel());
+ input_port->setParameter("NumberVirtualNetworks", number_vns);
+ input_port->setParameter("NumberVirtualChannelsPerVirtualNetwork", number_vcs_per_vn);
+ input_port->setParameter("NumberBuffersPerVirtualChannel", number_bufs_per_vc);
+ input_port->setParameter("NumberBitsPerFlit", number_bits_per_flit);
+ input_port->setParameter("BufferModel", buffer_model);
+ input_port->construct();
+
+ unsigned int number_input_port_outputs = input_port->getGenProperties()->get("NumberOutputs");
+ unsigned int number_input_port_addr_bits = input_port->getGenProperties()->get("NumberAddressBits");
+ getGenProperties()->set("InputPort->NumberOutputs", number_input_port_outputs);
+ getGenProperties()->set("InputPort->NumberAddressBits", number_input_port_addr_bits);
+
+ unsigned int total_number_vcs = input_port->getGenProperties()->get("TotalNumberVirtualChannels");
+ getGenProperties()->set("TotalNumberVirtualChannels", total_number_vcs);
+
+ // Add the instance and the results
+ addSubInstances(input_port, number_input_ports);
+ addElectricalSubResults(input_port, number_input_ports);
+
+ // Create connections
+ createNet("InputPort_In", makeNetIndex(0, number_bits_per_flit-1));
+ createNet("InputPort_Out", makeNetIndex(0, number_bits_per_flit-1));
+
+ assignVirtualFanout("InputPort_In", "PipelineReg0_Out");
+ portConnect(input_port, "FlitIn", "InputPort_In");
+ portConnect(input_port, "CK", "CK");
+ portConnect(input_port, "FlitOut", "InputPort_Out");
+ assignVirtualFanin("PipelineReg1_In", "InputPort_Out");
+
+ return;
+ }
+
+ void Router::createVirtualChannelAllocator()
+ {}
+
+ void Router::createSwitchAllocator()
+ {
+ // Get parameters
+ unsigned int number_input_ports = getParameter("NumberInputPorts").toUInt();
+ unsigned int number_output_ports = getParameter("NumberOutputPorts").toUInt();
+ unsigned int total_number_vcs = getGenProperties()->get("TotalNumberVirtualChannels").toUInt();
+ const String& arb_model = getParameter("SwitchAllocator->ArbiterModel");
+
+ // Init switch allocator model
+ const String& sw_allocator_name = "SwitchAllocator";
+ RouterSwitchAllocator* sw_allocator = new RouterSwitchAllocator(sw_allocator_name, getTechModel());
+ sw_allocator->setParameter("NumberInputPorts", number_input_ports);
+ sw_allocator->setParameter("NumberOutputPorts", number_output_ports);
+ sw_allocator->setParameter("TotalNumberVirtualChannels", total_number_vcs);
+ sw_allocator->setParameter("ArbiterModel", arb_model);
+ sw_allocator->construct();
+
+ // Add the instance and the results
+ addSubInstances(sw_allocator, 1.0);
+ addElectricalSubResults(sw_allocator, 1.0);
+
+ // Create connections (currently connect CK only)
+ portConnect(sw_allocator, "CK", "CK");
+ return;
+ }
+
+ void Router::createCrossbar()
+ {
+ // Get parameters
+ const String& crossbar_model = getParameter("CrossbarModel");
+ unsigned int number_input_ports = getParameter("NumberInputPorts").toUInt();
+ unsigned int number_output_ports = getParameter("NumberOutputPorts").toUInt();
+ unsigned int number_bits_per_flit = getParameter("NumberBitsPerFlit").toUInt();
+ unsigned int number_input_port_outputs = getGenProperties()->get("InputPort->NumberOutputs").toUInt();
+
+ unsigned int number_crossbar_inputs = number_input_port_outputs * number_input_ports;
+ unsigned int number_crossbar_outputs = number_output_ports;
+ getGenProperties()->set("Crossbar->NumberInputs", number_crossbar_inputs);
+ getGenProperties()->set("Crossbar->NumberOutputs", number_crossbar_outputs);
+
+ // Init crossbar model
+ const String& crossbar_name = "Crossbar";
+ ElectricalModel* crossbar = ModelGen::createCrossbar(crossbar_model, crossbar_name, getTechModel());
+ crossbar->setParameter("NumberInputs", number_crossbar_inputs);
+ crossbar->setParameter("NumberOutputs", number_crossbar_outputs);
+ crossbar->setParameter("NumberBits", number_bits_per_flit);
+ crossbar->setParameter("BitDuplicate", "TRUE");
+ crossbar->construct();
+
+ unsigned int number_crossbar_selects = crossbar->getGenProperties()->get("NumberSelectsPerPort");
+ getGenProperties()->set("Crossbar->NumberSelects", number_crossbar_selects);
+
+ // Init DFF for crossbar selections
+ const String& crossbar_sel_dff_name = "Crossbar_Sel_DFF";
+ StdCell* crossbar_sel_dff = getTechModel()->getStdCellLib()->createStdCell("DFFQ", crossbar_sel_dff_name);
+ crossbar_sel_dff->construct();
+
+ // Add instances and results
+ addSubInstances(crossbar, 1.0);
+ addElectricalSubResults(crossbar, 1.0);
+
+ addSubInstances(crossbar_sel_dff, number_crossbar_outputs * number_crossbar_selects);
+ addElectricalSubResults(crossbar_sel_dff, number_crossbar_outputs * number_crossbar_selects);
+
+ // Create connections
+ createNet("Crossbar_Sel_DFF_Out");
+ for(unsigned int i = 0; i < number_crossbar_outputs; ++i)
+ {
+ for(unsigned int j = 0; j < number_crossbar_selects; ++j)
+ {
+ createNet(String::format("Crossbar_Sel%d_%d", i, j));
+ }
+ createNet("Crossbar_Out" + (String)i, makeNetIndex(0, number_bits_per_flit-1));
+ }
+ for(unsigned int i = 0; i < number_crossbar_inputs; ++i)
+ {
+ createNet("Crossbar_In" + (String)i, makeNetIndex(0, number_bits_per_flit-1));
+ }
+
+ for(unsigned int i = 0; i < number_crossbar_selects; ++i)
+ {
+ portConnect(crossbar_sel_dff, "CK", "CK");
+ }
+ portConnect(crossbar_sel_dff, "Q", "Crossbar_Sel_DFF_Out");
+ for(unsigned int i = 0; i < number_crossbar_inputs; ++i)
+ {
+ assignVirtualFanout("Crossbar_In" + (String)i, "PipelineReg1_Out");
+ portConnect(crossbar, "In" + (String)i, "Crossbar_In" + (String)i);
+ }
+ for(unsigned int i = 0; i < number_crossbar_outputs; ++i)
+ {
+ for(unsigned int j = 0; j < number_crossbar_selects; ++j)
+ {
+ assignVirtualFanout(String::format("Crossbar_Sel%d_%d", i, j), "Crossbar_Sel_DFF_Out");
+ portConnect(crossbar, String::format("Sel%d_%d", i, j), String::format("Crossbar_Sel%d_%d", i, j));
+ }
+ portConnect(crossbar, "Out" + (String)i, "Crossbar_Out" + (String)i);
+ assignVirtualFanin("PipelineReg2_In" + (String)i, "Crossbar_Out" + (String)i);
+ }
+
+ return;
+ }
+
+ void Router::createPipelineReg()
+ {
+ // Get parameters
+ unsigned int number_input_ports = getParameter("NumberInputPorts").toUInt();
+ unsigned int number_output_ports = getParameter("NumberOutputPorts").toUInt();
+ unsigned int number_bits_per_flit = getParameter("NumberBitsPerFlit").toUInt();
+ unsigned int number_crossbar_inputs = getGenProperties()->get("Crossbar->NumberInputs");
+
+ // Init pipeline reg model
+ // First stage: from router input to input port
+ const String& pipeline_reg0_name = "PipelineReg0";
+ StdCell* pipeline_reg0 = getTechModel()->getStdCellLib()->createStdCell("DFFQ", pipeline_reg0_name);
+ pipeline_reg0->construct();
+ // Second stage: from input port to crossbar
+ const String& pipeline_reg1_name = "PipelineReg1";
+ StdCell* pipeline_reg1 = getTechModel()->getStdCellLib()->createStdCell("DFFQ", pipeline_reg1_name);
+ pipeline_reg1->construct();
+
+ // Third stage: from crossbar to router output
+ vector<StdCell*> pipeline_reg2s(number_output_ports, (StdCell*)NULL);
+ vector<String> pipeline_reg2_names(number_output_ports, "");
+ for(unsigned int i = 0; i < number_output_ports; ++i)
+ {
+ pipeline_reg2_names[i] = "PipelineReg2_" + (String)i;
+ pipeline_reg2s[i] = getTechModel()->getStdCellLib()->createStdCell("DFFQ", pipeline_reg2_names[i]);
+ pipeline_reg2s[i]->construct();
+ }
+
+ // Add instances and results
+ addSubInstances(pipeline_reg0, number_input_ports * number_bits_per_flit);
+ addElectricalSubResults(pipeline_reg0, number_input_ports * number_bits_per_flit);
+
+ addSubInstances(pipeline_reg1, number_crossbar_inputs * number_bits_per_flit);
+ addElectricalSubResults(pipeline_reg1, number_crossbar_inputs * number_bits_per_flit);
+
+ for(unsigned int i = 0; i < number_output_ports; ++i)
+ {
+ addSubInstances(pipeline_reg2s[i], number_bits_per_flit);
+ addElectricalSubResults(pipeline_reg2s[i], number_bits_per_flit);
+ }
+
+ // Create data connections
+ for(unsigned int i = 0; i < number_input_ports; ++i)
+ {
+ assignVirtualFanin("PipelineReg0_In", "FlitIn" + (String)i);
+ }
+ portConnect(pipeline_reg0, "D", "PipelineReg0_In");
+ portConnect(pipeline_reg0, "Q", "PipelineReg0_Out");
+ portConnect(pipeline_reg1, "D", "PipelineReg1_In");
+ portConnect(pipeline_reg1, "Q", "PipelineReg1_Out");
+ for(unsigned int i = 0; i < number_output_ports; ++i)
+ {
+ portConnect(pipeline_reg2s[i], "D", "PipelineReg2_In" + (String)i);
+ portConnect(pipeline_reg2s[i], "Q", "PipelineReg2_Out" + (String)i);
+ assignVirtualFanout("FlitOut" + (String)i, "PipelineReg2_Out" + (String)i);
+ }
+
+ // Create CK connections
+ for(unsigned int n = 0; n < number_bits_per_flit; ++n)
+ {
+ for(unsigned int i = 0; i < number_input_ports; ++i)
+ {
+ portConnect(pipeline_reg0, "CK", "CK");
+ }
+ for(unsigned int i = 0; i < number_crossbar_inputs; ++i)
+ {
+ portConnect(pipeline_reg1, "CK", "CK");
+ }
+ for(unsigned int i = 0; i < number_output_ports; ++i)
+ {
+ portConnect(pipeline_reg2s[i], "CK", "CK");
+ }
+ }
+ return;
+ }
+
+ void Router::createClockTree()
+ {
+ // Get parameters
+ const String& clock_tree_model = getParameter("ClockTreeModel");
+ const String& clock_tree_number_levels = getParameter("ClockTree->NumberLevels");
+ const String& clock_tree_wire_layer = getParameter("ClockTree->WireLayer");
+ const String& clock_tree_wire_width_multiplier = getParameter("ClockTree->WireWidthMultiplier");
+ const String& clock_tree_wire_spacing_multiplier = getParameter("ClockTree->WireSpacingMultiplier");
+
+ // Init clock tree model
+ const String& clock_tree_name = "ClockTree";
+ ElectricalModel* clock_tree = (ElectricalModel*)ModelGen::createModel(clock_tree_model, clock_tree_name, getTechModel());
+ clock_tree->setParameter("NumberLevels", clock_tree_number_levels);
+ clock_tree->setParameter("NumberBits", 1);
+ clock_tree->setParameter("WireLayer", clock_tree_wire_layer);
+ clock_tree->setParameter("WireWidthMultiplier", clock_tree_wire_width_multiplier);
+ clock_tree->setParameter("WireSpacingMultiplier", clock_tree_wire_spacing_multiplier);
+ clock_tree->construct();
+
+ // Add instances and results
+ addSubInstances(clock_tree, 1.0);
+ addElectricalSubResults(clock_tree, 1.0);
+
+ return;
+ }
+} // namespace DSENT
+
diff --git a/ext/dsent/model/electrical/router/Router.h b/ext/dsent/model/electrical/router/Router.h
new file mode 100644
index 000000000..c2c1df3bc
--- /dev/null
+++ b/ext/dsent/model/electrical/router/Router.h
@@ -0,0 +1,46 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_ROUTER_ROUTER_H__
+#define __DSENT_MODEL_ELECTRICAL_ROUTER_ROUTER_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+ /** \class Router
+ * \param Input ports: In[0-9]*
+ * \param Output ports: Out[0-9]*
+ */
+ class Router : public ElectricalModel
+ {
+ public:
+ Router(const String& instance_name_, const TechModel* tech_model_);
+ virtual ~Router();
+
+ public:
+ // Set a list of properties' name needed to construct model
+ void initParameters();
+ // Set a list of properties' name needed to construct model
+ void initProperties();
+
+ // Clone and return a new instance
+ virtual Router* clone() const;
+
+ protected:
+ // Build the model
+ virtual void constructModel();
+ virtual void updateModel();
+ virtual void propagateTransitionInfo();
+
+ private:
+ void createRouterInputPort();
+ void createVirtualChannelAllocator();
+ void createSwitchAllocator();
+ void createCrossbar();
+ void createClockTree();
+ void createPipelineReg();
+
+ }; // class Router
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_ROUTER_ROUTER_H__
+
diff --git a/ext/dsent/model/electrical/router/RouterInputPort.cc b/ext/dsent/model/electrical/router/RouterInputPort.cc
new file mode 100644
index 000000000..b698d3d80
--- /dev/null
+++ b/ext/dsent/model/electrical/router/RouterInputPort.cc
@@ -0,0 +1,201 @@
+#include "model/electrical/router/RouterInputPort.h"
+
+#include <cmath>
+#include <vector>
+
+#include "model/PortInfo.h"
+#include "model/EventInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/ModelGen.h"
+#include "model/std_cells/StdCellLib.h"
+#include "model/std_cells/StdCell.h"
+
+namespace DSENT
+{
+ using std::ceil;
+ using std::vector;
+ using LibUtil::castStringVector;
+
+ RouterInputPort::RouterInputPort(const String& instance_name_, const TechModel* tech_model_)
+ : ElectricalModel(instance_name_, tech_model_)
+ {
+ initParameters();
+ initProperties();
+ }
+
+ RouterInputPort::~RouterInputPort()
+ {}
+
+ void RouterInputPort::initParameters()
+ {
+ addParameterName("NumberVirtualNetworks");
+ addParameterName("NumberVirtualChannelsPerVirtualNetwork");
+ addParameterName("NumberBuffersPerVirtualChannel");
+ addParameterName("NumberBitsPerFlit");
+ addParameterName("BufferModel");
+ return;
+ }
+
+ void RouterInputPort::initProperties()
+ {
+ return;
+ }
+
+ RouterInputPort* RouterInputPort::clone() const
+ {
+ // TODO
+ return NULL;
+ }
+
+ void RouterInputPort::constructModel()
+ {
+ // Get parameters
+ unsigned int number_vns = getParameter("NumberVirtualNetworks").toUInt();
+ const vector<unsigned int>& number_vcs_per_vn_vector = castStringVector<unsigned int>(getParameter("NumberVirtualChannelsPerVirtualNetwork").split("[,]"));
+ const vector<unsigned int>& number_bufs_per_vc_vector = castStringVector<unsigned int>(getParameter("NumberBuffersPerVirtualChannel").split("[,]"));
+ unsigned int number_bits_per_flit = getParameter("NumberBitsPerFlit").toUInt();
+ const String& buffer_model = getParameter("BufferModel");
+
+ ASSERT(number_vns > 0, "[Error] " + getInstanceName() +
+ " -> Number of virtual networks must be > 0!");
+ ASSERT(number_vcs_per_vn_vector.size() == number_vns, "[Error] " + getInstanceName() +
+ " -> Expecting " + (String)number_vns + " number of vcs, got " +
+ getParameter("NumberVirtualChannelsPerVirtualNetwork"));
+ for(unsigned int i = 0; i < number_vns; ++i)
+ {
+ ASSERT(number_vcs_per_vn_vector[i] > 0, "[Error] " + getInstanceName() +
+ " -> Number of virtual channels per virtual network must be > 0!");
+ }
+ ASSERT(number_bufs_per_vc_vector.size() == number_vns, "[Error] " + getInstanceName() +
+ " -> Expecting " + (String)number_vns + " number of bufs per vc, got " +
+ getParameter("NumberBuffersPerVirtualChannel"));
+ for(unsigned int i = 0; i < number_vns; ++i)
+ {
+ ASSERT(number_bufs_per_vc_vector[i] > 0, "[Error] " + getInstanceName() +
+ " -> Number of buffers per virtual channel must be > 0!");
+ }
+ ASSERT(number_bits_per_flit > 0, "[Error] " + getInstanceName() +
+ " -> Number of bits per buffer must be > 0!");
+
+ // Calculate total number of buffers needed in the RAM
+ unsigned int total_number_vcs = 0;
+ unsigned int total_number_bufs = 0;
+ for(unsigned int i = 0; i < number_vns; ++i)
+ {
+ total_number_vcs += number_vcs_per_vn_vector[i];
+ total_number_bufs += number_vcs_per_vn_vector[i] * number_bufs_per_vc_vector[i];
+ }
+ unsigned int number_addr_bits = (unsigned int)ceil(log2(total_number_bufs));
+
+ getGenProperties()->set("TotalNumberVirtualChannels", total_number_vcs);
+ getGenProperties()->set("TotalNumberBuffers", total_number_bufs);
+ getGenProperties()->set("NumberAddressBits", number_addr_bits);
+ getGenProperties()->set("NumberOutputs", 1);
+
+ createInputPort("CK");
+ createInputPort("FlitIn", makeNetIndex(0, number_bits_per_flit-1));
+ createOutputPort("FlitOut", makeNetIndex(0, number_bits_per_flit-1));
+
+ // Create energy, power, and area results
+ createElectricalResults();
+ getEventInfo("Idle")->setStaticTransitionInfos();
+ getEventInfo("Idle")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
+
+ addEventResult(new Result("ReadBuffer"));
+ addEventResult(new Result("WriteBuffer"));
+
+ // Init RAM
+ const String& ram_name = "RAM";
+ ElectricalModel* ram = ModelGen::createRAM(buffer_model, ram_name, getTechModel());
+ ram->setParameter("NumberEntries", total_number_bufs);
+ ram->setParameter("NumberBits", number_bits_per_flit);
+ ram->construct();
+
+ // Init DFF for read address
+ vector<String> rd_addr_dff_names(number_addr_bits, "");
+ vector<StdCell*> rd_addr_dffs(number_addr_bits, NULL);
+ for(unsigned int i = 0; i < number_addr_bits; ++i)
+ {
+ rd_addr_dff_names[i] = "RDAddr_DFF" + (String)i;
+ rd_addr_dffs[i] = getTechModel()->getStdCellLib()->createStdCell("DFFQ", rd_addr_dff_names[i]);
+ rd_addr_dffs[i]->construct();
+ }
+
+ // Connect RDAddr_DFFs
+ for(unsigned int i = 0; i < number_addr_bits; ++i)
+ {
+ createNet("RDAddr_DFF_Out" + (String)i);
+
+ portConnect(rd_addr_dffs[i], "CK", "CK");
+ portConnect(rd_addr_dffs[i], "Q", "RDAddr_DFF_Out" + (String)i);
+ }
+
+ // Connect RAM
+ portConnect(ram, "In", "FlitIn");
+ for(unsigned int i = 0; i < number_addr_bits; ++i)
+ {
+ portConnect(ram, "WRAddr" + (String)i, "FlitIn", makeNetIndex(i));
+ portConnect(ram, "RDAddr" + (String)i, "RDAddr_DFF_Out" + (String)i);
+ }
+ portConnect(ram, "WE", "FlitIn", makeNetIndex(number_bits_per_flit-1));
+ portConnect(ram, "CK", "CK");
+ portConnect(ram, "Out", "FlitOut");
+
+ // Add area, power, event results
+ for(unsigned int i = 0; i < number_addr_bits; ++i)
+ {
+ addSubInstances(rd_addr_dffs[i], number_addr_bits);
+ addElectricalSubResults(rd_addr_dffs[i], number_addr_bits);
+ }
+ addSubInstances(ram, 1.0);
+ addElectricalSubResults(ram, 1.0);
+
+ getEventResult("WriteBuffer")->addSubResult(ram->getEventResult("Write"), ram_name, 1.0);
+
+ for(unsigned int i = 0; i < number_addr_bits; ++i)
+ {
+ getEventResult("ReadBuffer")->addSubResult(rd_addr_dffs[i]->getEventResult("DFFD"), rd_addr_dff_names[i], number_addr_bits);
+ getEventResult("ReadBuffer")->addSubResult(rd_addr_dffs[i]->getEventResult("DFFQ"), rd_addr_dff_names[i], number_addr_bits);
+ getEventResult("ReadBuffer")->addSubResult(rd_addr_dffs[i]->getEventResult("CK"), rd_addr_dff_names[i], number_addr_bits);
+ }
+ getEventResult("ReadBuffer")->addSubResult(ram->getEventResult("Read"), ram_name, 1.0);
+
+ return;
+ }
+
+ void RouterInputPort::propagateTransitionInfo()
+ {
+ // Update probability and activity
+ unsigned int number_addr_bits = getGenProperties()->get("NumberAddressBits").toUInt();
+
+ vector<ElectricalModel*> rd_addr_dffs(number_addr_bits, NULL);
+ for(unsigned int i = 0; i < number_addr_bits; ++i)
+ {
+ rd_addr_dffs[i] = (ElectricalModel*)getSubInstance("RDAddr_DFF" + (String)i);
+ assignPortTransitionInfo(rd_addr_dffs[i], "D", TransitionInfo());
+ propagatePortTransitionInfo(rd_addr_dffs[i], "CK", "CK");
+ rd_addr_dffs[i]->use();
+ }
+
+ ElectricalModel* ram = (ElectricalModel*)getSubInstance("RAM");
+
+ // Setup default transition info
+ const String& current_event = getGenProperties()->get("UseModelEvent");
+ if(current_event != "Idle")
+ {
+ propagatePortTransitionInfo(ram, "In", "FlitIn");
+ propagatePortTransitionInfo(ram, "CK", "CK");
+ assignPortTransitionInfo(ram, "WE", TransitionInfo(0.0, 0.0, 1.0));
+ for(unsigned int i = 0; i < number_addr_bits; ++i)
+ {
+ assignPortTransitionInfo(ram, "WRAddr" + (String)i, TransitionInfo(0.25, 0.25, 0.25));
+ assignPortTransitionInfo(ram, "RDAddr" + (String)i, TransitionInfo(0.25, 0.25, 0.25));
+ }
+ }
+ ram->use();
+ // Set output probability
+ propagatePortTransitionInfo("FlitOut", ram, "Out");
+ return;
+ }
+} // namespace DSENT
+
diff --git a/ext/dsent/model/electrical/router/RouterInputPort.h b/ext/dsent/model/electrical/router/RouterInputPort.h
new file mode 100644
index 000000000..1d326a5cf
--- /dev/null
+++ b/ext/dsent/model/electrical/router/RouterInputPort.h
@@ -0,0 +1,33 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_ROUTER_ROUTER_INPUT_PORT_H__
+#define __DSENT_MODEL_ELECTRICAL_ROUTER_ROUTER_INPUT_PORT_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+ class RouterInputPort : public ElectricalModel
+ {
+ public:
+ RouterInputPort(const String& instance_name_, const TechModel* tech_model_);
+ virtual ~RouterInputPort();
+
+ public:
+ // Set a list of properties' name needed to construct model
+ void initParameters();
+ // Set a list of properties' name needed to construct model
+ void initProperties();
+
+ // Clone and return a new instance
+ virtual RouterInputPort* clone() const;
+
+ protected:
+ // Build the model
+ virtual void constructModel();
+ virtual void propagateTransitionInfo();
+
+ }; // class RouterInputPort
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_ROUTER_ROUTER_INPUT_PORT_H__
+
diff --git a/ext/dsent/model/electrical/router/RouterSwitchAllocator.cc b/ext/dsent/model/electrical/router/RouterSwitchAllocator.cc
new file mode 100644
index 000000000..92e5431b1
--- /dev/null
+++ b/ext/dsent/model/electrical/router/RouterSwitchAllocator.cc
@@ -0,0 +1,199 @@
+#include "model/electrical/router/RouterSwitchAllocator.h"
+
+#include "model/PortInfo.h"
+#include "model/EventInfo.h"
+#include "model/TransitionInfo.h"
+#include "model/ModelGen.h"
+#include "model/std_cells/StdCell.h"
+#include "model/std_cells/StdCellLib.h"
+
+namespace DSENT
+{
+ RouterSwitchAllocator::RouterSwitchAllocator(const String& instance_name_, const TechModel* tech_model_)
+ : ElectricalModel(instance_name_, tech_model_)
+ {
+ initParameters();
+ initProperties();
+ }
+
+ RouterSwitchAllocator::~RouterSwitchAllocator()
+ {}
+
+ void RouterSwitchAllocator::initParameters()
+ {
+ addParameterName("NumberInputPorts");
+ addParameterName("NumberOutputPorts");
+ addParameterName("TotalNumberVirtualChannels");
+ addParameterName("ArbiterModel");
+ return;
+ }
+
+ void RouterSwitchAllocator::initProperties()
+ {}
+
+ RouterSwitchAllocator* RouterSwitchAllocator::clone() const
+ {
+ // TODO
+ return NULL;
+ }
+
+ void RouterSwitchAllocator::constructModel()
+ {
+ // Get parameters
+ unsigned int number_input_ports = getParameter("NumberInputPorts").toUInt();
+ unsigned int number_output_ports = getParameter("NumberOutputPorts").toUInt();
+ unsigned int total_number_vcs = getParameter("TotalNumberVirtualChannels").toUInt();
+ const String& arb_model = getParameter("ArbiterModel");
+
+ ASSERT(number_input_ports > 0, "[Error] " + getInstanceName() +
+ " -> Number of input ports must be > 0!");
+ ASSERT(number_output_ports > 0, "[Error] " + getInstanceName() +
+ " -> Number of output ports must be > 0!");
+ ASSERT(total_number_vcs > 0, "[Error] " + getInstanceName() +
+ " -> Total number of virtual channels must be > 0!");
+
+ unsigned int stage1_number_requests = total_number_vcs;
+ unsigned int number_stage1_arbiters = number_input_ports;
+ unsigned int stage2_number_requests = number_input_ports;
+ unsigned int number_stage2_arbiters = number_output_ports;
+
+ getGenProperties()->set("NumberStage1Arbiters", number_stage1_arbiters);
+ getGenProperties()->set("Stage1->NumberRequests", stage1_number_requests);
+ getGenProperties()->set("NumberStage2Arbiters", number_stage2_arbiters);
+ getGenProperties()->set("Stage2->NumberRequests", stage2_number_requests);
+
+ // Create ports
+ createInputPort("CK");
+ for(unsigned int i = 0; i < number_stage1_arbiters; ++i)
+ {
+ for(unsigned int j = 0; j < stage1_number_requests; ++j)
+ {
+ createInputPort(String::format("Stage1Arb%d->Request%d", i, j));
+ createInputPort(String::format("Stage1Arb%d->Grant%d", i, j));
+ }
+ }
+ for(unsigned int i = 0; i < number_stage2_arbiters; ++i)
+ {
+ for(unsigned int j = 0; j < stage2_number_requests; ++j)
+ {
+ createInputPort(String::format("Stage2Arb%d->Request%d", i, j));
+ createInputPort(String::format("Stage2Arb%d->Grant%d", i, j));
+ }
+ }
+
+ // Create area, power, and event results
+ createElectricalResults();
+ getEventInfo("Idle")->setStaticTransitionInfos();
+ getEventInfo("Idle")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
+
+ createElectricalEventResult("ArbitrateStage1");
+ getEventInfo("ArbitrateStage1")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
+ createElectricalEventResult("ArbitrateStage2");
+ getEventInfo("ArbitrateStage2")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
+
+ // Init Stage1 arbiter
+ vector<String> stage1_arb_dff_names(stage1_number_requests, "");
+ vector<StdCell*> stage1_arb_dffs(stage1_number_requests, NULL);
+ for(unsigned int i = 0; i < stage1_number_requests; ++i)
+ {
+ stage1_arb_dff_names[i] = "Stage1ArbDFF" + (String)i;
+ stage1_arb_dffs[i] = getTechModel()->getStdCellLib()->createStdCell("DFFQ", stage1_arb_dff_names[i]);
+ stage1_arb_dffs[i]->construct();
+ }
+ const String& stage1_arb_name = "Stage1Arb";
+ ElectricalModel* stage1_arb = (ElectricalModel*)ModelGen::createModel(arb_model, stage1_arb_name, getTechModel());
+ stage1_arb->setParameter("NumberRequests", stage1_number_requests);
+ stage1_arb->construct();
+
+ // Init stage2 arbiter
+ vector<String> stage2_arb_dff_names(stage2_number_requests, "");
+ vector<StdCell*> stage2_arb_dffs(stage2_number_requests, NULL);
+ for(unsigned int i = 0; i < stage2_number_requests; ++i)
+ {
+ stage2_arb_dff_names[i] = "Stage2ArbDFF" + (String)i;
+ stage2_arb_dffs[i] = getTechModel()->getStdCellLib()->createStdCell("DFFQ", stage2_arb_dff_names[i]);
+ stage2_arb_dffs[i]->construct();
+ }
+ const String& stage2_arb_name = "Stage2Arb";
+ ElectricalModel* stage2_arb = (ElectricalModel*)ModelGen::createModel(arb_model, stage2_arb_name, getTechModel());
+ stage2_arb->setParameter("NumberRequests", stage2_number_requests);
+ stage2_arb->construct();
+
+ // Connect ports
+ for(unsigned int i = 0; i < stage1_number_requests; ++i)
+ {
+ const String& dff_in_name = "Stage1Arb_DFF_In" + (String)i;
+ const String& req_name = "Stage1Arb->Request" + (String)i;
+ const String& grant_name = "Stage1Arb->Grant" + (String)i;
+ createNet(dff_in_name);
+ createNet(req_name);
+ createNet(grant_name);
+ portConnect(stage1_arb_dffs[i], "D", dff_in_name);
+ portConnect(stage1_arb_dffs[i], "CK", "CK");
+ portConnect(stage1_arb_dffs[i], "Q", req_name);
+ portConnect(stage1_arb, "Request" + (String)i, req_name);
+ portConnect(stage1_arb, "Grant" + (String)i, grant_name);
+ for(unsigned int j = 0; j < number_stage1_arbiters; ++j)
+ {
+ assignVirtualFanin(dff_in_name, String::format("Stage1Arb%d->Request%d", j, i));
+ assignVirtualFanout(String::format("Stage1Arb%d->Grant%d", j, i), grant_name);
+ }
+ }
+ for(unsigned int i = 0; i < stage2_number_requests; ++i)
+ {
+ const String& dff_in_name = "Stage2Arb_DFF_In" + (String)i;
+ const String& req_name = "Stage2Arb->Request" + (String)i;
+ const String& grant_name = "Stage2Arb->Grant" + (String)i;
+ createNet(dff_in_name);
+ createNet(req_name);
+ createNet(grant_name);
+ portConnect(stage2_arb_dffs[i], "D", dff_in_name);
+ portConnect(stage2_arb_dffs[i], "CK", "CK");
+ portConnect(stage2_arb_dffs[i], "Q", req_name);
+ portConnect(stage2_arb, "Request" + (String)i, req_name);
+ portConnect(stage2_arb, "Grant" + (String)i, grant_name);
+ for(unsigned int j = 0; j < number_stage2_arbiters; ++j)
+ {
+ assignVirtualFanin(dff_in_name, String::format("Stage2Arb%d->Request%d", j, i));
+ assignVirtualFanout(String::format("Stage2Arb%d->Grant%d", j, i), grant_name);
+ }
+ }
+
+ // Add sub components
+ for(unsigned int i = 0; i < stage1_number_requests; ++i)
+ {
+ addSubInstances(stage1_arb_dffs[i], 1.0);
+ addElectricalSubResults(stage1_arb_dffs[i], 1.0);
+ }
+ addSubInstances(stage1_arb, number_stage1_arbiters);
+ addElectricalSubResults(stage1_arb, number_stage1_arbiters);
+ for(unsigned int i = 0; i < stage2_number_requests; ++i)
+ {
+ addSubInstances(stage2_arb_dffs[i], 1.0);
+ addElectricalSubResults(stage2_arb_dffs[i], 1.0);
+ }
+ addSubInstances(stage2_arb, number_stage2_arbiters);
+ addElectricalSubResults(stage2_arb, number_stage2_arbiters);
+
+ // Update stage1 arb arbitrate
+ getEventResult("ArbitrateStage1")->addSubResult(stage1_arb->getEventResult("Arbitrate"), stage1_arb_name, 1.0);
+
+ // Update stage2 arb arbitrate
+ getEventResult("ArbitrateStage2")->addSubResult(stage2_arb->getEventResult("Arbitrate"), stage2_arb_name, 1.0);
+ return;
+ }
+
+ void RouterSwitchAllocator::propagateTransitionInfo()
+ {
+ ElectricalModel* stage1_arb = (ElectricalModel*)getSubInstance("Stage1Arb");
+ stage1_arb->applyTransitionInfo("Arbitrate");
+ stage1_arb->use();
+
+ ElectricalModel* stage2_arb = (ElectricalModel*)getSubInstance("Stage2Arb");
+ stage2_arb->applyTransitionInfo("Arbitrate");
+ stage2_arb->use();
+
+ return;
+ }
+} // namespace DSENT
+
diff --git a/ext/dsent/model/electrical/router/RouterSwitchAllocator.h b/ext/dsent/model/electrical/router/RouterSwitchAllocator.h
new file mode 100644
index 000000000..8b18e199f
--- /dev/null
+++ b/ext/dsent/model/electrical/router/RouterSwitchAllocator.h
@@ -0,0 +1,33 @@
+#ifndef __DSENT_MODEL_ELECTRICAL_ROUTER_ROUTER_SWITCH_ALLOCATOR_H__
+#define __DSENT_MODEL_ELECTRICAL_ROUTER_ROUTER_SWITCH_ALLOCATOR_H__
+
+#include "util/CommonType.h"
+#include "model/ElectricalModel.h"
+
+namespace DSENT
+{
+ class RouterSwitchAllocator : public ElectricalModel
+ {
+ public:
+ RouterSwitchAllocator(const String& instance_name_, const TechModel* tech_model_);
+ virtual ~RouterSwitchAllocator();
+
+ public:
+ // Set a list of properties' name needed to construct model
+ void initParameters();
+ // Set a list of properties' name needed to construct model
+ void initProperties();
+
+ // Clone and return a new instance
+ virtual RouterSwitchAllocator* clone() const;
+
+ protected:
+ // Build the model
+ virtual void constructModel();
+ virtual void propagateTransitionInfo();
+
+ }; // RouterSwitchAllocator
+} // namespace DSENT
+
+#endif // __DSENT_MODEL_ELECTRICAL_ROUTER_ROUTER_SWITCH_ALLOCATOR_H__
+