| /* Copyright (c) 2012 Massachusetts Institute of Technology | |
| * | |
| * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| * of this software and associated documentation files (the "Software"), to deal | |
| * in the Software without restriction, including without limitation the rights | |
| * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| * copies of the Software, and to permit persons to whom the Software is | |
| * furnished to do so, subject to the following conditions: | |
| * | |
| * The above copyright notice and this permission notice shall be included in | |
| * all copies or substantial portions of the Software. | |
| * | |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| * THE SOFTWARE. | |
| */ | |
| #include <cstdlib> | |
| #include <iostream> | |
| #include "DSENT.h" | |
| #include "model/std_cells/StdCellLib.h" | |
| using namespace std; | |
| namespace DSENT | |
| { | |
| static void performTimingOpt(const map<String, String> ¶ms, | |
| Model *ms_model) | |
| { | |
| // Get the frequency it is optimizing to | |
| double freq = params.at("Frequency").toDouble(); | |
| // Get all the starting net names | |
| const vector<String>& start_net_names = | |
| params.at("TimingOptimization->StartNetNames").split("[,]"); | |
| ASSERT((start_net_names.size() > 0), | |
| "[Error] Expecting net names in TimingOptimization->StartNetNames"); | |
| if(start_net_names[0] == "*") | |
| { | |
| // Optimize from all input ports | |
| ElectricalModel* electrical_model = (ElectricalModel*)ms_model; | |
| ElectricalTimingOptimizer timing_optimizer( | |
| "Optimizer", electrical_model->getTechModel()); | |
| timing_optimizer.setModel(electrical_model); | |
| timing_optimizer.construct(); | |
| timing_optimizer.update(); | |
| ElectricalTimingTree timing_tree( | |
| timing_optimizer.getInstanceName(), &timing_optimizer); | |
| const Map<PortInfo*>* input_ports = timing_optimizer.getInputs(); | |
| Map<PortInfo*>::ConstIterator it_begin = input_ports->begin(); | |
| Map<PortInfo*>::ConstIterator it_end = input_ports->end(); | |
| Map<PortInfo*>::ConstIterator it; | |
| for(it = it_begin; it != it_end; ++it) | |
| { | |
| const String& net_name = it->first; | |
| Log::printLine("Optimizing net: " + net_name); | |
| timing_tree.performTimingOpt( | |
| timing_optimizer.getNet(net_name, makeNetIndex(0)), 1.0 / freq); | |
| } | |
| // Loop the second times | |
| for(it = it_begin; it != it_end; ++it) | |
| { | |
| const String& net_name = it->first; | |
| Log::printLine("Optimizing net: " + net_name); | |
| } | |
| } | |
| else | |
| { | |
| // TODO : parse the net name so that we could do hierarchical optimization | |
| // Currently we can only optimize timing at the top level | |
| ElectricalModel* electrical_model = (ElectricalModel*)ms_model; | |
| ElectricalTimingTree timing_tree( | |
| electrical_model->getInstanceName(), electrical_model); | |
| for(unsigned int i = 0; i < start_net_names.size(); ++i) | |
| { | |
| const String& net_name = start_net_names[i]; | |
| timing_tree.performTimingOpt( | |
| electrical_model->getNet(net_name), 1.0 / freq); | |
| } | |
| } | |
| } | |
| static void reportTiming(const map<String, String> ¶ms, Model *ms_model) | |
| { | |
| // Get all the starting net names | |
| const vector<String>& start_net_names = | |
| params.at("ReportTiming->StartNetNames").split("[,]"); | |
| ElectricalModel* electrical_model = (ElectricalModel*)ms_model; | |
| ElectricalTimingTree timing_tree( | |
| electrical_model->getInstanceName(), electrical_model); | |
| cout << "Report timing:" << endl; | |
| cout << "==============" << endl; | |
| for(unsigned int i = 0; i < start_net_names.size(); ++i) | |
| { | |
| const String& net_name = start_net_names[i]; | |
| double timing = timing_tree.performCritPathExtract(electrical_model->getNet(net_name)); | |
| cout << net_name << " = " << timing << endl; | |
| } | |
| cout << "==============" << endl; | |
| } | |
| static Model *buildModel(const map<String, String> ¶ms, | |
| TechModel *tech_model) | |
| { | |
| // Create the model specified | |
| const String& model_name = params.at("ModelName"); | |
| Model *ms_model = ModelGen::createModel(model_name, model_name, | |
| tech_model); | |
| // Construct the model | |
| // Read all parameters the model requires | |
| const vector<String>* parameter_names = ms_model->getParameterNames(); | |
| // For all parameters, grab values from the config file | |
| for(vector<String>::const_iterator it = parameter_names->begin(); | |
| it != parameter_names->end(); ++it) | |
| { | |
| const String& parameter_name = *it; | |
| // If it exists in the config file, set the parameter | |
| if(params.count(parameter_name) > 0) | |
| { | |
| ms_model->setParameter(parameter_name, | |
| params.at(parameter_name)); | |
| } | |
| } | |
| ms_model->construct(); | |
| // Update the model | |
| // Read all properties the model requires | |
| const vector<String>* property_names = ms_model->getPropertyNames(); | |
| // For all properties, grab values from the config file | |
| for(vector<String>::const_iterator it = property_names->begin(); | |
| it != property_names->end(); ++it) | |
| { | |
| const String& property_name = *it; | |
| // If it exists in the config file, set the parameter | |
| if(params.count(property_name) > 0) | |
| { | |
| ms_model->setProperty(property_name, | |
| params.at(property_name)); | |
| } | |
| } | |
| ms_model->update(); | |
| // Evaluate the model | |
| // Perform timing optimization if needed | |
| if(params.find("IsPerformTimingOptimization") != params.end() && | |
| params.at("IsPerformTimingOptimization").toBool()) | |
| { | |
| performTimingOpt(params, ms_model); | |
| } | |
| ms_model->evaluate(); | |
| // Report timing if needed | |
| if(params.count("IsReportTiming") > 0 && | |
| params.at("IsReportTiming") != "false") | |
| { | |
| reportTiming(params, ms_model); | |
| } | |
| return ms_model; | |
| } | |
| static const void* processQuery(const String& query_str_, | |
| Model *ms_model, bool is_print_) | |
| { | |
| vector<String> type_split = query_str_.splitByString(Model::TYPE_SEPARATOR); | |
| ASSERT((type_split.size() == 2), "[Error] Invalid query format: " + query_str_); | |
| String query_type = type_split[0]; | |
| vector<String> detail_split = | |
| type_split[1].splitByString(Model::DETAIL_SEPARATOR); | |
| ASSERT((detail_split.size() == 2), "[Error] Invalid query format: " + query_str_); | |
| String query_detail = detail_split[1]; | |
| vector<String> subfield_split = | |
| detail_split[0].splitByString(Model::SUBFIELD_SEPARATOR); | |
| ASSERT(((subfield_split.size() == 2) || (subfield_split.size() == 1)), | |
| "[Error] Invalid query format: " + query_str_); | |
| String query_hier = subfield_split[0]; | |
| String query_subfield = ""; | |
| if(subfield_split.size() == 2) | |
| { | |
| query_subfield = subfield_split[1]; | |
| } | |
| const void* query_result = ms_model->parseQuery(query_type, query_hier, | |
| query_subfield); | |
| if(query_type == "Property") | |
| { | |
| const PropertyMap* property = (const PropertyMap*)query_result; | |
| if(is_print_) | |
| { | |
| cout << *property; | |
| } | |
| } | |
| else if(query_type == "Parameter") | |
| { | |
| const ParameterMap* parameter = (const ParameterMap*)query_result; | |
| if(is_print_) | |
| { | |
| cout << *parameter; | |
| } | |
| } | |
| else if(query_type.contain("Hier")) | |
| { | |
| const Model* model = (const Model*)query_result; | |
| if(is_print_) | |
| { | |
| model->printHierarchy(query_type, query_subfield, "", query_detail, cout); | |
| } | |
| } | |
| else | |
| { | |
| const Result* result = (const Result*)query_result; | |
| if(is_print_) | |
| { | |
| result->print(query_type + Model::TYPE_SEPARATOR + query_hier + | |
| Model::SUBFIELD_SEPARATOR + query_subfield, query_detail, cout); | |
| } | |
| } | |
| return query_result; | |
| } | |
| void processQuery(const vector<String> &queries, | |
| Model *ms_model, vector<String> &outputs) | |
| { | |
| for(unsigned int i = 0; i < queries.size(); ++i) | |
| { | |
| const String& curr_query = queries[i]; | |
| processQuery(curr_query, ms_model, true); | |
| } | |
| } | |
| static TechModel* constructTechModel(const map<String, String>& params) | |
| { | |
| // Allocate static TechModel instance | |
| const String& electrical_tech_model_filename = | |
| params.at("ElectricalTechModelFilename"); | |
| TechModel* tech_model = new TechModel(); | |
| tech_model->readFile(electrical_tech_model_filename); | |
| if (params.count("PhotonicTechModelFilename") != 0) { | |
| const String& photonic_tech_model_filename = | |
| params.at("PhotonicTechModelFilename"); | |
| tech_model->readFile(photonic_tech_model_filename); | |
| } | |
| // Allocate static StdCellLib instance | |
| StdCellLib* std_cell_lib = new StdCellLib(tech_model); | |
| // Set the StdCellLib pointer in static TechModel instance | |
| tech_model->setStdCellLib(std_cell_lib); | |
| return tech_model; | |
| } | |
| Model *initialize(const char *config_file_name, map<String, String> &config) | |
| { | |
| // Init the log file | |
| Log::allocate("/tmp/dsent.log"); | |
| // Init the config file | |
| LibUtil::readFile(config_file_name, config); | |
| // Overwrite the technology file | |
| TechModel *tech_model = constructTechModel(config); | |
| // Build the specified model in the config file | |
| return buildModel(config, tech_model); | |
| } | |
| void finalize(map<String, String> &config, Model *ms_model) | |
| { | |
| // Delete the model | |
| delete ms_model; | |
| // Discard all the (key, value) pairs. | |
| config.clear(); | |
| // Release the log file | |
| Log::release(); | |
| } | |
| void run(const map<String, String> ¶ms, Model *ms_model, | |
| map<string, double> &outputs) | |
| { | |
| // Process the specified queries | |
| const auto &it = params.find("EvaluateString"); | |
| if(it == params.end()) { | |
| return; | |
| } | |
| String eval_str = it->second; | |
| if (eval_str == "") { | |
| return; | |
| } | |
| DSENTCalculator calc; | |
| calc.evaluateString(eval_str, params, ms_model, outputs); | |
| } | |
| DSENTCalculator::DSENTCalculator() {} | |
| DSENTCalculator::~DSENTCalculator() {} | |
| double DSENTCalculator::getEnvVar(const String& var_name_, | |
| const map<String, String> &config, | |
| Model *ms_model) const | |
| { | |
| if (m_var_.keyExist(var_name_)) { | |
| return m_var_.get(var_name_); | |
| } else if (config.count(var_name_) > 0) { | |
| return config.at(var_name_); | |
| } else { | |
| // Wish there was a way to not have to pass in a stream if we aren't | |
| // doing anything with it | |
| const Result* result = (const Result*)DSENT::processQuery( | |
| var_name_ + "@0", ms_model, false); | |
| return result->calculateSum(); | |
| } | |
| } | |
| } // namespace DSENT |