diff options
Diffstat (limited to 'ext/dsent/model/electrical')
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__ + |