2014-10-11 23:16:00 +02:00
|
|
|
/* 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.
|
|
|
|
*/
|
2014-10-11 22:02:23 +02:00
|
|
|
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <iostream>
|
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
#include "DSENT.h"
|
|
|
|
#include "model/std_cells/StdCellLib.h"
|
2014-10-11 22:02:23 +02:00
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
using namespace std;
|
2014-10-11 22:02:23 +02:00
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
namespace DSENT
|
|
|
|
{
|
|
|
|
static void performTimingOpt(const map<String, String> ¶ms,
|
|
|
|
Model *ms_model)
|
2014-10-11 22:02:23 +02:00
|
|
|
{
|
2014-10-11 23:16:00 +02:00
|
|
|
// Get the frequency it is optimizing to
|
|
|
|
double freq = params.at("Frequency").toDouble();
|
2014-10-11 22:02:23 +02:00
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
// Get all the starting net names
|
|
|
|
const vector<String>& start_net_names =
|
|
|
|
params.at("TimingOptimization->StartNetNames").split("[,]");
|
2014-10-11 22:02:23 +02:00
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
ASSERT((start_net_names.size() > 0),
|
|
|
|
"[Error] Expecting net names in TimingOptimization->StartNetNames");
|
2014-10-11 22:02:23 +02:00
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
if(start_net_names[0] == "*")
|
2014-10-11 22:02:23 +02:00
|
|
|
{
|
2014-10-11 23:16:00 +02:00
|
|
|
// Optimize from all input ports
|
|
|
|
ElectricalModel* electrical_model = (ElectricalModel*)ms_model;
|
2014-10-11 22:02:23 +02:00
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
ElectricalTimingOptimizer timing_optimizer(
|
|
|
|
"Optimizer", electrical_model->getTechModel());
|
|
|
|
timing_optimizer.setModel(electrical_model);
|
|
|
|
timing_optimizer.construct();
|
|
|
|
timing_optimizer.update();
|
2014-10-11 22:02:23 +02:00
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
ElectricalTimingTree timing_tree(
|
|
|
|
timing_optimizer.getInstanceName(), &timing_optimizer);
|
2014-10-11 22:02:23 +02:00
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
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)
|
2014-10-11 22:02:23 +02:00
|
|
|
{
|
2014-10-11 23:16:00 +02:00
|
|
|
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);
|
2014-10-11 22:02:23 +02:00
|
|
|
}
|
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
// Loop the second times
|
|
|
|
for(it = it_begin; it != it_end; ++it)
|
2014-10-11 22:02:23 +02:00
|
|
|
{
|
2014-10-11 23:16:00 +02:00
|
|
|
const String& net_name = it->first;
|
|
|
|
Log::printLine("Optimizing net: " + net_name);
|
2014-10-11 22:02:23 +02:00
|
|
|
}
|
|
|
|
}
|
2014-10-11 23:16:00 +02:00
|
|
|
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);
|
2014-10-11 22:02:23 +02:00
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2014-10-11 22:02:23 +02:00
|
|
|
}
|
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
static void reportTiming(const map<String, String> ¶ms, Model *ms_model)
|
2014-10-11 22:02:23 +02:00
|
|
|
{
|
2014-10-11 23:16:00 +02:00
|
|
|
// 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);
|
2014-10-11 22:02:23 +02:00
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
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)
|
|
|
|
{
|
2014-10-11 22:02:23 +02:00
|
|
|
// Create the model specified
|
2014-10-11 23:16:00 +02:00
|
|
|
const String& model_name = params.at("ModelName");
|
|
|
|
Model *ms_model = ModelGen::createModel(model_name, model_name,
|
|
|
|
tech_model);
|
2014-10-11 22:02:23 +02:00
|
|
|
|
|
|
|
// Construct the model
|
|
|
|
// Read all parameters the model requires
|
2014-10-11 23:16:00 +02:00
|
|
|
const vector<String>* parameter_names = ms_model->getParameterNames();
|
2014-10-11 22:02:23 +02:00
|
|
|
// For all parameters, grab values from the config file
|
2014-10-11 23:16:00 +02:00
|
|
|
for(vector<String>::const_iterator it = parameter_names->begin();
|
|
|
|
it != parameter_names->end(); ++it)
|
2014-10-11 22:02:23 +02:00
|
|
|
{
|
|
|
|
const String& parameter_name = *it;
|
|
|
|
// If it exists in the config file, set the parameter
|
2014-10-11 23:16:00 +02:00
|
|
|
if(params.count(parameter_name) > 0)
|
2014-10-11 22:02:23 +02:00
|
|
|
{
|
2014-10-11 23:16:00 +02:00
|
|
|
ms_model->setParameter(parameter_name,
|
|
|
|
params.at(parameter_name));
|
2014-10-11 22:02:23 +02:00
|
|
|
}
|
|
|
|
}
|
2014-10-11 23:16:00 +02:00
|
|
|
|
|
|
|
ms_model->construct();
|
2014-10-11 22:02:23 +02:00
|
|
|
|
|
|
|
// Update the model
|
|
|
|
// Read all properties the model requires
|
2014-10-11 23:16:00 +02:00
|
|
|
const vector<String>* property_names = ms_model->getPropertyNames();
|
2014-10-11 22:02:23 +02:00
|
|
|
// For all properties, grab values from the config file
|
2014-10-11 23:16:00 +02:00
|
|
|
for(vector<String>::const_iterator it = property_names->begin();
|
|
|
|
it != property_names->end(); ++it)
|
2014-10-11 22:02:23 +02:00
|
|
|
{
|
|
|
|
const String& property_name = *it;
|
|
|
|
// If it exists in the config file, set the parameter
|
2014-10-11 23:16:00 +02:00
|
|
|
if(params.count(property_name) > 0)
|
2014-10-11 22:02:23 +02:00
|
|
|
{
|
2014-10-11 23:16:00 +02:00
|
|
|
ms_model->setProperty(property_name,
|
|
|
|
params.at(property_name));
|
2014-10-11 22:02:23 +02:00
|
|
|
}
|
|
|
|
}
|
2014-10-11 23:16:00 +02:00
|
|
|
ms_model->update();
|
2014-10-11 22:02:23 +02:00
|
|
|
|
|
|
|
// Evaluate the model
|
|
|
|
// Perform timing optimization if needed
|
2014-10-11 23:16:00 +02:00
|
|
|
if(params.find("IsPerformTimingOptimization") != params.end() &&
|
|
|
|
params.at("IsPerformTimingOptimization").toBool())
|
2014-10-11 22:02:23 +02:00
|
|
|
{
|
2014-10-11 23:16:00 +02:00
|
|
|
performTimingOpt(params, ms_model);
|
2014-10-11 22:02:23 +02:00
|
|
|
}
|
2014-10-11 23:16:00 +02:00
|
|
|
ms_model->evaluate();
|
2014-10-11 22:02:23 +02:00
|
|
|
|
|
|
|
// Report timing if needed
|
2014-10-11 23:16:00 +02:00
|
|
|
if(params.count("IsReportTiming") > 0 &&
|
|
|
|
params.at("IsReportTiming") != "false")
|
2014-10-11 22:02:23 +02:00
|
|
|
{
|
2014-10-11 23:16:00 +02:00
|
|
|
reportTiming(params, ms_model);
|
2014-10-11 22:02:23 +02:00
|
|
|
}
|
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
return ms_model;
|
2014-10-11 22:02:23 +02:00
|
|
|
}
|
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
static const void* processQuery(const String& query_str_,
|
|
|
|
Model *ms_model, bool is_print_)
|
2014-10-11 22:02:23 +02:00
|
|
|
{
|
|
|
|
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];
|
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
vector<String> detail_split =
|
|
|
|
type_split[1].splitByString(Model::DETAIL_SEPARATOR);
|
|
|
|
|
2014-10-11 22:02:23 +02:00
|
|
|
ASSERT((detail_split.size() == 2), "[Error] Invalid query format: " + query_str_);
|
|
|
|
String query_detail = detail_split[1];
|
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
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_);
|
|
|
|
|
2014-10-11 22:02:23 +02:00
|
|
|
String query_hier = subfield_split[0];
|
|
|
|
String query_subfield = "";
|
2014-10-11 23:16:00 +02:00
|
|
|
|
2014-10-11 22:02:23 +02:00
|
|
|
if(subfield_split.size() == 2)
|
|
|
|
{
|
|
|
|
query_subfield = subfield_split[1];
|
|
|
|
}
|
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
const void* query_result = ms_model->parseQuery(query_type, query_hier,
|
|
|
|
query_subfield);
|
2014-10-11 22:02:23 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
void processQuery(const vector<String> &queries,
|
|
|
|
Model *ms_model, vector<String> &outputs)
|
2014-10-11 22:02:23 +02:00
|
|
|
{
|
2014-10-11 23:16:00 +02:00
|
|
|
for(unsigned int i = 0; i < queries.size(); ++i)
|
|
|
|
{
|
|
|
|
const String& curr_query = queries[i];
|
|
|
|
processQuery(curr_query, ms_model, true);
|
2014-10-11 22:02:23 +02:00
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
}
|
2014-10-11 22:02:23 +02:00
|
|
|
}
|
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
static TechModel* constructTechModel(const map<String, String>& params)
|
2014-10-11 22:02:23 +02:00
|
|
|
{
|
2014-10-11 23:16:00 +02:00
|
|
|
// Allocate static TechModel instance
|
|
|
|
const String& electrical_tech_model_filename =
|
|
|
|
params.at("ElectricalTechModelFilename");
|
2014-10-11 22:02:23 +02:00
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
TechModel* tech_model = new TechModel();
|
|
|
|
tech_model->readFile(electrical_tech_model_filename);
|
2014-10-11 22:02:23 +02:00
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
if (params.count("PhotonicTechModelFilename") != 0) {
|
|
|
|
const String& photonic_tech_model_filename =
|
|
|
|
params.at("PhotonicTechModelFilename");
|
|
|
|
tech_model->readFile(photonic_tech_model_filename);
|
|
|
|
}
|
2014-10-11 22:02:23 +02:00
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
// Allocate static StdCellLib instance
|
|
|
|
StdCellLib* std_cell_lib = new StdCellLib(tech_model);
|
2014-10-11 22:02:23 +02:00
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
// Set the StdCellLib pointer in static TechModel instance
|
|
|
|
tech_model->setStdCellLib(std_cell_lib);
|
|
|
|
return tech_model;
|
2014-10-11 22:02:23 +02:00
|
|
|
}
|
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
Model *initialize(const char *config_file_name, map<String, String> &config)
|
2014-10-11 22:02:23 +02:00
|
|
|
{
|
2014-10-11 23:16:00 +02:00
|
|
|
// Init the log file
|
|
|
|
Log::allocate("/tmp/dsent.log");
|
2014-10-11 22:02:23 +02:00
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
// Init the config file
|
|
|
|
LibUtil::readFile(config_file_name, config);
|
2014-10-11 22:02:23 +02:00
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
// Overwrite the technology file
|
|
|
|
TechModel *tech_model = constructTechModel(config);
|
2014-10-11 22:02:23 +02:00
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
// Build the specified model in the config file
|
|
|
|
return buildModel(config, tech_model);
|
2014-10-11 22:02:23 +02:00
|
|
|
}
|
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
void finalize(map<String, String> &config, Model *ms_model)
|
2014-10-11 22:02:23 +02:00
|
|
|
{
|
2014-10-11 23:16:00 +02:00
|
|
|
// Delete the model
|
|
|
|
delete ms_model;
|
2014-10-11 22:02:23 +02:00
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
// Discard all the (key, value) pairs.
|
|
|
|
config.clear();
|
2014-10-11 22:02:23 +02:00
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
// Release the log file
|
|
|
|
Log::release();
|
|
|
|
}
|
2014-10-11 22:02:23 +02:00
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
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;
|
2014-10-11 22:02:23 +02:00
|
|
|
}
|
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
String eval_str = it->second;
|
2014-10-11 22:02:23 +02:00
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
if (eval_str == "") {
|
|
|
|
return;
|
2014-10-11 22:02:23 +02:00
|
|
|
}
|
2014-10-11 23:16:00 +02:00
|
|
|
|
|
|
|
DSENTCalculator calc;
|
|
|
|
calc.evaluateString(eval_str, params, ms_model, outputs);
|
2014-10-11 22:02:23 +02:00
|
|
|
}
|
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
DSENTCalculator::DSENTCalculator() {}
|
2014-10-11 22:02:23 +02:00
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
DSENTCalculator::~DSENTCalculator() {}
|
2014-10-11 22:02:23 +02:00
|
|
|
|
2014-10-11 23:16:00 +02:00
|
|
|
double DSENTCalculator::getEnvVar(const String& var_name_,
|
|
|
|
const map<String, String> &config,
|
|
|
|
Model *ms_model) const
|
2014-10-11 22:02:23 +02:00
|
|
|
{
|
2014-10-11 23:16:00 +02:00
|
|
|
if (m_var_.keyExist(var_name_)) {
|
2014-10-11 22:02:23 +02:00
|
|
|
return m_var_.get(var_name_);
|
2014-10-11 23:16:00 +02:00
|
|
|
} 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);
|
2014-10-11 22:02:23 +02:00
|
|
|
return result->calculateSum();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} // namespace DSENT
|