1 /* Copyright (c) 2012 Massachusetts Institute of Technology
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:
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
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
26 #include "model/std_cells/StdCellLib.h"
32 static void performTimingOpt(const map
<String
, String
> ¶ms
,
35 // Get the frequency it is optimizing to
36 double freq
= params
.at("Frequency").toDouble();
38 // Get all the starting net names
39 const vector
<String
>& start_net_names
=
40 params
.at("TimingOptimization->StartNetNames").split("[,]");
42 ASSERT((start_net_names
.size() > 0),
43 "[Error] Expecting net names in TimingOptimization->StartNetNames");
45 if(start_net_names
[0] == "*")
47 // Optimize from all input ports
48 ElectricalModel
* electrical_model
= (ElectricalModel
*)ms_model
;
50 ElectricalTimingOptimizer
timing_optimizer(
51 "Optimizer", electrical_model
->getTechModel());
52 timing_optimizer
.setModel(electrical_model
);
53 timing_optimizer
.construct();
54 timing_optimizer
.update();
56 ElectricalTimingTree
timing_tree(
57 timing_optimizer
.getInstanceName(), &timing_optimizer
);
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
)
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
);
71 // Loop the second times
72 for(it
= it_begin
; it
!= it_end
; ++it
)
74 const String
& net_name
= it
->first
;
75 Log::printLine("Optimizing net: " + net_name
);
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
);
86 for(unsigned int i
= 0; i
< start_net_names
.size(); ++i
)
88 const String
& net_name
= start_net_names
[i
];
89 timing_tree
.performTimingOpt(
90 electrical_model
->getNet(net_name
), 1.0 / freq
);
95 static void reportTiming(const map
<String
, String
> ¶ms
, Model
*ms_model
)
97 // Get all the starting net names
98 const vector
<String
>& start_net_names
=
99 params
.at("ReportTiming->StartNetNames").split("[,]");
101 ElectricalModel
* electrical_model
= (ElectricalModel
*)ms_model
;
102 ElectricalTimingTree
timing_tree(
103 electrical_model
->getInstanceName(), electrical_model
);
105 cout
<< "Report timing:" << endl
;
106 cout
<< "==============" << endl
;
107 for(unsigned int i
= 0; i
< start_net_names
.size(); ++i
)
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
;
113 cout
<< "==============" << endl
;
116 static Model
*buildModel(const map
<String
, String
> ¶ms
,
117 TechModel
*tech_model
)
119 // Create the model specified
120 const String
& model_name
= params
.at("ModelName");
121 Model
*ms_model
= ModelGen::createModel(model_name
, model_name
,
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
)
131 const String
& parameter_name
= *it
;
132 // If it exists in the config file, set the parameter
133 if(params
.count(parameter_name
) > 0)
135 ms_model
->setParameter(parameter_name
,
136 params
.at(parameter_name
));
140 ms_model
->construct();
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
)
149 const String
& property_name
= *it
;
150 // If it exists in the config file, set the parameter
151 if(params
.count(property_name
) > 0)
153 ms_model
->setProperty(property_name
,
154 params
.at(property_name
));
159 // Evaluate the model
160 // Perform timing optimization if needed
161 if(params
.find("IsPerformTimingOptimization") != params
.end() &&
162 params
.at("IsPerformTimingOptimization").toBool())
164 performTimingOpt(params
, ms_model
);
166 ms_model
->evaluate();
168 // Report timing if needed
169 if(params
.count("IsReportTiming") > 0 &&
170 params
.at("IsReportTiming") != "false")
172 reportTiming(params
, ms_model
);
178 static const void* processQuery(const String
& query_str_
,
179 Model
*ms_model
, bool is_print_
)
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];
185 vector
<String
> detail_split
=
186 type_split
[1].splitByString(Model::DETAIL_SEPARATOR
);
188 ASSERT((detail_split
.size() == 2), "[Error] Invalid query format: " + query_str_
);
189 String query_detail
= detail_split
[1];
191 vector
<String
> subfield_split
=
192 detail_split
[0].splitByString(Model::SUBFIELD_SEPARATOR
);
194 ASSERT(((subfield_split
.size() == 2) || (subfield_split
.size() == 1)),
195 "[Error] Invalid query format: " + query_str_
);
197 String query_hier
= subfield_split
[0];
198 String query_subfield
= "";
200 if(subfield_split
.size() == 2)
202 query_subfield
= subfield_split
[1];
205 const void* query_result
= ms_model
->parseQuery(query_type
, query_hier
,
207 if(query_type
== "Property")
209 const PropertyMap
* property
= (const PropertyMap
*)query_result
;
215 else if(query_type
== "Parameter")
217 const ParameterMap
* parameter
= (const ParameterMap
*)query_result
;
223 else if(query_type
.contain("Hier"))
225 const Model
* model
= (const Model
*)query_result
;
228 model
->printHierarchy(query_type
, query_subfield
, "", query_detail
, cout
);
233 const Result
* result
= (const Result
*)query_result
;
236 result
->print(query_type
+ Model::TYPE_SEPARATOR
+ query_hier
+
237 Model::SUBFIELD_SEPARATOR
+ query_subfield
, query_detail
, cout
);
243 void processQuery(const vector
<String
> &queries
,
244 Model
*ms_model
, vector
<String
> &outputs
)
246 for(unsigned int i
= 0; i
< queries
.size(); ++i
)
248 const String
& curr_query
= queries
[i
];
249 processQuery(curr_query
, ms_model
, true);
254 static TechModel
* constructTechModel(const map
<String
, String
>& params
)
256 // Allocate static TechModel instance
257 const String
& electrical_tech_model_filename
=
258 params
.at("ElectricalTechModelFilename");
260 TechModel
* tech_model
= new TechModel();
261 tech_model
->readFile(electrical_tech_model_filename
);
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
);
269 // Allocate static StdCellLib instance
270 StdCellLib
* std_cell_lib
= new StdCellLib(tech_model
);
272 // Set the StdCellLib pointer in static TechModel instance
273 tech_model
->setStdCellLib(std_cell_lib
);
277 Model
*initialize(const char *config_file_name
, map
<String
, String
> &config
)
280 Log::allocate("/tmp/dsent.log");
282 // Init the config file
283 LibUtil::readFile(config_file_name
, config
);
285 // Overwrite the technology file
286 TechModel
*tech_model
= constructTechModel(config
);
288 // Build the specified model in the config file
289 return buildModel(config
, tech_model
);
292 void finalize(map
<String
, String
> &config
, Model
*ms_model
)
297 // Discard all the (key, value) pairs.
300 // Release the log file
304 void run(const map
<String
, String
> ¶ms
, Model
*ms_model
,
305 map
<string
, double> &outputs
)
307 // Process the specified queries
308 const auto &it
= params
.find("EvaluateString");
309 if(it
== params
.end()) {
313 String eval_str
= it
->second
;
315 if (eval_str
== "") {
319 DSENTCalculator calc
;
320 calc
.evaluateString(eval_str
, params
, ms_model
, outputs
);
323 DSENTCalculator::DSENTCalculator() {}
325 DSENTCalculator::~DSENTCalculator() {}
327 double DSENTCalculator::getEnvVar(const String
& var_name_
,
328 const map
<String
, String
> &config
,
329 Model
*ms_model
) const
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_
);
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();