MuxTreeSerializer.cc revision 10447:a465576671d4
1#include "model/electrical/MuxTreeSerializer.h"
2
3#include <cmath>
4
5#include "model/PortInfo.h"
6#include "model/TransitionInfo.h"
7#include "model/EventInfo.h"
8#include "model/std_cells/StdCellLib.h"
9#include "model/std_cells/StdCell.h"
10#include "model/electrical/Multiplexer.h"
11#include "model/timing_graph/ElectricalNet.h"
12
13namespace DSENT
14{
15    using std::ceil;
16
17    MuxTreeSerializer::MuxTreeSerializer(const String& instance_name_, const TechModel* tech_model_)
18        : ElectricalModel(instance_name_, tech_model_)
19    {
20        initParameters();
21        initProperties();
22    }
23
24    MuxTreeSerializer::~MuxTreeSerializer()
25    {}
26
27    void MuxTreeSerializer::initParameters()
28    {
29        addParameterName("InDataRate");
30        addParameterName("OutDataRate");
31        addParameterName("InBits");              //Output width will just be input width / serialization ratio
32    }
33
34    void MuxTreeSerializer::initProperties()
35    {
36        return;
37    }
38
39    MuxTreeSerializer* MuxTreeSerializer::clone() const
40    {
41        // TODO
42        return NULL;
43    }
44
45    void MuxTreeSerializer::constructModel()
46    {
47        // Get parameters
48        double in_data_rate = getParameter("InDataRate").toDouble();
49        double out_data_rate = getParameter("OutDataRate").toDouble();
50        unsigned int in_bits = getParameter("InBits").toUInt();
51
52        // Calculate serialization ratio
53        unsigned int serialization_ratio = (unsigned int) floor(out_data_rate / in_data_rate);
54        ASSERT(serialization_ratio == out_data_rate / in_data_rate,
55            "[Error] " + getInstanceName() + " -> Cannot have non-integer serialization ratios " +
56            "(" + (String) (in_data_rate / out_data_rate) + ")!");
57
58        // Calculate output width
59        ASSERT(floor((double) in_bits / serialization_ratio) == (double) in_bits / serialization_ratio,
60            "[Error] " + getInstanceName() + " -> Input width (" + (String) in_bits + ") " +
61            "must be a multiple of the serialization ratio (" + (String) serialization_ratio + ")!");
62        unsigned int output_bits = in_bits / serialization_ratio;
63
64        // Calculate the number of multiplexer stages
65        unsigned int number_stages = (unsigned int)ceil(log2((double) serialization_ratio));
66
67        // Store calculated values
68        getGenProperties()->set("SerializationRatio", serialization_ratio);
69        getGenProperties()->set("OutputBits", output_bits);
70        getGenProperties()->set("NumberStages", number_stages);
71
72        // Create ports
73        createInputPort("In", makeNetIndex(0, in_bits-1));
74        createInputPort("OutCK");
75        createOutputPort("Out", makeNetIndex(0, output_bits-1));
76
77        //Create energy, power, and area results
78        createElectricalResults();
79        createElectricalEventResult("Serialize");
80        getEventInfo("Serialize")->setTransitionInfo("OutCK", TransitionInfo(0.0, (double) serialization_ratio / 2.0, 0.0));
81        //Set conditions during idle state
82        getEventInfo("Idle")->setStaticTransitionInfos();
83        getEventInfo("Idle")->setTransitionInfo("OutCK", TransitionInfo(0.0, (double) serialization_ratio / 2.0, 0.0));
84
85        // Mark OutCK as a false path (since timing tool will do strange stuff due to all the clock divides and stuff)
86        getNet("OutCK")->setFalsePath(true);
87
88        // Create mux-tree instance
89        if (serialization_ratio == 1)
90        {
91            // No need to do anything, hohoho
92            assign("Out", "In");
93        }
94        else
95        {
96            // Create multiplexer
97            String mux_tree_name = "MuxTree";
98            ElectricalModel* mux_tree = new Multiplexer(mux_tree_name, getTechModel());
99            mux_tree->setParameter("NumberInputs", serialization_ratio);
100            mux_tree->setParameter("NumberBits", output_bits);
101            mux_tree->setParameter("BitDuplicate", "TRUE");
102            mux_tree->construct();
103            // Create nets
104            if (number_stages > 1)
105                createNet("MuxSel_b", makeNetIndex(0, number_stages-2));
106            createNet("MuxSel", makeNetIndex(0, number_stages-1));
107            assign("MuxSel", makeNetIndex(number_stages-1), "OutCK");
108            // Create reindexed net (to help out with indexing)
109            createNet("InTmp", makeNetIndex(0, in_bits-1));
110            for (unsigned int i = 0; i < serialization_ratio; ++i)
111                for (unsigned int j = 0; j < output_bits; ++j)
112                    assign("InTmp", makeNetIndex(i*output_bits+j), "In", makeNetIndex(j*serialization_ratio+i));
113
114            // Connect ports
115            for (unsigned int i = 0; i < serialization_ratio; ++i)
116                portConnect(mux_tree, "In" + (String) i, "InTmp", makeNetIndex(i*output_bits, (i+1)*output_bits-1));
117
118            for (unsigned int i = 0; i < number_stages; ++i)
119                portConnect(mux_tree, "Sel" + (String) i, "MuxSel", makeNetIndex(i));
120            portConnect(mux_tree, "Out", "Out");
121
122            // Add subinstance and events
123            addSubInstances(mux_tree, 1.0);
124            addElectricalSubResults(mux_tree, 1.0);
125            // Add serialize event/power
126            getEventResult("Serialize")->addSubResult(mux_tree->getEventResult("Mux"), mux_tree_name, 1.0);
127
128            // Create clock dividers (assumes power of 2...), don't need divider for fastest output stage
129            for (unsigned int i = 0; i < number_stages - 1; ++i)
130            {
131                // Clk dividing registers
132                const String& clk_div_dff_name = "ClkDivDFF_" + (String) i;
133                StdCell* clk_div_dff = getTechModel()->getStdCellLib()->createStdCell("DFFQ", clk_div_dff_name);
134                clk_div_dff->construct();
135                portConnect(clk_div_dff, "D", "MuxSel_b", makeNetIndex(i));
136                portConnect(clk_div_dff, "Q", "MuxSel", makeNetIndex(i));
137                portConnect(clk_div_dff, "CK", "MuxSel", makeNetIndex(i+1));
138                addSubInstances(clk_div_dff, 1.0);
139                addElectricalSubResults(clk_div_dff, 1.0);
140
141                // Inversions
142                const String& clk_div_inv_name = "ClkDivINV_" + (String) i;
143                StdCell* clk_div_inv = getTechModel()->getStdCellLib()->createStdCell("INV", clk_div_inv_name);
144                clk_div_inv->construct();
145                portConnect(clk_div_inv, "A", "MuxSel", makeNetIndex(i));
146                portConnect(clk_div_inv, "Y", "MuxSel_b", makeNetIndex(i));
147                addSubInstances(clk_div_inv, 1.0);
148                addElectricalSubResults(clk_div_inv, 1.0);
149
150                getEventResult("Serialize")->addSubResult(clk_div_dff->getEventResult("CK"), clk_div_dff_name, 1.0);
151                getEventResult("Serialize")->addSubResult(clk_div_dff->getEventResult("DFFD"), clk_div_dff_name, 1.0);
152                getEventResult("Serialize")->addSubResult(clk_div_dff->getEventResult("DFFQ"), clk_div_dff_name, 1.0);
153                getEventResult("Serialize")->addSubResult(clk_div_inv->getEventResult("INV"), clk_div_inv_name, 1.0);
154            }
155        }
156
157        return;
158    }
159
160    void MuxTreeSerializer::propagateTransitionInfo()
161    {
162        // Get some generated properties
163        const unsigned int serialization_ratio = getGenProperties()->get("SerializationRatio");
164        const unsigned int number_stages = getGenProperties()->get("NumberStages");
165
166        // Set transition info of the mux tree and clock divide DFF
167        if (serialization_ratio == 1)
168        {
169            // If no serialization, then just propagate input transition info to output port
170            propagatePortTransitionInfo("Out", "In");
171        }
172        else
173        {
174
175            // Propagate transition probabilities to the mux tree
176            ElectricalModel* mux_tree = (ElectricalModel*) getSubInstance("MuxTree");
177            // All input ports of the mux have the same probability
178            for (unsigned int i = 0; i < serialization_ratio; ++i)
179                propagatePortTransitionInfo(mux_tree, "In" + (String) i, "In");
180            // Connect last stage of the mux
181            propagatePortTransitionInfo(mux_tree, "Sel" + (String) (number_stages - 1), "OutCK");
182            // Keep track of the last clock divider
183            ElectricalModel* last_clk_div_dff = NULL;
184            // Find P01 of OutCK
185            double last_P01_CK = getInputPort("OutCK")->getTransitionInfo().getNumberTransitions01();
186            // Start from the last stage (since it is the stage with no clock division)
187            for (unsigned int i = 0; i < number_stages - 1; ++i)
188            {
189                const String& clk_div_dff_name = "ClkDivDFF_" + (String) (number_stages - i - 2);
190                const String& clk_div_inv_name = "ClkDivINV_" + (String) (number_stages - i - 2);
191
192                ElectricalModel* clk_div_dff = (ElectricalModel*) getSubInstance(clk_div_dff_name);
193                if (last_clk_div_dff == NULL)
194                    propagatePortTransitionInfo(clk_div_dff, "CK", "OutCK");
195                else
196                    propagatePortTransitionInfo(clk_div_dff, "CK", last_clk_div_dff, "Q");
197                // Since it is a clock divider, P01 is D and Q are simply half the P01 of D and Q of
198                // the input clock
199                if (last_P01_CK != 0) clk_div_dff->getInputPort("D")->setTransitionInfo(TransitionInfo(0.0, last_P01_CK * 0.5, 0.0));
200                else clk_div_dff->getInputPort("D")->setTransitionInfo(TransitionInfo(0.5, 0.0, 0.5));
201
202                clk_div_dff->use();
203
204                ElectricalModel* clk_div_inv = (ElectricalModel*) getSubInstance(clk_div_inv_name);
205                propagatePortTransitionInfo(clk_div_inv, "A", clk_div_dff, "Q");
206                clk_div_inv->use();
207
208                // Connect select port of the mux
209                propagatePortTransitionInfo(mux_tree, "Sel" + (String) (number_stages - i - 2), clk_div_dff, "Q");
210
211                // Clk divide by 2;
212                last_P01_CK = last_P01_CK * 0.5;
213                // Remember the last clk div DFF
214                last_clk_div_dff = clk_div_dff;
215            }
216
217            mux_tree->use();
218            // Set output transition info to be the output transition info of the mux tree
219            propagatePortTransitionInfo("Out", mux_tree, "Out");
220        }
221
222        return;
223    }
224
225} // namespace DSENT
226
227