PandA-2024.02
XilinxBackendFlow.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 "XilinxBackendFlow.hpp"
45 
46 #include "config_PANDA_DATA_INSTALLDIR.hpp"
47 
48 #include "DesignParameters.hpp"
49 #include "Parameter.hpp"
50 #include "XilinxWrapper.hpp"
51 #include "area_info.hpp"
52 #include "dbgPrintHelper.hpp"
53 #include "fileIO.hpp"
54 #include "generic_device.hpp"
55 #include "map_wrapper.hpp"
56 #include "string_manipulation.hpp"
57 #include "structural_objects.hpp"
58 #include "synthesis_constants.hpp"
59 #include "time_info.hpp"
60 #include "trce_wrapper.hpp"
61 #include "utility.hpp"
62 #include "xml_dom_parser.hpp"
63 #include "xml_script_command.hpp"
64 
65 #define XST_NUMBER_OF_SLICE_REGISTERS "XST_NUMBER_OF_SLICE_REGISTERS"
66 #define XST_NUMBER_OF_SLICE_LUTS "XST_NUMBER_OF_SLICE_LUTS"
67 #define XST_NUMBER_OF_LUT_FLIP_FLOP_PAIRS_USED "XST_NUMBER_OF_LUT_FLIP_FLOP_PAIRS_USED"
68 #define XST_NUMBER_OF_BLOCK_RAMFIFO "XST_NUMBER_OF_BLOCK_RAMFIFO"
69 
70 #define VIVADO_XILINX_LUT_FLIP_FLOP_PAIRS_USED "XILINX_LUT_FLIP_FLOP_PAIRS_USED"
71 #define VIVADO_XILINX_SLICE "XILINX_SLICE"
72 #define VIVADO_XILINX_SLICE_REGISTERS "XILINX_SLICE_REGISTERS"
73 #define VIVADO_XILINX_SLICE_LUTS "XILINX_SLICE_LUTS"
74 #define VIVADO_XILINX_BLOCK_RAMFIFO "XILINX_BLOCK_RAMFIFO"
75 #define VIVADO_XILINX_IOPIN "XILINX_IOPIN"
76 #define VIVADO_XILINX_DSPS "XILINX_DSPS"
77 #define VIVADO_XILINX_OUTPUT "XILINX_OUTPUT"
78 #define VIVADO_XILINX_POWER "XILINX_POWER"
79 #define VIVADO_XILINX_DESIGN_DELAY "XILINX_DESIGN_DELAY"
80 #define VIVADO_XILINX_URAM "XILINX_URAM"
81 
82 XilinxBackendFlow::XilinxBackendFlow(const ParameterConstRef _Param, const std::string& _flow_name,
83  const generic_deviceRef _device)
84  : BackendFlow(_Param, _flow_name, _device)
85 {
86  debug_level = _Param->get_class_debug_level(GET_CLASS(*this));
87  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "---Creating Xilinx Backend Flow ::.");
88  std::filesystem::create_directories(UCF_SUBDIR);
89 
90  default_data["Virtex-4"] = "Virtex-4.data";
91 #if HAVE_TASTE
92  default_data["Virtex-4-Taste"] = "Virtex-4-Taste.data";
93 #endif
94  default_data["Virtex-5"] = "Virtex-5.data";
95  default_data["Virtex-6"] = "Virtex-6.data";
96  default_data["Virtex-7"] = "Virtex-7.data";
97  default_data["Virtex-7-VVD"] = "Virtex-7-VVD.data";
98  default_data["Artix-7-VVD"] = "Artix-7-VVD.data";
99  default_data["Zynq-VVD"] = "Zynq-VVD.data";
100  default_data["Zynq-YOSYS-VVD"] = "Zynq-YOSYS-VVD.data";
101  default_data["Zynq"] = "Zynq.data";
102  default_data["Kintex-Ultrascale-VVD"] = "Kintex-Ultrascale-VVD.data";
103  default_data["Alveo-Ultrascale-VVD"] = "Alveo-Ultrascale-VVD.data";
104 
106  if(Param->isOption(OPT_target_device_script))
107  {
108  auto xml_file_path = Param->getOption<std::string>(OPT_target_device_script);
109  if(!std::filesystem::exists(xml_file_path))
110  {
111  THROW_ERROR("File \"" + xml_file_path + "\" does not exist!");
112  }
113  INDENT_OUT_MEX(OUTPUT_LEVEL_VERBOSE, output_level, "---Importing scripts from file: " + xml_file_path);
114  parser = XMLDomParserRef(new XMLDomParser(xml_file_path));
115  }
116  else
117  {
118  std::string device_string;
119  if(device->has_parameter("family"))
120  {
121  device_string = device->get_parameter<std::string>("family");
122  }
123  else
124  {
125  device_string = "Zynq-VVD";
126  }
127 #if HAVE_TASTE
128  if(Param->isOption(OPT_generate_taste_architecture) and Param->getOption<bool>(OPT_generate_taste_architecture))
129  {
130  device_string = device_string + "-Taste";
131  }
132 #endif
133  if(default_data.find(device_string) == default_data.end())
134  {
135  THROW_ERROR("Device family \"" + device_string + "\" not supported!");
136  }
138  "---Importing default scripts for target device family: " + device_string);
139  parser = XMLDomParserRef(
140  new XMLDomParser(relocate_compiler_path(PANDA_DATA_INSTALLDIR "/panda/wrapper/synthesis/xilinx/", true) +
141  default_data[device_string]));
142  }
143  parse_flow(parser);
144 }
145 
147 
148 void XilinxBackendFlow::xparse_map_utilization(const std::string& fn)
149 {
150  std::ifstream output_file(fn.c_str());
151  if(output_file.is_open())
152  {
153  while(!output_file.eof())
154  {
155  std::string line;
156  getline(output_file, line);
157  if(line.size() and line.find("Number of Slice Registers:") != std::string::npos)
158  {
159  std::string tk = "Number of Slice Registers:";
160  std::string token = line.substr(line.find(tk) + tk.size() + 1, line.length());
161  boost::algorithm::trim(token);
162  token = token.substr(0, token.find(' '));
163  boost::algorithm::trim(token);
164  boost::replace_all(token, ",", "");
165  if(!area_m)
166  {
168  }
169  area_m->set_resource_value(area_info::REGISTERS, std::stod(token));
170  }
171  else if(line.size() and line.find("Number of Slice Flip Flops:") != std::string::npos)
172  {
173  std::string tk = "Number of Slice Flip Flops:";
174  std::string token = line.substr(line.find(tk) + tk.size() + 1, line.length());
175  boost::algorithm::trim(token);
176  token = token.substr(0, token.find(' '));
177  boost::algorithm::trim(token);
178  boost::replace_all(token, ",", "");
179  if(!area_m)
180  {
182  }
183  area_m->set_resource_value(area_info::REGISTERS, std::stod(token));
184  }
185  else if(line.size() and line.find("Number of 4 input LUTs:") != std::string::npos)
186  {
187  std::string tk = "Number of 4 input LUTs:";
188  std::string token = line.substr(line.find(tk) + tk.size() + 1, line.length());
189  boost::algorithm::trim(token);
190  token = token.substr(0, token.find(' '));
191  boost::algorithm::trim(token);
192  boost::replace_all(token, ",", "");
193  if(!area_m)
194  {
196  }
197  area_m->set_resource_value(area_info::SLICE_LUTS, std::stod(token));
198  }
199  else if(line.size() and line.find("Number of Slice LUTs:") != std::string::npos)
200  {
201  std::string tk = "Number of Slice LUTs:";
202  std::string token = line.substr(line.find(tk) + tk.size() + 1, line.length());
203  boost::algorithm::trim(token);
204  token = token.substr(0, token.find(' '));
205  boost::algorithm::trim(token);
206  boost::replace_all(token, ",", "");
207  if(!area_m)
208  {
210  }
211  area_m->set_resource_value(area_info::SLICE_LUTS, std::stod(token));
212  }
213  else if(line.size() and line.find("Number of occupied Slices:") != std::string::npos)
214  {
215  std::string tk = "Number of occupied Slices:";
216  std::string token = line.substr(line.find(tk) + tk.size() + 1, line.length());
217  boost::algorithm::trim(token);
218  token = token.substr(0, token.find(' '));
219  boost::algorithm::trim(token);
220  boost::replace_all(token, ",", "");
221  if(!area_m)
222  {
224  }
225  area_m->set_resource_value(area_info::SLICE, std::stod(token));
226  }
227  else if(line.size() and line.find("Number of LUT Flip Flop pairs used:") != std::string::npos)
228  {
229  std::string tk = "Number of LUT Flip Flop pairs used:";
230  std::string token = line.substr(line.find(tk) + tk.size() + 1, line.length());
231  boost::algorithm::trim(token);
232  token = token.substr(0, token.find(' '));
233  boost::algorithm::trim(token);
234  boost::replace_all(token, ",", "");
235  if(!area_m)
236  {
238  }
239  area_m->set_resource_value(area_info::LUT_FF_PAIRS, std::stod(token));
240  area_m->set_area_value(std::stod(token));
241  }
242  else if(line.size() and line.find("Number of DSP48Es:") != std::string::npos)
243  {
244  std::string tk = "Number of DSP48Es:";
245  std::string token = line.substr(line.find(tk) + tk.size() + 1, line.length());
246  boost::algorithm::trim(token);
247  token = token.substr(0, token.find(' '));
248  boost::algorithm::trim(token);
249  boost::replace_all(token, ",", "");
250  if(!area_m)
251  {
253  }
254  area_m->set_resource_value(area_info::DSP, std::stod(token));
255  }
256  else if(line.size() and line.find("Number of DSP48E1s:") != std::string::npos)
257  {
258  std::string tk = "Number of DSP48E1s:";
259  std::string token = line.substr(line.find(tk) + tk.size() + 1, line.length());
260  boost::algorithm::trim(token);
261  token = token.substr(0, token.find(' '));
262  boost::algorithm::trim(token);
263  boost::replace_all(token, ",", "");
264  if(!area_m)
265  {
267  }
268  area_m->set_resource_value(area_info::DSP, std::stod(token));
269  }
270  else if(line.size() and line.find("Number of BlockRAM/FIFO:") != std::string::npos)
271  {
272  std::string tk = "Number of BlockRAM/FIFO:";
273  std::string token = line.substr(line.find(tk) + tk.size() + 1, line.length());
274  boost::algorithm::trim(token);
275  token = token.substr(0, token.find(' '));
276  boost::algorithm::trim(token);
277  boost::replace_all(token, ",", "");
278  if(!area_m)
279  {
281  }
282  area_m->set_resource_value(area_info::BRAM, std::stod(token));
283  }
284  else if(line.size() and line.find("Number of RAMB36E1/FIFO36E1s:") != std::string::npos)
285  {
286  std::string tk = "Number of RAMB36E1/FIFO36E1s:";
287  std::string token = line.substr(line.find(tk) + tk.size() + 1, line.length());
288  boost::algorithm::trim(token);
289  token = token.substr(0, token.find(' '));
290  boost::algorithm::trim(token);
291  boost::replace_all(token, ",", "");
292  if(!area_m)
293  {
295  }
296  area_m->set_resource_value(area_info::BRAM, std::stod(token));
297  }
298  else if(line.size() and line.find("Number of FIFO16/RAMB16s:") != std::string::npos)
299  {
300  std::string tk = "Number of FIFO16/RAMB16s:";
301  std::string token = line.substr(line.find(tk) + tk.size() + 1, line.length());
302  boost::algorithm::trim(token);
303  token = token.substr(0, token.find(' '));
304  boost::algorithm::trim(token);
305  boost::replace_all(token, ",", "");
306  if(!area_m)
307  {
309  }
310  area_m->set_resource_value(area_info::BRAM, std::stod(token));
311  }
312  }
313  }
314 }
315 
316 void XilinxBackendFlow::xparse_xst_utilization(const std::string& fn)
317 {
318  try
319  {
320  XMLDomParser parser(fn);
321  parser.Exec();
322  if(parser)
323  {
324  // Walk the tree:
325  const xml_element* node = parser.get_document()->get_root_node(); // deleted by DomParser.
326  THROW_ASSERT(node->get_name() == "document", "Wrong root name: " + node->get_name());
327 
328  const xml_node::node_list list_int = node->get_children();
329  for(const auto& iter_int : list_int)
330  {
331  const auto* EnodeC = GetPointer<const xml_element>(iter_int);
332  if(!EnodeC)
333  {
334  continue;
335  }
336 
337  if(EnodeC->get_name() == "application")
338  {
339  const xml_node::node_list list_sec = EnodeC->get_children();
340  for(const auto& iter_sec : list_sec)
341  {
342  const auto* nodeS = GetPointer<const xml_element>(iter_sec);
343  if(!nodeS)
344  {
345  continue;
346  }
347 
348  if(nodeS->get_name() == "section")
349  {
350  std::string stringID;
351  if(CE_XVM(stringID, nodeS))
352  {
353  LOAD_XVM(stringID, nodeS);
354  }
355  if(stringID == "XST_DEVICE_UTILIZATION_SUMMARY")
356  {
357  const xml_node::node_list list_item = nodeS->get_children();
358  for(const auto& it_item : list_item)
359  {
360  const auto* nodeIt = GetPointer<const xml_element>(it_item);
361  if(!nodeIt or nodeIt->get_name() != "item")
362  {
363  continue;
364  }
365 
366  if(CE_XVM(stringID, nodeIt))
367  {
368  LOAD_XVM(stringID, nodeIt);
369  }
370 
371  if(stringID != "XST_SELECTED_DEVICE")
372  {
373  std::string value;
374  if(CE_XVM(value, nodeIt))
375  {
376  LOAD_XVM(value, nodeIt);
377  boost::replace_all(value, ",", "");
378  design_values[stringID] = std::stod(value);
379  }
380  }
381  }
382  }
383  }
384  }
385  }
386  }
387 
390  {
392  }
394  {
396  }
398  {
400  }
401 
404  {
406  0; // it may happen when the component will be completely "destroyed" by the logic synthesisstep
407  }
408 
410  area_m->set_area_value(design_values[XST_NUMBER_OF_LUT_FLIP_FLOP_PAIRS_USED]);
411 
412  return;
413  }
414  }
415  catch(const char* msg)
416  {
417  std::cerr << msg << std::endl;
418  }
419  catch(const std::string& msg)
420  {
421  std::cerr << msg << std::endl;
422  }
423  catch(const std::exception& ex)
424  {
425  std::cout << "Exception caught: " << ex.what() << std::endl;
426  }
427  catch(...)
428  {
429  std::cerr << "unknown exception" << std::endl;
430  }
431  THROW_ERROR("Error during XST report parsing: " + fn);
432 }
433 
434 void XilinxBackendFlow::parse_timing(const std::string& log_file)
435 {
436  std::ifstream output_file(log_file.c_str());
437  if(output_file.is_open())
438  {
439  while(!output_file.eof())
440  {
441  std::string line;
442  getline(output_file, line);
443  if(line.size() and line.find("Minimum period:") != std::string::npos)
444  {
445  if(line.find("No path found") != std::string::npos)
446  {
449  }
450  else
451  {
452  std::string token("Minimum period:");
453  std::string tk = line.substr(line.find(token) + token.size() + 1, line.size());
454  boost::trim(tk);
455  tk = tk.substr(0, tk.find_first_of(' '));
456  boost::replace_all(tk, "ns", "");
458  time_m->set_execution_time(std::stod(tk));
459  if(std::stod(tk) > Param->getOption<double>(OPT_clock_period))
460  {
461  CopyFile(Param->getOption<std::string>(OPT_output_directory) + "/Synthesis/xst/" +
463  Param->getOption<std::string>(OPT_output_directory) + "/" + flow_name + "/" +
465  }
466  }
467  }
469  }
470  if(!time_m)
471  {
472  THROW_WARNING("Something wrong happened during synthesis.");
474  }
475  }
476 }
477 
478 void XilinxBackendFlow::parse_DSPs(const std::string& log_file)
479 {
480  std::ifstream output_file(log_file.c_str());
481  if(output_file.is_open())
482  {
483  while(!output_file.eof())
484  {
485  std::string line;
486  getline(output_file, line);
487  if(line.size() and line.find("Number of DSP48Es:") != std::string::npos)
488  {
489  std::string token("Number of DSP48Es:");
490  std::string tk = line.substr(line.find(token) + token.size() + 1, line.size());
491  boost::trim(tk);
492  tk = tk.substr(0, tk.find_first_of(' '));
493  THROW_ASSERT(area_m, "missing area model");
494  area_m->set_resource_value(area_info::DSP, std::stod(tk));
495  }
496  }
497  }
498 }
499 
500 void XilinxBackendFlow::xparse_timing(const std::string& fn)
501 {
502  try
503  {
504  XMLDomParser parser(fn);
505  parser.Exec();
506  if(parser)
507  {
508  // Walk the tree:
509  const xml_element* node = parser.get_document()->get_root_node(); // deleted by DomParser.
510  const xml_text_node* child_text = [&]() -> const xml_text_node* {
511  THROW_ASSERT(node->get_name() == "twReport", "Wrong root name: " + node->get_name());
512 
513  const xml_node::node_list list_int = node->get_children();
514  for(const auto& iter_int : list_int)
515  {
516  const auto* EnodeC = GetPointer<const xml_element>(iter_int);
517  if(!EnodeC)
518  {
519  continue;
520  }
521  if(flow_name == "Characterization" and EnodeC->get_name() == "twBody" &&
522  EnodeC->CGetDescendants("twErrRpt/twConst/twPathRpt/twConstPath/twSlack").size())
523  {
524  const auto tw_slacks = EnodeC->CGetDescendants("twErrRpt/twConst/twPathRpt/twConstPath/twSlack");
525  if(tw_slacks.size() == 0)
526  {
527  THROW_ERROR("Pattern not found in trce report");
528  }
529  if(tw_slacks.size() > 1)
530  {
531  THROW_ERROR("Found multiple twSlack fields");
532  }
533  const auto tw_slack = *(tw_slacks.begin());
534  THROW_ASSERT(GetPointer<const xml_element>(tw_slack), "");
535  return GetPointer<const xml_element>(tw_slack)->get_child_text();
536  }
537  else if(EnodeC->get_name() == "twSum")
538  {
539  const xml_node::node_list list = EnodeC->get_children();
540  for(const auto& iter : list)
541  {
542  const auto* Enode = GetPointer<const xml_element>(iter);
543  if(!Enode)
544  {
545  continue;
546  }
547  if(Enode->get_name() == "twStats")
548  {
549  const xml_node::node_list listS = Enode->get_children();
550  for(const auto& iterS : listS)
551  {
552  const auto* EnodeS = GetPointer<const xml_element>(iterS);
553  if(!EnodeS)
554  {
555  continue;
556  }
557  if(EnodeS->get_name() == "twMinPer" or EnodeS->get_name() == "twMaxCombDel")
558  {
559  return EnodeS->get_child_text();
560  }
561  }
562  }
563  }
564  }
565  }
566  THROW_UNREACHABLE("");
567  return nullptr;
568  }();
569  double period = std::abs(std::stod(child_text->get_content()));
571  time_m->set_execution_time(period);
572  return;
573  }
574  }
575  catch(const char* msg)
576  {
577  THROW_ERROR("Error during TRCE report (" + fn + ") :" + *msg);
578  }
579  catch(const std::string& msg)
580  {
581  THROW_ERROR("Error during TRCE report (" + fn + ") :" + msg);
582  }
583  catch(const std::exception& ex)
584  {
585  THROW_ERROR("Error during TRCE report (" + fn + ") :" + ex.what());
586  }
587  catch(...)
588  {
589  THROW_ERROR("Error during TRCE report (" + fn + ") :" + "Unknown exception");
590  }
591 }
592 
594 {
595  PRINT_OUT_MEX(OUTPUT_LEVEL_VERBOSE, output_level, "Analyzing Xilinx synthesis results");
596  bool is_vivado = false;
597  std::string device_string;
598  device_string = device->get_parameter<std::string>("family");
599  if(device_string.find("-VVD") != std::string::npos)
600  {
601  is_vivado = true;
602  }
603 
604  if(!is_vivado)
605  {
606  if(std::filesystem::exists(actual_parameters->parameter_values[PARAM_map_report]))
607  {
609  }
610  else if(std::filesystem::exists(actual_parameters->parameter_values[PARAM_xst_report]))
611  {
614  std::filesystem::exists(actual_parameters->parameter_values[PARAM_xst_log_file]))
615  {
617  }
618  }
619  else
620  {
621  THROW_ERROR("the script does not have a synthesis step");
622  }
623 
626  std::filesystem::exists(actual_parameters->parameter_values[PARAM_trce_report_post]))
627  {
629  }
632  std::filesystem::exists(actual_parameters->parameter_values[PARAM_trce_report_pre]))
633  {
635  }
638  std::filesystem::exists(actual_parameters->parameter_values[PARAM_xst_log_file]))
639  {
641  }
642  else
643  {
644  THROW_ERROR("the script does not have a timing evaluation step");
645  }
646  }
647  else
648  {
649  std::string report_filename = actual_parameters->parameter_values[PARAM_vivado_report];
650  vivado_xparse_utilization(report_filename);
654  {
656  }
657 
658  if(design_values[VIVADO_XILINX_SLICE_LUTS] != 0.0)
659  {
660  area_m->set_resource_value(area_info::SLICE_LUTS, design_values[VIVADO_XILINX_SLICE_LUTS]);
661  }
662 
668 
671  {
673  if(design_values[VIVADO_XILINX_DESIGN_DELAY] > Param->getOption<double>(OPT_clock_period) and
676  std::filesystem::exists(actual_parameters->parameter_values.find(PARAM_vivado_timing_report)->second))
677  {
679  Param->getOption<std::string>(OPT_output_directory) + "/" + flow_name + "/" +
681  }
682  }
683  else
684  {
686  }
687  }
689  (Param->IsParameter("DumpingTimingReport") and Param->GetParameter<int>("DumpingTimingReport"))) and
692  std::filesystem::exists(actual_parameters->parameter_values.find(PARAM_vivado_timing_report)->second))))
693  {
695  }
696 }
697 
699 {
700  try
701  {
702  XMLDomParser parser(fn);
703  parser.Exec();
704  if(parser)
705  {
706  // Walk the tree:
707  const xml_element* node = parser.get_document()->get_root_node(); // deleted by DomParser.
708  THROW_ASSERT(node->get_name() == "document", "Wrong root name: " + node->get_name());
709 
710  const xml_node::node_list list_int = node->get_children();
711  for(const auto& iter_int : list_int)
712  {
713  const auto* EnodeC = GetPointer<const xml_element>(iter_int);
714  if(!EnodeC)
715  {
716  continue;
717  }
718 
719  if(EnodeC->get_name() == "application")
720  {
721  const xml_node::node_list list_sec = EnodeC->get_children();
722  for(const auto& iter_sec : list_sec)
723  {
724  const auto* nodeS = GetPointer<const xml_element>(iter_sec);
725  if(!nodeS)
726  {
727  continue;
728  }
729 
730  if(nodeS->get_name() == "section")
731  {
732  std::string stringID;
733  if(CE_XVM(stringID, nodeS))
734  {
735  LOAD_XVM(stringID, nodeS);
736  }
737  if(stringID == "XILINX_SYNTHESIS_SUMMARY")
738  {
739  const xml_node::node_list list_item = nodeS->get_children();
740  for(const auto& it_item : list_item)
741  {
742  const auto* nodeIt = GetPointer<const xml_element>(it_item);
743  if(!nodeIt or nodeIt->get_name() != "item")
744  {
745  continue;
746  }
747 
748  if(CE_XVM(stringID, nodeIt))
749  {
750  LOAD_XVM(stringID, nodeIt);
751  }
752 
753  std::string value;
754  if(CE_XVM(value, nodeIt))
755  {
756  LOAD_XVM(value, nodeIt);
757  boost::replace_all(value, ",", "");
758  design_values[stringID] = std::stod(value);
759  }
760  }
761  }
762  }
763  }
764  }
765  }
766  return;
767  }
768  }
769  catch(const char* msg)
770  {
771  std::cerr << msg << std::endl;
772  }
773  catch(const std::string& msg)
774  {
775  std::cerr << msg << std::endl;
776  }
777  catch(const std::exception& ex)
778  {
779  std::cout << "Exception caught: " << ex.what() << std::endl;
780  }
781  catch(...)
782  {
783  std::cerr << "unknown exception" << std::endl;
784  }
785  THROW_ERROR("Error during VIVADO report parsing: " + fn);
786 }
787 
789 {
790  std::string setupscr;
791  std::string device_string;
792  device_string = device->get_parameter<std::string>("family");
793  if(device_string.find("-VVD") != std::string::npos)
794  {
795  setupscr =
796  Param->isOption(OPT_xilinx_vivado_settings) ? Param->getOption<std::string>(OPT_xilinx_vivado_settings) : "";
797  }
798  else
799  {
800  setupscr = Param->isOption(OPT_xilinx_settings) ? Param->getOption<std::string>(OPT_xilinx_settings) : "";
801  }
802  if(setupscr.size() && setupscr != "0")
803  {
804  script << "#configuration" << std::endl;
805  if(starts_with(setupscr, "export"))
806  {
807  script << setupscr + " >& /dev/null; ";
808  }
809  else
810  {
811  script << ". " << setupscr << " >& /dev/null; ";
812  }
813  script << std::endl << std::endl;
814  }
815 }
816 
818 {
820 }
821 
823 {
824  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->XilinxBackendFlow - Init Design Parameters");
825 
826  std::string ise_style;
828  {
829  ise_style = std::string(INTSTYLE_ISE);
830  }
831  else
832  {
833  ise_style = std::string(INTSTYLE_SILENT);
834  }
836 
838  bool xpwr_enabled = false;
839  if(Param->isOption("power_optimization") && Param->getOption<bool>("power_optimization"))
840  {
841  xpwr_enabled = true;
842  }
844  auto device_name = device->get_parameter<std::string>("model");
845  auto package = device->get_parameter<std::string>("package");
846  auto speed_grade = device->get_parameter<std::string>("speed_grade");
847  std::string device_string = device_name + package + speed_grade;
849 
850  bool is_vivado = false;
851  if(device->get_parameter<std::string>("family").find("-VVD") != std::string::npos)
852  {
853  is_vivado = true;
854  }
855 
856  if(is_vivado)
857  {
859  std::string HDL_files = actual_parameters->parameter_values[PARAM_HDL_files];
860  std::vector<std::string> file_list = string_to_container<std::vector<std::string>>(HDL_files, ";");
861  std::string sources_macro_list;
862  bool has_vhdl_library = Param->isOption(OPT_VHDL_library);
863  std::string vhdl_library;
864  if(has_vhdl_library)
865  {
866  vhdl_library = Param->getOption<std::string>(OPT_VHDL_library);
867  }
868  for(unsigned int v = 0; v < file_list.size(); v++)
869  {
870  if(v)
871  {
872  sources_macro_list += "\n";
873  }
874  std::filesystem::path file_path(file_list[v]);
875  std::string extension = file_path.extension().string();
876  if(extension == ".vhd" || extension == ".vhdl" || extension == ".VHD" || extension == ".VHDL")
877  {
878  if(has_vhdl_library)
879  {
880  sources_macro_list += "read_vhdl -library " + vhdl_library + " " + file_list[v];
881  }
882  else
883  {
884  sources_macro_list += "read_vhdl " + file_list[v];
885  }
886  }
887  else if(extension == ".v" || extension == ".V")
888  {
889  sources_macro_list += "read_verilog " + file_list[v];
890  }
891  else if(extension == ".sv" || extension == ".SV")
892  {
893  sources_macro_list += "read_verilog -sv " + file_list[v];
894  }
895  else
896  {
897  THROW_ERROR("Extension not recognized! " + extension);
898  }
899  }
901  if(Param->isOption(OPT_backend_sdc_extensions))
902  {
903  sources_macro_list += "\nread_xdc " + Param->getOption<std::string>(OPT_backend_sdc_extensions);
904  }
905 
907 
908  if(device->get_parameter<std::string>("family").find("-YOSYS-VVD") != std::string::npos)
909  {
910  sources_macro_list = "";
911  for(unsigned int v = 0; v < file_list.size(); v++)
912  {
913  if(v)
914  {
915  sources_macro_list += " -p ";
916  }
917  std::filesystem::path file_path(file_list[v]);
918  std::string extension = file_path.extension().string();
919  if(extension == ".v" || extension == ".V")
920  {
921  sources_macro_list += "\\\"read_verilog -defer " + file_list[v] + "\\\"";
922  }
923  else if(extension == ".sv" || extension == ".SV")
924  {
925  sources_macro_list += "\\\"read_verilog -sv -defer " + file_list[v] + "\\\"";
926  }
927  else
928  {
929  THROW_ERROR("Extension not recognized! " + extension);
930  }
931  }
933  }
934  }
935  else
936  {
939  }
940  for(auto& step : steps)
941  {
942  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Evaluating variables of step " + step->name);
943  step->tool->EvaluateVariables(actual_parameters);
944  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Evaluated variables of step " + step->name);
945  }
946  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--XilinxBackendFlow - Init Design Parameters");
947 }
948 
950 {
951  std::string ucf_filename = UCF_SUBDIR + dp->component_name + (xst ? ".xcf" : ".ucf");
952  std::ofstream UCF_file(ucf_filename);
953  THROW_ASSERT(dp->parameter_values.find(PARAM_clk_name) != dp->parameter_values.end(), "");
954  if(!static_cast<bool>(std::stoi(dp->parameter_values[PARAM_is_combinational])))
955  {
956  UCF_file << "NET \"" << dp->parameter_values[PARAM_clk_name]
957  << "\" TNM_NET = " << dp->parameter_values[PARAM_clk_name] << ";" << std::endl;
958  if(xst)
959  {
960  UCF_file << "BEGIN MODEL \"" << dp->component_name << "\"" << std::endl;
961  UCF_file << "NET \"" << dp->parameter_values[PARAM_clk_name] << "\" buffer_type=bufgp;" << std::endl;
962  UCF_file << "END;" << std::endl;
963  }
964  UCF_file << "TIMESPEC TS_" << dp->parameter_values[PARAM_clk_name] << " = PERIOD \""
966  << " ns HIGH 50%;" << std::endl;
967  }
968  else if(Param->isOption(OPT_connect_iob) && not Param->getOption<bool>(OPT_connect_iob))
969  {
970  THROW_ERROR("ISE needs IOB to perform timing analysis of combinational circuit");
971  }
972 
973  UCF_file.close();
974  if(xst)
975  {
976  dp->parameter_values[PARAM_xcf_file] = ucf_filename;
977  }
978  else
979  {
980  dp->parameter_values[PARAM_ucf_file] = ucf_filename;
981  }
982 }
#define PARAM_vivado_report
Wrapper to trce by XILINX.
#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.
#define PARAM_target_device
void parse_DSPs(const std::string &log_file)
retrieve the number of DSPs from the xst log
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 DEBUG_LEVEL_PEDANTIC
very verbose debugging print is performed.
DesignParametersRef actual_parameters
set of design parameters with the actual values
#define GET_CLASS(obj)
Macro returning the actual type of an object.
#define PARAM_xcf_file
#define PARAM_trce_report_post
constants used in synthesis wrappers
#define INDENT_OUT_MEX(outLevel, curOutLevel, mex)
void set_execution_time(double execution_time, unsigned int cycles=time_info::cycles_time_DEFAULT)
Definition: time_info.cpp:64
#define VIVADO_XILINX_LUT_FLIP_FLOP_PAIRS_USED
void xparse_timing(const std::string &fn)
Fixed the parsing of timing results from trce.
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
#define PARAM_map_report
Definition: map_wrapper.hpp:53
~XilinxBackendFlow() override
Destructor.
std::string flow_name
string-based identifier of the flow
void set_resource_value(value_t val, double num)
Definition: area_info.cpp:67
#define abs(x)
Definition: main.c:3
void parse_timing(const std::string &log_file)
Fixed the parsing of timing results from xst.
void parse_flow(const XMLDomParserRef parser)
Creates the synthesis flow based on the user&#39;s requirements.
time_infoRef time_m
pointer to the data structure containing timing information
const generic_deviceRef device
information about the target device
#define UCF_SUBDIR
int debug_level
debugging level of the class
Wrapper to synthesis tools by Xilinx.
Wrapper to implement a synthesis tools by Xilinx.
#define THROW_WARNING(str_expr)
helper function used to throw a warning in a standard way: though it uses PRINT_DBG_MEX, the debug level used is such that the message is always printed
Definition: exceptions.hpp:300
#define STR(s)
Macro which performs a lexical_cast to a string.
#define XST_NUMBER_OF_SLICE_REGISTERS
void vivado_xparse_utilization(const std::string &fn)
parse vivado results
void line(int x1, int y1, int x2, int y2, unsigned int color)
Definition: main.c:110
Auxiliary methods for manipulating string.
#define VIVADO_XILINX_DSPS
#define XST_NUMBER_OF_SLICE_LUTS
void CheckSynthesisResults() override
Checks the synthesis results and fills the corresponding data-structures.
#define THROW_UNREACHABLE(str_expr)
helper function used to specify that some points should never be reached
Definition: exceptions.hpp:292
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
virtual void create_cf(const DesignParametersRef dp, bool xst)
Creates the UCF file.
#define VIVADO_XILINX_SLICE_REGISTERS
This file contains the definition of the parameters for the synthesis tools.
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.
#define VIVADO_XILINX_SLICE
#define VIVADO_XILINX_POWER
void ExecuteSynthesis() override
Checks if the execution can be performed and, in case, performs the synthesis.
XilinxBackendFlow(const ParameterConstRef Param, const std::string &flow_name, const generic_deviceRef _device)
Constructor.
This file collects some utility functions and macros.
void xparse_map_utilization(const std::string &fn)
Parses the utilization file in XML format.
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 PARAM_xst_log_file
void InitDesignParameters() override
Initializes the parameters.
#define PARAM_vivado_timing_report
#define XST_NUMBER_OF_LUT_FLIP_FLOP_PAIRS_USED
Classes for handling configuration files.
std::map< std::string, double > design_values
results from the synthesis
#define VIVADO_XILINX_SLICE_LUTS
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 component_name
Name of the component.
#define INTSTYLE_SILENT
#define PARAM_power_optimization
#define OUTPUT_LEVEL_VERY_PEDANTIC
verbose debugging print is performed.
void WriteFlowConfiguration(std::ostream &script) override
Writes the proper flow configuration in the output script.
unsigned int output_level
verbosity level of the class
#define VIVADO_XILINX_DESIGN_DELAY
#define PARAM_ise_style
void set_area_value(const double &_area_)
Set the nominal value for the area of the component.
Definition: area_info.cpp:62
std::string get_content() const
Get the text of this content node.
void xparse_xst_utilization(const std::string &fn)
Parses the utilization file in XML format.
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_yosys_vivado_sources_macro_list
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_xst_report
Wrapper to map by XILINX.
node_list const & get_children()
Obtain the list of child nodes.
Definition: xml_node.hpp:310
#define PARAM_clk_period
Generic device description.
#define PARAM_ucf_file
#define PRINT_OUT_MEX(profLevel, curprofLevel, mex)
void CopyStdout(const std::string &filename)
Copy a file to the standard output.
Definition: fileIO.hpp:106
#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 VIVADO_XILINX_BLOCK_RAMFIFO
#define PARAM_clk_name
#define INTSTYLE_ISE
static time_infoRef factory(const ParameterConstRef Param)
Definition: time_info.cpp:110
#define XST_NUMBER_OF_BLOCK_RAMFIFO
#define PARAM_HDL_files
#define PARAM_trce_report_pre
#define PARAM_vivado_sources_macro_list
#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