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 <cstdlib> 23#include <iostream> 24 25#include "DSENT.h" 26#include "model/std_cells/StdCellLib.h" 27 28using namespace std; 29 30namespace DSENT 31{ 32 static void performTimingOpt(const map<String, String> ¶ms, 33 Model *ms_model) 34 { 35 // Get the frequency it is optimizing to 36 double freq = params.at("Frequency").toDouble(); 37 38 // Get all the starting net names 39 const vector<String>& start_net_names = 40 params.at("TimingOptimization->StartNetNames").split("[,]"); 41 42 ASSERT((start_net_names.size() > 0), 43 "[Error] Expecting net names in TimingOptimization->StartNetNames"); 44 45 if(start_net_names[0] == "*") 46 { 47 // Optimize from all input ports 48 ElectricalModel* electrical_model = (ElectricalModel*)ms_model; 49 50 ElectricalTimingOptimizer timing_optimizer( 51 "Optimizer", electrical_model->getTechModel()); 52 timing_optimizer.setModel(electrical_model); 53 timing_optimizer.construct(); 54 timing_optimizer.update(); 55 56 ElectricalTimingTree timing_tree( 57 timing_optimizer.getInstanceName(), &timing_optimizer); 58 59 const Map<PortInfo*>* input_ports = timing_optimizer.getInputs(); 60 Map<PortInfo*>::ConstIterator it_begin = input_ports->begin(); 61 Map<PortInfo*>::ConstIterator it_end = input_ports->end(); 62 Map<PortInfo*>::ConstIterator it; 63 for(it = it_begin; it != it_end; ++it) 64 { 65 const String& net_name = it->first; 66 Log::printLine("Optimizing net: " + net_name); 67 timing_tree.performTimingOpt( 68 timing_optimizer.getNet(net_name, makeNetIndex(0)), 1.0 / freq); 69 } 70 71 // Loop the second times 72 for(it = it_begin; it != it_end; ++it) 73 { 74 const String& net_name = it->first; 75 Log::printLine("Optimizing net: " + net_name); 76 } 77 } 78 else 79 { 80 // TODO : parse the net name so that we could do hierarchical optimization 81 // Currently we can only optimize timing at the top level 82 ElectricalModel* electrical_model = (ElectricalModel*)ms_model; 83 ElectricalTimingTree timing_tree( 84 electrical_model->getInstanceName(), electrical_model); 85 86 for(unsigned int i = 0; i < start_net_names.size(); ++i) 87 { 88 const String& net_name = start_net_names[i]; 89 timing_tree.performTimingOpt( 90 electrical_model->getNet(net_name), 1.0 / freq); 91 } 92 } 93 } 94 95 static void reportTiming(const map<String, String> ¶ms, Model *ms_model) 96 { 97 // Get all the starting net names 98 const vector<String>& start_net_names = 99 params.at("ReportTiming->StartNetNames").split("[,]"); 100 101 ElectricalModel* electrical_model = (ElectricalModel*)ms_model; 102 ElectricalTimingTree timing_tree( 103 electrical_model->getInstanceName(), electrical_model); 104 105 cout << "Report timing:" << endl; 106 cout << "==============" << endl; 107 for(unsigned int i = 0; i < start_net_names.size(); ++i) 108 { 109 const String& net_name = start_net_names[i]; 110 double timing = timing_tree.performCritPathExtract(electrical_model->getNet(net_name)); 111 cout << net_name << " = " << timing << endl; 112 } 113 cout << "==============" << endl; 114 } 115 116 static Model *buildModel(const map<String, String> ¶ms, 117 TechModel *tech_model) 118 { 119 // Create the model specified 120 const String& model_name = params.at("ModelName"); 121 Model *ms_model = ModelGen::createModel(model_name, model_name, 122 tech_model); 123 124 // Construct the model 125 // Read all parameters the model requires 126 const vector<String>* parameter_names = ms_model->getParameterNames(); 127 // For all parameters, grab values from the config file 128 for(vector<String>::const_iterator it = parameter_names->begin(); 129 it != parameter_names->end(); ++it) 130 { 131 const String& parameter_name = *it; 132 // If it exists in the config file, set the parameter 133 if(params.count(parameter_name) > 0) 134 { 135 ms_model->setParameter(parameter_name, 136 params.at(parameter_name)); 137 } 138 } 139 140 ms_model->construct(); 141 142 // Update the model 143 // Read all properties the model requires 144 const vector<String>* property_names = ms_model->getPropertyNames(); 145 // For all properties, grab values from the config file 146 for(vector<String>::const_iterator it = property_names->begin(); 147 it != property_names->end(); ++it) 148 { 149 const String& property_name = *it; 150 // If it exists in the config file, set the parameter 151 if(params.count(property_name) > 0) 152 { 153 ms_model->setProperty(property_name, 154 params.at(property_name)); 155 } 156 } 157 ms_model->update(); 158 159 // Evaluate the model 160 // Perform timing optimization if needed 161 if(params.find("IsPerformTimingOptimization") != params.end() && 162 params.at("IsPerformTimingOptimization").toBool()) 163 { 164 performTimingOpt(params, ms_model); 165 } 166 ms_model->evaluate(); 167 168 // Report timing if needed 169 if(params.count("IsReportTiming") > 0 && 170 params.at("IsReportTiming") != "false") 171 { 172 reportTiming(params, ms_model); 173 } 174 175 return ms_model; 176 } 177 178 static const void* processQuery(const String& query_str_, 179 Model *ms_model, bool is_print_) 180 { 181 vector<String> type_split = query_str_.splitByString(Model::TYPE_SEPARATOR); 182 ASSERT((type_split.size() == 2), "[Error] Invalid query format: " + query_str_); 183 String query_type = type_split[0]; 184 185 vector<String> detail_split = 186 type_split[1].splitByString(Model::DETAIL_SEPARATOR); 187 188 ASSERT((detail_split.size() == 2), "[Error] Invalid query format: " + query_str_); 189 String query_detail = detail_split[1]; 190 191 vector<String> subfield_split = 192 detail_split[0].splitByString(Model::SUBFIELD_SEPARATOR); 193 194 ASSERT(((subfield_split.size() == 2) || (subfield_split.size() == 1)), 195 "[Error] Invalid query format: " + query_str_); 196 197 String query_hier = subfield_split[0]; 198 String query_subfield = ""; 199 200 if(subfield_split.size() == 2) 201 { 202 query_subfield = subfield_split[1]; 203 } 204 205 const void* query_result = ms_model->parseQuery(query_type, query_hier, 206 query_subfield); 207 if(query_type == "Property") 208 { 209 const PropertyMap* property = (const PropertyMap*)query_result; 210 if(is_print_) 211 { 212 cout << *property; 213 } 214 } 215 else if(query_type == "Parameter") 216 { 217 const ParameterMap* parameter = (const ParameterMap*)query_result; 218 if(is_print_) 219 { 220 cout << *parameter; 221 } 222 } 223 else if(query_type.contain("Hier")) 224 { 225 const Model* model = (const Model*)query_result; 226 if(is_print_) 227 { 228 model->printHierarchy(query_type, query_subfield, "", query_detail, cout); 229 } 230 } 231 else 232 { 233 const Result* result = (const Result*)query_result; 234 if(is_print_) 235 { 236 result->print(query_type + Model::TYPE_SEPARATOR + query_hier + 237 Model::SUBFIELD_SEPARATOR + query_subfield, query_detail, cout); 238 } 239 } 240 return query_result; 241 } 242 243 void processQuery(const vector<String> &queries, 244 Model *ms_model, vector<String> &outputs) 245 { 246 for(unsigned int i = 0; i < queries.size(); ++i) 247 { 248 const String& curr_query = queries[i]; 249 processQuery(curr_query, ms_model, true); 250 251 } 252 } 253 254 static TechModel* constructTechModel(const map<String, String>& params) 255 { 256 // Allocate static TechModel instance 257 const String& electrical_tech_model_filename = 258 params.at("ElectricalTechModelFilename"); 259 260 TechModel* tech_model = new TechModel(); 261 tech_model->readFile(electrical_tech_model_filename); 262 263 if (params.count("PhotonicTechModelFilename") != 0) { 264 const String& photonic_tech_model_filename = 265 params.at("PhotonicTechModelFilename"); 266 tech_model->readFile(photonic_tech_model_filename); 267 } 268 269 // Allocate static StdCellLib instance 270 StdCellLib* std_cell_lib = new StdCellLib(tech_model); 271 272 // Set the StdCellLib pointer in static TechModel instance 273 tech_model->setStdCellLib(std_cell_lib); 274 return tech_model; 275 } 276 277 Model *initialize(const char *config_file_name, map<String, String> &config) 278 { 279 // Init the log file 280 Log::allocate("/tmp/dsent.log"); 281 282 // Init the config file 283 LibUtil::readFile(config_file_name, config); 284 285 // Overwrite the technology file 286 TechModel *tech_model = constructTechModel(config); 287 288 // Build the specified model in the config file 289 return buildModel(config, tech_model); 290 } 291 292 void finalize(map<String, String> &config, Model *ms_model) 293 { 294 // Delete the model 295 delete ms_model; 296 297 // Discard all the (key, value) pairs. 298 config.clear(); 299 300 // Release the log file 301 Log::release(); 302 } 303 304 void run(const map<String, String> ¶ms, Model *ms_model, 305 map<string, double> &outputs) 306 { 307 // Process the specified queries 308 const auto &it = params.find("EvaluateString"); 309 if(it == params.end()) { 310 return; 311 } 312 313 String eval_str = it->second; 314 315 if (eval_str == "") { 316 return; 317 } 318 319 DSENTCalculator calc; 320 calc.evaluateString(eval_str, params, ms_model, outputs); 321 } 322 323 DSENTCalculator::DSENTCalculator() {} 324 325 DSENTCalculator::~DSENTCalculator() {} 326 327 double DSENTCalculator::getEnvVar(const String& var_name_, 328 const map<String, String> &config, 329 Model *ms_model) const 330 { 331 if (m_var_.keyExist(var_name_)) { 332 return m_var_.get(var_name_); 333 } else if (config.count(var_name_) > 0) { 334 return config.at(var_name_); 335 } else { 336 // Wish there was a way to not have to pass in a stream if we aren't 337 // doing anything with it 338 const Result* result = (const Result*)DSENT::processQuery( 339 var_name_ + "@0", ms_model, false); 340 return result->calculateSum(); 341 } 342 } 343} // namespace DSENT 344