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 34namespace 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 248