PandA-2024.02
AlteraBackendFlow.cpp
Go to the documentation of this file.
1 /*
2  *
3  * _/_/_/ _/_/ _/ _/ _/_/_/ _/_/
4  * _/ _/ _/ _/ _/_/ _/ _/ _/ _/ _/
5  * _/_/_/ _/_/_/_/ _/ _/_/ _/ _/ _/_/_/_/
6  * _/ _/ _/ _/ _/ _/ _/ _/ _/
7  * _/ _/ _/ _/ _/ _/_/_/ _/ _/
8  *
9  * ***********************************************
10  * PandA Project
11  * URL: http://panda.dei.polimi.it
12  * Politecnico di Milano - DEIB
13  * System Architectures Group
14  * ***********************************************
15  * Copyright (C) 2004-2024 Politecnico di Milano
16  *
17  * This file is part of the PandA framework.
18  *
19  * The PandA framework is free software; you can redistribute it and/or modify
20  * it under the terms of the GNU General Public License as published by
21  * the Free Software Foundation; either version 3 of the License, or
22  * (at your option) any later version.
23  *
24  * This program is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27  * GNU General Public License for more details.
28  *
29  * You should have received a copy of the GNU General Public License
30  * along with this program. If not, see <http://www.gnu.org/licenses/>.
31  *
32  */
46 #include "AlteraBackendFlow.hpp"
48 
49 #include "config_PANDA_DATA_INSTALLDIR.hpp"
50 
51 #include "AlteraWrapper.hpp"
52 #include "DesignParameters.hpp"
53 #include "Parameter.hpp"
54 #include "area_info.hpp"
55 #include "dbgPrintHelper.hpp"
56 #include "fileIO.hpp"
57 #include "generic_device.hpp"
58 #include "string_manipulation.hpp"
59 #include "structural_objects.hpp"
60 #include "synthesis_constants.hpp"
61 #include "time_info.hpp"
62 #include "utility.hpp"
63 #include "xml_dom_parser.hpp"
64 #include "xml_script_command.hpp"
65 
66 #define ALTERA_LE "ALTERA_LE"
67 #define ALTERA_LAB "ALTERA_LAB"
68 #define ALTERA_FMAX "ALTERA_FMAX"
69 #define ALTERA_FMAX_RESTRICTED "ALTERA_FMAX_RESTRICTED"
70 #define ALTERA_REGISTERS "ALTERA_REGISTERS"
71 #define ALTERA_IOPIN "ALTERA_IOPIN"
72 #define ALTERA_ALUT "ALTERA_ALUT"
73 #define ALTERA_ALM "ALTERA_ALM"
74 #define ALTERA_DSP "ALTERA_DSP"
75 #define ALTERA_MEM "ALTERA_MEM"
76 
77 AlteraBackendFlow::AlteraBackendFlow(const ParameterConstRef _Param, const std::string& _flow_name,
78  const generic_deviceRef _device)
79  : BackendFlow(_Param, _flow_name, _device)
80 {
81  debug_level = _Param->get_class_debug_level(GET_CLASS(*this));
82  PRINT_OUT_MEX(OUTPUT_LEVEL_VERBOSE, output_level, " .:: Creating Altera Backend Flow ::.");
83 
84  default_data["CycloneII"] = "CycloneII.data";
85 
86  default_data["CycloneII-R"] = "CycloneII-R.data";
87 
88  default_data["CycloneV"] = "CycloneV.data";
89  default_data["StratixV"] = "StratixV.data";
90  default_data["StratixIV"] = "StratixIV.data";
92  if(Param->isOption(OPT_target_device_script))
93  {
94  auto xml_file_path = Param->getOption<std::string>(OPT_target_device_script);
95  if(!std::filesystem::exists(xml_file_path))
96  {
97  THROW_ERROR("File \"" + xml_file_path + "\" does not exist!");
98  }
99  PRINT_OUT_MEX(OUTPUT_LEVEL_VERBOSE, output_level, "Importing scripts from file: " + xml_file_path);
100  parser = XMLDomParserRef(new XMLDomParser(xml_file_path));
101  }
102  else
103  {
104  std::string device_string;
105  if(device->has_parameter("family"))
106  {
107  device_string = device->get_parameter<std::string>("family");
108  }
109  else
110  {
111  device_string = "CycloneII";
112  }
113  if(default_data.find(device_string) == default_data.end())
114  {
115  THROW_ERROR("Device family \"" + device_string + "\" not supported!");
116  }
118  "Importing default scripts for target device family: " + device_string);
119  parser = XMLDomParserRef(
120  new XMLDomParser(relocate_compiler_path(PANDA_DATA_INSTALLDIR "/panda/wrapper/synthesis/altera/", true) +
121  default_data[device_string]));
122  }
123  parse_flow(parser);
124 }
125 
127 
128 void AlteraBackendFlow::xparse_utilization(const std::string& fn)
129 {
130  try
131  {
132  XMLDomParser parser(fn);
133  parser.Exec();
134  if(parser)
135  {
136  // Walk the tree:
137  const xml_element* node = parser.get_document()->get_root_node(); // deleted by DomParser.
138  THROW_ASSERT(node->get_name() == "document", "Wrong root name: " + node->get_name());
139 
140  const xml_node::node_list list_int = node->get_children();
141  for(const auto& iter_int : list_int)
142  {
143  const auto* EnodeC = GetPointer<const xml_element>(iter_int);
144  if(!EnodeC)
145  {
146  continue;
147  }
148 
149  if(EnodeC->get_name() == "application")
150  {
151  const xml_node::node_list list_sec = EnodeC->get_children();
152  for(const auto& iter_sec : list_sec)
153  {
154  const auto* nodeS = GetPointer<const xml_element>(iter_sec);
155  if(!nodeS)
156  {
157  continue;
158  }
159 
160  if(nodeS->get_name() == "section")
161  {
162  std::string stringID;
163  if(CE_XVM(stringID, nodeS))
164  {
165  LOAD_XVM(stringID, nodeS);
166  }
167  if(stringID == "QUARTUS_SYNTHESIS_SUMMARY")
168  {
169  const xml_node::node_list list_item = nodeS->get_children();
170  for(const auto& it_item : list_item)
171  {
172  const auto* nodeIt = GetPointer<const xml_element>(it_item);
173  if(!nodeIt or nodeIt->get_name() != "item")
174  {
175  continue;
176  }
177 
178  if(CE_XVM(stringID, nodeIt))
179  {
180  LOAD_XVM(stringID, nodeIt);
181  }
182 
183  std::string value;
184  if(CE_XVM(value, nodeIt))
185  {
186  LOAD_XVM(value, nodeIt);
187  boost::replace_all(value, ",", "");
188  design_values[stringID] = std::stod(value);
189  }
190  }
191  }
192  }
193  }
194  }
195  }
196  return;
197  }
198  }
199  catch(const char* msg)
200  {
201  std::cerr << msg << std::endl;
202  }
203  catch(const std::string& msg)
204  {
205  std::cerr << msg << std::endl;
206  }
207  catch(const std::exception& ex)
208  {
209  std::cout << "Exception caught: " << ex.what() << std::endl;
210  }
211  catch(...)
212  {
213  std::cerr << "unknown exception" << std::endl;
214  }
215  THROW_ERROR("Error during QUARTUS_SH report parsing: " + fn);
216 }
217 
219 {
220  PRINT_OUT_MEX(OUTPUT_LEVEL_MINIMUM, output_level, "Analyzing Altera synthesis results");
221  std::string report_filename = actual_parameters->parameter_values[PARAM_quartus_report];
222  xparse_utilization(report_filename);
223 
224  THROW_ASSERT(design_values.find(ALTERA_LE) != design_values.end(), "Missing logic elements");
226  if(design_values[ALTERA_LE] != 0.0)
227  {
228  area_m->set_area_value(design_values[ALTERA_LE]);
229  }
230  else
231  {
232  area_m->set_area_value(design_values[ALTERA_ALM]);
233  }
234  if(design_values[ALTERA_LE] != 0.0)
235  {
236  area_m->set_resource_value(area_info::LOGIC_ELEMENTS, design_values[ALTERA_LE]);
237  }
238  else
239  {
240  area_m->set_resource_value(area_info::ALMS, design_values[ALTERA_ALM]);
241  }
242 
243  area_m->set_resource_value(area_info::REGISTERS, design_values[ALTERA_REGISTERS]);
244  area_m->set_resource_value(area_info::DSP, design_values[ALTERA_DSP]);
245  area_m->set_resource_value(area_info::BRAM, design_values[ALTERA_MEM]);
246 
248  const auto combinational_delay = [&]() -> double {
249  if(design_values[ALTERA_FMAX] != 0.0)
250  {
251  return 1000 / design_values[ALTERA_FMAX];
252  }
253  else if(design_values.find("SLACK") != design_values.end())
254  {
255  return Param->getOption<double>(OPT_clock_period) - design_values.find("SLACK")->second;
256  }
257  else
258  {
259  return 0.0;
260  }
261  }();
262  time_m->set_execution_time(combinational_delay);
263  if(combinational_delay > Param->getOption<double>(OPT_clock_period))
264  {
266  Param->getOption<std::string>(OPT_output_directory) + "/" + flow_name + "/" +
268  }
269 }
270 
272 {
273  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Writing flow configuration");
274  auto device_string = Param->getOption<std::string>(OPT_device_string);
275  std::string setupscr;
276  if(Param->isOption(OPT_quartus_settings) and device_string.find("EP2C") == std::string::npos)
277  {
278  setupscr = Param->getOption<std::string>(OPT_quartus_settings);
279  }
280  else if(Param->isOption(OPT_quartus_13_settings))
281  {
282  setupscr = Param->getOption<std::string>(OPT_quartus_13_settings);
283  }
284  if(setupscr.size())
285  {
286  script << "#configuration" << std::endl;
287  if(starts_with(setupscr, "export"))
288  {
289  script << setupscr + " >& /dev/null; ";
290  }
291  else
292  {
293  script << ". " << setupscr << " >& /dev/null; ";
294  }
295  script << std::endl << std::endl;
296  }
297  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Written flow configuration");
298 }
299 
301 {
302  std::string clock = dp->parameter_values[PARAM_clk_name];
303 
304  std::string sdc_filename = out_dir + "/" + dp->component_name + ".sdc";
305  std::ofstream sdc_file(sdc_filename.c_str());
306  if(!static_cast<bool>(std::stoi(dp->parameter_values[PARAM_is_combinational])))
307  {
308  sdc_file << "create_clock -period " + dp->parameter_values[PARAM_clk_period] + " -name " + clock +
309  " [get_ports " + clock + "]\n";
310  if(get_flow_name() != "Characterization" &&
311  (static_cast<bool>(std::stoi(dp->parameter_values[PARAM_connect_iob])) ||
312  (Param->IsParameter("profile-top") && Param->GetParameter<int>("profile-top") == 1)) &&
313  !Param->isOption(OPT_backend_sdc_extensions))
314  {
315  sdc_file << "set_min_delay 0 -from [all_inputs] -to [all_registers]\n";
316  sdc_file << "set_min_delay 0 -from [all_registers] -to [all_outputs]\n";
317  sdc_file << "set_max_delay " + dp->parameter_values[PARAM_clk_period] +
318  " -from [all_inputs] -to [all_registers]\n";
319  sdc_file << "set_max_delay " + dp->parameter_values[PARAM_clk_period] +
320  " -from [all_registers] -to [all_outputs]\n";
321  sdc_file << "set_max_delay " + dp->parameter_values[PARAM_clk_period] +
322  " -from [all_inputs] -to [all_outputs]\n";
323  }
324  sdc_file << "derive_pll_clocks\n";
325  sdc_file << "derive_clock_uncertainty\n";
326  }
327  else
328  {
329  sdc_file << "set_max_delay " + dp->parameter_values[PARAM_clk_period] + " -from [all_inputs] -to [all_outputs]\n";
330  }
331 
332  if(Param->isOption(OPT_backend_sdc_extensions))
333  {
334  sdc_file << "source " + Param->getOption<std::string>(OPT_backend_sdc_extensions) + "\n";
335  }
336  sdc_file.close();
337  dp->parameter_values[PARAM_sdc_file] = sdc_filename;
338 }
339 
341 {
342  actual_parameters->parameter_values[PARAM_target_device] = device->get_parameter<std::string>("model");
343  auto device_family = device->get_parameter<std::string>("family");
344  if(device_family.find('-') != std::string::npos)
345  {
346  device_family = device_family.substr(0, device_family.find('-'));
347  }
349 
350  std::string HDL_files = actual_parameters->parameter_values[PARAM_HDL_files];
351  const auto file_list = string_to_container<std::vector<std::string>>(HDL_files, ";");
352  std::string sources_macro_list;
353  bool has_vhdl_library = Param->isOption(OPT_VHDL_library);
354  std::string vhdl_library;
355  if(has_vhdl_library)
356  {
357  vhdl_library = Param->getOption<std::string>(OPT_VHDL_library);
358  }
359  for(const auto& v : file_list)
360  {
361  if(has_vhdl_library)
362  {
363  sources_macro_list += "set_global_assignment -name SOURCE_FILE " + v + " -library " + vhdl_library + "\n";
364  }
365  else
366  {
367  sources_macro_list += "set_global_assignment -name SOURCE_FILE " + v + "\n";
368  }
369  }
371 
373 
374  for(auto& step : steps)
375  {
376  step->tool->EvaluateVariables(actual_parameters);
377  }
378 }
379 
381 {
383 }
#define PARAM_sources_macro_list
#define DEBUG_LEVEL_VERY_PEDANTIC
extremely verbose debugging print is performed.
#define INDENT_DBG_MEX(dbgLevel, curDbgLevel, mex)
We are producing a debug version of the program, so the message is printed;.
Collect information about resource area.
void CheckSynthesisResults() override
Checks the synthesis results and fills the corresponding data-structures.
#define PARAM_target_device
File containing functions and utilities to support the printing of debug messagges.
area_infoRef area_m
pointer to the data structure containing information about the resources
#define PARAM_sdc_file
DesignParametersRef actual_parameters
set of design parameters with the actual values
#define GET_CLASS(obj)
Macro returning the actual type of an object.
~AlteraBackendFlow() override
Destructor.
std::map< std::string, double > design_values
design values reported by the tools
constants used in synthesis wrappers
void create_sdc(const DesignParametersRef dp)
Creates the constraint file.
void set_execution_time(double execution_time, unsigned int cycles=time_info::cycles_time_DEFAULT)
Definition: time_info.cpp:64
Collect information about resource performance.
#define ALTERA_LE
Header include.
#define ALTERA_REGISTERS
#define CE_XVM(variable, node)
Check existence XML Value Macro. Check if an XML attribute is present in the XML tree.
Definition: xml_helper.hpp:88
std::string flow_name
string-based identifier of the flow
void parse_flow(const XMLDomParserRef parser)
Creates the synthesis flow based on the user&#39;s requirements.
#define OUTPUT_LEVEL_MINIMUM
minimum debugging print is performed.
time_infoRef time_m
pointer to the data structure containing timing information
const generic_deviceRef device
information about the target device
void InitDesignParameters() override
Initializes the parameters.
int debug_level
debugging level of the class
Auxiliary methods for manipulating string.
#define ALTERA_DSP
void ExecuteSynthesis() override
Checks if the execution can be performed and, in case, performs the synthesis.
bool starts_with(const std::string &str, const std::string &pattern)
map_t parameter_values
Map between the name of the parameter and the corresponding string-based value.
#define STR_CST_synthesis_timing_violation_report
The file containing the timing violation report.
void CopyFile(std::filesystem::path file_source, std::filesystem::path file_target)
Copy file; if target already exist, overwrite.
Definition: fileIO.hpp:187
std::string get_name() const
Get the name of this node.
Definition: xml_node.hpp:132
std::vector< BackendStepRef > steps
ordered list of synthesis steps
This file contains the definition of the parameters for the synthesis tools.
void WriteFlowConfiguration(std::ostream &script) override
Writes the proper flow configuration in the output script.
refcount< XMLDomParser > XMLDomParserRef
void xparse_utilization(const std::string &fn)
Parses device utilization.
XML DOM parser.
XML DOM parser.
utility function used to read files.
virtual void ExecuteSynthesis()
Executes the synthesis with the implemented flow.
This file collects some utility functions and macros.
void Exec()
Parse an XML document from a file.
const ParameterConstRef Param
class containing all the parameters
std::list< xml_nodeRef > node_list
type for list of xml nodes
Definition: xml_node.hpp:90
std::map< std::string, std::string > default_data
map between the identifiers of the synthesis flows and the corresponding implementations ...
#define THROW_ERROR(str_expr)
helper function used to throw an error in a standard way
Definition: exceptions.hpp:263
#define ALTERA_FMAX
std::string out_dir
name of the output directory
Classes for handling configuration files.
AlteraBackendFlow(const ParameterConstRef Param, const std::string &flow_name, const generic_deviceRef _device)
Constructor.
#define ALTERA_ALM
#define PARAM_quartus_report
#define PARAM_top_id
This class describes all classes used to represent a structural object.
static area_infoRef factory(const ParameterConstRef &Param)
Factory method.
Definition: area_info.cpp:52
std::string GetPath(std::filesystem::path path)
Definition: fileIO.hpp:140
std::string component_name
Name of the component.
unsigned int output_level
verbosity level of the class
std::string get_flow_name() const
Returns the name of the flow.
Template borrowed from the ANTLR library by Terence Parr (http://www.jGuru.com - Software rights: htt...
Definition: refcount.hpp:94
xml_documentRef get_document()
Obtain the parsed document.
#define PARAM_connect_iob
this class is used to manage the command-line or XML options.
#define LOAD_XVM(variable, node)
LOAD XML Value Macro. Set a variable starting from an XML value. Conversion is performed if needed...
Definition: xml_helper.hpp:65
#define ALTERA_MEM
Wrapper to synthesis tools by Altera.
node_list const & get_children()
Obtain the list of child nodes.
Definition: xml_node.hpp:310
#define PARAM_clk_period
Generic device description.
#define PRINT_OUT_MEX(profLevel, curprofLevel, mex)
#define OUTPUT_LEVEL_VERBOSE
verbose debugging print is performed.
#define DEBUG_LEVEL_VERBOSE
verbose debugging print is performed.
std::string relocate_compiler_path(const std::string &path, bool resolve_path=false)
Definition: fileIO.hpp:149
#define PARAM_clk_name
static time_infoRef factory(const ParameterConstRef Param)
Definition: time_info.cpp:110
#define PARAM_target_family
Wrapper to implement a synthesis tools by Altera.
#define PARAM_HDL_files
#define PARAM_is_combinational
#define THROW_ASSERT(cond, str_expr)
helper function used to check an assert and if needed to throw an error in a standard way ...
Definition: exceptions.hpp:289

Generated on Mon Feb 12 2024 13:02:56 for PandA-2024.02 by doxygen 1.8.13