PandA-2024.02
hls_c_writer.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  */
43 #include "hls_c_writer.hpp"
44 
45 #include "Parameter.hpp"
47 #include "behavioral_helper.hpp"
49 #include "call_graph_manager.hpp"
50 #include "custom_map.hpp"
51 #include "custom_set.hpp"
52 #include "dbgPrintHelper.hpp" // for DEBUG_LEVEL_NONE
53 #include "function_behavior.hpp"
54 #include "hls_manager.hpp"
56 #include "instruction_writer.hpp"
57 #include "math_function.hpp"
58 #include "memory.hpp"
60 #include "string_manipulation.hpp" // for GET_CLASS
61 #include "structural_objects.hpp"
62 #include "technology_node.hpp"
63 #include "testbench_generation.hpp"
65 #include "tree_helper.hpp"
66 #include "tree_manager.hpp"
67 #include "tree_node.hpp"
68 #include "tree_reindex.hpp"
69 #include "var_pp_functor.hpp"
70 
71 #include <boost/algorithm/string/trim_all.hpp>
72 #include <regex>
73 
74 #include <list>
75 #include <string>
76 #include <vector>
77 
79 
80 static const std::regex wrapper_def("(ac_channel|stream|hls::stream)<(.*)>");
81 #define WRAPPER_GROUP_WTYPE 2
82 
84  const InstructionWriterRef _instruction_writer,
85  const IndentedOutputStreamRef _indented_output_stream, const ParameterConstRef _parameters,
86  bool _verbose)
87  : CWriter(_HLSMgr, _instruction_writer, _indented_output_stream, _parameters, _verbose),
88  c_backend_info(_c_backend_info)
89 {
90  debug_level = _parameters->get_class_debug_level(GET_CLASS(*this));
91 }
92 
93 HLSCWriter::~HLSCWriter() = default;
94 
96 {
98 #define _FILE_OFFSET_BITS 64
99 
100 #define __Inf (1.0 / 0.0)
101 #define __Nan (0.0 / 0.0)
102 
103 #ifdef __cplusplus
104 #undef printf
105 
106 #include <cstdio>
107 #include <cstdlib>
108 
109 typedef bool _Bool;
110 #else
111 #include <stdio.h>
112 #include <stdlib.h>
113 
114 extern void exit(int status);
115 #endif
116 
117 #include <sys/types.h>
118 
119 #ifdef __AC_NAMESPACE
120 using namespace __AC_NAMESPACE;
121 #endif
122 
123 #ifdef __clang__
124 #define GCC_VERSION 0
125 #else
126 #define GCC_VERSION (__GNUC__ * 10000 \
127  + __GNUC_MINOR__ * 100 \
128  + __GNUC_PATCHLEVEL__)
129 #endif
130 
131 )");
132 
133  // get the root function to be tested by the testbench
134  const auto top_function_ids = HLSMgr->CGetCallGraphManager()->GetRootFunctions();
136  CustomSet<std::string> top_fnames;
137  for(auto function_id : top_function_ids)
138  {
139  const auto fnode = TM->CGetTreeNode(function_id);
140  const auto fd = GetPointerS<const function_decl>(fnode);
141  const auto fname = tree_helper::GetMangledFunctionName(fd);
142  const auto& parms = HLSMgr->module_arch->GetArchitecture(fname)->parms;
143  for(const auto& [parm, attrs] : parms)
144  {
145  const auto attr_it = attrs.find(FunctionArchitecture::parm_includes);
146  if(attr_it != attrs.end())
147  {
148  string_to_container(std::inserter(includes, includes.end()), attr_it->second, ";");
149  }
150  }
151  top_fnames.insert(fname);
152  }
153  if(includes.size())
154  {
155  for(const auto& fname : top_fnames)
156  {
157  indented_output_stream->Append("#define " + fname + " __keep_your_declaration_out_of_my_code\n");
158  }
159  for(const auto& inc : includes)
160  {
161  indented_output_stream->Append("#include \"" + inc + "\"\n");
162  }
163  for(const auto& fname : top_fnames)
164  {
165  indented_output_stream->Append("#undef " + fname + "\n");
166  }
167  }
169 
170 #ifndef CDECL
171 #ifdef __cplusplus
172 #define CDECL extern "C"
173 #else
174 #define CDECL
175 #endif
176 #endif
177 
178 #ifndef EXTERN_CDECL
179 #ifdef __cplusplus
180 #define EXTERN_CDECL extern "C"
181 #else
182 #define EXTERN_CDECL extern
183 #endif
184 #endif
185 
186 )");
187 }
188 
190 {
191  instrWriter->write_declarations();
192 }
193 
195 {
196  indented_output_stream->Append("// parameters declaration\n");
197 
198  for(const auto& par : BH->GetParameters())
199  {
200  const auto parm_type = tree_helper::CGetType(par);
201  const auto type = tree_helper::IsPointerType(par) ? "void*" : tree_helper::PrintType(TM, parm_type);
202  const auto param = BH->PrintVariable(par->index);
203 
204  if(tree_helper::IsVectorType(parm_type))
205  {
206  THROW_ERROR("parameter " + param + " of function under test " + BH->get_function_name() + " has type " + type +
207  "\nco-simulation does not support vectorized parameters at top level");
208  }
209  indented_output_stream->Append(type + " " + param + ";\n");
210  }
211 }
212 
214  const std::map<std::string, std::string>& curr_test_vector)
215 {
216  const auto fname = BH->GetMangledFunctionName();
217  const auto& parm_attrs = HLSMgr->module_arch->GetArchitecture(fname)->parms;
218  const auto params = BH->GetParameters();
219  for(auto par_idx = 0U; par_idx < params.size(); ++par_idx)
220  {
221  const auto& par = params.at(par_idx);
222  const auto parm_type = tree_helper::CGetType(par);
223  const auto param = BH->PrintVariable(GET_INDEX_CONST_NODE(par));
224  const auto has_file_init = [&]() {
225  if(parm_attrs.size()) // FIX: this is probably always true
226  {
227  const auto& type_name = parm_attrs.at(param).at(FunctionArchitecture::parm_typename);
228  return std::regex_search(type_name.c_str(), wrapper_def);
229  }
230  return false;
231  }();
232  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Writing initialization of " + param);
234  "---Type: " + GET_CONST_NODE(parm_type)->get_kind_text() + " - " + STR(parm_type));
235  const auto init_it = curr_test_vector.find(param);
236  if(init_it == curr_test_vector.end())
237  {
238  THROW_ERROR("Value of " + param + " is missing in test vector");
239  }
240  const auto test_v =
241  (has_file_init && ends_with(init_it->second, ".dat")) ? ("\"" + init_it->second + "\"") : init_it->second;
242  if(tree_helper::IsPointerType(parm_type))
243  {
244  const auto is_binary_init = ends_with(test_v, ".dat");
245 
246  std::string var_ptdtype;
247  std::string temp_var_decl;
248  bool is_a_true_pointer = true;
249  if(!is_binary_init && parm_attrs.size())
250  {
251  var_ptdtype = parm_attrs.at(param).at(FunctionArchitecture::parm_original_typename);
252  static const std::regex voidP = std::regex(R"(\bvoid\b)");
253  while(std::regex_search(var_ptdtype, voidP))
254  {
255  var_ptdtype = std::regex_replace(var_ptdtype, voidP, "char");
256  }
257  is_a_true_pointer = var_ptdtype.back() == '*';
258  if(is_a_true_pointer || var_ptdtype.back() == '&')
259  {
260  var_ptdtype.pop_back();
261  }
262  if(var_ptdtype.find("(*)") != std::string::npos)
263  {
264  temp_var_decl = var_ptdtype;
265  temp_var_decl.replace(var_ptdtype.find("(*)"), 3, param + "_temp[]");
266  }
267  else
268  {
269  temp_var_decl = var_ptdtype + " " + param + "_temp" + (is_a_true_pointer ? "[]" : "");
270  }
271  }
272  if(temp_var_decl == "")
273  {
274  const auto var_functor = var_pp_functorRef(new std_var_pp_functor(BH));
275  const auto ptd = tree_helper::CGetPointedType(parm_type);
276  temp_var_decl = tree_helper::PrintType(TM, ptd, false, false, false, par, var_functor);
277  var_ptdtype = temp_var_decl.substr(0, temp_var_decl.find_last_of((*var_functor)(par->index)));
278  if(tree_helper::IsVoidType(ptd))
279  {
280  boost::replace_all(temp_var_decl, "void ", "char ");
281  boost::replace_all(var_ptdtype, "void ", "char ");
282  }
283  const auto first_square = temp_var_decl.find('[');
284  if(first_square == std::string::npos)
285  {
286  temp_var_decl = temp_var_decl + "_temp[]";
287  }
288  else
289  {
290  temp_var_decl.insert(first_square, "_temp[]");
291  }
292  }
293  THROW_ASSERT(temp_var_decl.size() && var_ptdtype.size(),
294  "var_decl: " + temp_var_decl + ", ptd_type: " + var_ptdtype);
295  const auto arg_channel = std::regex_search(var_ptdtype, std::regex("(ac_channel|stream|hls::stream)<(.*)>"));
296  const auto ptd_type = tree_helper::GetRealType(tree_helper::CGetPointedType(parm_type));
298  "---Pointed type: " + GET_CONST_NODE(ptd_type)->get_kind_text() + " - " + STR(ptd_type));
299 
300  std::string param_size;
301  if(is_binary_init)
302  {
303  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Initialized from binary file: " + test_v);
304  const auto fp = param + "_fp";
305  indented_output_stream->Append("FILE* " + fp + " = fopen(\"" + test_v + "\", \"rb\");\n");
306  indented_output_stream->Append("fseek(" + fp + ", 0, SEEK_END);\n");
307  indented_output_stream->Append("size_t " + param + "_size = ftell(" + fp + ");\n");
308  indented_output_stream->Append("fseek(" + fp + ", 0, SEEK_SET);\n");
309  indented_output_stream->Append("void* " + param + "_buf = malloc(" + param + "_size);\n");
310  indented_output_stream->Append("if(fread((unsigned char*)" + param + "_buf, 1, " + param + "_size, " + fp +
311  ") != " + param + "_size)\n");
313  indented_output_stream->Append("fclose(" + fp + ");\n");
314  indented_output_stream->Append("printf(\"Unable to read " + test_v + " to initialize parameter " + param +
315  "\");\n");
316  indented_output_stream->Append("exit(-1);\n");
318  indented_output_stream->Append("fclose(" + fp + ");\n");
319  indented_output_stream->Append(param + " = " + param + "_buf;\n");
320  indented_output_stream->Append("m_param_alloc(" + STR(par_idx) + ", " + param + "_size);\n");
321  }
322  else
323  {
324  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Inline pointer initialization");
325  const auto temp_initialization =
326  temp_var_decl + " = " +
327  ((test_v.front() != '{' && test_v.back() != '}' && is_a_true_pointer) ? "{" + test_v + "}" : test_v) +
328  ";\n";
329  indented_output_stream->Append(temp_initialization);
330  indented_output_stream->Append(param + " = (void*)" + (is_a_true_pointer ? "" : "&") + param + "_temp;\n");
331  if(!arg_channel)
332  {
333  indented_output_stream->Append("m_param_alloc(" + STR(par_idx) + ", sizeof(" + param + "_temp));\n");
334  }
335  }
336  }
337  else
338  {
339  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Inline initialization");
340  if(tree_helper::IsRealType(parm_type) && test_v == "-0")
341  {
342  indented_output_stream->Append(param + " = -0.0;\n");
343  }
344  else
345  {
346  indented_output_stream->Append(param + " = " + test_v + ";\n");
347  }
348  }
349  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Written initialization of " + param);
350  }
351 }
352 
354 {
355  const auto function_index = BH->get_function_index();
356  const auto return_type_index = BH->GetFunctionReturnType(function_index);
357 
358  const auto top_fname_mngl = BH->GetMangledFunctionName();
359  const auto function_name = [&]() -> std::string {
360  const auto is_discrepancy = (Param->isOption(OPT_discrepancy) && Param->getOption<bool>(OPT_discrepancy)) ||
361  (Param->isOption(OPT_discrepancy_hw) && Param->getOption<bool>(OPT_discrepancy_hw));
362  if(is_discrepancy)
363  {
364  // avoid collision with the main
365  if(top_fname_mngl == "main")
366  {
367  return "_main";
368  }
369  return BH->get_function_name();
370  }
371  return top_fname_mngl;
372  }();
373  if(return_type_index)
374  {
376  }
377 
378  indented_output_stream->Append(function_name + "(");
379  bool is_first_argument = true;
380  const auto& parms = HLSMgr->module_arch->GetArchitecture(top_fname_mngl)->parms;
381  for(const auto& par : BH->GetParameters())
382  {
383  const auto param = BH->PrintVariable(GET_INDEX_CONST_NODE(par));
384  if(!is_first_argument)
385  {
387  }
388  else
389  {
390  is_first_argument = false;
391  }
393  {
394  auto arg_typename = parms.at(param).at(FunctionArchitecture::parm_original_typename);
395  if(arg_typename.find("(*)") != std::string::npos)
396  {
397  arg_typename = arg_typename.substr(0, arg_typename.find("(*)")) + "*";
398  }
399  if(arg_typename.back() != '*')
400  {
402  indented_output_stream->Append(arg_typename.substr(0, arg_typename.size() - (arg_typename.back() == '&')) +
403  "*");
405  }
406  else
407  {
409  indented_output_stream->Append(arg_typename);
411  }
412  }
414  }
416 }
417 
418 void HLSCWriter::WriteSimulatorInitMemory(const unsigned int function_id)
419 {
420  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Writing simulator init memory");
421  const auto mem_vars = HLSMgr->Rmem->get_ext_memory_variables();
422  const auto BH = HLSMgr->CGetFunctionBehavior(function_id)->CGetBehavioralHelper();
423  const auto parameters = BH->get_parameters();
424 
425  const auto align_bus = std::max(8ULL, HLSMgr->Rmem->get_bus_data_bitsize() / 8ULL);
426  const auto align_infer = [&]() {
427  const auto funcSymbol = BH->GetMangledFunctionName();
428  const auto& ifaces = HLSMgr->module_arch->GetArchitecture(funcSymbol)->ifaces;
429  unsigned long long max = 0ULL;
430  for(const auto& [name, attrs] : ifaces)
431  {
432  max = std::max(max, std::stoull(attrs.at(FunctionArchitecture::iface_alignment)));
433  }
434  return max;
435  }();
436  const auto align = std::max(align_bus, align_infer);
437  const auto tb_map_mode = "MDPI_MEMMAP_" + Param->getOption<std::string>(OPT_testbench_map_mode);
438 
440 typedef struct
441 {
442 const char* filename;
443 size_t size;
444 const ptr_t addrmap;
445 void* addr;
446 } __m_memmap_t;
447 
448 typedef struct
449 {
450 void* addr;
451 size_t align;
452 void* map_addr;
453 } __m_argmap_t;
454 
455 static void __m_memsetup(__m_argmap_t args[], size_t args_count)
456 {
457 int error = 0;
458 size_t i;
459 )");
460  auto base_addr = HLSMgr->base_address;
461  indented_output_stream->Append("static __m_memmap_t memmap_init[] = {\n");
462  if(mem_vars.size())
463  {
464  const auto output_directory = Param->getOption<std::string>(OPT_output_directory) + "/simulation/";
465  for(const auto& mem_var : mem_vars)
466  {
467  const auto var_id = mem_var.first;
468  const auto is_top_param = std::find(parameters.begin(), parameters.end(), var_id) != parameters.end();
469  if(!is_top_param)
470  {
471  const auto var_name = BH->PrintVariable(var_id);
472  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Writing initialization for " + var_name);
473  const auto var_addr = HLSMgr->Rmem->get_external_base_address(var_id);
474  const auto var_init_dat = output_directory + "mem_" + STR(var_id) + "." + var_name + ".dat";
475  const auto byte_count = TestbenchGeneration::generate_init_file(var_init_dat, TM, var_id, HLSMgr->Rmem);
476  indented_output_stream->Append(" {\"" + boost::replace_all_copy(var_init_dat, "\"", "\\\"") + "\", " +
477  STR(byte_count) + ", " + STR(var_addr) + ", NULL},\n");
478  base_addr = std::max(base_addr, var_addr + byte_count);
479  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Init file : '" + var_init_dat + "'");
480  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Memory usage: " + STR(byte_count) + " bytes");
481  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Base address: " + STR(var_addr));
483  }
484  }
485  }
487  indented_output_stream->Append("const ptr_t align = " + STR(align) + ";\n");
488  indented_output_stream->Append("ptr_t base_addr = " + STR(base_addr) + ";\n\n");
489 
490  indented_output_stream->Append("__m_memmap_init(" + tb_map_mode + ");\n");
492 
493 // Memory-mapped internal variables initialization
494 for(i = 0; i < sizeof(memmap_init) / sizeof(*memmap_init); ++i)
495 {
496 FILE* fp = fopen(memmap_init[i].filename, "rb");
497 if(!fp)
498 {
499 error("Unable to open file: %s\n", memmap_init[i].filename);
500 perror("Unable to open memory variable initialization file");
501 error |= 2;
502 continue;
503 }
504 if(memmap_init[i].addr == NULL)
505 {
506 memmap_init[i].addr = malloc(memmap_init[i].size);
507 }
508 size_t nbytes = fread(memmap_init[i].addr, 1, memmap_init[i].size, fp);
509 if(nbytes != memmap_init[i].size)
510 {
511 error("Only %zu/%zu bytes were read from file: %s\n", nbytes, memmap_init[i].size, memmap_init[i].filename);
512 if(ferror(fp))
513 {
514 perror("Unable to read from memory variable initialization file");
515 }
516 error |= 4;
517 fclose(fp);
518 continue;
519 }
520 fclose(fp);
521 error |= __m_memmap(memmap_init[i].addrmap, memmap_init[i].addr, memmap_init[i].size);
522 }
523 
524 for(i = 0; i < args_count; ++i)
525 {
526 if(args[i].map_addr == NULL)
527 {
528 args[i].map_addr = args[i].addr;
529 continue;
530 }
531 const size_t arg_size = __m_param_size(i);
532 size_t map_size = arg_size;
533 base_addr += (align - 1) - ((base_addr - 1) % align);
534 args[i].map_addr = args[i].addr;
535 if(arg_size % args[i].align)
536 {
537 map_size = arg_size + (args[i].align - 1) - ((arg_size - 1) % args[i].align);
538 info("Parameter %zu map size extended: %zu bytes -> %zu bytes\n", i, arg_size, map_size);
539 args[i].map_addr = malloc(map_size);
540 memcpy(args[i].map_addr, args[i].addr, arg_size);
541 }
542 error |= __m_memmap(base_addr, args[i].map_addr, map_size);
543 base_addr += map_size;
544 }
545 if(error)
546 {
547 __m_abort();
548 }
549 }
550 
551 static void __m_argmap_fini(__m_argmap_t args[], size_t args_count)
552 {
553 size_t i = 0;
554 for(i = 0; i < args_count; i++)
555 {
556 if(args[i].map_addr != args[i].addr)
557 {
558 memcpy(args[i].addr, args[i].map_addr, __m_param_size(i));
559 free(args[i].map_addr);
560 args[i].map_addr = args[i].addr;
561 }
562 }
563 }
564 
565 )");
566  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Written simulator init memory");
567 }
568 
570 {
571 }
572 
574 {
575 }
576 
578 {
579  const auto top_symbols = Param->getOption<std::vector<std::string>>(OPT_top_functions_names);
580  THROW_ASSERT(top_symbols.size() == 1, "Expected single top function name");
581  const auto top_fnode = TM->GetFunction(top_symbols.front());
582  const auto top_fb = HLSMgr->CGetFunctionBehavior(GET_INDEX_CONST_NODE(top_fnode));
583  const auto top_bh = top_fb->CGetBehavioralHelper();
584  const auto top_fname = top_bh->get_function_name();
585  const auto top_fname_mngl = top_bh->GetMangledFunctionName();
586  const auto interface_type = Param->getOption<HLSFlowStep_Type>(OPT_interface_type);
587  const auto is_interface_inferred = interface_type == HLSFlowStep_Type::INFERRED_INTERFACE_GENERATION;
588  const auto& func_arch = HLSMgr->module_arch->GetArchitecture(top_fname_mngl);
589  THROW_ASSERT(func_arch, "Expected interface architecture for function " + top_fname_mngl);
590 
591  const auto return_type = tree_helper::GetFunctionReturnType(top_fnode);
592  const auto top_params = top_bh->GetParameters();
593  const auto args_decl_size = top_params.size() + (return_type != nullptr);
594  const auto has_subnormals = Param->isOption(OPT_fp_subnormal) && Param->getOption<bool>(OPT_fp_subnormal);
595  const auto cmp_type = [&](tree_nodeConstRef t, const std::string& tname) -> std::string {
596  if(std::regex_search(tname, std::regex("^a[pc]_u?(int|fixed)<")))
597  {
598  return "val";
599  }
600  else if(std::regex_search(tname, std::regex(R"((\bfloat\b|\bdouble\b))")))
601  {
602  return has_subnormals ? "flts" : "flt";
603  }
604  else if(t)
605  {
607  {
609  }
610  while(tree_helper::IsArrayType(t))
611  {
613  }
615  {
616  return has_subnormals ? "flts" : "flt";
617  }
619  starts_with(tname, "void"))
620  {
621  return "mem";
622  }
623  }
624  return "val";
625  };
626  const auto param_size_default = [&]() {
628  if(Param->isOption(OPT_testbench_param_size))
629  {
630  const auto param_size_str = Param->getOption<std::string>(OPT_testbench_param_size);
631  size_t param_idx = 0;
632  for(const auto& param : top_bh->GetParameters())
633  {
634  const auto parm_name = top_bh->PrintVariable(GET_INDEX_CONST_NODE(param));
635  std::cmatch what;
636  if(std::regex_search(param_size_str.c_str(), what, std::regex("\\b" + parm_name + ":(\\d+)")))
637  {
638  idx_size[param_idx] = what[1u].str();
639  }
640  ++param_idx;
641  }
642  }
643  return idx_size;
644  }();
645 
646  std::string top_decl;
647  std::string gold_decl = "EXTERN_CDECL ";
648  std::string pp_decl = tree_helper::PrintType(TM, top_fnode, false, true, false, nullptr,
650  ";\n";
651  THROW_ASSERT(pp_decl.find(top_fname) != std::string::npos, "");
652  boost::replace_first(pp_decl, top_fname, "__m_pp_" + top_fname);
653  std::string gold_call;
654  std::string pp_call;
655  std::string args_init;
656  std::string args_decl = "__m_argmap_t args[] = {\n";
657  std::string args_set;
658  std::string gold_cmp;
659  size_t param_idx = 0;
660  if(return_type)
661  {
662  const auto return_type_str = tree_helper::PrintType(TM, return_type);
663  top_decl += return_type_str;
664  gold_decl += return_type_str;
665  gold_call += "retval_gold = ";
666  pp_call += "retval_pp = ";
667  args_decl = return_type_str + " retval, retval_gold, retval_pp;\n" + args_decl;
668  }
669  else
670  {
671  top_decl += "void";
672  gold_decl += "void";
673  }
674  top_decl += " " + top_fname_mngl + "(";
675  gold_decl += " " + cxa_prefix_mangled(top_fname_mngl, "__m_") + "(";
676  gold_call += cxa_prefix_mangled(top_fname_mngl, "__m_") + "(";
677  pp_call += "__m_pp_" + top_fname + "(";
678  if(top_params.size())
679  {
680  for(const auto& arg : top_params)
681  {
682  const auto parm_name = top_bh->PrintVariable(GET_INDEX_CONST_NODE(arg));
683  THROW_ASSERT(func_arch->parms.find(parm_name) != func_arch->parms.end(),
684  "Attributes missing for parameter " + parm_name + " in function " + top_fname);
685  const auto& parm_attrs = func_arch->parms.at(parm_name);
686  const auto& iface_attrs = func_arch->ifaces.at(parm_attrs.at(FunctionArchitecture::parm_bundle));
687  const auto arg_type = tree_helper::CGetType(arg);
688  const auto& arg_interface = iface_attrs.at(FunctionArchitecture::iface_mode);
689  const auto& arg_bitsize = iface_attrs.at(FunctionArchitecture::iface_bitwidth);
690  const auto arg_align = [&]() {
691  if(iface_attrs.find(FunctionArchitecture::iface_cache_bus_size) != iface_attrs.end())
692  {
693  const auto bus_size = std::stoull(iface_attrs.at(FunctionArchitecture::iface_cache_bus_size));
694  const auto line_size = std::stoull(iface_attrs.at(FunctionArchitecture::iface_cache_line_size));
695  return std::to_string(line_size * bus_size / 8ULL);
696  }
697  return iface_attrs.at(FunctionArchitecture::iface_alignment);
698  }();
699  std::string iface_type, arg_size;
700 
701  auto arg_typename = parm_attrs.at(FunctionArchitecture::parm_original_typename);
702  if(arg_typename.find("(*)") != std::string::npos)
703  {
704  arg_typename = arg_typename.substr(0, arg_typename.find("(*)")) + "*";
705  }
706  const auto arg_name = "P" + std::to_string(param_idx);
707  const auto is_pointer_type = arg_typename.back() == '*';
708  const auto is_reference_type = arg_typename.back() == '&';
709  top_decl += arg_typename + " " + arg_name + ", ";
710  gold_decl += arg_typename + ", ";
711  std::cmatch what;
712  const auto arg_is_channel =
713  std::regex_search(arg_typename.data(), what, std::regex("(ac_channel|stream|hls::stream)<(.*)>"));
714  if(arg_is_channel)
715  {
716  THROW_ASSERT(is_pointer_type || is_reference_type, "Channel parameters must be pointers or references.");
717  const std::string channel_type(what[1].first, what[1].second);
718  arg_typename.pop_back();
719  gold_call += arg_name + "_gold, ";
720  gold_cmp += "m_channelcmp(" + STR(param_idx) + ", " + cmp_type(arg_type, channel_type) + ");\n";
721  iface_type = "channel";
722  THROW_ASSERT(iface_attrs.find(FunctionArchitecture::iface_depth) != iface_attrs.end(),
723  "Expected channel depth information.");
724  arg_size = iface_attrs.at(FunctionArchitecture::iface_depth);
725  }
726  else if(is_pointer_type)
727  {
728  gold_call += "(" + arg_typename + ")" + arg_name + "_gold, ";
729  pp_call += "(" + tree_helper::PrintType(TM, arg, false, true) + ")" + arg_name + "_pp, ";
730  gold_cmp += "m_argcmp(" + STR(param_idx) + ", " + cmp_type(arg_type, arg_typename) + ");\n";
731  iface_type = arg_interface == "default" ? "ptr" : arg_interface;
732  if(param_size_default.find(param_idx) != param_size_default.end())
733  {
734  arg_size = param_size_default.at(param_idx);
735  }
736  else
737  {
738  if(is_interface_inferred)
739  {
740  THROW_ASSERT(parm_attrs.find(FunctionArchitecture::parm_size_in_bytes) != parm_attrs.end(),
741  "Attributes parm_size_in_bytes missing for parameter " + parm_name + " in function " +
742  top_fname);
743  arg_size = parm_attrs.at(FunctionArchitecture::parm_size_in_bytes);
744  }
745  else
746  {
747  const auto array_size = [&]() {
748  const auto ptd_type = tree_helper::CGetPointedType(arg_type);
749  return tree_helper::IsArrayType(ptd_type) ? tree_helper::GetArrayTotalSize(ptd_type) : 1ULL;
750  }();
751  arg_size = "sizeof(*" + arg_name + ") * " + std::to_string(array_size);
752  }
753  }
754  }
755  else if(is_reference_type)
756  {
757  arg_typename.pop_back();
758  gold_call += "*(" + arg_typename + "*)" + arg_name + "_gold, ";
759  pp_call += "(" + tree_helper::PrintType(TM, arg, false, true) + "*)" + arg_name + "_pp, ";
760  gold_cmp += "m_argcmp(" + STR(param_idx) + ", " + cmp_type(arg_type, arg_typename) + ");\n";
761  iface_type = arg_interface == "default" ? "ptr" : arg_interface;
762  arg_size = "sizeof(" + arg_typename + ")";
763  }
764  else
765  {
766  gold_call += arg_name + ", ";
767  pp_call += arg_name + ", ";
768  iface_type = arg_interface;
769  arg_size = "sizeof(" + arg_typename + ")";
770  }
771  const auto arg_ptr = (is_pointer_type ? "(void*)" : "(void*)&") + arg_name;
772  args_init += "__m_param_alloc(" + std::to_string(param_idx) + ", " + arg_size + ");\n";
773  args_decl += "{" + arg_ptr + ", " + arg_align + ", m_map_" + iface_type + "(" + arg_ptr + ")},\n";
774  args_set += "m_interface_" + iface_type + "(" + std::to_string(param_idx) + ", args[" +
775  std::to_string(param_idx) + "].map_addr, " + arg_bitsize + ", " + arg_align + ");\n";
776  ++param_idx;
777  }
778  top_decl.erase(top_decl.size() - 2);
779  gold_decl.erase(gold_decl.size() - 2);
780  gold_call.erase(gold_call.size() - 2);
781  pp_call.erase(pp_call.size() - 2);
782  if(!return_type)
783  {
784  args_decl.erase(args_decl.size() - 2);
785  }
786  }
787  if(return_type)
788  {
789  args_init += "__m_param_alloc(" + std::to_string(param_idx) + ", sizeof(retval));\n";
790  args_decl += "{&retval, 1, m_map_default(&retval)}";
791  args_set += "m_interface_default(" + std::to_string(param_idx) + ", args[" + std::to_string(param_idx) +
792  "].map_addr, " + std::to_string(tree_helper::Size(return_type)) + ", sizeof(retval));\n";
793  ++param_idx;
794  }
795  args_set += "__m_interface_mem(" + std::to_string(param_idx) + ");\n";
796  top_decl += ")\n";
797  gold_decl += ");\n";
798  gold_call += ");\n";
799  pp_call += ");\n";
800  args_decl += "};\n";
801 
802  indented_output_stream->AppendIndented("CDECL " + top_decl.substr(0, top_decl.size() - 1) + R"(;
803 
804 #ifdef LIBMDPI_DRIVER
805 
806 #ifdef __cplusplus
807 #include <cstring>
808 #else
809 #include <string.h>
810 #endif
811 
812 #define __LOCAL_ENTITY MDPI_ENTITY_DRIVER
813 #include <mdpi/mdpi_debug.h>
814 #include <mdpi/mdpi_driver.h>
815 #include <mdpi/mdpi_user.h>
816 
817 #define typeof __typeof__
818 #ifdef __cplusplus
819 template <typename T> struct __m_type { typedef T type; };
820 template <typename T> struct __m_type<T*> { typedef typename __m_type<T>::type type; };
821 #define m_getptrt(val) __m_type<typeof(val)>::type*
822 #define m_getvalt(val) __m_type<typeof(val)>::type
823 template <typename T> T* m_getptr(T& obj) { return &obj; }
824 template <typename T> T* m_getptr(T* obj) { return obj; }
825 #define __m_float_distance(a, b) m_float_distance(a, b)
826 #else
827 #define m_getptrt(val) typeof(val)
828 #define m_getvalt(val) typeof(*val)
829 #define m_getptr(ptr) (ptr)
830 #define __m_float_distance(a, b) \
831  ((typeof(a)(*)(typeof(a), typeof(a)))((sizeof(a) == sizeof(float)) ? m_float_distancef : m_float_distance))(a, b)
832 #define __m_floats_distance(a, b) \
833  ((typeof(a)(*)(typeof(a), typeof(a)))((sizeof(a) == sizeof(float)) ? m_floats_distancef : m_floats_distance))(a, b)
834 #endif
835 
836 #define m_cmpval(ptra, ptrb) *(ptra) != *(ptrb)
837 #define m_cmpmem(ptra, ptrb) memcmp(ptra, ptrb, sizeof(*ptrb))
838 #define m_cmpflt(ptra, ptrb) __m_float_distance(*(ptra), *(ptrb)) > max_ulp
839 #define m_cmpflts(ptra, ptrb) __m_floats_distance(*(ptra), *(ptrb)) > max_ulp
840 
841 #define _ms_setargptr(suffix, idx, ptr) \
842  const size_t P##idx##_size_##suffix = __m_param_size(idx); \
843  void* P##idx##_##suffix = malloc(P##idx##_size_##suffix); \
844  memcpy(P##idx##_##suffix, ptr, P##idx##_size_##suffix)
845 
846 #define _ms_argcmp(suffix, idx, cmp) \
847  const size_t P##idx##_count_##suffix = P##idx##_size_##suffix / sizeof(m_getvalt(P##idx)); \
848  for(i = 0; i < P##idx##_count_##suffix; ++i) \
849  { \
850  if(m_cmp##cmp((m_getptrt(P##idx))P##idx##_##suffix + i, &m_getptr(P##idx)[i])) \
851  { \
852  error("Memory parameter %u (%zu/%zu) mismatch with respect to " #suffix " reference.\n", idx, i + 1, \
853  P##idx##_count_##suffix); \
854  ++mismatch_count; \
855  } \
856  } \
857  free(P##idx##_##suffix)
858 
859 #define _ms_setargchannel(suffix, idx) m_getvalt(P##idx) P##idx##_##suffix = *m_getptr(P##idx)
860 
861 #define _ms_channelcmp(suffix, idx, cmp) \
862  if(m_getptr(P##idx)->size() != m_getptr(P##idx##_##suffix)->size()) \
863  { \
864  error("Channel parameter %u size mismatch with respect to " #suffix " reference: %zu != %zu.\n", idx, \
865  m_getptr(P##idx)->size(), m_getptr(P##idx##_##suffix)->size()); \
866  ++mismatch_count; \
867  } \
868  else \
869  { \
870  for(i = 0; i < m_getptr(P##idx)->size(); ++i) \
871  { \
872  if(m_cmp##cmp(&m_getptr(P##idx)->operator[](i), &m_getptr(P##idx##_##suffix)->operator[](i))) \
873  { \
874  error("Channel parameter %u (%zu/%zu) mismatch with respect to " #suffix " reference.\n", idx, i + 1, \
875  m_getptr(P##idx)->size()); \
876  ++mismatch_count; \
877  } \
878  } \
879  }
880 
881 #define _ms_retvalcmp(suffix, cmp) \
882  if(m_cmp##cmp(&retval, &retval_##suffix)) \
883  { \
884  error("Return value mismatch with respect to " #suffix " reference.\n"); \
885  ++mismatch_count; \
886  }
887 
888 #ifndef CUSTOM_VERIFICATION
889 #define _m_setargptr(idx, ptr) _ms_setargptr(gold, idx, ptr)
890 #define _m_argcmp(idx, cmp) _ms_argcmp(gold, idx, cmp)
891 #define _m_setargchannel(idx) _ms_setargchannel(gold, idx)
892 #define _m_channelcmp(idx, cmp) _ms_channelcmp(gold, idx, cmp)
893 #define _m_retvalcmp(cmp) _ms_retvalcmp(gold, cmp)
894 
895 )" + gold_decl +
896  R"(#else
897 #define _m_setargptr(...)
898 #define _m_argcmp(...)
899 #define _m_setargchannel(...)
900 #define _m_channelcmp(...)
901 #define _m_retvalcmp(...)
902 #endif
903 
904 #ifdef PP_VERIFICATION
905 #define _m_pp_setargptr(idx, ptr) _ms_setargptr(pp, idx, ptr)
906 #define _m_pp_argcmp(idx, cmp) _ms_argcmp(pp, idx, cmp)
907 #define _m_pp_retvalcmp(cmp) _ms_retvalcmp(pp, cmp)
908 
909 )" + pp_decl +
910  R"(#else
911 #define _m_pp_setargptr(...)
912 #define _m_pp_argcmp(...)
913 #define _m_pp_retvalcmp(...)
914 #endif
915 
916 #ifdef DUMP_COSIM_OUTPUT
917 static size_t __m_call_count = 0;
918 
919 #ifndef CUSTOM_VERIFICATION
920 #define _m_golddump(idx) \
921  do \
922  { \
923  char filename[32]; \
924  sprintf(filename, "P" #idx "_gold.%zu.dat", __m_call_count); \
925  FILE* out = fopen(filename, "wb"); \
926  if(out != NULL) \
927  { \
928  fwrite(P##idx##_gold, 1, __m_param_size(idx), out); \
929  fclose(out); \
930  debug("Parameter " #idx " gold output dump for execution %zu stored in '%s'\n", __m_call_count, filename); \
931  } \
932  else \
933  { \
934  error("Unable to open parameter dump file '%s'\n", filename); \
935  } \
936  } while(0)
937 #else
938 #define _m_golddump(idx)
939 #endif
940 
941 #define _m_argdump(idx) \
942  do \
943  { \
944  char filename[32]; \
945  sprintf(filename, "P" #idx ".%zu.dat", __m_call_count); \
946  FILE* out = fopen(filename, "wb"); \
947  if(out != NULL) \
948  { \
949  fwrite(P##idx, 1, __m_param_size(idx), out); \
950  fclose(out); \
951  debug("Parameter " #idx " output dump for execution %zu stored in '%s'\n", __m_call_count, filename); \
952  } \
953  else \
954  { \
955  error("Unable to open parameter dump file '%s'\n", filename); \
956  } \
957  } while(0)
958 #else
959 #define _m_argdump(idx)
960 #define _m_golddump(idx)
961 #endif
962 
963 #define m_map_default(ptr) NULL
964 #define m_interface_default(idx, ptr, bitsize, align) \
965  __m_interface_port(idx, ptr, bitsize); \
966  _m_pp_setargptr(idx, ptr); \
967  _m_setargptr(idx, ptr)
968 
969 #define m_map_ptr(ptr) (void*)ptr
970 #define m_interface_ptr(idx, ptr, bitsize, align) \
971  bptr_t __ptrval_##idx = (bptr_t)ptr; \
972  __m_interface_ptr(idx, &__ptrval_##idx, sizeof(bptr_t) * 8); \
973  _m_pp_setargptr(idx, ptr); \
974  _m_setargptr(idx, ptr)
975 
976 #define m_map_array(...) m_map_default(__VA_ARGS__)
977 #define m_interface_array(idx, ptr, bitsize, align) \
978  __m_interface_array(idx, ptr, bitsize, align, __m_param_size(idx) / align); \
979  _m_pp_setargptr(idx, ptr); \
980  _m_setargptr(idx, ptr)
981 
982 #define m_map_fifo(...) m_map_default(__VA_ARGS__)
983 #define m_interface_fifo(idx, ptr, bitsize, align) \
984  __m_interface_fifo(idx, ptr, bitsize, align, __m_param_size(idx) / align); \
985  _m_pp_setargptr(idx, ptr); \
986  _m_setargptr(idx, ptr)
987 
988 #define m_map_channel(ptr) NULL
989 #define m_interface_channel(idx, ptr, bitsize, align) \
990  __m_interface_channel(idx, *m_getptr(P##idx), __m_param_size(idx)); \
991  _m_setargchannel(idx)
992 
993 #define m_map_none(...) m_map_default(__VA_ARGS__)
994 #define m_interface_none(...) m_interface_default(__VA_ARGS__)
995 
996 #define m_map_valid(...) m_map_default(__VA_ARGS__)
997 #define m_interface_valid(...) m_interface_default(__VA_ARGS__)
998 
999 #define m_map_ovalid(...) m_map_default(__VA_ARGS__)
1000 #define m_interface_ovalid(...) m_interface_default(__VA_ARGS__)
1001 
1002 #define m_map_acknowledge(...) m_map_default(__VA_ARGS__)
1003 #define m_interface_acknowledge(...) m_interface_default(__VA_ARGS__)
1004 
1005 #define m_map_handshake(...) m_map_default(__VA_ARGS__)
1006 #define m_interface_handshake(...) m_interface_default(__VA_ARGS__)
1007 
1008 #define m_map_axis(...) m_map_fifo(__VA_ARGS__)
1009 #define m_interface_axis(...) m_interface_fifo(__VA_ARGS__)
1010 
1011 #define m_map_m_axi(...) m_map_ptr(__VA_ARGS__)
1012 #define m_interface_m_axi(...) m_interface_ptr(__VA_ARGS__)
1013 
1014 #define m_argcmp(idx, cmp) \
1015  _m_argdump(idx); \
1016  _m_golddump(idx); \
1017  _m_pp_argcmp(idx, cmp); \
1018  _m_argcmp(idx, cmp)
1019 
1020 #define m_channelcmp(idx, cmp) _m_channelcmp(idx, cmp)
1021 
1022 #define m_retvalcmp(cmp) _m_pp_retvalcmp(cmp) _m_retvalcmp(cmp)
1023 )");
1024 
1025  // write C code used to print initialization values for the HDL simulator's memory
1027 
1028  indented_output_stream->Append(top_decl);
1030  const auto max_ulp = [&]() -> std::string {
1031  const auto par = Param->getOption<std::string>(OPT_max_ulp);
1032  if(par.find(".") != std::string::npos)
1033  {
1034  return par + ".0L";
1035  }
1036  return par;
1037  }();
1038  indented_output_stream->Append("const long double max_ulp = " + max_ulp + ";\n");
1039  indented_output_stream->Append("size_t i;\n");
1040  indented_output_stream->Append(args_decl);
1041  indented_output_stream->Append(args_init);
1042  indented_output_stream->Append("__m_memsetup(args, " + STR(args_decl_size) + ");\n\n");
1043 
1044  indented_output_stream->Append(args_set);
1045 
1046  indented_output_stream->Append("\n__m_sim_start();\n\n");
1047  indented_output_stream->Append("#ifndef CUSTOM_VERIFICATION\n");
1048  indented_output_stream->Append(gold_call);
1049  indented_output_stream->Append("#endif\n\n");
1050  indented_output_stream->Append("#ifdef PP_VERIFICATION\n");
1051  indented_output_stream->Append(pp_call);
1052  indented_output_stream->Append("#endif\n\n");
1053  indented_output_stream->Append("__m_sim_end();\n");
1054  indented_output_stream->Append("__m_interface_fini();\n\n");
1055 
1056  if(gold_cmp.size() || return_type)
1057  {
1059 #ifdef __clang__
1060 #pragma clang diagnostic push
1061 #pragma clang diagnostic ignored "-Wpointer-type-mismatch"
1062 #elif GCC_VERSION >= 40600
1063 #pragma GCC diagnostic push
1064 #pragma GCC diagnostic ignored "-Wpointer-type-mismatch"
1065 #endif
1066 
1067 )");
1068  indented_output_stream->Append("__m_argmap_fini(args, " + STR(args_decl_size) + ");\n\n");
1069  indented_output_stream->Append("size_t mismatch_count = 0;\n");
1070  indented_output_stream->Append(gold_cmp + "\n");
1071  if(return_type)
1072  {
1073  indented_output_stream->Append("// Return value compare\n");
1074  indented_output_stream->Append("m_retvalcmp(" + cmp_type(return_type, "") + ")\n\n");
1075  }
1077 if(mismatch_count)
1078 {
1079 error("Memory parameter mismatch has been found.\n");
1080 __m_abort();
1081 }
1082 
1083 #ifdef DUMP_COSIM_OUTPUT
1084 ++__m_call_count;
1085 #endif
1086 
1087 #ifdef __clang__
1088 #pragma clang diagnostic pop
1089 #elif GCC_VERSION >= 40600
1090 #pragma GCC diagnostic pop
1091 #endif
1092 )");
1093  }
1094 
1095  if(return_type)
1096  {
1097  indented_output_stream->Append("return retval;\n");
1098  }
1099  indented_output_stream->Append("}\n\n");
1100 
1101  const auto& test_vectors = HLSMgr->RSim->test_vectors;
1102  if(top_fname != "main" && test_vectors.size())
1103  {
1104  indented_output_stream->Append("#else\n");
1105  indented_output_stream->Append("#include <mdpi/mdpi_user.h>\n\n");
1106 
1107  indented_output_stream->Append("int main()\n{\n");
1108  // write additional initialization code needed by subclasses
1110  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Written extra init code");
1111 
1112  // parameters declaration
1113  WriteParamDecl(top_bh);
1114 
1115  // ---- WRITE VARIABLES DECLARATIONS ----
1116  // declaration of the return variable of the top function, if not void
1117  if(return_type)
1118  {
1119  const auto ret_type = tree_helper::PrintType(TM, return_type);
1120  if(tree_helper::IsVectorType(return_type))
1121  {
1122  THROW_ERROR("return type of function under test " + top_fname + " is " + STR(ret_type) +
1123  "\nco-simulation does not support vectorized return types at top level");
1124  }
1125  indented_output_stream->Append("// return variable initialization\n");
1126  indented_output_stream->Append("volatile " + ret_type + " " RETURN_PORT_NAME ";\n");
1127  }
1128  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Written parameters declaration");
1129  // ---- WRITE PARAMETERS INITIALIZATION AND FUNCTION CALLS ----
1130  for(unsigned int v_idx = 0; v_idx < test_vectors.size(); v_idx++)
1131  {
1133  "-->Writing initialization for test vector " + STR(v_idx));
1135  const auto& curr_test_vector = test_vectors.at(v_idx);
1136  // write parameter initialization
1137  indented_output_stream->Append("// parameter initialization\n");
1138  WriteParamInitialization(top_bh, curr_test_vector);
1140  // write the call to the top function to be tested
1141  indented_output_stream->Append("// function call\n");
1143 
1146  "<--Written initialization for test vector " + STR(v_idx));
1147  }
1148  indented_output_stream->Append("return 0;\n");
1150  }
1151  indented_output_stream->Append("#endif");
1152 }
1153 
1154 void HLSCWriter::WriteFile(const std::string& file_name)
1155 {
1156  const auto top_symbols = Param->getOption<std::vector<std::string>>(OPT_top_functions_names);
1157  THROW_ASSERT(top_symbols.size() == 1, "Expected single top function name");
1158  const auto top_fnode = TM->GetFunction(top_symbols.front());
1159  const auto BH = HLSMgr->CGetFunctionBehavior(GET_INDEX_CONST_NODE(top_fnode))->CGetBehavioralHelper();
1161  "-->C-based testbench generation for function " + BH->get_function_name() + ": " + file_name);
1162 
1164  INDENT_OUT_MEX(OUTPUT_LEVEL_VERBOSE, output_level, "<--Prepared testbench");
1165 
1166  indented_output_stream->WriteFile(file_name);
1167 }
1168 
1170 {
1172 }
1173 
1175 {
1177 }
#define DEBUG_LEVEL_VERY_PEDANTIC
extremely verbose debugging print is performed.
static bool IsUnionType(const tree_nodeConstRef &type)
Return if treenode is an union.
Data structure representing the entire HLS information.
#define INDENT_DBG_MEX(dbgLevel, curDbgLevel, mex)
We are producing a debug version of the program, so the message is printed;.
TVMValue param[3]
HLSCWriter(const CBackendInformationConstRef hls_c_backend_information, const HLS_managerConstRef _HLSMgr, const InstructionWriterRef instruction_writer, const IndentedOutputStreamRef indented_output_stream, const ParameterConstRef _parameters, bool verbose=true)
Constructor of the class.
File containing functions and utilities to support the printing of debug messagges.
void WriteFile(const std::string &file_name)
Write the indented output on a file.
std::string GetMangledFunctionName() const
#define GET_CLASS(obj)
Macro returning the actual type of an object.
std::string get_function_name() const
Return the name of the function.
virtual ~HLSCWriter()
int debug_level
the debug level
Definition: c_writer.hpp:122
void WriteHeader() override
Writes the header of the file.
Class used to write the C code representing a program, this class can&#39;t be directly instantiated sinc...
Definition: c_writer.hpp:91
void AppendIndented(const std::string &str)
Append a pre-indented string to the output.
mathematical utility function not provided by standard libraries
#define INDENT_OUT_MEX(outLevel, curOutLevel, mex)
std::vector< tree_nodeRef > GetParameters() const
Return the list of index of original parameters of the function.
static unsigned long long int align(unsigned long long int address, unsigned long long int alignment)
STL includes.
Definition: memory.cpp:81
static unsigned long long generate_init_file(const std::string &dat_filename, const tree_managerConstRef TreeM, unsigned int var, const memoryRef mem)
static tree_nodeConstRef CGetElements(const tree_nodeConstRef &type)
Given an array or a vector return the element type.
Generate HDL testbench for the top-level kernel testing.
CustomOrderedMap< T, U > CustomMap
Definition: custom_map.hpp:167
void WriteBuiltinWaitCall() override
Writes implementation of __builtin_wait_call.
unsigned int get_function_index() const
Return the index of the function.
Class to print indented code.
static bool IsVoidType(const tree_nodeConstRef &type)
Return true if the treenode is of void type.
Simple class to print single instruction.
const tree_managerConstRef TM
The tree manager.
Definition: c_writer.hpp:98
Interface to parse the initialization of c variable.
#define RETURN_PORT_NAME
redefinition of map to manage ordered/unordered structures
const tree_nodeConstRef CGetTreeNode(const unsigned int i) const
static std::string GetMangledFunctionName(const function_decl *fd)
Return the mangled function name.
REF_FORWARD_DECL(memory_symbol)
void WriteFunctionImplementation(unsigned int function_index) override
Write function implementation.
#define STR(s)
Macro which performs a lexical_cast to a string.
Auxiliary methods for manipulating string.
#define max
Definition: backprop.h:17
void WriteSimulatorInitMemory(const unsigned int function_id)
Write some print statements used to dump the values used by the HDL to initialize the memory before t...
void WriteTestbenchFunctionCall(const BehavioralHelperConstRef behavioral_helper)
Writes a call to the top function to be tested, using its parameters.
static bool IsArrayType(const tree_nodeConstRef &type)
Return true if treenode is an array.
bool starts_with(const std::string &str, const std::string &pattern)
const IndentedOutputStreamRef indented_output_stream
Represents the stream we are currently writing to.
Definition: c_writer.hpp:101
Standard functor that returns the name of a variable.
static unsigned long long Size(const tree_nodeConstRef &tn)
Return the size of a tree object.
void WriteParamInitialization(const BehavioralHelperConstRef behavioral_helper, const std::map< std::string, std::string > &curr_test_vector)
Initialize the parameters of the function.
const ParameterConstRef Param
set of parameters
Definition: c_writer.hpp:119
HLSFlowStep_Type
Definition: hls_step.hpp:95
void Append(const std::string &str)
Append a string to the output.
Class specification of the data structures used to manage technology information. ...
unsigned int GetFunctionReturnType(unsigned int function) const
Return the index associated with the type of the return of the function.
redefinition of set to manage ordered/unordered structures
static bool IsVectorType(const tree_nodeConstRef &type)
Return true if the treenode is a vector.
#define GET_CONST_NODE(t)
Definition: tree_node.hpp:347
bool ends_with(const std::string &str, const std::string &pattern)
Classes specification of the tree_node data structures.
constexpr void string_to_container(_OutputIt first, const std::string &str, const std::string &separator, bool trim_empty=true)
Definition: utility.hpp:148
#define THROW_ERROR(str_expr)
helper function used to throw an error in a standard way
Definition: exceptions.hpp:263
std::string PrintVariable(unsigned int var) const
Print the name of the variable associated to the index.
constants used in testbench generation
This file collects some utility functions.
static unsigned int GetRealType(const tree_managerConstRef &TM, unsigned int index)
Return the real type.
const HLS_managerConstRef HLSMgr
the hls manager
Definition: c_writer.hpp:95
This class describes all classes used to represent a structural object.
Class specification of the tree_reindex support class.
void WriteGlobalDeclarations() override
Writes the global declarations.
static std::string PrintType(const tree_managerConstRef &TM, const tree_nodeConstRef &type, bool global=false, bool print_qualifiers=false, bool print_storage=false, const tree_nodeConstRef &var=nullptr, const var_pp_functorConstRef &vppf=var_pp_functorConstRef(), const std::string &prefix="", const std::string &tail="")
Print a type and its variable in case var is not zero.
static const std::regex wrapper_def("(ac_channel|stream|hls::stream)<(.*)>")
virtual void WriteExtraInitCode()
Write additional initialization code needed by subclasses.
Template borrowed from the ANTLR library by Terence Parr (http://www.jGuru.com - Software rights: htt...
Definition: refcount.hpp:94
static tree_nodeConstRef CGetType(const tree_nodeConstRef &node)
Return the treenode of the type of node.
static bool IsStructType(const tree_nodeConstRef &type)
Return true if treenode is a record.
static tree_nodeConstRef CGetPointedType(const tree_nodeConstRef &pointer)
Return the pointed type of a pointer object.
this class is used to manage the command-line or XML options.
Wrapper to call graph.
virtual void WriteMainTestbench()
Writes the main() of the testbench C program.
Functor used to write c code which writes initialization of the memory.
void WriteFile(const std::string &file_name) override
Writes the final C file.
#define OUTPUT_LEVEL_VERBOSE
verbose debugging print is performed.
refcount< var_pp_functor > var_pp_functorRef
#define GET_INDEX_CONST_NODE(t)
Definition: tree_node.hpp:363
refcount< const var_pp_functor > var_pp_functorConstRef
virtual void WriteExtraCodeBeforeEveryMainCall()
static bool IsPointerType(const tree_nodeConstRef &type)
Return true if treenode index is a pointer.
static tree_nodeConstRef GetFunctionReturnType(const tree_nodeConstRef &function, bool void_as_null=true)
Return the return type of a function.
std::string cxa_prefix_mangled(const std::string &signature, const std::string &prefix)
tree_nodeRef GetFunction(const std::string &function_name) const
Return the index of a function given its name.
void WriteParamDecl(const BehavioralHelperConstRef behavioral_helper)
Write declaration of the top function parameters.
Datastructure to represent memory information in high-level synthesis.
Class specification of the manager of the tree structures extracted from the raw file.
static unsigned long long GetArrayTotalSize(const tree_nodeConstRef &node)
Return the total number of elements of the the base type in the array.
int output_level
the output level
Definition: c_writer.hpp:125
A brief description of the C++ Header File.
static bool IsRealType(const tree_nodeConstRef &type)
Return true if the treenode is of real type.
const InstructionWriterRef instrWriter
Contains the class used to write instructions.
Definition: c_writer.hpp:109
#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:51 for PandA-2024.02 by doxygen 1.8.13