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