1 /* Copyright (c) 2012 Massachusetts Institute of Technology
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:
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
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
22 #include "model/electrical/MuxTreeSerializer.h"
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"
38 MuxTreeSerializer::MuxTreeSerializer(const String
& instance_name_
, const TechModel
* tech_model_
)
39 : ElectricalModel(instance_name_
, tech_model_
)
45 MuxTreeSerializer::~MuxTreeSerializer()
48 void MuxTreeSerializer::initParameters()
50 addParameterName("InDataRate");
51 addParameterName("OutDataRate");
52 addParameterName("InBits"); //Output width will just be input width / serialization ratio
55 void MuxTreeSerializer::initProperties()
60 MuxTreeSerializer
* MuxTreeSerializer::clone() const
66 void MuxTreeSerializer::constructModel()
69 double in_data_rate
= getParameter("InDataRate").toDouble();
70 double out_data_rate
= getParameter("OutDataRate").toDouble();
71 unsigned int in_bits
= getParameter("InBits").toUInt();
73 // Calculate serialization ratio
74 unsigned int serialization_ratio
= (unsigned int) floor(out_data_rate
/ in_data_rate
);
75 ASSERT(serialization_ratio
== out_data_rate
/ in_data_rate
,
76 "[Error] " + getInstanceName() + " -> Cannot have non-integer serialization ratios " +
77 "(" + (String
) (in_data_rate
/ out_data_rate
) + ")!");
79 // Calculate output width
80 ASSERT(floor((double) in_bits
/ serialization_ratio
) == (double) in_bits
/ serialization_ratio
,
81 "[Error] " + getInstanceName() + " -> Input width (" + (String
) in_bits
+ ") " +
82 "must be a multiple of the serialization ratio (" + (String
) serialization_ratio
+ ")!");
83 unsigned int output_bits
= in_bits
/ serialization_ratio
;
85 // Calculate the number of multiplexer stages
86 unsigned int number_stages
= (unsigned int)ceil(log2((double) serialization_ratio
));
88 // Store calculated values
89 getGenProperties()->set("SerializationRatio", serialization_ratio
);
90 getGenProperties()->set("OutputBits", output_bits
);
91 getGenProperties()->set("NumberStages", number_stages
);
94 createInputPort("In", makeNetIndex(0, in_bits
-1));
95 createInputPort("OutCK");
96 createOutputPort("Out", makeNetIndex(0, output_bits
-1));
98 //Create energy, power, and area results
99 createElectricalResults();
100 createElectricalEventResult("Serialize");
101 getEventInfo("Serialize")->setTransitionInfo("OutCK", TransitionInfo(0.0, (double) serialization_ratio
/ 2.0, 0.0));
102 //Set conditions during idle state
103 getEventInfo("Idle")->setStaticTransitionInfos();
104 getEventInfo("Idle")->setTransitionInfo("OutCK", TransitionInfo(0.0, (double) serialization_ratio
/ 2.0, 0.0));
106 // Mark OutCK as a false path (since timing tool will do strange stuff due to all the clock divides and stuff)
107 getNet("OutCK")->setFalsePath(true);
109 // Create mux-tree instance
110 if (serialization_ratio
== 1)
112 // No need to do anything, hohoho
117 // Create multiplexer
118 String mux_tree_name
= "MuxTree";
119 ElectricalModel
* mux_tree
= new Multiplexer(mux_tree_name
, getTechModel());
120 mux_tree
->setParameter("NumberInputs", serialization_ratio
);
121 mux_tree
->setParameter("NumberBits", output_bits
);
122 mux_tree
->setParameter("BitDuplicate", "TRUE");
123 mux_tree
->construct();
125 if (number_stages
> 1)
126 createNet("MuxSel_b", makeNetIndex(0, number_stages
-2));
127 createNet("MuxSel", makeNetIndex(0, number_stages
-1));
128 assign("MuxSel", makeNetIndex(number_stages
-1), "OutCK");
129 // Create reindexed net (to help out with indexing)
130 createNet("InTmp", makeNetIndex(0, in_bits
-1));
131 for (unsigned int i
= 0; i
< serialization_ratio
; ++i
)
132 for (unsigned int j
= 0; j
< output_bits
; ++j
)
133 assign("InTmp", makeNetIndex(i
*output_bits
+j
), "In", makeNetIndex(j
*serialization_ratio
+i
));
136 for (unsigned int i
= 0; i
< serialization_ratio
; ++i
)
137 portConnect(mux_tree
, "In" + (String
) i
, "InTmp", makeNetIndex(i
*output_bits
, (i
+1)*output_bits
-1));
139 for (unsigned int i
= 0; i
< number_stages
; ++i
)
140 portConnect(mux_tree
, "Sel" + (String
) i
, "MuxSel", makeNetIndex(i
));
141 portConnect(mux_tree
, "Out", "Out");
143 // Add subinstance and events
144 addSubInstances(mux_tree
, 1.0);
145 addElectricalSubResults(mux_tree
, 1.0);
146 // Add serialize event/power
147 getEventResult("Serialize")->addSubResult(mux_tree
->getEventResult("Mux"), mux_tree_name
, 1.0);
149 // Create clock dividers (assumes power of 2...), don't need divider for fastest output stage
150 for (unsigned int i
= 0; i
< number_stages
- 1; ++i
)
152 // Clk dividing registers
153 const String
& clk_div_dff_name
= "ClkDivDFF_" + (String
) i
;
154 StdCell
* clk_div_dff
= getTechModel()->getStdCellLib()->createStdCell("DFFQ", clk_div_dff_name
);
155 clk_div_dff
->construct();
156 portConnect(clk_div_dff
, "D", "MuxSel_b", makeNetIndex(i
));
157 portConnect(clk_div_dff
, "Q", "MuxSel", makeNetIndex(i
));
158 portConnect(clk_div_dff
, "CK", "MuxSel", makeNetIndex(i
+1));
159 addSubInstances(clk_div_dff
, 1.0);
160 addElectricalSubResults(clk_div_dff
, 1.0);
163 const String
& clk_div_inv_name
= "ClkDivINV_" + (String
) i
;
164 StdCell
* clk_div_inv
= getTechModel()->getStdCellLib()->createStdCell("INV", clk_div_inv_name
);
165 clk_div_inv
->construct();
166 portConnect(clk_div_inv
, "A", "MuxSel", makeNetIndex(i
));
167 portConnect(clk_div_inv
, "Y", "MuxSel_b", makeNetIndex(i
));
168 addSubInstances(clk_div_inv
, 1.0);
169 addElectricalSubResults(clk_div_inv
, 1.0);
171 getEventResult("Serialize")->addSubResult(clk_div_dff
->getEventResult("CK"), clk_div_dff_name
, 1.0);
172 getEventResult("Serialize")->addSubResult(clk_div_dff
->getEventResult("DFFD"), clk_div_dff_name
, 1.0);
173 getEventResult("Serialize")->addSubResult(clk_div_dff
->getEventResult("DFFQ"), clk_div_dff_name
, 1.0);
174 getEventResult("Serialize")->addSubResult(clk_div_inv
->getEventResult("INV"), clk_div_inv_name
, 1.0);
181 void MuxTreeSerializer::propagateTransitionInfo()
183 // Get some generated properties
184 const unsigned int serialization_ratio
= getGenProperties()->get("SerializationRatio");
185 const unsigned int number_stages
= getGenProperties()->get("NumberStages");
187 // Set transition info of the mux tree and clock divide DFF
188 if (serialization_ratio
== 1)
190 // If no serialization, then just propagate input transition info to output port
191 propagatePortTransitionInfo("Out", "In");
196 // Propagate transition probabilities to the mux tree
197 ElectricalModel
* mux_tree
= (ElectricalModel
*) getSubInstance("MuxTree");
198 // All input ports of the mux have the same probability
199 for (unsigned int i
= 0; i
< serialization_ratio
; ++i
)
200 propagatePortTransitionInfo(mux_tree
, "In" + (String
) i
, "In");
201 // Connect last stage of the mux
202 propagatePortTransitionInfo(mux_tree
, "Sel" + (String
) (number_stages
- 1), "OutCK");
203 // Keep track of the last clock divider
204 ElectricalModel
* last_clk_div_dff
= NULL
;
206 double last_P01_CK
= getInputPort("OutCK")->getTransitionInfo().getNumberTransitions01();
207 // Start from the last stage (since it is the stage with no clock division)
208 for (unsigned int i
= 0; i
< number_stages
- 1; ++i
)
210 const String
& clk_div_dff_name
= "ClkDivDFF_" + (String
) (number_stages
- i
- 2);
211 const String
& clk_div_inv_name
= "ClkDivINV_" + (String
) (number_stages
- i
- 2);
213 ElectricalModel
* clk_div_dff
= (ElectricalModel
*) getSubInstance(clk_div_dff_name
);
214 if (last_clk_div_dff
== NULL
)
215 propagatePortTransitionInfo(clk_div_dff
, "CK", "OutCK");
217 propagatePortTransitionInfo(clk_div_dff
, "CK", last_clk_div_dff
, "Q");
218 // Since it is a clock divider, P01 is D and Q are simply half the P01 of D and Q of
220 if (last_P01_CK
!= 0) clk_div_dff
->getInputPort("D")->setTransitionInfo(TransitionInfo(0.0, last_P01_CK
* 0.5, 0.0));
221 else clk_div_dff
->getInputPort("D")->setTransitionInfo(TransitionInfo(0.5, 0.0, 0.5));
225 ElectricalModel
* clk_div_inv
= (ElectricalModel
*) getSubInstance(clk_div_inv_name
);
226 propagatePortTransitionInfo(clk_div_inv
, "A", clk_div_dff
, "Q");
229 // Connect select port of the mux
230 propagatePortTransitionInfo(mux_tree
, "Sel" + (String
) (number_stages
- i
- 2), clk_div_dff
, "Q");
233 last_P01_CK
= last_P01_CK
* 0.5;
234 // Remember the last clk div DFF
235 last_clk_div_dff
= clk_div_dff
;
239 // Set output transition info to be the output transition info of the mux tree
240 propagatePortTransitionInfo("Out", mux_tree
, "Out");