71 #include <boost/algorithm/string/trim_all.hpp> 80 static const std::regex
wrapper_def(
"(ac_channel|stream|hls::stream)<(.*)>");
81 #define WRAPPER_GROUP_WTYPE 2 87 :
CWriter(_HLSMgr, _instruction_writer, _indented_output_stream, _parameters, _verbose),
88 c_backend_info(_c_backend_info)
98 #define _FILE_OFFSET_BITS 64 100 #define __Inf (1.0 / 0.0) 101 #define __Nan (0.0 / 0.0) 114 extern void exit(int status); 117 #include <sys/types.h> 119 #ifdef __AC_NAMESPACE 120 using namespace __AC_NAMESPACE; 124 #define GCC_VERSION 0 126 #define GCC_VERSION (__GNUC__ * 10000 \ 127 + __GNUC_MINOR__ * 100 \ 128 + __GNUC_PATCHLEVEL__) 134 const auto top_function_ids =
HLSMgr->CGetCallGraphManager()->GetRootFunctions();
137 for(
auto function_id : top_function_ids)
140 const auto fd = GetPointerS<const function_decl>(fnode);
142 const auto& parms =
HLSMgr->module_arch->GetArchitecture(fname)->parms;
143 for(
const auto& [parm, attrs] : parms)
145 const auto attr_it = attrs.find(FunctionArchitecture::parm_includes);
146 if(attr_it != attrs.end())
151 top_fnames.insert(fname);
155 for(
const auto& fname : top_fnames)
159 for(
const auto& inc : includes)
163 for(
const auto& fname : top_fnames)
172 #define CDECL extern "C" 180 #define EXTERN_CDECL extern "C" 182 #define EXTERN_CDECL extern 207 "\nco-simulation does not support vectorized parameters at top level");
214 const std::map<std::string, std::string>& curr_test_vector)
217 const auto& parm_attrs =
HLSMgr->module_arch->GetArchitecture(fname)->parms;
219 for(
auto par_idx = 0
U; par_idx <
params.size(); ++par_idx)
221 const auto& par =
params.at(par_idx);
224 const auto has_file_init = [&]() {
225 if(parm_attrs.size())
227 const auto& type_name = parm_attrs.at(
param).at(FunctionArchitecture::parm_typename);
228 return std::regex_search(type_name.c_str(),
wrapper_def);
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())
241 (has_file_init &&
ends_with(init_it->second,
".dat")) ? (
"\"" + init_it->second +
"\"") : init_it->second;
244 const auto is_binary_init =
ends_with(test_v,
".dat");
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())
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))
255 var_ptdtype = std::regex_replace(var_ptdtype, voidP,
"char");
257 is_a_true_pointer = var_ptdtype.back() ==
'*';
258 if(is_a_true_pointer || var_ptdtype.back() ==
'&')
260 var_ptdtype.pop_back();
262 if(var_ptdtype.find(
"(*)") != std::string::npos)
264 temp_var_decl = var_ptdtype;
265 temp_var_decl.replace(var_ptdtype.find(
"(*)"), 3,
param +
"_temp[]");
269 temp_var_decl = var_ptdtype +
" " +
param +
"_temp" + (is_a_true_pointer ?
"[]" :
"");
272 if(temp_var_decl ==
"")
277 var_ptdtype = temp_var_decl.substr(0, temp_var_decl.find_last_of((*var_functor)(par->index)));
280 boost::replace_all(temp_var_decl,
"void ",
"char ");
281 boost::replace_all(var_ptdtype,
"void ",
"char ");
283 const auto first_square = temp_var_decl.find(
'[');
284 if(first_square == std::string::npos)
286 temp_var_decl = temp_var_decl +
"_temp[]";
290 temp_var_decl.insert(first_square,
"_temp[]");
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)<(.*)>"));
298 "---Pointed type: " +
GET_CONST_NODE(ptd_type)->get_kind_text() +
" - " +
STR(ptd_type));
300 std::string param_size;
304 const auto fp =
param +
"_fp";
311 ") != " +
param +
"_size)\n");
325 const auto temp_initialization =
326 temp_var_decl +
" = " +
327 ((test_v.front() !=
'{' && test_v.back() !=
'}' && is_a_true_pointer) ?
"{" + test_v +
"}" : test_v) +
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));
365 if(top_fname_mngl ==
"main")
371 return top_fname_mngl;
373 if(return_type_index)
379 bool is_first_argument =
true;
380 const auto& parms =
HLSMgr->module_arch->GetArchitecture(top_fname_mngl)->parms;
384 if(!is_first_argument)
390 is_first_argument =
false;
394 auto arg_typename = parms.at(
param).at(FunctionArchitecture::parm_original_typename);
395 if(arg_typename.find(
"(*)") != std::string::npos)
397 arg_typename = arg_typename.substr(0, arg_typename.find(
"(*)")) +
"*";
399 if(arg_typename.back() !=
'*')
421 const auto mem_vars =
HLSMgr->Rmem->get_ext_memory_variables();
422 const auto BH =
HLSMgr->CGetFunctionBehavior(function_id)->CGetBehavioralHelper();
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)
432 max =
std::max(max, std::stoull(attrs.at(FunctionArchitecture::iface_alignment)));
437 const auto tb_map_mode =
"MDPI_MEMMAP_" +
Param->getOption<std::string>(OPT_testbench_map_mode);
442 const char* filename; 455 static void __m_memsetup(__m_argmap_t args[], size_t args_count) 460 auto base_addr =
HLSMgr->base_address;
464 const auto output_directory =
Param->getOption<std::string>(OPT_output_directory) +
"/simulation/";
465 for(
const auto& mem_var : mem_vars)
467 const auto var_id = mem_var.first;
471 const auto var_name = BH->PrintVariable(var_id);
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";
477 STR(byte_count) +
", " +
STR(var_addr) +
", NULL},\n");
478 base_addr =
std::max(base_addr, var_addr + byte_count);
493 // Memory-mapped internal variables initialization 494 for(i = 0; i < sizeof(memmap_init) / sizeof(*memmap_init); ++i) 496 FILE* fp = fopen(memmap_init[i].filename, "rb"); 499 error("Unable to open file: %s\n", memmap_init[i].filename); 500 perror("Unable to open memory variable initialization file"); 504 if(memmap_init[i].addr == NULL) 506 memmap_init[i].addr = malloc(memmap_init[i].size); 508 size_t nbytes = fread(memmap_init[i].addr, 1, memmap_init[i].size, fp); 509 if(nbytes != memmap_init[i].size) 511 error("Only %zu/%zu bytes were read from file: %s\n", nbytes, memmap_init[i].size, memmap_init[i].filename); 514 perror("Unable to read from memory variable initialization file"); 521 error |= __m_memmap(memmap_init[i].addrmap, memmap_init[i].addr, memmap_init[i].size); 524 for(i = 0; i < args_count; ++i) 526 if(args[i].map_addr == NULL) 528 args[i].map_addr = args[i].addr; 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) 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); 542 error |= __m_memmap(base_addr, args[i].map_addr, map_size); 543 base_addr += map_size; 551 static void __m_argmap_fini(__m_argmap_t args[], size_t args_count) 554 for(i = 0; i < args_count; i++) 556 if(args[i].map_addr != args[i].addr) 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; 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");
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();
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);
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)<")))
600 else if(std::regex_search(tname, std::regex(R
"((\bfloat\b|\bdouble\b))"))) 602 return has_subnormals ?
"flts" :
"flt";
616 return has_subnormals ?
"flts" :
"flt";
626 const auto param_size_default = [&]() {
628 if(
Param->isOption(OPT_testbench_param_size))
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())
636 if(std::regex_search(param_size_str.c_str(), what, std::regex(
"\\b" + parm_name +
":(\\d+)")))
638 idx_size[param_idx] = what[1u].str();
646 std::string top_decl;
647 std::string gold_decl =
"EXTERN_CDECL ";
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;
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;
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;
674 top_decl +=
" " + top_fname_mngl +
"(";
677 pp_call +=
"__m_pp_" + top_fname +
"(";
678 if(top_params.size())
680 for(
const auto&
arg : top_params)
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));
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())
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);
697 return iface_attrs.at(FunctionArchitecture::iface_alignment);
699 std::string iface_type, arg_size;
701 auto arg_typename = parm_attrs.at(FunctionArchitecture::parm_original_typename);
702 if(arg_typename.find(
"(*)") != std::string::npos)
704 arg_typename = arg_typename.substr(0, arg_typename.find(
"(*)")) +
"*";
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 +
", ";
712 const auto arg_is_channel =
713 std::regex_search(arg_typename.data(), what, std::regex(
"(ac_channel|stream|hls::stream)<(.*)>"));
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);
726 else if(is_pointer_type)
728 gold_call +=
"(" + arg_typename +
")" + arg_name +
"_gold, ";
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())
734 arg_size = param_size_default.at(param_idx);
738 if(is_interface_inferred)
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 " +
743 arg_size = parm_attrs.at(FunctionArchitecture::parm_size_in_bytes);
747 const auto array_size = [&]() {
751 arg_size =
"sizeof(*" + arg_name +
") * " + std::to_string(array_size);
755 else if(is_reference_type)
757 arg_typename.pop_back();
758 gold_call +=
"*(" + arg_typename +
"*)" + arg_name +
"_gold, ";
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 +
")";
766 gold_call += arg_name +
", ";
767 pp_call += arg_name +
", ";
768 iface_type = arg_interface;
769 arg_size =
"sizeof(" + arg_typename +
")";
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";
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);
784 args_decl.erase(args_decl.size() - 2);
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";
795 args_set +=
"__m_interface_mem(" + std::to_string(param_idx) +
");\n";
804 #ifdef LIBMDPI_DRIVER 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> 817 #define typeof __typeof__ 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) 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) 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 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) 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) \ 850 if(m_cmp##cmp((m_getptrt(P##idx))P##idx##_##suffix + i, &m_getptr(P##idx)[i])) \ 852 error("Memory parameter %u (%zu/%zu) mismatch with respect to " #suffix " reference.\n", idx, i + 1, \ 853 P##idx##_count_##suffix); \ 857 free(P##idx##_##suffix) 859 #define _ms_setargchannel(suffix, idx) m_getvalt(P##idx) P##idx##_##suffix = *m_getptr(P##idx) 861 #define _ms_channelcmp(suffix, idx, cmp) \ 862 if(m_getptr(P##idx)->size() != m_getptr(P##idx##_##suffix)->size()) \ 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()); \ 870 for(i = 0; i < m_getptr(P##idx)->size(); ++i) \ 872 if(m_cmp##cmp(&m_getptr(P##idx)->operator[](i), &m_getptr(P##idx##_##suffix)->operator[](i))) \ 874 error("Channel parameter %u (%zu/%zu) mismatch with respect to " #suffix " reference.\n", idx, i + 1, \ 875 m_getptr(P##idx)->size()); \ 881 #define _ms_retvalcmp(suffix, cmp) \ 882 if(m_cmp##cmp(&retval, &retval_##suffix)) \ 884 error("Return value mismatch with respect to " #suffix " reference.\n"); \ 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) 897 #define _m_setargptr(...) 898 #define _m_argcmp(...) 899 #define _m_setargchannel(...) 900 #define _m_channelcmp(...) 901 #define _m_retvalcmp(...) 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) 911 #define _m_pp_setargptr(...) 912 #define _m_pp_argcmp(...) 913 #define _m_pp_retvalcmp(...) 916 #ifdef DUMP_COSIM_OUTPUT 917 static size_t __m_call_count = 0; 919 #ifndef CUSTOM_VERIFICATION 920 #define _m_golddump(idx) \ 924 sprintf(filename, "P" #idx "_gold.%zu.dat", __m_call_count); \ 925 FILE* out = fopen(filename, "wb"); \ 928 fwrite(P##idx##_gold, 1, __m_param_size(idx), out); \ 930 debug("Parameter " #idx " gold output dump for execution %zu stored in '%s'\n", __m_call_count, filename); \ 934 error("Unable to open parameter dump file '%s'\n", filename); \ 938 #define _m_golddump(idx) 941 #define _m_argdump(idx) \ 945 sprintf(filename, "P" #idx ".%zu.dat", __m_call_count); \ 946 FILE* out = fopen(filename, "wb"); \ 949 fwrite(P##idx, 1, __m_param_size(idx), out); \ 951 debug("Parameter " #idx " output dump for execution %zu stored in '%s'\n", __m_call_count, filename); \ 955 error("Unable to open parameter dump file '%s'\n", filename); \ 959 #define _m_argdump(idx) 960 #define _m_golddump(idx) 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) 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) 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) 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) 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) 993 #define m_map_none(...) m_map_default(__VA_ARGS__) 994 #define m_interface_none(...) m_interface_default(__VA_ARGS__) 996 #define m_map_valid(...) m_map_default(__VA_ARGS__) 997 #define m_interface_valid(...) m_interface_default(__VA_ARGS__) 999 #define m_map_ovalid(...) m_map_default(__VA_ARGS__) 1000 #define m_interface_ovalid(...) m_interface_default(__VA_ARGS__) 1002 #define m_map_acknowledge(...) m_map_default(__VA_ARGS__) 1003 #define m_interface_acknowledge(...) m_interface_default(__VA_ARGS__) 1005 #define m_map_handshake(...) m_map_default(__VA_ARGS__) 1006 #define m_interface_handshake(...) m_interface_default(__VA_ARGS__) 1008 #define m_map_axis(...) m_map_fifo(__VA_ARGS__) 1009 #define m_interface_axis(...) m_interface_fifo(__VA_ARGS__) 1011 #define m_map_m_axi(...) m_map_ptr(__VA_ARGS__) 1012 #define m_interface_m_axi(...) m_interface_ptr(__VA_ARGS__) 1014 #define m_argcmp(idx, cmp) \ 1017 _m_pp_argcmp(idx, cmp); \ 1020 #define m_channelcmp(idx, cmp) _m_channelcmp(idx, cmp) 1022 #define m_retvalcmp(cmp) _m_pp_retvalcmp(cmp) _m_retvalcmp(cmp) 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)
1056 if(gold_cmp.size() || return_type)
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" 1079 error("Memory parameter mismatch has been found.\n"); 1083 #ifdef DUMP_COSIM_OUTPUT 1088 #pragma clang diagnostic pop 1089 #elif GCC_VERSION >= 40600 1090 #pragma GCC diagnostic pop 1101 const auto& test_vectors =
HLSMgr->RSim->test_vectors;
1102 if(top_fname !=
"main" && test_vectors.size())
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");
1130 for(
unsigned int v_idx = 0; v_idx < test_vectors.size(); v_idx++)
1133 "-->Writing initialization for test vector " +
STR(v_idx));
1135 const auto& curr_test_vector = test_vectors.at(v_idx);
1146 "<--Written initialization for test vector " +
STR(v_idx));
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());
1161 "-->C-based testbench generation for function " + BH->get_function_name() +
": " + file_name);
#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;.
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.
int debug_level
the debug level
void WriteHeader() override
Writes the header of the file.
Class used to write the C code representing a program, this class can't be directly instantiated sinc...
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.
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
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.
Interface to parse the initialization of c variable.
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.
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.
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
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)
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)
#define THROW_ERROR(str_expr)
helper function used to throw an error in a standard way
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
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...
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.
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)
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
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.
#define THROW_ASSERT(cond, str_expr)
helper function used to check an assert and if needed to throw an error in a standard way ...