PandA-2024.02
testbench_generation.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  */
41 #include "testbench_generation.hpp"
42 
43 #include "Discrepancy.hpp"
44 #include "HDL_manager.hpp"
46 #include "Parameter.hpp"
48 #include "behavioral_helper.hpp"
49 #include "c_backend.hpp"
52 #include "call_graph_manager.hpp"
53 #include "copyrights_strings.hpp"
54 #include "design_flow_graph.hpp"
55 #include "design_flow_manager.hpp"
56 #include "fu_binding.hpp"
57 #include "function_behavior.hpp"
58 #include "hls.hpp"
59 #include "hls_constraints.hpp"
60 #include "hls_device.hpp"
61 #include "hls_manager.hpp"
62 #include "language_writer.hpp"
63 #include "library_manager.hpp"
64 #include "math_function.hpp"
65 #include "memory.hpp"
66 #include "memory_symbol.hpp"
67 #include "structural_manager.hpp"
68 #include "structural_objects.hpp"
69 #include "technology_manager.hpp"
70 #include "technology_node.hpp"
71 #include "technology_wishbone.hpp"
73 #include "tree_helper.hpp"
74 #include "tree_manager.hpp"
75 #include "tree_node.hpp"
76 #include "tree_reindex.hpp"
77 #include "utility.hpp"
78 
79 #include <algorithm>
80 #include <filesystem>
81 #include <fstream>
82 #include <iterator>
83 #include <list>
84 #include <string>
85 #include <utility>
86 
87 #define CST_STR_BAMBU_TESTBENCH "bambu_testbench"
88 
89 #define SETUP_PORT_NAME "setup_port"
90 
92  const DesignFlowManagerConstRef _design_flow_manager)
93  : HLS_step(_parameters, _HLSMgr, _design_flow_manager, HLSFlowStep_Type::TESTBENCH_GENERATION),
94  writer(language_writer::create_writer(HDLWriter_Language::VERILOG,
95  _HLSMgr->get_HLS_device()->get_technology_manager(), _parameters)),
96  cir(nullptr),
97  mod(nullptr),
98  output_directory(parameters->getOption<std::string>(OPT_output_directory) + "/simulation/"),
99  c_testbench_basename(STR_CST_testbench_generation_basename)
100 {
101  debug_level = parameters->get_class_debug_level(GET_CLASS(*this));
102 }
103 
106 {
108  switch(relationship_type)
109  {
111  {
114  if(parameters->isOption(OPT_discrepancy) && parameters->getOption<bool>(OPT_discrepancy))
115  {
116  ret.insert(std::make_tuple(HLSFlowStep_Type::VCD_SIGNAL_SELECTION, HLSFlowStepSpecializationConstRef(),
118  }
119  break;
120  }
122  {
123  break;
124  }
126  {
127  break;
128  }
129  default:
130  THROW_UNREACHABLE("");
131  }
132  return ret;
133 }
134 
136  const DesignFlowStep::RelationshipType relationship_type)
137 {
138  HLS_step::ComputeRelationships(design_flow_step_set, relationship_type);
139 
140  switch(relationship_type)
141  {
143  {
144  const auto c_backend_factory =
145  GetPointer<const CBackendStepFactory>(design_flow_manager.lock()->CGetDesignFlowStepFactory("CBackend"));
146 
147  design_flow_step_set.insert(c_backend_factory->CreateCBackendStep(CBackendInformationConstRef(
148  new CBackendInformation(CBackendInformation::CB_HLS, output_directory + c_testbench_basename + ".c"))));
149  break;
150  }
152  {
153  break;
154  }
156  {
157  break;
158  }
159  default:
160  {
161  THROW_UNREACHABLE("");
162  break;
163  }
164  }
165 }
166 
168 {
169  return true;
170 }
171 
173 {
174  const auto top_symbols = parameters->getOption<std::vector<std::string>>(OPT_top_functions_names);
175  THROW_ASSERT(top_symbols.size() == 1, "Expected single top function name");
176  const auto top_fnode = HLSMgr->get_tree_manager()->GetFunction(top_symbols.front());
177  const auto top_hls = HLSMgr->get_HLS(GET_INDEX_CONST_NODE(top_fnode));
178  cir = top_hls->top->get_circ();
179  THROW_ASSERT(GetPointer<const module>(cir), "Not a module");
180  mod = GetPointer<const module>(cir);
181  hdl_testbench_basename = "testbench_" + cir->get_id();
182 }
183 
185 {
186  INDENT_DBG_MEX(DEBUG_LEVEL_MINIMUM, debug_level, "-->Generating testbench HDL");
188  tb_top->set_top_info(CST_STR_BAMBU_TESTBENCH "_impl",
190  const auto tb_cir = tb_top->get_circ();
191  const auto tb_mod = GetPointerS<module>(tb_cir);
192  const auto add_internal_connection = [&](structural_objectRef src, structural_objectRef dest) {
193  THROW_ASSERT(src->get_kind() == dest->get_kind(), "Port with different types cannot be connected.");
194  const auto sig_id = "sig_" + dest->get_id();
195  auto sig = tb_cir->find_member(sig_id, signal_o_K, tb_cir);
196  if(!sig)
197  {
198  sig = tb_top->add_sign(sig_id, tb_cir, dest->get_typeRef());
199  tb_top->add_connection(dest, sig);
200  }
201  src->type_resize(STD_GET_SIZE(dest->get_typeRef()));
202 
203  tb_top->add_connection(sig, src);
204  };
205 
207  tb_mod->set_description("Testbench top component");
208  tb_mod->set_copyright(GENERATED_COPYRIGHT);
209  tb_mod->set_authors("Component automatically generated by bambu");
210  tb_mod->set_license(GENERATED_LICENSE);
211 
213  const structural_type_descriptorRef bool_type(new structural_type_descriptor("bool", 0));
215  const auto clock_port = tb_top->add_port(CLOCK_PORT_NAME, port_o::IN, tb_cir, bool_type);
216  GetPointerS<port_o>(clock_port)->set_is_clock(true);
217 
218  const auto TechM = HLSMgr->get_HLS_device()->get_technology_manager();
219  const auto std_lib_manager = TechM->get_library_manager(LIBRARY_STD);
221 
222  // Add top module wrapper
223  INDENT_DBG_MEX(DEBUG_LEVEL_MINIMUM, debug_level, "Generating top level interface wrapper...");
224  const auto top_id = [&]() {
225  const auto top_symbols = parameters->getOption<std::vector<std::string>>(OPT_top_functions_names);
226  THROW_ASSERT(top_symbols.size() == 1, "Expected single top function name");
227  const auto top_fnode = HLSMgr->get_tree_manager()->GetFunction(top_symbols.front());
228  return GET_INDEX_CONST_NODE(top_fnode);
229  }();
230  const auto top_fb = HLSMgr->CGetFunctionBehavior(top_id);
231  const auto top_bh = top_fb->CGetBehavioralHelper();
232  mgm.create_generic_module("TestbenchDUT", nullptr, top_fb, LIBRARY_STD, "TestbenchDUT");
233  const auto dut = tb_top->add_module_from_technology_library("DUT", "TestbenchDUT", LIBRARY_STD, tb_cir, TechM);
234  const auto dut_clock = dut->find_member(CLOCK_PORT_NAME, port_o_K, dut);
235  THROW_ASSERT(dut_clock, "");
236  tb_top->add_connection(clock_port, dut_clock);
237 
238  // Add generated testbench FSM
239  INDENT_DBG_MEX(DEBUG_LEVEL_MINIMUM, debug_level, "Generating testbench FSM...");
240  const auto tb_fsm =
241  tb_top->add_module_from_technology_library("SystemFSM", "TestbenchFSM", LIBRARY_STD, tb_cir, TechM);
242  tb_fsm->SetParameter("RESFILE", "\"\"" + parameters->getOption<std::string>(OPT_simulation_output) + "\"\"");
243  tb_fsm->SetParameter("RESET_ACTIVE", parameters->getOption<bool>(OPT_reset_level) ? "1" : "0");
244  tb_fsm->SetParameter("CLOCK_PERIOD", "2.0");
245  tb_fsm->SetParameter("MAX_SIM_CYCLES", parameters->getOption<std::string>(OPT_max_sim_cycles));
246  const auto fsm_clock = tb_fsm->find_member(CLOCK_PORT_NAME, port_o_K, tb_fsm);
247  tb_top->add_connection(clock_port, fsm_clock);
248 
249  const auto fsm_reset = tb_fsm->find_member(RESET_PORT_NAME, port_o_K, tb_fsm);
250  const auto fsm_setup = tb_fsm->find_member(SETUP_PORT_NAME, port_o_K, tb_fsm);
251  auto fsm_start = tb_fsm->find_member(START_PORT_NAME, port_o_K, tb_fsm);
252  auto dut_done = dut->find_member(DONE_PORT_NAME, port_o_K, dut);
253  THROW_ASSERT(dut_done, "DUT done_port is missing.");
254 
255  std::list<structural_objectRef> if_modules;
256  const auto interface_type = parameters->getOption<HLSFlowStep_Type>(OPT_interface_type);
257  INDENT_DBG_MEX(DEBUG_LEVEL_MINIMUM, debug_level, "Generating memory interface...");
258  structural_objectRef tb_mem;
259  if(interface_type == HLSFlowStep_Type::MINIMAL_INTERFACE_GENERATION ||
262  {
263  tb_mem =
264  tb_top->add_module_from_technology_library("SystemMEM", "TestbenchMEMMinimal", LIBRARY_STD, tb_cir, TechM);
265  tb_mem->SetParameter("QUEUE_SIZE", STR(HLSMgr->get_parameter()->getOption<unsigned int>(OPT_tb_queue_size)));
266  const auto bp_port = dut->find_member(MOUT_BACK_PRESSURE_PORT_NAME, port_o_K, dut);
267  if(bp_port ==
268  nullptr) // if the the internal memory_ctrl does not use bp I have to set the correct size of the bp signal
269  {
270  const auto bp_port_tb = tb_mem->find_member(MOUT_BACK_PRESSURE_PORT_NAME, port_o_K, tb_mem);
271  const auto oe_port = dut->find_member(MOUT_OE_PORT_NAME, port_o_K, dut);
272  if(oe_port)
273  {
274  bp_port_tb->type_resize(STD_GET_SIZE(oe_port->get_typeRef()));
275  }
276  }
277  if(interface_type == HLSFlowStep_Type::INTERFACE_CS_GENERATION)
278  {
279  tb_mem->SetParameter("PIPELINED", "0");
280  }
281  }
282  else if(interface_type == HLSFlowStep_Type::WB4_INTERFACE_GENERATION ||
284  {
285  tb_mem =
286  tb_top->add_module_from_technology_library("SystemMEM", "TestbenchMEMWishboneB4", LIBRARY_STD, tb_cir, TechM);
287  }
288  else
289  {
290  THROW_ERROR("Testbench generation for selected interface type is not yet supported.");
291  }
292  tb_mem->SetParameter("MEM_DELAY_READ", parameters->getOption<std::string>(OPT_bram_high_latency) == "_3" ?
293  "3" :
294  parameters->getOption<std::string>(OPT_bram_high_latency) == "_4" ?
295  "4" :
296  parameters->getOption<std::string>(OPT_mem_delay_read));
297  tb_mem->SetParameter("MEM_DELAY_WRITE", parameters->getOption<std::string>(OPT_mem_delay_write));
298  tb_mem->SetParameter("base_addr", STR(HLSMgr->base_address));
299  tb_mem->SetParameter("index",
300  std::to_string(top_bh->GetParameters().size() + (top_bh->GetFunctionReturnType(top_id) != 0)));
301  if_modules.push_back(tb_mem);
302 
303  INDENT_DBG_MEX(DEBUG_LEVEL_MINIMUM, debug_level, "Generating handler modules for top level parameters...");
304  if(parameters->getOption<bool>(OPT_memory_mapped_top))
305  {
306  const std::string if_suffix =
307  interface_type == HLSFlowStep_Type::MINIMAL_INTERFACE_GENERATION ? "Minimal" : "WishboneB4";
308  const auto master_port_module = "TestbenchArgMap" + if_suffix;
309  size_t idx = 0;
310  std::list<structural_objectRef> master_ports;
311  for(const auto& par : top_bh->GetParameters())
312  {
313  const auto par_name = top_bh->PrintVariable(GET_INDEX_CONST_NODE(par));
314  INDENT_DBG_MEX(DEBUG_LEVEL_MINIMUM, debug_level, "-->Parameter " + par_name);
315  const auto par_bitsize = tree_helper::Size(par);
316  const auto par_symbol = HLSMgr->Rmem->get_symbol(GET_INDEX_CONST_NODE(par), top_id);
318  "---Interface: " + STR(par_bitsize) + "-bits memory mapped at " +
319  STR(par_symbol->get_address()));
320  const auto master_port = tb_top->add_module_from_technology_library("master_" + par_name, master_port_module,
321  LIBRARY_STD, tb_cir, TechM);
322  master_port->SetParameter("index", STR(idx));
323  master_port->SetParameter("bitsize", STR(par_bitsize));
324  master_port->SetParameter("tgt_addr", STR(par_symbol->get_address()));
325 
326  master_ports.push_back(master_port);
327  ++idx;
329  }
330 
331  const auto return_type = tree_helper::GetFunctionReturnType(HLSMgr->get_tree_manager()->CGetTreeReindex(top_id));
332  if(return_type)
333  {
334  INDENT_DBG_MEX(DEBUG_LEVEL_MINIMUM, debug_level, "-->Return value port");
335  const auto return_bitsize = tree_helper::Size(return_type);
336  const auto return_symbol = HLSMgr->Rmem->get_symbol(GET_INDEX_CONST_NODE(return_type), top_id);
338  "---Interface: " + STR(return_bitsize) + "-bits memory mapped at " +
339  STR(return_symbol->get_address()));
340  const auto master_port = tb_top->add_module_from_technology_library(
341  "master_return_port", "TestbenchReturnMap" + if_suffix, LIBRARY_STD, tb_cir, TechM);
342  master_port->SetParameter("index", STR(idx));
343  master_port->SetParameter("bitsize", STR(return_bitsize));
344  master_port->SetParameter("tgt_addr", STR(return_symbol->get_address()));
345 
346  const auto m_i_done = master_port->find_member("i_" DONE_PORT_NAME, port_o_K, master_port);
347  const auto m_done = master_port->find_member(DONE_PORT_NAME, port_o_K, master_port);
348  THROW_ASSERT(m_i_done, "Port i_" DONE_PORT_NAME " not found in module " + master_port->get_path());
349  THROW_ASSERT(m_done, "Port " DONE_PORT_NAME " not found in module " + master_port->get_path());
350  const auto sig = tb_top->add_sign("sig_map_" DONE_PORT_NAME, tb_cir, dut_done->get_typeRef());
351  tb_top->add_connection(dut_done, sig);
352  tb_top->add_connection(sig, m_i_done);
353  dut_done = m_done;
354 
355  master_ports.push_back(master_port);
357  }
358 
359  const auto start_symbol = HLSMgr->Rmem->get_symbol(top_id, top_id);
360  const auto master_start = tb_top->add_module_from_technology_library(
361  "start_master", "TestbenchStartMap" + if_suffix, LIBRARY_STD, tb_cir, TechM);
362  master_start->SetParameter("tgt_addr", STR(start_symbol->get_address()));
363  master_ports.push_back(master_start);
364 
365  if_modules.insert(if_modules.end(), master_ports.begin(), master_ports.end());
366  if(master_ports.size())
367  {
368  const auto master_mod = GetPointerS<module>(master_ports.front());
369  unsigned int k = 0;
370 
371  // Daisy chain start signal through all memory master modules
372  for(const auto& master_port : master_ports)
373  {
374  const auto m_i_start = master_port->find_member("i_" START_PORT_NAME, port_o_K, master_port);
375  const auto m_start = master_port->find_member(START_PORT_NAME, port_o_K, master_port);
376  THROW_ASSERT(m_i_start, "Port i_" START_PORT_NAME " not found in module " + master_port->get_path());
377  THROW_ASSERT(m_start, "Port " START_PORT_NAME " not found in module " + master_port->get_path());
378  const auto sig = tb_top->add_sign("sig_" START_PORT_NAME "_" + STR(k), tb_cir, fsm_start->get_typeRef());
379  tb_top->add_connection(fsm_start, sig);
380  tb_top->add_connection(sig, m_i_start);
381  fsm_start = m_start;
382  ++k;
383  }
384 
385  // Merge all matching out signals from memory master modules and testbench memory
386  master_ports.push_front(tb_mem);
387  for(unsigned int i = 0; i < master_mod->get_out_port_size(); ++i)
388  {
389  const auto out_port = master_mod->get_out_port(i);
390  if(!GetPointerS<const port_o>(out_port)->get_is_memory())
391  {
392  continue;
393  }
394  const auto bus_merger = tb_top->add_module_from_technology_library(
395  "merge_" + out_port->get_id(), "bus_merger", LIBRARY_STD, tb_cir, TechM);
396  const auto merge_out = GetPointerS<module>(bus_merger)->get_out_port(0);
397  const auto dut_port = dut->find_member(out_port->get_id(), port_o_K, dut);
398  THROW_ASSERT(dut_port, "Port " + out_port->get_id() + " not found in module " + dut->get_path());
399  add_internal_connection(merge_out, dut_port);
400  const auto merge_port = GetPointerS<module>(bus_merger)->get_in_port(0);
401  const auto merge_port_o = GetPointerS<port_o>(merge_port);
402  merge_port_o->add_n_ports(static_cast<unsigned int>(master_ports.size()), merge_port);
403  merge_port_o->type_resize(STD_GET_SIZE(dut_port->get_typeRef()));
404  k = 0;
405  for(const auto& master_port : master_ports)
406  {
407  const auto m_port = master_port->find_member(out_port->get_id(), port_o_K, master_port);
408  THROW_ASSERT(m_port, "Port " + out_port->get_id() + " not found in module " + master_port->get_id());
409  m_port->type_resize(STD_GET_SIZE(dut_port->get_typeRef()));
410  const auto sig =
411  tb_top->add_sign("sig_" + out_port->get_id() + "_" + STR(k), tb_cir, dut_port->get_typeRef());
412  tb_top->add_connection(m_port, sig);
413  tb_top->add_connection(sig, merge_port_o->get_port(k));
414  ++k;
415  }
416  }
417  }
418  }
419  else
420  {
421  // Add interface components relative to each top function parameter
422  const auto is_interface_inferred = interface_type == HLSFlowStep_Type::INFERRED_INTERFACE_GENERATION;
423  const auto func_arch = HLSMgr->module_arch->GetArchitecture(top_bh->GetMangledFunctionName());
424  size_t idx = 0;
425  for(const auto& arg : top_bh->GetParameters())
426  {
427  const auto arg_name = top_bh->PrintVariable(GET_INDEX_CONST_NODE(arg));
428  const auto& parm_attrs = func_arch->parms.at(arg_name);
429  const auto& bundle_name = parm_attrs.at(FunctionArchitecture::parm_bundle);
430  const auto& iface_attrs = func_arch->ifaces.at(bundle_name);
431  INDENT_DBG_MEX(DEBUG_LEVEL_MINIMUM, debug_level, "-->Parameter " + arg_name);
432  if(is_interface_inferred && tree_helper::IsPointerType(arg) &&
433  iface_attrs.find(FunctionArchitecture::iface_direction) == iface_attrs.end())
434  {
435  INDENT_DBG_MEX(DEBUG_LEVEL_MINIMUM, debug_level, "<--Unused parameter");
436  ++idx;
437  continue;
438  }
439  const auto arg_port = dut->find_member(arg_name, port_o_K, dut);
440  const auto arg_interface = iface_attrs.at(FunctionArchitecture::iface_mode);
441 
442  if(arg_interface == "default")
443  {
444  const auto arg_port_dir = GetPointer<port_o>(arg_port)->get_port_direction();
446  "---Interface: " + arg_interface + " " + port_o::GetString(arg_port_dir));
447  const auto if_port = tb_top->add_module_from_technology_library(
448  "if_" + arg_interface + "_" + arg_name, "IF_PORT_" + port_o::GetString(arg_port_dir), LIBRARY_STD,
449  tb_cir, TechM);
450  if_modules.push_back(if_port);
451  if_port->SetParameter("index", STR(idx));
452 
453  THROW_ASSERT(arg_port, "Top level interface is missing port for argument '" + arg_name + "'");
454  const auto val_port = if_port->find_member("val_port", port_o_K, if_port);
455  add_internal_connection(val_port, arg_port);
456  }
457  else if(arg_interface == "m_axi")
458  {
460  "---Interface: " + arg_interface + " (bundle: " + bundle_name + ")");
461  const auto axim_bundle_name = "if_m_axi_" + bundle_name;
462  const auto axim_bundle = tb_cir->find_member(axim_bundle_name + "_fu", component_o_K, tb_cir);
463  if(!axim_bundle)
464  {
465  mgm.create_generic_module("TestbenchAXIM", nullptr, top_fb, LIBRARY_STD, axim_bundle_name);
466  const auto if_port = tb_top->add_module_from_technology_library(
467  axim_bundle_name + "_fu", axim_bundle_name, LIBRARY_STD, tb_cir, TechM);
468  if_modules.push_back(if_port);
469  if_port->SetParameter("index", tb_mem->GetParameter("index"));
470  }
471  const auto if_port = tb_top->add_module_from_technology_library("if_addr_" + arg_name, "IF_PORT_IN",
472  LIBRARY_STD, tb_cir, TechM);
473  if_modules.push_back(if_port);
474  if_port->SetParameter("index", STR(idx));
475 
476  THROW_ASSERT(arg_port, "Top level interface is missing port for argument '" + arg_name + "'");
477  const auto val_port = if_port->find_member("val_port", port_o_K, if_port);
478  add_internal_connection(val_port, arg_port);
479  }
480  else
481  {
483  "---Interface: " + arg_interface + " " +
484  iface_attrs.at(FunctionArchitecture::iface_direction) +
485  (bundle_name != arg_name ? (" (bundle: " + bundle_name + ")") : ""));
486  const auto if_port_name = "if_" + arg_interface + "_" + bundle_name;
487  const auto if_port_bundle = tb_cir->find_member(if_port_name + "_fu", component_o_K, tb_cir);
488  if(!if_port_bundle)
489  {
490  mgm.create_generic_module("Testbench" + capitalize(arg_interface), nullptr, top_fb, LIBRARY_STD,
491  if_port_name);
492  const auto if_port = tb_top->add_module_from_technology_library(if_port_name + "_fu", if_port_name,
493  LIBRARY_STD, tb_cir, TechM);
494  if_port->SetParameter("index", STR(idx));
495  if_modules.push_back(if_port);
496  }
497  }
499  ++idx;
500  }
501 
502  const auto return_port = dut->find_member(RETURN_PORT_NAME, port_o_K, dut);
503  if(return_port)
504  {
505  const auto if_port =
506  tb_top->add_module_from_technology_library("if_return_port", "IF_PORT_OUT", LIBRARY_STD, tb_cir, TechM);
507  if_modules.push_back(if_port);
508  if_port->SetParameter("index", STR(idx));
509 
510  const auto val_port = if_port->find_member("val_port", port_o_K, if_port);
511  add_internal_connection(val_port, return_port);
512  }
513 
514  const auto dut_start = dut->find_member(START_PORT_NAME, port_o_K, dut);
515  THROW_ASSERT(dut_start, "");
516  add_internal_connection(fsm_start, dut_start);
517  }
518 
519  INDENT_DBG_MEX(DEBUG_LEVEL_MINIMUM, debug_level, "Connecting DUT control ports...");
520  {
521  const auto has_dataflow =
522  std::any_of(HLSMgr->module_arch->begin(), HLSMgr->module_arch->end(), [](const auto& fsymbol_arch) {
523  return fsymbol_arch.second->attrs.find(FunctionArchitecture::func_dataflow) !=
524  fsymbol_arch.second->attrs.end();
525  });
526  if(has_dataflow)
527  {
528  INDENT_DBG_MEX(DEBUG_LEVEL_MINIMUM, debug_level, "-->Generating dataflow termination logic...");
529  std::vector<structural_objectRef> tb_done_ports;
530  for(const auto& if_obj : if_modules)
531  {
532  const auto tb_done_port = if_obj->find_member("tb_done_port", port_o_K, if_obj);
533  if(tb_done_port)
534  {
536  "---Considering testbench done port form " + if_obj->get_path());
537  tb_done_ports.push_back(tb_done_port);
538  }
539  }
540  if(tb_done_ports.size())
541  {
542  // Compute logic AND between all dataflow done ports from testbench interface modules
543  const auto tb_done =
544  tb_top->add_module_from_technology_library("tb_done_and", AND_GATE_STD, LIBRARY_STD, tb_cir, TechM);
545  const auto tb_done_out = GetPointerS<module>(tb_done)->get_out_port(0);
546  {
547  const auto merge_port = GetPointerS<module>(tb_done)->get_in_port(0);
548  const auto merge_port_o = GetPointerS<port_o>(merge_port);
549  merge_port_o->add_n_ports(static_cast<unsigned int>(tb_done_ports.size()), merge_port);
550 
551  unsigned int i = 0;
552  for(const auto& tb_done_port : tb_done_ports)
553  {
554  const auto sig =
555  tb_top->add_sign("sig_tb_done_" + std::to_string(i), tb_cir, tb_done_port->get_typeRef());
556  tb_top->add_connection(tb_done_port, sig);
557  tb_top->add_connection(sig, merge_port_o->get_port(i));
558  ++i;
559  }
560  }
561 
562  // Compute logic OR between dataflow done ports' logic AND and standard DUT done port
563  const auto done_or =
564  tb_top->add_module_from_technology_library("tb_done_port", OR_GATE_STD, LIBRARY_STD, tb_cir, TechM);
565  const auto tb_done_port = GetPointerS<module>(done_or)->get_out_port(0);
566  {
567  const auto merge_port = GetPointerS<module>(done_or)->get_in_port(0);
568  const auto merge_port_o = GetPointerS<port_o>(merge_port);
569  merge_port_o->add_n_ports(2U, merge_port);
570 
571  add_internal_connection(merge_port_o->get_port(0U), dut_done);
572  {
573  const auto sig = tb_top->add_sign("sig_tb_done_port", tb_cir, tb_done_out->get_typeRef());
574  tb_top->add_connection(tb_done_out, sig);
575  tb_top->add_connection(sig, merge_port_o->get_port(1U));
576  }
577  }
578 
579  dut_done = tb_done_port;
581  }
582  }
583 
584  const auto dut_reset = dut->find_member(RESET_PORT_NAME, port_o_K, dut);
585  THROW_ASSERT(dut_reset, "");
586  add_internal_connection(fsm_reset, dut_reset);
587  const auto fsm_done = tb_fsm->find_member(DONE_PORT_NAME, port_o_K, tb_fsm);
588  add_internal_connection(fsm_done, dut_done);
589  }
590  INDENT_DBG_MEX(DEBUG_LEVEL_MINIMUM, debug_level, "Connecting testbench modules...");
591  for(const auto& if_obj : if_modules)
592  {
593  INDENT_DBG_MEX(DEBUG_LEVEL_MINIMUM, debug_level, "-->Module " + if_obj->get_id());
594  const auto if_mod = GetPointerS<module>(if_obj);
595  for(unsigned i = 0; i < if_mod->get_in_port_size(); ++i)
596  {
597  const auto in_port = if_mod->get_in_port(i);
598  if(GetPointerS<port_o>(in_port)->get_connections_size())
599  {
600  INDENT_DBG_MEX(DEBUG_LEVEL_MINIMUM, debug_level, "---" + in_port->get_path() + " already connected");
601  continue;
602  }
603  if(in_port->get_id() == CLOCK_PORT_NAME)
604  {
606  "---" + in_port->get_path() + " <-> " + clock_port->get_path());
607  tb_top->add_connection(clock_port, in_port);
608  }
609  else if(in_port->get_id() == RESET_PORT_NAME)
610  {
612  "---" + in_port->get_path() + " <-> " + fsm_reset->get_path());
613  add_internal_connection(in_port, fsm_reset);
614  }
615  else if(in_port->get_id() == SETUP_PORT_NAME)
616  {
618  "---" + in_port->get_path() + " <-> " + fsm_setup->get_path());
619  add_internal_connection(in_port, fsm_setup);
620  }
621  else
622  {
623  const auto dut_port = dut->find_member(in_port->get_id(), port_o_K, dut);
624  if(dut_port)
625  {
627  "---" + in_port->get_path() + " <-> " + dut_port->get_path());
628  add_internal_connection(in_port, dut_port);
629  }
630  else if(GetPointerS<port_o>(in_port)->get_is_memory())
631  {
633  "---Memory port " + in_port->get_id() + " not present in DUT module " + dut->get_path());
634  }
635  else
636  {
637  THROW_UNREACHABLE("Port " + in_port->get_id() + " not found in DUT module " + dut->get_path());
638  }
639  }
640  }
641 
642  for(unsigned i = 0; i < if_mod->get_out_port_size(); ++i)
643  {
644  const auto out_port = if_mod->get_out_port(i);
645  if(GetPointerS<port_o>(out_port)->get_connections_size())
646  {
647  INDENT_DBG_MEX(DEBUG_LEVEL_MINIMUM, debug_level, "---" + out_port->get_path() + " already connected");
648  continue;
649  }
650  const auto dut_port = dut->find_member(out_port->get_id(), port_o_K, dut);
651  if(dut_port)
652  {
654  "---" + out_port->get_path() + " <-> " + dut_port->get_path());
655  add_internal_connection(out_port, dut_port);
656  }
657  else if(GetPointerS<port_o>(out_port)->get_is_memory())
658  {
660  "---Memory port " + out_port->get_id() + " not present in DUT module " + dut->get_path());
661  }
662  else
663  {
664  THROW_UNREACHABLE("Port " + out_port->get_id() + " not found in DUT module " + dut->get_path());
665  }
666  }
668  }
669 
670  INDENT_DBG_MEX(DEBUG_LEVEL_MINIMUM, debug_level, "Generating testbench HDL...");
671  const auto tb_filename = output_directory + CST_STR_BAMBU_TESTBENCH;
672  const auto is_sim_verilator = parameters->getOption<std::string>(OPT_simulator) == "VERILATOR";
673  HDL_manager HDLMgr(HLSMgr, HLSMgr->get_HLS_device(), parameters);
674  std::list<std::string> hdl_files, aux_files;
675  const std::list<structural_objectRef> tb_circuits = {tb_cir};
676  HDLMgr.hdl_gen(tb_filename, tb_circuits, hdl_files, aux_files, true);
677  THROW_ASSERT(hdl_files.size() == 1, "Expected single testbench file");
678  THROW_ASSERT(aux_files.size() <= 1, "Expected at most a single testbench aux file");
679  if(aux_files.size())
680  {
681  HLSMgr->aux_files.push_back(hdl_files.front());
682  HLSMgr->RSim->filename_bench = aux_files.front();
683  }
684  else
685  {
686  HLSMgr->RSim->filename_bench = hdl_files.front();
687  }
688  {
689  std::ifstream bambu_tb(HLSMgr->RSim->filename_bench);
690  std::ofstream bambu_tb_dpi(HLSMgr->RSim->filename_bench + ".dpi");
691 
692  if(is_sim_verilator)
693  {
694  bambu_tb_dpi << "// verilator lint_off BLKANDNBLK\n"
695  << "// verilator lint_off BLKSEQ\n\n";
696  }
697 
698  bambu_tb_dpi << "`timescale 1ns / 1ps\n"
699  << "// CONSTANTS DECLARATION\n"
700  << "`define MAX_COMMENT_LENGTH 1000\n"
701  << "`define INIT_TIME " STR_CST_INIT_TIME "\n\n";
702 
703  if(parameters->getOption<int>(OPT_output_level) < OUTPUT_LEVEL_VERY_PEDANTIC)
704  {
705  bambu_tb_dpi << "`define NDEBUG\n\n";
706  }
707 
708  bambu_tb_dpi << R"(
709 `ifdef __M64
710 typedef longint unsigned ptr_t;
711 `else
712 typedef int unsigned ptr_t;
713 `endif
714 
715 )";
716  bambu_tb_dpi << bambu_tb.rdbuf();
717 
719  HLSMgr->get_HLS_device()->get_technology_manager(), parameters);
720 
721  tb_writer->write_comment("MODULE DECLARATION\n");
722  tb_writer->write("module " CST_STR_BAMBU_TESTBENCH "(" CLOCK_PORT_NAME ");\n");
723  tb_writer->write(STR(STD_OPENING_CHAR));
724  tb_writer->write("\ninput " CLOCK_PORT_NAME ";\n\n");
725 
726  tb_writer->write("initial\n");
727  tb_writer->write(STR(STD_OPENING_CHAR));
728  tb_writer->write("begin\n");
729 
731  tb_writer->write("`ifndef VERILATOR\n");
732  tb_writer->write_comment("VCD file generation\n");
733  const auto vcd_output_filename = output_directory + "test.vcd";
734  tb_writer->write("$dumpfile(\"" + vcd_output_filename + "\");\n");
735  const auto dumpvars_discrepancy =
736  parameters->isOption(OPT_discrepancy) && parameters->getOption<bool>(OPT_discrepancy);
737  if(dumpvars_discrepancy)
738  {
739  tb_writer->write("`ifdef GENERATE_VCD_DISCREPANCY\n");
740  const auto simulator_supports_dumpvars_directive =
741  parameters->getOption<std::string>(OPT_simulator) == "MODELSIM" ||
742  parameters->getOption<std::string>(OPT_simulator) == "ICARUS" ||
743  parameters->getOption<std::string>(OPT_simulator) == "XSIM";
744  if(!simulator_supports_dumpvars_directive ||
745  (static_cast<HDLWriter_Language>(parameters->getOption<unsigned int>(OPT_writer_language)) ==
747  HLSMgr->RDiscr->selected_vcd_signals.empty())
748  {
749  tb_writer->write("`define GENERATE_VCD\n");
750  }
751 #if HAVE_FROM_DISCREPANCY_BUILT
752  else
753  {
754  for(const auto& sig_scope : HLSMgr->RDiscr->selected_vcd_signals)
755  {
756  /*
757  * since the SignalSelectorVisitor used to select the signals is
758  * quite optimistic and it is based only on naming conventions on
759  * the signals, it can select more signal than needed or even select
760  * some signals that are not present. if this happens, asking the
761  * simulator to dump the missing signal through the $dumpvars
762  * directive would result in an error, aborting the simulation. for
763  * this reason we use the dumpvars directive to select only the
764  * scopes, and we then print all the signals in the scope, without
765  * naming them one-by-one
766  */
767  const auto sigscope = boost::replace_all_copy(sig_scope.first, STR(HIERARCHY_SEPARATOR), ".");
768  for(const auto& signame : sig_scope.second)
769  {
770  tb_writer->write("$dumpvars(1, " + sigscope + signame + ");\n");
771  }
772  }
773  }
774 #endif
775  tb_writer->write("`else\n");
776  }
777 
778  tb_writer->write("`ifdef GENERATE_VCD\n");
779  tb_writer->write("$dumpvars;\n");
780  tb_writer->write("`endif\n");
781  if(dumpvars_discrepancy)
782  {
783  tb_writer->write("`endif\n");
784  }
785  tb_writer->write("`endif\n");
786 
787  tb_writer->write(STR(STD_CLOSING_CHAR));
788  tb_writer->write("end\n\n");
789 
790  tb_writer->write(tb_cir->get_id() + " system(." CLOCK_PORT_NAME "(" CLOCK_PORT_NAME "));\n\n");
791 
792  tb_writer->write(STR(STD_CLOSING_CHAR));
793  tb_writer->write("endmodule\n\n");
794 
795  tb_writer->write("`ifndef VERILATOR\n");
796  tb_writer->write("module clocked_" CST_STR_BAMBU_TESTBENCH ";\n");
797  tb_writer->write(STR(STD_OPENING_CHAR));
798  tb_writer->write("parameter HALF_CLOCK_PERIOD=1.0;\n");
799  tb_writer->write("\nreg " CLOCK_PORT_NAME ";\n");
800  tb_writer->write("initial " CLOCK_PORT_NAME " = 1;\n");
801  tb_writer->write("always # HALF_CLOCK_PERIOD " CLOCK_PORT_NAME " = !" CLOCK_PORT_NAME ";\n\n");
802  tb_writer->write(CST_STR_BAMBU_TESTBENCH " bambu_testbench(." CLOCK_PORT_NAME "(" CLOCK_PORT_NAME "));\n\n");
803  tb_writer->write(STR(STD_CLOSING_CHAR));
804  tb_writer->write("endmodule\n");
805  tb_writer->write("`endif\n\n");
806 
807  bambu_tb_dpi << tb_writer->WriteString();
808 
809  if(is_sim_verilator)
810  {
811  bambu_tb_dpi << "// verilator lint_on BLKANDNBLK\n";
812  bambu_tb_dpi << "// verilator lint_on BLKSEQ\n";
813  }
814  }
815  std::filesystem::remove(HLSMgr->RSim->filename_bench);
816  std::filesystem::rename(HLSMgr->RSim->filename_bench + ".dpi", HLSMgr->RSim->filename_bench);
817 
818  if(parameters->getOption<std::string>(OPT_simulator) == "VERILATOR")
819  {
820  HLSMgr->aux_files.push_back(write_verilator_testbench());
821  }
822 
825 }
826 
828 {
829  const std::string filename = output_directory + "bambu_testbench.cpp";
830  std::ofstream os(filename, std::ios::out);
831  simple_indent PP('{', '}', 3);
832 
833  std::string top_fname = mod->get_typeRef()->id_type;
834  PP(os, "#include <memory>\n");
835  PP(os, "\n");
836  PP(os, "#include <verilated.h>\n");
837  PP(os, "\n");
838  PP(os, "#if VM_TRACE\n");
839  PP(os, "# include <verilated_vcd_c.h>\n");
840  PP(os, "#endif\n");
841  PP(os, "\n");
842  PP(os, "#include \"Vbambu_testbench.h\"\n");
843  PP(os, "\n");
844  PP(os, "\n");
845  PP(os, "static vluint64_t CLOCK_PERIOD = 2;\n");
846  PP(os, "static vluint64_t HALF_CLOCK_PERIOD = CLOCK_PERIOD/2;\n");
847  PP(os, "\n");
848  PP(os, "vluint64_t main_time = 0;\n");
849  PP(os, "\n");
850  PP(os, "double sc_time_stamp () {return main_time;}\n");
851  PP(os, "\n");
852  PP(os, "int main (int argc, char **argv, char **env)\n");
853  PP(os, "{\n");
854  PP(os, "Verilated::commandArgs(argc, argv);\n");
855  PP(os, "Verilated::debug(0);\n");
856  PP(os,
857  "const std::unique_ptr<Vbambu_testbench> top{new Vbambu_testbench{\"clocked_" CST_STR_BAMBU_TESTBENCH "\"}};");
858  PP(os, "\n");
859  PP(os, "\n");
860  PP(os, "main_time=0;\n");
861  PP(os, "#if VM_TRACE\n");
862  PP(os, "Verilated::traceEverOn(true);\n");
863  PP(os, "const std::unique_ptr<VerilatedVcdC> tfp{new VerilatedVcdC};\n");
864  PP(os, "top->trace (tfp.get(), 99);\n");
865  PP(os, "tfp->set_time_unit(\"p\");\n");
866  PP(os, "tfp->set_time_resolution(\"p\");\n");
867  PP(os, "tfp->open (\"" + output_directory + "test.vcd\");\n");
868  PP(os, "#endif\n");
869  PP(os, "top->" CLOCK_PORT_NAME " = 1;\n");
870  PP(os, "while (!Verilated::gotFinish())\n");
871  PP(os, "{\n");
872  PP(os, "top->" CLOCK_PORT_NAME " = !top->" CLOCK_PORT_NAME ";\n");
873  PP(os, "top->eval();\n");
874  PP(os, "#if VM_TRACE\n");
875  PP(os, "tfp->dump (main_time);\n");
876  PP(os, "#endif\n");
877  PP(os, "main_time += HALF_CLOCK_PERIOD;\n");
878  PP(os, "}\n");
879  PP(os, "#if VM_TRACE\n");
880  PP(os, "tfp->dump (main_time);\n");
881  PP(os, "tfp->close();\n");
882  PP(os, "#endif\n");
883  PP(os, "top->final();\n");
884  PP(os, "\n");
885  PP(os, "return 0;\n");
886  PP(os, "}");
887 
888  return filename;
889 }
890 
891 std::vector<std::string> TestbenchGeneration::print_var_init(const tree_managerConstRef TM, unsigned int var,
892  const memoryRef mem)
893 {
894  std::vector<std::string> init_els;
895  const auto tn = TM->CGetTreeReindex(var);
896  const auto init_node = [&]() -> tree_nodeRef {
897  const auto vd = GetPointer<const var_decl>(GET_CONST_NODE(tn));
898  if(vd && vd->init)
899  {
900  return vd->init;
901  }
902  return nullptr;
903  }();
904 
905  if(init_node && (!GetPointer<const constructor>(GET_CONST_NODE(init_node)) ||
906  GetPointerS<const constructor>(GET_CONST_NODE(init_node))->list_of_idx_valu.size()))
907  {
908  fu_binding::write_init(TM, tn, init_node, init_els, mem, 0);
909  }
910  else if(GET_CONST_NODE(tn)->get_kind() == string_cst_K || GET_CONST_NODE(tn)->get_kind() == integer_cst_K ||
911  GET_CONST_NODE(tn)->get_kind() == real_cst_K)
912  {
913  fu_binding::write_init(TM, tn, tn, init_els, mem, 0);
914  }
915  else if(!GetPointer<gimple_call>(GET_CONST_NODE(tn)))
916  {
918  {
919  const auto type = tree_helper::CGetType(tn);
920  const auto data_bitsize = tree_helper::GetArrayElementSize(type);
921  const auto num_elements = tree_helper::GetArrayTotalSize(type);
922  init_els.insert(init_els.end(), num_elements, std::string(data_bitsize, '0'));
923  }
924  else
925  {
926  const auto data_bitsize = tree_helper::Size(tn);
927  init_els.push_back(std::string(data_bitsize, '0'));
928  }
929  }
930  return init_els;
931 }
932 
933 unsigned long long TestbenchGeneration::generate_init_file(const std::string& dat_filename,
934  const tree_managerConstRef TM, unsigned int var,
935  const memoryRef mem)
936 {
937  std::stringstream init_bits;
938  std::ofstream useless;
939  unsigned long long vec_size = 0, elts_size = 0;
940  const auto var_type = tree_helper::CGetType(TM->CGetTreeReindex(var));
941  const auto bitsize_align = GetPointer<const type_node>(GET_CONST_NODE(var_type))->algn;
942  THROW_ASSERT((bitsize_align % 8) == 0, "Alignement is not byte aligned.");
943  fu_binding::fill_array_ref_memory(init_bits, useless, var, vec_size, elts_size, mem, TM, false, bitsize_align);
944 
945  std::ofstream init_dat(dat_filename, std::ios::binary);
946  while(!init_bits.eof())
947  {
948  std::string bitstring;
949  init_bits >> bitstring;
950  THROW_ASSERT(bitstring.size() % 8 == 0, "Memory word initializer is not aligned");
951  size_t i;
952  // Memory is little-endian, thus last byte goes in first
953  for(i = bitstring.size(); i >= 8; i -= 8)
954  {
955  char byteval = 0;
956  for(size_t k = 0; k < 8; ++k)
957  {
958  byteval = byteval | static_cast<char>((bitstring.at(i - k - 1U) != '0') << k);
959  }
960  init_dat.put(byteval);
961  }
962  }
963  unsigned long long bytes = static_cast<unsigned long long>(init_dat.tellp());
964  THROW_ASSERT((bytes % (bitsize_align / 8)) == 0, "Memory initalization bytes not aligned");
965  return bytes;
966 }
void add_connection(structural_objectRef src, structural_objectRef dest)
Create a connection between a source structural object and a destination structural object...
void ComputeRelationships(DesignFlowStepSet &design_flow_step_set, const DesignFlowStep::RelationshipType relationship_type) override
Compute the relationships of a step with other steps.
const HLS_managerRef HLSMgr
information about all the HLS synthesis
Definition: hls_step.hpp:205
#define OR_GATE_STD
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;.
Factory class to create c backend.
refcount< structural_type_descriptor > structural_type_descriptorRef
RefCount type definition of the structural_type_descriptor class structure.
std::string capitalize(const std::string &str)
void hdl_gen(const std::string &filename, const std::list< structural_objectRef > &cirs, std::list< std::string > &hdl_files, std::list< std::string > &aux_files, bool tb)
Generates HDL code.
bool HasToBeExecuted() const override
Check if this step has actually to be executed.
#define START_PORT_NAME
Structure representing the most relevant information about the type of a structural object...
const std::string & get_id() const
Return the identifier associated with the structural_object.
const std::string c_testbench_basename
const tree_nodeRef CGetTreeReindex(const unsigned int i) const
Return a tree_reindex wrapping the i-th tree_node.
std::string filename
#define GET_CLASS(obj)
Macro returning the actual type of an object.
#define GENERATED_LICENSE
static std::string GetString(enum port_direction)
const structural_objectRef get_circ() const
Get a reference to circ field.
#define AND_GATE_STD
RelationshipType
The relationship type.
Source must be executed to satisfy target.
Datastructure to represent a memory symbol in HLS.
mathematical utility function not provided by standard libraries
static unsigned long long generate_init_file(const std::string &dat_filename, const tree_managerConstRef TreeM, unsigned int var, const memoryRef mem)
Generate HDL testbench for the top-level kernel testing.
This class manages the circuit structures.
static std::vector< std::string > print_var_init(const tree_managerConstRef TreeM, unsigned int var, const memoryRef mem)
static language_writerRef create_writer(HDLWriter_Language language, const technology_managerConstRef TM, const ParameterConstRef parameters)
Creates the specialization of the writer based on the desired language.
std::string hdl_testbench_basename
testbench basename
virtual structural_objectRef find_member(const std::string &id, so_kind type, const structural_objectRef owner) const =0
Return the object named id of a given type which belongs to or it is associated with the object...
static unsigned long long GetArrayElementSize(const tree_nodeConstRef &node)
Return the size (in bits) of the base element of the array.
Definition of hash function for EdgeDescriptor.
Definition: graph.hpp:1321
void Initialize() override
Initialize the step (i.e., like a constructor, but executed just before exec.
Class specification of the manager of the technology library data structures.
#define RETURN_PORT_NAME
#define CST_STR_BAMBU_TESTBENCH
Base class to pass information to a c backend.
std::string GetParameter(std::string name) const
Get the value associated to parameter if it has been associated; if it has not specified returns the ...
static void write_init(const tree_managerConstRef TreeM, tree_nodeRef var_node, tree_nodeRef init_node, std::vector< std::string > &init_file, const memoryRef mem, unsigned long long element_precision)
Simple class used to drive the backend in order to be able to print c source code.
#define STR(s)
Macro which performs a lexical_cast to a string.
HDLWriter_Language
#define CLOCK_PORT_NAME
standard name for ports
static void fill_array_ref_memory(std::ostream &init_file_a, std::ostream &init_file_b, unsigned int ar, unsigned long long &vec_size, unsigned long long &elts_size, const memoryRef mem, tree_managerConstRef TM, bool is_sds, unsigned long long bitsize_align)
fill the memory of the array ref
structural_objectRef cir
static bool IsArrayType(const tree_nodeConstRef &type)
Return true if treenode is an array.
#define THROW_UNREACHABLE(str_expr)
helper function used to specify that some points should never be reached
Definition: exceptions.hpp:292
static unsigned long long Size(const tree_nodeConstRef &tn)
Return the size of a tree object.
void set_top_info(const std::string &id, const technology_managerRef &LM, const std::string &Library="")
#define DONE_PORT_NAME
static const uint32_t k[]
Definition: sha-256.c:22
HLSFlowStep_Type
Definition: hls_step.hpp:95
This class writes different HDL based descriptions (VHDL, Verilog, SystemC) starting from a structura...
Class specification of the data structures used to manage technology information. ...
const CustomUnorderedSet< std::tuple< HLSFlowStep_Type, HLSFlowStepSpecializationConstRef, HLSFlowStep_Relationship > > ComputeHLSRelationships(const DesignFlowStep::RelationshipType relationship_type) const override
Return the set of analyses in relationship with this design step.
static structural_objectRef add_port(const std::string &id, port_o::port_direction pdir, structural_objectRef owner, structural_type_descriptorRef type_descr, unsigned int treenode=0)
Create a new port.
Classes to describe design flow graph.
#define LIBRARY_STD
standard library where all built-in ports are defined.
DesignFlowStep_Status Exec() override
Execute the step.
TestbenchGeneration(const ParameterConstRef parameters, const HLS_managerRef _HLSMgr, const DesignFlowManagerConstRef design_flow_manager)
Constructor.
const Wrefcount< const DesignFlowManager > design_flow_manager
The design flow manager.
#define GET_CONST_NODE(t)
Definition: tree_node.hpp:347
void SetParameter(const std::string &name, const std::string &value)
Set a parameter value.
virtual enum so_kind get_kind() const =0
Virtual function used to find the real type of a structural_object instance.
Classes specification of the tree_node data structures.
const ParameterConstRef parameters
Set of input parameters.
DesignFlowStep_Status
The status of a step.
This file collects some utility functions and macros.
#define STR_CST_INIT_TIME
Constant delay for testbench initialization. It is relevant for XILINX devices.
#define THROW_ERROR(str_expr)
helper function used to throw an error in a standard way
Definition: exceptions.hpp:263
Wrapper of design_flow.
#define STD_OPENING_CHAR
STD include.
const std::string output_directory
output directory
void type_resize(unsigned long long new_bit_size)
Just resize the size of the bits of the object.
Data structure definition for HLS constraints.
constants used in testbench generation
#define HIERARCHY_SEPARATOR
This file collects some utility functions.
void ComputeRelationships(DesignFlowStepSet &design_flow_step_set, const DesignFlowStep::RelationshipType relationship_type) override
Compute the relationships of a step with other steps.
Definition: hls_step.cpp:302
structural_objectRef add_module_from_technology_library(const std::string &id, const std::string &fu_name, const std::string &library_name, const structural_objectRef owner, const technology_managerConstRef TM)
Create a new object starting from a library component.
refcount< T > lock() const
Definition: refcount.hpp:212
Very simple pretty printer functor.
Utility header to access wishbone technology library.
std::string id_type
Original type id of the structural object.
#define STD_CLOSING_CHAR
Special closing character used to close the current nested level.
This class describes all classes used to represent a structural object.
const structural_type_descriptorRef & get_typeRef() const
Return the type descriptor of the structural_object.
Class specification of the tree_reindex support class.
static structural_objectRef add_sign(std::string id, structural_objectRef owner, structural_type_descriptorRef sign_type, unsigned int treenode=0)
Create a new signal.
#define OUTPUT_LEVEL_VERY_PEDANTIC
verbose debugging print is performed.
Data structure used to store the functional-unit binding of the vertexes.
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.
HDL writer base class used to specify the interface of the different language writers.
It collects all the common strings covering PandA copyrights issues.
this class is used to manage the command-line or XML options.
#define RESET_PORT_NAME
Wrapper to call graph.
Class implementation of the structural_manager.
std::string write_verilator_testbench() const
Write the verilator testbench.
Class specification of the manager for each library.
#define MOUT_OE_PORT_NAME
#define MOUT_BACK_PRESSURE_PORT_NAME
int debug_level
The debug level.
This class writes different HDL based descriptions (VHDL, Verilog, SystemC) starting from a structura...
refcount< const HLSFlowStepSpecialization > HLSFlowStepSpecializationConstRef
const refcount definition of the class
Definition: hls_step.hpp:93
#define GET_INDEX_CONST_NODE(t)
Definition: tree_node.hpp:363
Base class to pass information to a c backend.
void create_generic_module(const std::string &fu_name, vertex ve, const FunctionBehaviorConstRef FB, const std::string &libraryId, const std::string &new_fu_name)
static bool IsPointerType(const tree_nodeConstRef &type)
Return true if treenode index is a pointer.
Data structure definition for high-level synthesis flow.
static tree_nodeConstRef GetFunctionReturnType(const tree_nodeConstRef &function, bool void_as_null=true)
Return the return type of a function.
#define GENERATED_COPYRIGHT
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.
HLS specialization of generic_device.
A brief description of the C++ Header File.
#define DEBUG_LEVEL_MINIMUM
minimum debugging print is performed.
#define SETUP_PORT_NAME
#define STD_GET_SIZE(structural_obj)
Macro returning the size of a type.
#define STR_CST_testbench_generation_basename
The basename of the testbench files.
#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:54 for PandA-2024.02 by doxygen 1.8.13