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/DemuxTreeDeserializer.h"
23
24#include <cmath>
25
26#include "model/PortInfo.h"
27#include "model/TransitionInfo.h"
28#include "model/EventInfo.h"
29#include "model/std_cells/StdCellLib.h"
30#include "model/std_cells/StdCell.h"
31#include "model/electrical/Multiplexer.h"
32#include "model/timing_graph/ElectricalNet.h"
33
34namespace DSENT
35{
36    using std::ceil;
37
38    DemuxTreeDeserializer::DemuxTreeDeserializer(const String& instance_name_, const TechModel* tech_model_)
39        : ElectricalModel(instance_name_, tech_model_)
40    {
41        initParameters();
42        initProperties();
43    }
44
45    DemuxTreeDeserializer::~DemuxTreeDeserializer()
46    {}
47
48    void DemuxTreeDeserializer::initParameters()
49    {
50        addParameterName("InDataRate");
51        addParameterName("OutDataRate");
52        addParameterName("OutBits");              //Output width will just be output width / serialization ratio
53        addParameterName("BitDuplicate", "TRUE");
54        return;
55    }
56
57    void DemuxTreeDeserializer::initProperties()
58    {
59        return;
60    }
61
62    DemuxTreeDeserializer* DemuxTreeDeserializer::clone() const
63    {
64        // TODO
65        return NULL;
66    }
67
68    void DemuxTreeDeserializer::constructModel()
69    {
70
71        // Get parameters
72        double in_data_rate = getParameter("InDataRate");
73        double out_data_rate = getParameter("OutDataRate");
74        unsigned int out_bits = getParameter("OutBits");
75        bool bit_duplicate = getParameter("BitDuplicate");
76
77        // Calculate deserialization ratio
78        unsigned int deserialization_ratio = (unsigned int) floor(in_data_rate / out_data_rate);
79        ASSERT(deserialization_ratio == in_data_rate / out_data_rate,
80            "[Error] " + getInstanceName() + " -> Cannot have non-integer deserialization ratios!");
81        ASSERT((deserialization_ratio & (deserialization_ratio - 1)) == 0,
82            "[Error] " + getInstanceName() + " -> Deserialization ratio must be a power of 2");
83
84        // Calculate output width
85        unsigned int input_bits = out_bits / deserialization_ratio;
86        ASSERT(out_bits >= deserialization_ratio, "[Error] " + getInstanceName() +
87            " -> Output width must be >= deserialization ratio!");
88        ASSERT(floor((double) out_bits / deserialization_ratio) == input_bits,
89            "[Error] " + getInstanceName() + " -> Output width must be a multiple of the serialization ratio!");
90
91        // Store calculated numbers
92        getGenProperties()->set("DeserializationRatio", deserialization_ratio);
93        getGenProperties()->set("InputBits", input_bits);
94
95        // Create ports
96        createInputPort("In", makeNetIndex(0, input_bits-1));
97        createInputPort("InCK");
98        createOutputPort("Out", makeNetIndex(0, out_bits-1));
99
100        //Create energy, power, and area results
101        createElectricalResults();
102        createElectricalEventResult("Deserialize");
103        getEventInfo("Deserialize")->setTransitionInfo("InCK", TransitionInfo(0.0, (double) deserialization_ratio / 2.0, 0.0));
104        // Set conditions during idle state
105        getEventInfo("Idle")->setStaticTransitionInfos();
106        getEventInfo("Idle")->setTransitionInfo("InCK", TransitionInfo(0.0, (double) deserialization_ratio / 2.0, 0.0));
107
108        // Mark InCK as a false path (since timing tool will do strange stuff due to all the clock divides and stuff)
109        getNet("InCK")->setFalsePath(true);
110
111        // Create deserializer
112        if (deserialization_ratio == 1)
113        {
114            // No need to do anything, hohoho
115            assign("Out", "In");
116        }
117        else if (input_bits == 1)
118        {
119            //-----------------------------------------------------------------
120            // Create 2:1 demux deserializer
121            //-----------------------------------------------------------------
122            const String& des_dff_way0_name = "DesDFFWay0";
123            const String& des_dff_way1_name = "DesDFFWay1";
124            const String& des_latch_name = "DesLatch";
125            const String& ck_dff_name = "CKDFF";
126            const String& ck_inv_name = "CKINV";
127            const String& out_way0_name = "OutWay0";
128            const String& out_way1_name = "OutWay1";
129            const String& mid_way0_name = "MidWay0";
130            const String& ck_div2_name = "CK_div2";
131            const String& ck_div2_b_name = "CK_div2_b";
132
133            // Create nets
134            createNet(out_way0_name);
135            createNet(out_way1_name);
136            createNet(mid_way0_name);
137            createNet(ck_div2_name);
138            createNet(ck_div2_b_name);
139
140            // Create the dffs and latch needed on both ways
141            StdCell* des_dff_way0 = getTechModel()->getStdCellLib()->createStdCell("DFFQ", des_dff_way0_name);
142            des_dff_way0->construct();
143            StdCell* des_dff_way1 = getTechModel()->getStdCellLib()->createStdCell("DFFQ", des_dff_way1_name);
144            des_dff_way1->construct();
145            StdCell* des_latch = getTechModel()->getStdCellLib()->createStdCell("LATQ", des_latch_name);
146            des_latch->construct();
147
148            // Create clk divide circuit
149            StdCell* ck_dff = getTechModel()->getStdCellLib()->createStdCell("DFFQ", ck_dff_name);
150            ck_dff->construct();
151            StdCell* ck_inv = getTechModel()->getStdCellLib()->createStdCell("INV", ck_inv_name);
152            ck_inv->construct();
153
154            // Connect ports
155            portConnect(des_dff_way0, "CK", "InCK");
156            portConnect(des_dff_way0, "D", mid_way0_name);
157            portConnect(des_dff_way0, "Q", out_way0_name);
158            portConnect(des_latch, "G", "InCK");
159            portConnect(des_latch, "D", "In");
160            portConnect(des_latch, "Q", mid_way0_name);
161            portConnect(des_dff_way1, "CK", "InCK");
162            portConnect(des_dff_way1, "D", "In");
163            portConnect(des_dff_way1, "Q", out_way1_name);
164            portConnect(ck_dff, "CK", "InCK");
165            portConnect(ck_dff, "D", ck_div2_b_name);
166            portConnect(ck_dff, "Q", ck_div2_name);
167            portConnect(ck_inv, "A", ck_div2_name);
168            portConnect(ck_inv, "Y", ck_div2_b_name);
169
170            // Add sub instances
171            addSubInstances(des_dff_way0, 1.0);
172            addElectricalSubResults(des_dff_way0, 1.0);
173            addSubInstances(des_dff_way1, 1.0);
174            addElectricalSubResults(des_dff_way1, 1.0);
175            addSubInstances(des_latch, 1.0);
176            addElectricalSubResults(des_latch, 1.0);
177            addSubInstances(ck_dff, 1.0);
178            addElectricalSubResults(ck_dff, 1.0);
179            addSubInstances(ck_inv, 1.0);
180            addElectricalSubResults(ck_inv, 1.0);
181
182            Result* deserialize = getEventResult("Deserialize");
183            deserialize->addSubResult(des_dff_way0->getEventResult("CK"), des_dff_way0_name, 1.0);
184            deserialize->addSubResult(des_dff_way0->getEventResult("DFFD"), des_dff_way0_name, 1.0);
185            deserialize->addSubResult(des_dff_way0->getEventResult("DFFQ"), des_dff_way0_name, 1.0);
186            deserialize->addSubResult(des_dff_way1->getEventResult("CK"), des_dff_way1_name, 1.0);
187            deserialize->addSubResult(des_dff_way1->getEventResult("DFFD"), des_dff_way1_name, 1.0);
188            deserialize->addSubResult(des_dff_way1->getEventResult("DFFQ"), des_dff_way1_name, 1.0);
189            deserialize->addSubResult(des_latch->getEventResult("G"), des_latch_name, 1.0);
190            deserialize->addSubResult(des_latch->getEventResult("LATD"), des_latch_name, 1.0);
191            deserialize->addSubResult(des_latch->getEventResult("LATQ"), des_latch_name, 1.0);
192            deserialize->addSubResult(ck_dff->getEventResult("CK"), ck_dff_name, 1.0);
193            deserialize->addSubResult(ck_dff->getEventResult("DFFD"), ck_dff_name, 1.0);
194            deserialize->addSubResult(ck_dff->getEventResult("DFFQ"), ck_dff_name, 1.0);
195            deserialize->addSubResult(ck_inv->getEventResult("INV"), ck_inv_name, 1.0);
196            //-----------------------------------------------------------------
197
198            //-----------------------------------------------------------------
199            // Create Sub-deserializers
200            //-----------------------------------------------------------------
201            // Create sub-deserializers
202            const String& demux_way0_name = "DemuxTree_way0_" + (String) deserialization_ratio + "_to_1";
203            const String& demux_way1_name = "DemuxTree_way1_" + (String) deserialization_ratio + "_to_1";
204
205            DemuxTreeDeserializer* demux_way0 = new DemuxTreeDeserializer(demux_way0_name, getTechModel());
206            demux_way0->setParameter("InDataRate", in_data_rate / 2.0);
207            demux_way0->setParameter("OutDataRate", out_data_rate);
208            demux_way0->setParameter("OutBits", out_bits / 2);
209            demux_way0->setParameter("BitDuplicate", "TRUE");
210            demux_way0->construct();
211
212            DemuxTreeDeserializer* demux_way1 = new DemuxTreeDeserializer(demux_way1_name, getTechModel());
213            demux_way1->setParameter("InDataRate", in_data_rate / 2.0);
214            demux_way1->setParameter("OutDataRate", out_data_rate);
215            demux_way1->setParameter("OutBits", out_bits / 2);
216            demux_way1->setParameter("BitDuplicate", "TRUE");
217            demux_way1->construct();
218
219            // Connect ports
220            portConnect(demux_way0, "In", out_way0_name);
221            portConnect(demux_way0, "InCK", ck_div2_name);
222            portConnect(demux_way0, "Out", "Out", makeNetIndex(0, out_bits/2-1));
223
224            portConnect(demux_way1, "In", out_way1_name);
225            portConnect(demux_way1, "InCK", ck_div2_name);
226            portConnect(demux_way1, "Out", "Out", makeNetIndex(out_bits/2, out_bits-1));
227
228            // Add subinstances and area results
229            addSubInstances(demux_way0, 1.0);
230            addElectricalSubResults(demux_way0, 1.0);
231            addSubInstances(demux_way1, 1.0);
232            addElectricalSubResults(demux_way1, 1.0);
233
234            deserialize->addSubResult(demux_way0->getEventResult("Deserialize"), demux_way0_name, 1.0);
235            deserialize->addSubResult(demux_way1->getEventResult("Deserialize"), demux_way1_name, 1.0);
236            //-----------------------------------------------------------------
237
238        }
239        else if (bit_duplicate)
240        {
241            const String& demux_name = "DemuxTree_" + (String) deserialization_ratio + "_to_1";
242
243            DemuxTreeDeserializer* des_bit = new DemuxTreeDeserializer(demux_name, getTechModel());
244            des_bit->setParameter("InDataRate", in_data_rate);
245            des_bit->setParameter("OutDataRate", out_data_rate);
246            des_bit->setParameter("OutBits", deserialization_ratio);
247            des_bit->setParameter("BitDuplicate", "TRUE");
248            des_bit->construct();
249
250            // Create VFI and VFO nets
251            createNet("InVFI");
252            createNet("OutVFO", makeNetIndex(0, deserialization_ratio-1));
253
254            // Connect ports
255            portConnect(des_bit, "In", "InVFI");
256            portConnect(des_bit, "Out", "OutVFO");
257
258            // Do VFI and VFO
259            assignVirtualFanin("InVFI", "In");
260            for (unsigned int i = 0; i < input_bits; ++i)
261            {
262                portConnect(des_bit, "InCK", "InCK");
263                for (unsigned int j = 0; j < deserialization_ratio; ++j)
264                    assignVirtualFanout("Out", makeNetIndex(i*deserialization_ratio + j), "OutVFO", makeNetIndex(j));
265            }
266            // Add subinstances and area results
267            addSubInstances(des_bit, input_bits);
268            addElectricalSubResults(des_bit, input_bits);
269            getEventResult("Deserialize")->addSubResult(des_bit->getEventResult("Deserialize"), demux_name, input_bits);
270        }
271        else
272        {
273            //Instantiate a bunch of 1 input bit deserializers
274            for (unsigned int i = 0; i < input_bits; ++i)
275            {
276                const String& demux_name = "DemuxTree_" + (String) deserialization_ratio + "_to_1_bit" + (String) i;
277
278                DemuxTreeDeserializer* des_bit = new DemuxTreeDeserializer(demux_name, getTechModel());
279                des_bit->setParameter("InDataRate", in_data_rate);
280                des_bit->setParameter("OutDataRate", out_data_rate);
281                des_bit->setParameter("OutBits", deserialization_ratio);
282                des_bit->setParameter("BitDuplicate", "TRUE");
283                des_bit->construct();
284
285                portConnect(des_bit, "In", "In", makeNetIndex(i));
286                portConnect(des_bit, "InCK", "InCK");
287                portConnect(des_bit, "Out", "Out", makeNetIndex(i*deserialization_ratio, (i+1)*deserialization_ratio-1));
288
289                addSubInstances(des_bit, 1.0);
290                addElectricalSubResults(des_bit, 1.0);
291                getEventResult("Deserialize")->addSubResult(des_bit->getEventResult("Deserialize"), demux_name, 1.0);
292            }
293        }
294
295        return;
296    }
297
298    void DemuxTreeDeserializer::propagateTransitionInfo()
299    {
300        // Get parameters
301        bool bit_duplicate = getParameter("BitDuplicate");
302        // Get generated properties
303        unsigned int deserialization_ratio = getGenProperties()->get("DeserializationRatio");
304        unsigned int input_bits = getGenProperties()->get("InputBits");
305
306        // Calculate output transitions and activities
307        if (deserialization_ratio == 1)
308        {
309            // If no deserialization, then just propagate input transition info to output port
310            propagatePortTransitionInfo("Out", "In");
311        }
312        else if (input_bits == 1)
313        {
314            const String& des_dff_way0_name = "DesDFFWay0";
315            const String& des_dff_way1_name = "DesDFFWay1";
316            const String& des_latch_name = "DesLatch";
317            const String& ck_dff_name = "CKDFF";
318            const String& ck_inv_name = "CKINV";
319
320            // Sub-deserializer names
321            const String& demux_way0_name = "DemuxTree_way0_" + (String) deserialization_ratio + "_to_1";
322            const String& demux_way1_name = "DemuxTree_way1_" + (String) deserialization_ratio + "_to_1";
323
324            // Update transition info for deserialization registers/latches
325            ElectricalModel* des_latch = (ElectricalModel*) getSubInstance(des_latch_name);
326            propagatePortTransitionInfo(des_latch, "G", "InCK");
327            propagatePortTransitionInfo(des_latch, "D", "In");
328            des_latch->use();
329
330            ElectricalModel* des_dff_way0 = (ElectricalModel*) getSubInstance(des_dff_way0_name);
331            propagatePortTransitionInfo(des_dff_way0, "CK", "InCK");
332            propagatePortTransitionInfo(des_dff_way0, "D", des_latch, "Q");
333            des_dff_way0->use();
334
335            ElectricalModel* des_dff_way1 = (ElectricalModel*) getSubInstance(des_dff_way1_name);
336            propagatePortTransitionInfo(des_dff_way1, "CK", "InCK");
337            propagatePortTransitionInfo(des_dff_way1, "D", "In");
338            des_dff_way1->use();
339
340            // Get input transitions of input clock
341            double P01_CK = getInputPort("InCK")->getTransitionInfo().getNumberTransitions01();
342            // Update transition info for clk division DFF
343            ElectricalModel* ck_dff = (ElectricalModel*) getSubInstance(ck_dff_name);
344            propagatePortTransitionInfo(ck_dff, "CK", "InCK");
345            // Since it is a clock divider, P01 is D and Q are simply half the P01 of D and Q of
346            // the input clock
347            if (P01_CK != 0) ck_dff->getInputPort("D")->setTransitionInfo(TransitionInfo(0.0, P01_CK * 0.5, 0.0));
348            else ck_dff->getInputPort("D")->setTransitionInfo(TransitionInfo(0.5, 0.0, 0.5));
349
350            ck_dff->use();
351            // Update transition info of clk divided inverter
352            ElectricalModel* ck_inv = (ElectricalModel*) getSubInstance(ck_inv_name);
353            propagatePortTransitionInfo(ck_inv, "A", ck_dff, "Q");
354            ck_inv->use();
355
356            // Update transition info for next demux stages
357            ElectricalModel* demux_way0 = (ElectricalModel*) getSubInstance(demux_way0_name);
358            propagatePortTransitionInfo(demux_way0, "In", des_dff_way0, "Q");
359            propagatePortTransitionInfo(demux_way0, "InCK", ck_dff, "Q");
360            demux_way0->use();
361            ElectricalModel* demux_way1 = (ElectricalModel*) getSubInstance(demux_way1_name);
362            propagatePortTransitionInfo(demux_way1, "In", des_dff_way1, "Q");
363            propagatePortTransitionInfo(demux_way1, "InCK", ck_dff, "Q");
364            demux_way1->use();
365
366            propagatePortTransitionInfo("Out", demux_way0, "Out");
367        }
368        else if (bit_duplicate)
369        {
370            // Propagate transition info
371            const String& demux_name = "DemuxTree_" + (String) deserialization_ratio + "_to_1";
372            ElectricalModel* demux = (ElectricalModel*) getSubInstance(demux_name);
373            propagatePortTransitionInfo(demux, "In", "In");
374            propagatePortTransitionInfo(demux, "InCK", "InCK");
375            demux->use();
376
377            propagatePortTransitionInfo("Out", demux, "Out");
378        }
379        else
380        {
381            // Set output probability to be average that of probabilties of each output bit
382            // Update all 1 bit deserializers
383            for (unsigned int i = 0; i < input_bits; ++i)
384            {
385                const String& demux_name = "DemuxTree_" + (String) deserialization_ratio + "_to_1_bit" + (String) i;
386                ElectricalModel* demux_bit = (ElectricalModel*) getSubInstance(demux_name);
387                propagatePortTransitionInfo(demux_bit, "In", "In");
388                propagatePortTransitionInfo(demux_bit, "InCK", "InCK");
389                demux_bit->use();
390
391                propagatePortTransitionInfo("Out", demux_bit, "Out");
392            }
393        }
394
395        return;
396    }
397
398} // namespace DSENT
399
400