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/Multiplexer.h"
23
24#include <cmath>
25
26#include "model/PortInfo.h"
27#include "model/TransitionInfo.h"
28#include "model/EventInfo.h"
29#include "model/timing_graph/ElectricalDriverMultiplier.h"
30#include "model/timing_graph/ElectricalNet.h"
31#include "model/std_cells/StdCell.h"
32#include "model/std_cells/StdCellLib.h"
33
34namespace DSENT
35{
36    Multiplexer::Multiplexer(const String& instance_name_, const TechModel* tech_model_)
37        : ElectricalModel(instance_name_, tech_model_)
38    {
39        initParameters();
40        initProperties();
41    }
42
43    Multiplexer::~Multiplexer()
44    {}
45
46    void Multiplexer::initParameters()
47    {
48        addParameterName("NumberInputs");
49        addParameterName("NumberBits");
50        addParameterName("BitDuplicate", "TRUE");
51        addParameterName("IsTopLevel", "TRUE");
52        return;
53    }
54
55    void Multiplexer::initProperties()
56    {
57        return;
58    }
59
60    Multiplexer* Multiplexer::clone() const
61    {
62        return NULL;
63    }
64
65    void Multiplexer::constructModel()
66    {
67        // Get parameters
68        unsigned int number_bits = (unsigned int) getParameter("NumberBits");
69        unsigned int number_inputs = (unsigned int) getParameter("NumberInputs");
70        unsigned int number_selects = (unsigned int) ceil(log2((double) number_inputs));
71        bool bit_duplicate = (bool) getParameter("BitDuplicate");
72        bool is_top_level = getParameter("IsTopLevel").toBool();
73
74        ASSERT(number_inputs > 0, "[Error] " + getInstanceName() + " -> Number of inputs must be > 0!");
75        ASSERT(number_bits > 0, "[Error] " + getInstanceName() + " -> Number of bits must be > 0!");
76
77        //Construct electrical ports and nets
78        //Create each input port
79        for(unsigned int i = 0; i < number_inputs; ++i)
80            createInputPort(    "In" + (String) i, makeNetIndex(0, number_bits-1));
81        //Create select signals
82        for(unsigned int i = 0; i < number_selects; ++i)
83        {
84            createInputPort(    "Sel" + (String)i);
85        }
86        //Create output
87        createOutputPort(   "Out", makeNetIndex(0, number_bits-1));
88
89        //Create energy, power, and area results
90        createElectricalResults();
91        getEventInfo("Idle")->setStaticTransitionInfos();
92        createElectricalEventResult("Mux");
93
94        //Number of inputs on the 0 side
95        unsigned int inputs_0 = (unsigned int) ceil((double) number_inputs / 2.0);
96        unsigned int selects_0 = (unsigned int) ceil(log2((double) inputs_0));
97        //Number of inputs on the 1 side
98        unsigned int inputs_1 = (unsigned int) floor((double) number_inputs / 2.0);
99        unsigned int selects_1 = (unsigned int) ceil(log2((double) inputs_1));
100
101        //Depending on whether we want to create a 1-bit instance and have it multiplied
102        //up by number of bits or actually instantiate number_bits of 1-bit instances.
103        //Recursively instantiates smaller multiplexers
104        if (bit_duplicate || number_bits == 1)
105        {
106            //If it is just a 1-input multiplexer, just connect output to input and be done
107            if (number_inputs == 1)
108            {
109                assign("Out", "In0");
110            }
111            else
112            {
113                //If it is more than 1 input, instantiate two sub multiplexers (Mux_way0 and Mux_way1)
114                //and create a final 2:1 mux (muxf) to select between them
115                String mux0_name = "Mux_way0";
116                String mux1_name = "Mux_way1";
117                String muxf_name = "Mux2_i" + (String)number_inputs;
118
119                Multiplexer* mux0 = new Multiplexer(mux0_name, getTechModel());
120                mux0->setParameter("NumberInputs", inputs_0);
121                mux0->setParameter("NumberBits", 1);
122                mux0->setParameter("BitDuplicate", "TRUE");
123                mux0->setParameter("IsTopLevel", "FALSE");
124                mux0->construct();
125
126                Multiplexer* mux1 = new Multiplexer(mux1_name, getTechModel());
127                mux1->setParameter("NumberInputs", inputs_1);
128                mux1->setParameter("NumberBits", 1);
129                mux1->setParameter("BitDuplicate", "TRUE");
130                mux1->setParameter("IsTopLevel", "FALSE");
131                mux1->construct();
132
133                StdCell* muxf = getTechModel()->getStdCellLib()->createStdCell("MUX2", muxf_name);
134                muxf->construct();
135
136                // TODO hack
137                // create selector driver at the top level
138                if(is_top_level)
139                {
140                    for(unsigned int i = 0; i < number_selects; ++i)
141                    {
142                        StdCell* selinv0 = getTechModel()->getStdCellLib()->createStdCell("INV", String::format("Sel%dInv0", i));
143                        StdCell* selinv1 = getTechModel()->getStdCellLib()->createStdCell("INV", String::format("Sel%dInv1", i));
144                        selinv0->construct();
145                        selinv1->construct();
146
147                        addSubInstances(selinv0, 1.0);
148                        addElectricalSubResults(selinv0, 1.0);
149                        addSubInstances(selinv1, 1.0);
150                        addElectricalSubResults(selinv1, 1.0);
151                        getEventResult("Mux")->addSubResult(selinv0->getEventResult("INV"), String::format("Sel%dInv0", i), 1.0);
152                        getEventResult("Mux")->addSubResult(selinv1->getEventResult("INV"), String::format("Sel%dInv1", i), 1.0);
153                    }
154                }
155
156                //Create outputs of way0 and way1 multiplexers with final mux
157                createNet("way0Out");
158                createNet("way1Out");
159                portConnect(mux0, "Out", "way0Out");
160                portConnect(mux1, "Out", "way1Out");
161                portConnect(muxf, "A", "way0Out");
162                portConnect(muxf, "B", "way1Out");
163
164                // TODO hack
165                // Connect selector bits
166                if(is_top_level)
167                {
168                    for(unsigned int i = 0; i < number_selects; ++i)
169                    {
170                        ElectricalModel* selinv0 = (ElectricalModel*)getSubInstance(String::format("Sel%dInv0", i));
171                        ElectricalModel* selinv1 = (ElectricalModel*)getSubInstance(String::format("Sel%dInv1", i));
172                        createNet("SelInv" + (String)i);
173                        createNet("SelBuf" + (String)i);
174                        portConnect(selinv0, "A", "Sel" + (String)i);
175                        portConnect(selinv0, "Y", "SelInv" + (String)i);
176                        portConnect(selinv1, "A", "SelInv" + (String)i);
177                        portConnect(selinv1, "Y", "SelBuf" + (String)i);
178                    }
179                }
180                //Connect inputs to the sub multiplexers.
181                //Note that multiple inputs are connected to the mux0 and mux1 input and the
182                //selector signals are connected multiple times. This is just so that everything
183                //is loaded appropriately since bit duplication is applied
184                for (unsigned int n = 0; n < number_bits; ++n)
185                {
186                    //Connect inputs
187                    for (unsigned int i = 0; i < inputs_0; ++i)
188                        portConnect(mux0, "In" + (String) i, "In" + (String) i, makeNetIndex(n));
189                    for (unsigned int i = 0; i < inputs_1; ++i)
190                        portConnect(mux1, "In" + (String) i, "In" + (String) (i + inputs_0), makeNetIndex(n));
191                    // TODO hack
192                    if(is_top_level)
193                    {
194                        //Connect selector bits
195                        for (unsigned int i = 0; i < selects_0; ++i)
196                            portConnect(mux0, "Sel" + (String)i, "SelBuf" + (String)i);
197                        for (unsigned int i = 0; i < selects_1; ++i)
198                            portConnect(mux1, "Sel" + (String)i, "SelBuf" + (String)i);
199                        portConnect(muxf, "S0", "SelBuf" + (String)(number_selects - 1));
200                    }
201                    else
202                    {
203                        //Connect selector bits
204                        for (unsigned int i = 0; i < selects_0; ++i)
205                            portConnect(mux0, "Sel" + (String)i, "Sel" + (String)i);
206                        for (unsigned int i = 0; i < selects_1; ++i)
207                            portConnect(mux1, "Sel" + (String)i, "Sel" + (String)i);
208                        portConnect(muxf, "S0", "Sel" + (String)(number_selects - 1));
209                    }
210                }
211
212                //Connect final mux to outputs
213                //Because we use bit duplication and so there is only only one multiplexer
214                //instance, we must use driver multiplier to drive each output appropriately
215                if (number_bits == 1)
216                    portConnect(muxf, "Y", "Out");
217                else
218                {
219                    createNet("OutTemp");
220                    createDriverMultiplier("OutMult");
221                    ElectricalDriverMultiplier* drive_mult = getDriverMultiplier("OutMult");
222                    portConnect(muxf, "Y", "OutTemp");
223                    getNet("OutTemp")->addDownstreamNode(drive_mult);
224                    for (unsigned int n = 0; n < number_bits; ++n)
225                        drive_mult->addDownstreamNode(getNet("Out", makeNetIndex(n)));
226                }
227
228                //Add area, power, and event results for each mux
229                addSubInstances(mux0, number_bits);
230                addElectricalSubResults(mux0, number_bits);
231                addSubInstances(mux1, number_bits);
232                addElectricalSubResults(mux1, number_bits);
233                addSubInstances(muxf, number_bits);
234                addElectricalSubResults(muxf, number_bits);
235                getEventResult("Mux")->addSubResult(mux0->getEventResult("Mux"), mux0_name, number_bits);
236                getEventResult("Mux")->addSubResult(mux1->getEventResult("Mux"), mux1_name, number_bits);
237                getEventResult("Mux")->addSubResult(muxf->getEventResult("MUX2"), muxf_name, number_bits);
238
239            }
240
241        }
242        else
243        {
244            //Instantiate a bunch of 1-bit multiplexers
245            for (unsigned int n = 0; n < number_bits; ++n)
246            {
247                String mux_name = "Mux_bit" + (String) n;
248
249                Multiplexer* mux = new Multiplexer(mux_name, getTechModel());
250                mux->setParameter("NumberInputs", number_inputs);
251                mux->setParameter("NumberBits", 1);
252                mux->setParameter("BitDuplicate", "TRUE");
253                mux->construct();
254
255                // Connect inputs
256                for (unsigned int i = 0; i < number_inputs; ++i)
257                    portConnect(mux, "In" + (String) i, "In" + (String) i, makeNetIndex(n));
258                for(unsigned int i = 0; i < number_selects; ++i)
259                    portConnect(mux, "Sel" + (String)i, "Sel" + (String)i);
260                portConnect(mux, "Out", "Out", makeNetIndex(n));
261
262                //Add area, power, and event results for each mux
263                addSubInstances(mux, 1.0);
264                addElectricalSubResults(mux, 1.0);
265                getEventResult("Mux")->addSubResult(mux->getEventResult("Mux"), mux_name, 1.0);
266            }
267        }
268
269        return;
270    }
271
272    void Multiplexer::propagateTransitionInfo()
273    {
274        // The only thing can be updated are the input probabilities...so we will update them
275        unsigned int number_bits = (unsigned int) getParameter("NumberBits");
276        unsigned int number_inputs = (unsigned int) getParameter("NumberInputs");
277        unsigned int number_selects = (unsigned int) ceil(log2((double) number_inputs));
278        bool bit_duplicate = (bool) getParameter("BitDuplicate");
279        bool is_top_level = getParameter("IsTopLevel").toBool();
280
281        //Number of inputs on the 0 side
282        unsigned int inputs_0 = (unsigned int) ceil((double) number_inputs / 2.0);
283        unsigned int selects_0 = (unsigned int) ceil(log2((double) inputs_0));
284
285        //Number of inputs on the 1 side
286        unsigned int inputs_1 = (unsigned int) floor((double) number_inputs / 2.0);
287        unsigned int selects_1 = (unsigned int) ceil(log2((double) inputs_1));
288
289        if (bit_duplicate || number_bits == 1)
290        {
291            if (number_inputs == 1)
292            {
293                //If theres only 1 input, output transition = input transition
294                propagatePortTransitionInfo("Out", "In0");
295            }
296            else
297            {
298                // Update sub muxes with appropriate probabilities
299                ElectricalModel* mux0 = (ElectricalModel*)getSubInstance("Mux_way0");
300                for(unsigned int i = 0; i < inputs_0; ++i)
301                {
302                    propagatePortTransitionInfo(mux0, "In" + (String)i, "In" + (String)i);
303                }
304                for(unsigned int i = 0; i < selects_0; ++i)
305                {
306                    propagatePortTransitionInfo(mux0, "Sel" + (String)i, "Sel" + (String)i);
307                }
308                mux0->use();
309                ElectricalModel* mux1 = (ElectricalModel*)getSubInstance("Mux_way1");
310                for(unsigned int i = 0; i < inputs_1; ++i)
311                {
312                    propagatePortTransitionInfo(mux1, "In" + (String)i, "In" + (String)(i + inputs_0));
313                }
314                for(unsigned int i = 0; i < selects_1; ++i)
315                {
316                    propagatePortTransitionInfo(mux1, "Sel" + (String)i, "Sel" + (String)i);
317                }
318                mux1->use();
319                ElectricalModel* muxf = (ElectricalModel*)getSubInstance("Mux2_i" + (String)number_inputs);
320                propagatePortTransitionInfo(muxf, "A", mux0, "Out");
321                propagatePortTransitionInfo(muxf, "B", mux1, "Out");
322                propagatePortTransitionInfo(muxf, "S0", "Sel" + (String)(number_selects-1));
323                muxf->use();
324
325                // TODO hack
326                if(is_top_level)
327                {
328                    for(unsigned int i = 0; i < number_selects; ++i)
329                    {
330                        ElectricalModel* selinv0 = (ElectricalModel*)getSubInstance(String::format("Sel%dInv0", i));
331                        ElectricalModel* selinv1 = (ElectricalModel*)getSubInstance(String::format("Sel%dInv1", i));
332                        propagatePortTransitionInfo(selinv0, "A", "Sel" + (String)i);
333                        selinv0->use();
334                        propagatePortTransitionInfo(selinv1, "A", selinv0, "Y");
335                        selinv1->use();
336                    }
337                }
338
339                // Set output transition
340                propagatePortTransitionInfo("Out", muxf, "Y");
341            }
342        }
343        else
344        {
345            // Go through each bit and set the appropriate probability
346            for (unsigned int n = 0; n < number_bits; ++n)
347            {
348                ElectricalModel* mux_bit = (ElectricalModel*)getSubInstance("Mux_bit" + (String) n);
349                for(unsigned int i = 0; i < number_inputs; ++i)
350                {
351                    propagatePortTransitionInfo(mux_bit, "In" + (String)i, "In" + (String)i);
352                }
353                for(unsigned int i = 0; i < number_selects; ++i)
354                {
355                    propagatePortTransitionInfo(mux_bit, "Sel" + (String)i, "Sel" + (String)i);
356                }
357                mux_bit->use();
358            }
359
360            // Set output probability to be average that of probabilties of each output bit
361            ElectricalModel* mux_bit = (ElectricalModel*)getSubInstance("Mux_bit0");
362            propagatePortTransitionInfo("Out", mux_bit, "Out");
363        }
364        return;
365    }
366
367} // namespace DSENT
368
369