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