gem5/ext/dsent/model/electrical/router/Router.cc
Nilay Vaish e8ed7b1d1b 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.
2014-10-11 15:02:23 -05:00

536 lines
24 KiB
C++

#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