sim, kvm: make KvmVM a System parameter
[gem5.git] / ext / dsent / model / electrical / MuxTreeSerializer.cc
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/MuxTreeSerializer.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
34 namespace DSENT
35 {
36 using std::ceil;
37
38 MuxTreeSerializer::MuxTreeSerializer(const String& instance_name_, const TechModel* tech_model_)
39 : ElectricalModel(instance_name_, tech_model_)
40 {
41 initParameters();
42 initProperties();
43 }
44
45 MuxTreeSerializer::~MuxTreeSerializer()
46 {}
47
48 void MuxTreeSerializer::initParameters()
49 {
50 addParameterName("InDataRate");
51 addParameterName("OutDataRate");
52 addParameterName("InBits"); //Output width will just be input width / serialization ratio
53 }
54
55 void MuxTreeSerializer::initProperties()
56 {
57 return;
58 }
59
60 MuxTreeSerializer* MuxTreeSerializer::clone() const
61 {
62 // TODO
63 return NULL;
64 }
65
66 void MuxTreeSerializer::constructModel()
67 {
68 // Get parameters
69 double in_data_rate = getParameter("InDataRate").toDouble();
70 double out_data_rate = getParameter("OutDataRate").toDouble();
71 unsigned int in_bits = getParameter("InBits").toUInt();
72
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) + ")!");
78
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;
84
85 // Calculate the number of multiplexer stages
86 unsigned int number_stages = (unsigned int)ceil(log2((double) serialization_ratio));
87
88 // Store calculated values
89 getGenProperties()->set("SerializationRatio", serialization_ratio);
90 getGenProperties()->set("OutputBits", output_bits);
91 getGenProperties()->set("NumberStages", number_stages);
92
93 // Create ports
94 createInputPort("In", makeNetIndex(0, in_bits-1));
95 createInputPort("OutCK");
96 createOutputPort("Out", makeNetIndex(0, output_bits-1));
97
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));
105
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);
108
109 // Create mux-tree instance
110 if (serialization_ratio == 1)
111 {
112 // No need to do anything, hohoho
113 assign("Out", "In");
114 }
115 else
116 {
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();
124 // Create nets
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));
134
135 // Connect ports
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));
138
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");
142
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);
148
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)
151 {
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);
161
162 // Inversions
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);
170
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);
175 }
176 }
177
178 return;
179 }
180
181 void MuxTreeSerializer::propagateTransitionInfo()
182 {
183 // Get some generated properties
184 const unsigned int serialization_ratio = getGenProperties()->get("SerializationRatio");
185 const unsigned int number_stages = getGenProperties()->get("NumberStages");
186
187 // Set transition info of the mux tree and clock divide DFF
188 if (serialization_ratio == 1)
189 {
190 // If no serialization, then just propagate input transition info to output port
191 propagatePortTransitionInfo("Out", "In");
192 }
193 else
194 {
195
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;
205 // Find P01 of OutCK
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)
209 {
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);
212
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");
216 else
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
219 // the input clock
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));
222
223 clk_div_dff->use();
224
225 ElectricalModel* clk_div_inv = (ElectricalModel*) getSubInstance(clk_div_inv_name);
226 propagatePortTransitionInfo(clk_div_inv, "A", clk_div_dff, "Q");
227 clk_div_inv->use();
228
229 // Connect select port of the mux
230 propagatePortTransitionInfo(mux_tree, "Sel" + (String) (number_stages - i - 2), clk_div_dff, "Q");
231
232 // Clk divide by 2;
233 last_P01_CK = last_P01_CK * 0.5;
234 // Remember the last clk div DFF
235 last_clk_div_dff = clk_div_dff;
236 }
237
238 mux_tree->use();
239 // Set output transition info to be the output transition info of the mux tree
240 propagatePortTransitionInfo("Out", mux_tree, "Out");
241 }
242
243 return;
244 }
245
246 } // namespace DSENT
247