/* 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/MultiplexerCrossbar.h" #include #include #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 mux_names(number_outputs, ""); vector 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