/* Copyright (c) 2012 Massachusetts Institute of Technology * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "model/electrical/router/RouterInputPort.h" #include #include #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& number_vcs_per_vn_vector = castStringVector(getParameter("NumberVirtualChannelsPerVirtualNetwork").split("[,]")); const vector& number_bufs_per_vc_vector = castStringVector(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 rd_addr_dff_names(number_addr_bits, ""); vector 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 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