PandA-2024.02
LatticeBackendFlow.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  */
44 #include "LatticeBackendFlow.hpp"
46 
47 #include "config_PANDA_DATA_INSTALLDIR.hpp"
48 
49 #include "DesignParameters.hpp"
50 #include "LatticeWrapper.hpp"
51 #include "Parameter.hpp"
52 #include "area_info.hpp"
53 #include "dbgPrintHelper.hpp"
54 #include "fileIO.hpp"
55 #include "generic_device.hpp"
56 #include "structural_objects.hpp"
57 #include "time_info.hpp"
58 #include "utility.hpp"
59 #include "xml_dom_parser.hpp"
60 #include "xml_script_command.hpp"
61 
62 #define LATTICE_SLICE "LATTICE_SLICE"
63 #define LATTICE_DELAY "LATTICE_DELAY"
64 #define LATTICE_REGISTERS "LATTICE_REGISTERS"
65 #define LATTICE_IOPIN "LATTICE_IOPIN"
66 #define LATTICE_DSP "LATTICE_DSPS"
67 #define LATTICE_MEM "LATTICE_MEM"
68 
69 LatticeBackendFlow::LatticeBackendFlow(const ParameterConstRef _Param, const std::string& _flow_name,
70  const generic_deviceRef _device)
71  : BackendFlow(_Param, _flow_name, _device)
72 {
73  PRINT_OUT_MEX(OUTPUT_LEVEL_VERBOSE, output_level, " .:: Creating Lattice Backend Flow ::.");
74 
75  default_data["LatticeECP3"] = "LatticeECP3.data";
76  default_data["LatticeECP5"] = "LatticeECP5.data";
78  if(Param->isOption(OPT_target_device_script))
79  {
80  auto xml_file_path = Param->getOption<std::string>(OPT_target_device_script);
81  if(!std::filesystem::exists(xml_file_path))
82  {
83  THROW_ERROR("File \"" + xml_file_path + "\" does not exist!");
84  }
85  PRINT_OUT_MEX(OUTPUT_LEVEL_VERBOSE, output_level, "Importing scripts from file: " + xml_file_path);
86  parser = XMLDomParserRef(new XMLDomParser(xml_file_path));
87  }
88  else
89  {
90  std::string device_string;
91  if(device->has_parameter("family"))
92  {
93  device_string = device->get_parameter<std::string>("family");
94  }
95  else
96  {
97  device_string = "LatticeECP5";
98  }
99  if(default_data.find(device_string) == default_data.end())
100  {
101  THROW_ERROR("Device family \"" + device_string + "\" not supported!");
102  }
104  "Importing default scripts for target device family: " + device_string);
105  parser = XMLDomParserRef(
106  new XMLDomParser(relocate_compiler_path(PANDA_DATA_INSTALLDIR "/panda/wrapper/synthesis/lattice/", true) +
107  default_data[device_string]));
108  }
109  parse_flow(parser);
110 }
111 
113 
114 void LatticeBackendFlow::xparse_utilization(const std::string& fn)
115 {
116  try
117  {
118  XMLDomParser parser(fn);
119  parser.Exec();
120  if(parser)
121  {
122  // Walk the tree:
123  const xml_element* node = parser.get_document()->get_root_node(); // deleted by DomParser.
124  THROW_ASSERT(node->get_name() == "document", "Wrong root name: " + node->get_name());
125 
126  const xml_node::node_list list_int = node->get_children();
127  for(const auto& iter_int : list_int)
128  {
129  const auto* EnodeC = GetPointer<const xml_element>(iter_int);
130  if(!EnodeC)
131  {
132  continue;
133  }
134 
135  if(EnodeC->get_name() == "application")
136  {
137  const xml_node::node_list list_sec = EnodeC->get_children();
138  for(const auto& iter_sec : list_sec)
139  {
140  const auto* nodeS = GetPointer<const xml_element>(iter_sec);
141  if(!nodeS)
142  {
143  continue;
144  }
145 
146  if(nodeS->get_name() == "section")
147  {
148  std::string stringID;
149  if(CE_XVM(stringID, nodeS))
150  {
151  LOAD_XVM(stringID, nodeS);
152  }
153  if(stringID == "LATTICE_SYNTHESIS_SUMMARY")
154  {
155  const xml_node::node_list list_item = nodeS->get_children();
156  for(const auto& it_item : list_item)
157  {
158  const auto* nodeIt = GetPointer<const xml_element>(it_item);
159  if(!nodeIt or nodeIt->get_name() != "item")
160  {
161  continue;
162  }
163 
164  if(CE_XVM(stringID, nodeIt))
165  {
166  LOAD_XVM(stringID, nodeIt);
167  }
168 
169  std::string value;
170  if(CE_XVM(value, nodeIt))
171  {
172  LOAD_XVM(value, nodeIt);
173  boost::replace_all(value, ",", "");
174  design_values[stringID] = std::stod(value);
175  }
176  }
177  }
178  }
179  }
180  }
181  }
182  return;
183  }
184  }
185  catch(const char* msg)
186  {
187  std::cerr << msg << std::endl;
188  }
189  catch(const std::string& msg)
190  {
191  std::cerr << msg << std::endl;
192  }
193  catch(const std::exception& ex)
194  {
195  std::cout << "Exception caught: " << ex.what() << std::endl;
196  }
197  catch(...)
198  {
199  std::cerr << "unknown exception" << std::endl;
200  }
201  THROW_ERROR("Error during LATTICE report parsing: " + fn);
202 }
203 
205 {
206  PRINT_OUT_MEX(OUTPUT_LEVEL_MINIMUM, output_level, "Analyzing Lattice synthesis results");
207  std::string report_filename = GetPath(actual_parameters->parameter_values[PARAM_lattice_report]);
208  xparse_utilization(report_filename);
209 
210  THROW_ASSERT(design_values.find(LATTICE_SLICE) != design_values.end(), "Missing logic elements");
212  area_m->set_area_value(design_values[LATTICE_SLICE]);
213  area_m->set_resource_value(area_info::SLICE, design_values[LATTICE_SLICE]);
214  area_m->set_resource_value(area_info::REGISTERS, design_values[LATTICE_REGISTERS]);
215  area_m->set_resource_value(area_info::DSP, design_values[LATTICE_DSP]);
216  area_m->set_resource_value(area_info::BRAM, design_values[LATTICE_MEM]);
217 
219  if(design_values[LATTICE_DELAY] != 0.0)
220  {
222  }
223  else
224  {
226  }
227 }
228 
230 {
231  auto setupscr = Param->isOption(OPT_lattice_settings) ? Param->getOption<std::string>(OPT_lattice_settings) : "";
232  if(setupscr.size() && setupscr != "0")
233  {
234  script << "#configuration" << std::endl;
235  if(starts_with(setupscr, "export"))
236  {
237  script << setupscr + " >& /dev/null; ";
238  }
239  else
240  {
241  script << ". " << setupscr << " >& /dev/null; ";
242  }
243  script << std::endl << std::endl;
244  }
245 }
246 
248 {
249  std::string clock = dp->parameter_values[PARAM_clk_name];
250 
251  std::string sdc_filename = out_dir + "/" + dp->component_name + ".ldc";
252  std::ofstream sdc_file(sdc_filename.c_str());
253  if(!static_cast<bool>(std::stoi(dp->parameter_values[PARAM_is_combinational])))
254  {
255  sdc_file << "create_clock -period " + dp->parameter_values[PARAM_clk_period] + " -name " + clock +
256  " [get_ports " + clock + "]\n";
257  if((static_cast<bool>(std::stoi(dp->parameter_values[PARAM_connect_iob])) ||
258  (Param->IsParameter("profile-top") && Param->GetParameter<int>("profile-top") == 1)) &&
259  !Param->isOption(OPT_backend_sdc_extensions))
260  {
261  sdc_file << "set_max_delay " + dp->parameter_values[PARAM_clk_period] +
262  " -from [all_inputs] -to [all_outputs]\n";
263  }
264  }
265  else
266  {
267  sdc_file << "set_max_delay " + dp->parameter_values[PARAM_clk_period] + " -from [all_inputs] -to [all_outputs]\n";
268  }
269  if(Param->isOption(OPT_backend_sdc_extensions))
270  {
271  sdc_file << "source " + Param->getOption<std::string>(OPT_backend_sdc_extensions) + "\n";
272  }
273 
274  sdc_file.close();
275  dp->parameter_values[PARAM_sdc_file] = sdc_filename;
276 }
277 
279 {
280  actual_parameters->parameter_values[PARAM_target_device] = device->get_parameter<std::string>("model");
281  auto device_family = device->get_parameter<std::string>("family");
282  if(device_family.find('-') != std::string::npos)
283  {
284  device_family = device_family.substr(0, device_family.find('-'));
285  }
287 
288  std::string HDL_files = actual_parameters->parameter_values[PARAM_HDL_files];
289  const auto file_list = string_to_container<std::vector<std::filesystem::path>>(HDL_files, ";");
290  std::string sources_macro_list;
291  bool has_vhdl_library = Param->isOption(OPT_VHDL_library);
292  std::string vhdl_library;
293  if(has_vhdl_library)
294  {
295  vhdl_library = Param->getOption<std::string>(OPT_VHDL_library);
296  }
297  for(const auto& file : file_list)
298  {
299  const auto extension = file.extension().string();
300  if(extension == ".vhd" || extension == ".vhdl" || extension == ".VHD" || extension == ".VHDL")
301  {
302  if(has_vhdl_library)
303  {
304  sources_macro_list += "prj_src add -format VHDL -work " + vhdl_library + " " + file.string() + "\n";
305  }
306  else
307  {
308  sources_macro_list += "prj_src add -format VHDL " + file.string() + "\n";
309  }
310  }
311  else if(extension == ".v" || extension == ".V" || extension == ".sv" || extension == ".SV")
312  {
313  sources_macro_list += "prj_src add -format VERILOG " + file.string() + "\n";
314  }
315  else
316  {
317  THROW_ERROR("Extension not recognized! " + extension);
318  }
319  }
320  if(Param->isOption(OPT_lattice_pmi_def))
321  {
322  sources_macro_list += "prj_src add -format VERILOG " + Param->getOption<std::string>(OPT_lattice_pmi_def) + "\n";
323  }
325 
327 
328  for(auto& step : steps)
329  {
330  step->tool->EvaluateVariables(actual_parameters);
331  }
332 }
333 
335 {
337 }
#define PARAM_sources_macro_list
void ExecuteSynthesis() override
Checks if the execution can be performed and, in case, performs the synthesis.
#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.
#define PARAM_target_device
File containing functions and utilities to support the printing of debug messagges.
#define LATTICE_SLICE
Header include.
area_infoRef area_m
pointer to the data structure containing information about the resources
#define LATTICE_MEM
#define PARAM_sdc_file
DesignParametersRef actual_parameters
set of design parameters with the actual values
Wrapper to implement a synthesis tools by Lattice.
void set_execution_time(double execution_time, unsigned int cycles=time_info::cycles_time_DEFAULT)
Definition: time_info.cpp:64
void InitDesignParameters() override
Initializes the parameters.
Collect information about resource performance.
#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
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
#define LATTICE_DELAY
int debug_level
debugging level of the class
void xparse_utilization(const std::string &fn)
Parses device utilization.
#define LATTICE_REGISTERS
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.
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
std::map< std::string, double > design_values
design values reported by the tools
Wrapper to synthesis tools by Lattice.
This file contains the definition of the parameters for the synthesis tools.
~LatticeBackendFlow() override
Destructor.
refcount< XMLDomParser > XMLDomParserRef
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 create_sdc(const DesignParametersRef dp)
Creates the constraint file.
void Exec()
Parse an XML document from a file.
const ParameterConstRef Param
class containing all the parameters
void CheckSynthesisResults() override
Checks the synthesis results and fills the corresponding data-structures.
void WriteFlowConfiguration(std::ostream &script) override
Writes the proper flow configuration in the output script.
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
std::string out_dir
name of the output directory
Classes for handling configuration files.
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.
#define LATTICE_DSP
unsigned int output_level
verbosity level of the class
LatticeBackendFlow(const ParameterConstRef Param, const std::string &flow_name, const generic_deviceRef _device)
Constructor.
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 PARAM_lattice_report
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
#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