1/* Copyright (c) 2012 Massachusetts Institute of Technology
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to deal
5 * in the Software without restriction, including without limitation the rights
6 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 * copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 * THE SOFTWARE.
20 */
21
22#include "model/electrical/MultiplexerCrossbar.h"
23
24#include <vector>
25#include <cmath>
26
27#include "model/PortInfo.h"
28#include "model/EventInfo.h"
29#include "model/TransitionInfo.h"
30#include "model/timing_graph/ElectricalNet.h"
31#include "model/electrical/Multiplexer.h"
32
33namespace DSENT
34{
35    using std::ceil;
36    using std::vector;
37
38    MultiplexerCrossbar::MultiplexerCrossbar(const String& instance_name_, const TechModel* tech_model_)
39        : ElectricalModel(instance_name_, tech_model_)
40    {
41        initParameters();
42        initProperties();
43    }
44
45    MultiplexerCrossbar::~MultiplexerCrossbar()
46    {}
47
48    void MultiplexerCrossbar::initParameters()
49    {
50        addParameterName("NumberInputs");
51        addParameterName("NumberOutputs");
52        addParameterName("NumberBits");
53        addParameterName("BitDuplicate", "TRUE");
54        return;
55    }
56
57    void MultiplexerCrossbar::initProperties()
58    {
59        return;
60    }
61
62    MultiplexerCrossbar* MultiplexerCrossbar::clone() const
63    {
64        // TODO
65        return NULL;
66    }
67
68    void MultiplexerCrossbar::constructModel()
69    {
70        // Get Parameters
71        unsigned int number_inputs = getParameter("NumberInputs").toUInt();
72        unsigned int number_outputs = getParameter("NumberOutputs").toUInt();
73        unsigned int number_bits = getParameter("NumberBits").toUInt();
74        bool bit_duplicate = getParameter("BitDuplicate").toBool();
75
76        ASSERT(number_inputs > 0, "[Error] " + getInstanceName() + " -> Number of inputs must be > 0!");
77        ASSERT(number_outputs > 0, "[Error] " + getInstanceName() + " -> Number of outputs must be > 0!");
78        ASSERT(number_bits > 0, "[Error] " + getInstanceName() + " -> Number of bits must be > 0!");
79
80        unsigned int number_selects = (unsigned int)ceil(log2((double)number_inputs));
81        getGenProperties()->set("NumberSelectsPerPort", number_selects);
82
83        // Construct electrical ports and nets
84        // Create input ports
85        for(unsigned int i = 0; i < number_inputs; ++i)
86        {
87            createInputPort("In" + (String)i, makeNetIndex(0, number_bits-1));
88        }
89        // Create select signals
90        for(unsigned int i = 0; i < number_outputs; ++i)
91        {
92            for(unsigned int j = 0; j < number_selects; ++j)
93            {
94                createInputPort(String::format("Sel%d_%d", i, j));
95            }
96        }
97        // Create output ports
98        for(unsigned int i = 0; i < number_outputs; ++i)
99        {
100            createOutputPort("Out" + (String)i, makeNetIndex(0, number_bits-1));
101        }
102
103        // Create energy, power, and area results
104        addAreaResult(new AtomicResult("CrossbarWire"));
105        addAreaResult(new AtomicResult("CrossbarFill"));
106        createElectricalResults();
107        getEventInfo("Idle")->setStaticTransitionInfos();
108        createElectricalEventResult("Multicast0");
109        getEventInfo("Multicast0")->setStaticTransitionInfos();
110        for(unsigned int i = 1; i <= number_outputs; ++i)
111        {
112            createElectricalEventResult("Multicast" + (String)i);
113            EventInfo* event_info = getEventInfo("Multicast" + (String)i);
114            // Assuming that In0 is sending to Out0, Out1, ..., Outi
115            // and other input ports are static
116            for(unsigned int j = 1; j < number_inputs; ++j)
117            {
118                event_info->setStaticTransitionInfo("In" + (String)j);
119            }
120            for(unsigned int j = i; j < number_outputs; ++j)
121            {
122                for(unsigned int k = 0; k < number_selects; ++k)
123                {
124                    event_info->setStaticTransitionInfo(String::format("Sel%d_%d", j, k));
125                }
126            }
127        }
128        createElectricalEventResult("Crossbar");
129
130        // Initiate multiplexers
131        vector<String> mux_names(number_outputs, "");
132        vector<Multiplexer*> muxs(number_outputs, NULL);
133        for(unsigned int i = 0; i < number_outputs; ++i)
134        {
135            mux_names[i] = "Mux" + (String)i;
136            muxs[i] = new Multiplexer(mux_names[i], getTechModel());
137            muxs[i]->setParameter("NumberInputs", number_inputs);
138            muxs[i]->setParameter("NumberBits", number_bits);
139            muxs[i]->setParameter("BitDuplicate", bit_duplicate);
140            muxs[i]->construct();
141        }
142
143        // Connect inputs and outputs to multiplexers
144        for(unsigned int i = 0; i < number_outputs; ++i)
145        {
146            // Connect inputs
147            for(unsigned int j = 0; j < number_inputs; ++j)
148            {
149                portConnect(muxs[i], "In" + (String)j, "In" + (String)j, makeNetIndex(0, number_bits-1));
150            }
151
152            // Connect select signals
153            for(unsigned int j = 0; j < number_selects; ++j)
154            {
155                portConnect(muxs[i], "Sel" + (String)j, String::format("Sel%d_%d", i, j));
156            }
157
158            // Connect outputs
159            portConnect(muxs[i], "Out", "Out" + (String)i, makeNetIndex(0, number_bits-1));
160        }
161
162        // Add area, power, and event results for each mux
163        for(unsigned int i = 0; i < number_outputs; ++i)
164        {
165            addSubInstances(muxs[i], 1.0);
166            addElectricalSubResults(muxs[i], 1.0);
167            for(unsigned int j = 0; j <= number_outputs; ++j)
168            {
169                getEventResult("Multicast" + (String)j)->addSubResult(muxs[i]->getEventResult("Mux"), mux_names[i], 1.0);
170            }
171            getEventResult("Crossbar")->addSubResult(muxs[i]->getEventResult("Mux"), mux_names[i], 1.0);
172        }
173
174        // Estimate wiring area
175        const String& crossbar_wire_layer = "Intermediate";
176        addElectricalWireSubResult(crossbar_wire_layer, getAreaResult("CrossbarWire"), "Self", 1.0);
177        double wire_width = getTechModel()->get("Wire->" + crossbar_wire_layer + "->MinWidth").toDouble();
178        double wire_spacing = getTechModel()->get("Wire->" + crossbar_wire_layer + "->MinSpacing").toDouble();
179        double wire_pitch = wire_width + wire_spacing;
180        double wire_area = (number_bits * number_inputs * wire_pitch) * (number_bits * number_outputs * wire_pitch);
181        getAreaResult("CrossbarWire")->setValue(wire_area);
182
183        // Add filler area
184        getAreaResult("Active")->addSubResult(getAreaResult("CrossbarFill"), "Self", 1.0);
185        return;
186    }
187
188    void MultiplexerCrossbar::updateModel()
189    {
190        // Update all sub instances
191        Model::updateModel();
192
193        // Update filler area
194        // Total Active area = max(stdcell active area, wiring area);
195        double wire_area = getAreaResult("CrossbarWire")->calculateSum();
196        double active_area = getAreaResult("Active")->calculateSum();
197        double fill_area = 0.0;
198        if(active_area < wire_area)
199        {
200            fill_area = wire_area - active_area;
201        }
202        getAreaResult("CrossbarFill")->setValue(fill_area);
203        return;
204    }
205
206    void MultiplexerCrossbar::propagateTransitionInfo()
207    {
208        // The only thing can be updated are the input probabilities
209        const unsigned int number_inputs = getParameter("NumberInputs").toUInt();
210        const unsigned int number_outputs = getParameter("NumberOutputs").toUInt();
211
212        const unsigned int number_selects = getGenProperties()->get("NumberSelectsPerPort").toUInt();
213
214        for(unsigned int i = 0; i < number_outputs; ++i)
215        {
216            ElectricalModel* muxi = (ElectricalModel*)getSubInstance("Mux" + (String)i);
217            for(unsigned int j = 0; j < number_inputs; ++j)
218            {
219                propagatePortTransitionInfo(muxi, "In" + (String)j, "In" + (String)j);
220            }
221            for(unsigned int j = 0; j < number_selects; ++j)
222            {
223                propagatePortTransitionInfo(muxi, "Sel" + (String)j, String::format("Sel%d_%d", i, j));
224            }
225            muxi->use();
226
227            // Set output probability
228            propagatePortTransitionInfo("Out" + (String)i, muxi, "Out");
229        }
230
231        return;
232    }
233
234} // namespace DSENT
235
236