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 |
127 // For all parameters, grab values from the config file |
128 for(vector 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 |
145 // For all properties, grab values from the config file |
146 for(vector 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 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 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 } --- 20 unchanged lines hidden (view full) --- 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 |