diff options
author | Nilay Vaish <nilay@cs.wisc.edu> | 2014-10-11 15:02:23 -0500 |
---|---|---|
committer | Nilay Vaish <nilay@cs.wisc.edu> | 2014-10-11 15:02:23 -0500 |
commit | e8ed7b1d1b5bef31e9874f679a5797c2e00d06f1 (patch) | |
tree | 421c9c50377aa664958685914f5504c4c019e21f /ext/dsent/model/electrical/MuxTreeSerializer.cc | |
parent | a098fad174d8559037602b248b8e6f7f46bfebbb (diff) | |
download | gem5-e8ed7b1d1b5bef31e9874f679a5797c2e00d06f1.tar.xz |
ext: add the source code for DSENT
This patch adds a tool called DSENT to the ext/ directory. DSENT
is a tool that models power and area for on-chip networks. The next
patch adds a script for using the tool.
Diffstat (limited to 'ext/dsent/model/electrical/MuxTreeSerializer.cc')
-rw-r--r-- | ext/dsent/model/electrical/MuxTreeSerializer.cc | 226 |
1 files changed, 226 insertions, 0 deletions
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 + |