PandA-2024.02
allocation.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 "allocation.hpp"
42 
43 #include "HDL_manager.hpp" // for structural_managerRef, langu...
44 #include "ModuleGeneratorManager.hpp" // for structural_objectRef, struct...
45 #include "NP_functionality.hpp" // for NP_functionalityRef
46 #include "Parameter.hpp" // for ParameterConstRef
47 #include "allocation_information.hpp" // for technology_nodeRef, node_kin...
49 #include "area_info.hpp"
50 #include "behavioral_helper.hpp"
51 #include "call_graph_manager.hpp"
52 #include "config_HAVE_EXPERIMENTAL.hpp" // for HAVE_EXPERIMENTAL
53 #include "config_HAVE_FLOPOCO.hpp" // for HAVE_FLOPOCO
54 #include "cpu_time.hpp" // for START_TIME, STOP_TIME
55 #include "custom_map.hpp"
56 #include "custom_set.hpp"
57 #include "dbgPrintHelper.hpp" // for DEBUG_LEVEL_VERY_PEDANTIC
58 #include "design_flow_graph.hpp"
59 #include "design_flow_manager.hpp"
60 #include "design_flow_step_factory.hpp" // for DesignFlowManagerConstRef
61 #include "exceptions.hpp" // for THROW_ASSERT, THROW_ERROR
64 #include "functions.hpp"
65 #include "generic_device.hpp"
66 #include "hls.hpp" // for HLS_constraintsRef
67 #include "hls_constraints.hpp" // for ENCODE_FU_LIB
68 #include "hls_device.hpp"
69 #include "hls_flow_step_factory.hpp" // for HLS_managerRef
70 #include "language_writer.hpp"
71 #include "library_manager.hpp" // for library_managerRef, library_...
72 #include "memory.hpp"
73 #include "memory_allocation.hpp"
74 #include "op_graph.hpp" // for STORE, ADDR_EXPR, ASSERT_EXPR
75 #include "schedule.hpp" // for FunctionBehaviorConstRef
76 #include "string_manipulation.hpp" // for STR GET_CLASS
77 #include "structural_manager.hpp"
78 #include "structural_objects.hpp" // for PROXY_PREFIX, module, CLOCK_...
79 #include "technology_manager.hpp" // for PROXY_LIBRARY, WORK_LIBRARY
80 #include "technology_node.hpp" // for functional_unit, operation
81 #include "time_info.hpp" // for ParameterConstRef
82 #include "tree_helper.hpp"
83 #include "tree_manager.hpp"
84 #include "tree_node.hpp" // for GET_NODE, GET_INDEX_NODE
85 #include "tree_reindex.hpp"
86 #include "typed_node_info.hpp" // for GET_NAME, ENTRY, EXIT, GET_TYPE
87 #include "utility.hpp" // for INFINITE_UINT, ASSERT_PARAMETER
88 #include <algorithm>
89 #include <cstddef> // for size_t
90 #include <limits> // for numeric_limits
91 #include <tuple>
92 #include <utility>
93 #include <vector>
94 
95 static bool is_other_port(const structural_objectRef& port)
96 {
97  const auto p = GetPointer<port_o>(port);
98  return p->get_is_memory() or p->get_is_global() or p->get_is_extern() or
99  p->get_port_interface() != port_o::port_interface::PI_DEFAULT;
100 }
101 
102 static bool is_a_skip_operation(const std::string& op_name)
103 {
104  if(op_name == "mult_expr" || op_name == "widen_mult_expr" || op_name == "dot_prod_expr")
105  {
106  return true;
107  }
108  else
109  {
110  return false;
111  }
112 }
113 
114 static inline std::string encode_op_type(const std::string& op_name, const std::string& fu_supported_types)
115 {
116  return op_name + ":" + fu_supported_types;
117 }
118 
119 static inline std::string encode_op_type_prec(const std::string& op_name, const std::string& fu_supported_types,
120  node_kind_prec_infoRef node_info)
121 {
122  std::string op_type = encode_op_type(op_name, fu_supported_types);
123  const size_t n_ins = node_info->input_prec.size();
124  for(size_t ind = 0; ind < n_ins; ++ind)
125  {
126  if(node_info->base128_input_nelem[ind] == 0)
127  {
128  op_type += ":" + STR(node_info->input_prec[ind]);
129  }
130  else
131  {
132  op_type += ":" + STR(node_info->input_prec[ind]) + ":" + STR(node_info->base128_input_nelem[ind]);
133  }
134  }
135  if(node_info->base128_output_nelem == 0)
136  {
137  op_type += ":" + STR(node_info->output_prec);
138  }
139  else
140  {
141  op_type += ":" + STR(node_info->output_prec) + ":" + STR(node_info->base128_output_nelem);
142  }
143  return op_type;
144 }
145 
146 allocation::allocation(const ParameterConstRef _parameters, const HLS_managerRef _HLSMgr, unsigned _funId,
147  const DesignFlowManagerConstRef _design_flow_manager, const HLSFlowStep_Type _hls_flow_step_type)
148  : HLSFunctionStep(_parameters, _HLSMgr, _funId, _design_flow_manager, _hls_flow_step_type)
149 {
150  debug_level = _parameters->get_class_debug_level(GET_CLASS(*this));
151 }
152 
153 allocation::~allocation() = default;
154 
156 {
159  {
161  }
162  else
163  {
165  }
168  fu_list.clear();
169  HLS_D = HLSMgr->get_HLS_device();
171 }
172 
175 {
177  switch(relationship_type)
178  {
180  {
181  if(!parameters->getOption<int>(OPT_gcc_openmp_simd))
182  {
185  }
190  break;
191  }
193  {
194  break;
195  }
197  {
198  break;
199  }
200  default:
201  THROW_UNREACHABLE("");
202  }
203  return ret;
204 }
206  const DesignFlowStep::RelationshipType relationship_type)
207 {
208  if(relationship_type == DEPENDENCE_RELATIONSHIP)
209  {
210  if(!parameters->getOption<int>(OPT_gcc_openmp_simd))
211  {
212  const auto frontend_flow_step_factory = GetPointer<const FrontendFlowStepFactory>(
213  design_flow_manager.lock()->CGetDesignFlowStepFactory("Frontend"));
214  const auto frontend_step = design_flow_manager.lock()->GetDesignFlowStep(
215  FunctionFrontendFlowStep::ComputeSignature(FrontendFlowStepType::BIT_VALUE, funId));
216  const auto design_flow_graph = design_flow_manager.lock()->CGetDesignFlowGraph();
217  const auto design_flow_step =
218  frontend_step != NULL_VERTEX ?
219  design_flow_graph->CGetDesignFlowStepInfo(frontend_step)->design_flow_step :
220  frontend_flow_step_factory->CreateFunctionFrontendFlowStep(FrontendFlowStepType::BIT_VALUE, funId);
221  relationship.insert(design_flow_step);
222  }
223  }
224  HLSFunctionStep::ComputeRelationships(relationship, relationship_type);
225 }
226 
227 technology_nodeRef allocation::extract_bambu_provided(const std::string& library_name, operation* curr_op,
228  const std::string& bambu_provided_resource_)
229 {
230  technology_nodeRef current_fu;
231  std::string function_name;
232  bool build_proxy = false;
233  bool build_wrapper = false;
234  const auto bambu_provided_resource = functions::GetFUName(bambu_provided_resource_, HLSMgr);
235  if(HLSMgr->Rfuns->is_a_proxied_function(bambu_provided_resource))
236  {
237  if(HLSMgr->Rfuns->is_a_shared_function(funId, bambu_provided_resource))
238  {
239  function_name = WRAPPED_PROXY_PREFIX + bambu_provided_resource;
240  build_wrapper = true;
241  }
242  else
243  {
244  THROW_ASSERT(HLSMgr->Rfuns->is_a_proxied_shared_function(funId, bambu_provided_resource),
245  "expected a proxy module");
246  function_name = PROXY_PREFIX + bambu_provided_resource;
247  build_proxy = true;
248  }
249  }
250  else
251  {
252  function_name = bambu_provided_resource;
253  }
254  const library_managerRef libraryManager = TechM->get_library_manager(library_name);
255  THROW_ASSERT(libraryManager->is_fu(function_name),
256  "functional unit not yet synthesized: " + function_name + "(" + library_name + ")");
257  current_fu = libraryManager->get_fu(function_name);
258  THROW_ASSERT(current_fu, "functional unit not yet synthesized: " + function_name + "(" + library_name + ")");
259  const std::vector<technology_nodeRef>& op_vec = GetPointer<functional_unit>(current_fu)->get_operations();
260  bool has_current_op = false;
261 
262  std::string op_name = curr_op->get_name();
263  for(const auto& op_it : op_vec)
264  {
265  if(GetPointer<operation>(op_it)->get_name() == op_name)
266  {
267  has_current_op = true;
268  }
269  }
270 
271  if(!has_current_op)
272  {
274  auto* cop = GetPointer<operation>(op);
275  auto* ref_op = GetPointer<operation>(op_vec[0]);
276  cop->operation_name = op_name;
277  cop->time_m = ref_op->time_m;
278 #if HAVE_EXPERIMENTAL
279  cop->power_m = ref_op->power_m;
280 #endif
281  cop->commutative = curr_op->commutative;
282  cop->bounded = ref_op->bounded;
283  cop->supported_types = curr_op->supported_types;
284  cop->pipe_parameters = curr_op->pipe_parameters;
285  GetPointer<functional_unit>(current_fu)->add(op);
286  }
287  else
288  {
289  for(const auto& op_it : op_vec)
290  {
291  if(GetPointer<operation>(op_it)->get_name() == op_name)
292  {
293  auto* fu_ob = GetPointer<functional_unit>(TechM->get_fu(bambu_provided_resource, WORK_LIBRARY));
294  THROW_ASSERT(fu_ob, "Functional unit not found for " + bambu_provided_resource);
295  auto* op_ob = GetPointer<operation>(fu_ob->get_operation(bambu_provided_resource));
296  GetPointer<operation>(op_it)->bounded = op_ob->bounded;
297  }
298  }
299  }
300 
301  if(build_wrapper)
302  {
303  BuildProxyWrapper(GetPointer<functional_unit>(current_fu), bambu_provided_resource, WORK_LIBRARY);
304  }
305  if(build_proxy)
306  {
307  BuildProxyFunction(GetPointer<functional_unit>(current_fu));
308  }
309  return current_fu;
310 }
311 
312 static std::string fix_identifier(std::string port_name, language_writerRef writer)
313 {
314  std::string name = HDL_manager::convert_to_identifier(GetPointer<language_writer>(writer), port_name);
315  return name;
316 }
317 
319  structural_objectRef& component)
320 {
321  // Clock and Reset connection
322  structural_objectRef port_ck = component->find_member(CLOCK_PORT_NAME, port_o_K, component);
323  structural_objectRef clock = interfaceObj->find_member(CLOCK_PORT_NAME, port_o_K, interfaceObj);
324  if(port_ck and clock)
325  {
326  SM->add_connection(port_ck, clock);
327  }
328 
329  structural_objectRef port_rst = component->find_member(RESET_PORT_NAME, port_o_K, component);
330  structural_objectRef reset = interfaceObj->find_member(RESET_PORT_NAME, port_o_K, interfaceObj);
331  if(port_rst and reset)
332  {
333  SM->add_connection(port_rst, reset);
334  }
335 }
336 
337 void allocation::BuildProxyWrapper(functional_unit* current_fu, const std::string& orig_fun_name,
338  const std::string& orig_library_name)
339 {
340  const library_managerRef orig_libraryManager = TechM->get_library_manager(orig_library_name);
341  THROW_ASSERT(orig_libraryManager->is_fu(orig_fun_name),
342  "functional unit not yet synthesized: " + orig_fun_name + "(" + orig_library_name + ")");
343  technology_nodeRef orig_fun = orig_libraryManager->get_fu(orig_fun_name);
344  THROW_ASSERT(orig_fun, "functional unit not yet synthesized: " + orig_fun_name + "(" + orig_library_name + ")");
345 
346  structural_managerRef orig_fu_SM = GetPointer<functional_unit>(orig_fun)->CM;
347  structural_objectRef orig_top_obj = orig_fu_SM->get_circ();
348  orig_top_obj->set_id(orig_fun_name + "_i");
349  const module* orig_fu_module = GetPointer<module>(orig_top_obj);
350 
351  structural_managerRef wrapper_SM = current_fu->CM;
352  structural_objectRef wrapper_obj = wrapper_SM->get_circ();
353  connectClockAndReset(wrapper_SM, wrapper_obj, orig_top_obj);
354  // create the selector signal to tell proxied and unproxied calls apart
355  structural_type_descriptorRef bool_signal_type =
357  // select the operations mode of the functional unit, used to drive the proxy selector
358  const functional_unit::operation_vec& ops = current_fu->get_operations();
359  std::vector<structural_objectRef> op_ports;
360  for(const auto& o : ops)
361  {
362  const std::string op_name = GetPointer<operation>(o)->get_name();
363  if(!starts_with(op_name, WRAPPED_PROXY_PREFIX))
364  {
365  const std::string sel_port_name = "sel_" + op_name;
366  structural_objectRef new_sel_port = wrapper_obj->find_member(sel_port_name, port_o_K, wrapper_obj);
367  /*
368  * sometimes the selector port is already present in the proxy.
369  * This happens in particular this happens for abort and
370  * __builtin_abort.
371  * In this case there is no need to add the new port.
372  */
373  if(!new_sel_port)
374  {
375  wrapper_SM->add_port(sel_port_name, port_o::IN, wrapper_obj, bool_signal_type);
376  new_sel_port = wrapper_obj->find_member(sel_port_name, port_o_K, wrapper_obj);
377  }
378  op_ports.push_back(new_sel_port);
379  }
380  }
381  // build a binary tree of ors to drive the proxy selector
382  structural_objectRef selector_signal =
383  wrapper_SM->add_sign("proxy_selector____out_sel", wrapper_obj, bool_signal_type);
384  if(!op_ports.empty())
385  {
386  structural_objectRef or_gate = wrapper_SM->add_module_from_technology_library(
387  "proxy_selector____or_gate", OR_GATE_STD, HLS->HLS_D->get_technology_manager()->get_library(OR_GATE_STD),
388  wrapper_obj, HLS->HLS_D->get_technology_manager());
389  structural_objectRef or_in = or_gate->find_member("in", port_vector_o_K, or_gate);
390  auto* port = GetPointer<port_o>(or_in);
391  port->add_n_ports(static_cast<unsigned int>(op_ports.size()), or_in);
392  unsigned int port_n = 0;
393  for(const auto& p : op_ports)
394  {
395  wrapper_SM->add_connection(p, port->get_port(port_n));
396  port_n++;
397  }
398  structural_objectRef or_out = or_gate->find_member("out1", port_o_K, or_gate);
399  wrapper_SM->add_connection(or_out, selector_signal);
400  }
401 
402  auto inPortSize = static_cast<unsigned int>(orig_fu_module->get_in_port_size());
403  for(unsigned int port_id = 0; port_id < inPortSize; port_id++)
404  {
405  structural_objectRef curr_port = orig_fu_module->get_in_port(port_id);
406  const std::string port_name = curr_port->get_id();
407  if(port_name != CLOCK_PORT_NAME and port_name != RESET_PORT_NAME)
408  {
409  if(is_other_port(curr_port))
410  {
411  structural_objectRef wrapper_mem_port = wrapper_obj->find_member(port_name, port_o_K, wrapper_obj);
412  structural_objectRef wrapped_mem_port = orig_top_obj->find_member(port_name, port_o_K, orig_top_obj);
413  wrapper_SM->add_connection(wrapper_mem_port, wrapped_mem_port);
414  continue;
415  }
416  const std::string proxy_port_name = PROXY_PREFIX + port_name;
417  // insert wDataMux
418  const auto addwDataMux = [&](const std::string offset) {
419  structural_objectRef wrapped_fu_port = orig_top_obj->find_member(port_name, port_o_K, orig_top_obj);
420  if(offset.size())
421  {
422  wrapped_fu_port = wrapped_fu_port->find_member(offset, port_o_K, wrapped_fu_port);
423  }
424  structural_type_descriptorRef wrapped_port_type = wrapped_fu_port->get_typeRef();
425  auto bitwidth_size = STD_GET_SIZE(wrapped_port_type);
426 
427  structural_objectRef mux = wrapper_SM->add_module_from_technology_library(
428  "proxy_mux_____" + port_name + offset, MUX_GATE_STD,
429  HLS->HLS_D->get_technology_manager()->get_library(MUX_GATE_STD), wrapper_obj,
430  HLS->HLS_D->get_technology_manager());
431  structural_objectRef mux_in1 = mux->find_member("in1", port_o_K, mux);
432  GetPointer<port_o>(mux_in1)->type_resize(bitwidth_size);
433  structural_objectRef mux_in2 = mux->find_member("in2", port_o_K, mux);
434  GetPointer<port_o>(mux_in2)->type_resize(bitwidth_size);
435  structural_objectRef mux_out = mux->find_member("out1", port_o_K, mux);
436  GetPointer<port_o>(mux_out)->type_resize(bitwidth_size);
437  structural_objectRef mux_sel = mux->find_member("sel", port_o_K, mux);
438  structural_type_descriptorRef mux_out_type = mux_out->get_typeRef();
439  const std::string tmp_signal_name = "muxed_in_" + port_name + offset;
440  structural_objectRef proxied_in_signal = wrapper_SM->add_sign(tmp_signal_name, wrapper_obj, mux_out_type);
441 
442  structural_objectRef proxied_call_port = wrapper_obj->find_member(proxy_port_name, port_o_K, wrapper_obj);
443  if(offset.size())
444  {
445  proxied_call_port = proxied_call_port->find_member(offset, port_o_K, proxied_call_port);
446  }
447  GetPointer<port_o>(proxied_call_port)->type_resize(bitwidth_size);
448  structural_objectRef local_call_port = wrapper_obj->find_member(port_name, port_o_K, wrapper_obj);
449  if(offset.size())
450  {
451  local_call_port = local_call_port->find_member(offset, port_o_K, local_call_port);
452  }
453  GetPointer<port_o>(local_call_port)->type_resize(bitwidth_size);
454 
455  wrapper_SM->add_connection(mux_sel, selector_signal);
456  wrapper_SM->add_connection(mux_in1, local_call_port);
457  wrapper_SM->add_connection(mux_in2, proxied_call_port);
458  wrapper_SM->add_connection(mux_out, proxied_in_signal);
459  wrapper_SM->add_connection(proxied_in_signal, wrapped_fu_port);
460  };
461 
462  if(curr_port->get_kind() == port_o_K)
463  {
464  addwDataMux("");
465  }
466  else
467  {
468  for(unsigned int pindex = 0; pindex < GetPointer<port_o>(curr_port)->get_ports_size(); ++pindex)
469  {
470  addwDataMux(STR(pindex));
471  }
472  }
473  }
474  }
475  auto outPortSize = static_cast<unsigned int>(orig_fu_module->get_out_port_size());
476  for(unsigned int currentPort = 0; currentPort < outPortSize; ++currentPort)
477  {
478  structural_objectRef curr_port = orig_fu_module->get_out_port(currentPort);
479  const std::string port_name = curr_port->get_id();
480  if(is_other_port(curr_port))
481  {
482  structural_objectRef wrapper_mem_port = wrapper_obj->find_member(port_name, port_o_K, wrapper_obj);
483  structural_objectRef wrapped_mem_port = orig_top_obj->find_member(port_name, port_o_K, orig_top_obj);
484  wrapper_SM->add_connection(wrapper_mem_port, wrapped_mem_port);
485  continue;
486  }
487  const std::string proxy_port_name = PROXY_PREFIX + port_name;
488  const auto addwData = [&](const std::string offset) {
489  structural_objectRef local_port = wrapper_obj->find_member(port_name, port_o_K, wrapper_obj);
490  if(offset.size())
491  {
492  local_port = local_port->find_member(offset, port_o_K, local_port);
493  }
494  structural_objectRef proxied_port = wrapper_obj->find_member(proxy_port_name, port_o_K, wrapper_obj);
495  if(offset.size())
496  {
497  proxied_port = proxied_port->find_member(offset, port_o_K, proxied_port);
498  }
499  structural_objectRef wrapped_fu_port = orig_top_obj->find_member(port_name, port_o_K, orig_top_obj);
500  if(offset.size())
501  {
502  wrapped_fu_port = wrapped_fu_port->find_member(offset, port_o_K, wrapped_fu_port);
503  }
504  structural_type_descriptorRef wrapped_port_type = wrapped_fu_port->get_typeRef();
505  auto bitwidth_size = STD_GET_SIZE(wrapped_port_type);
506  GetPointer<port_o>(local_port)->type_resize(bitwidth_size);
507  GetPointer<port_o>(proxied_port)->type_resize(bitwidth_size);
508  const std::string tmp_signal_name = "tmp_out_" + port_name + offset;
509  structural_objectRef out_signal_tmp = wrapper_SM->add_sign(tmp_signal_name, wrapper_obj, wrapped_port_type);
510  wrapper_SM->add_connection(wrapped_fu_port, out_signal_tmp);
511  wrapper_SM->add_connection(out_signal_tmp, local_port);
512  wrapper_SM->add_connection(out_signal_tmp, proxied_port);
513  };
514  if(curr_port->get_kind() == port_o_K)
515  {
516  addwData("");
517  }
518  else
519  {
520  for(unsigned int pindex = 0; pindex < GetPointer<port_o>(curr_port)->get_ports_size(); ++pindex)
521  {
522  addwData(STR(pindex));
523  }
524  }
525  }
526 
527  memory::propagate_memory_parameters(orig_top_obj, wrapper_SM);
528 }
529 
530 void allocation::add_proxy_function_wrapper(const std::string& library_name, technology_nodeRef techNode_obj,
531  const std::string& orig_fun_name)
532 {
533  const std::string wrapped_fu_name = WRAPPED_PROXY_PREFIX + orig_fun_name;
534  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, " - adding proxy function wrapper " + wrapped_fu_name);
535  structural_managerRef structManager_obj = GetPointer<functional_unit>(techNode_obj)->CM;
536  structural_objectRef fu_obj = structManager_obj->get_circ();
537  auto* fu_module = GetPointer<module>(fu_obj);
538 
539  structural_objectRef wrapper_top;
541  structural_type_descriptorRef module_type =
543  CM->set_top_info(wrapped_fu_name, module_type);
544  wrapper_top = CM->get_circ();
546  GetPointer<module>(wrapper_top)->set_description("Proxy wrapper for function: " + wrapped_fu_name);
547  GetPointer<module>(wrapper_top)->set_copyright(fu_module->get_copyright());
548  GetPointer<module>(wrapper_top)->set_authors(fu_module->get_authors());
549  GetPointer<module>(wrapper_top)->set_license(fu_module->get_license());
550  GetPointer<module>(wrapper_top)->set_multi_unit_multiplicity(fu_module->get_multi_unit_multiplicity());
551  if(fu_module->ExistsParameter(MEMORY_PARAMETER))
552  {
553  GetPointer<module>(wrapper_top)->AddParameter(MEMORY_PARAMETER, fu_module->GetDefaultParameter(MEMORY_PARAMETER));
554  GetPointer<module>(wrapper_top)->SetParameter(MEMORY_PARAMETER, fu_module->GetParameter(MEMORY_PARAMETER));
555  }
556  // handle input ports
557  auto inPortSize = static_cast<unsigned int>(fu_module->get_in_port_size());
558  for(unsigned int currentPort = 0; currentPort < inPortSize; ++currentPort)
559  {
560  structural_objectRef curr_port = fu_module->get_in_port(currentPort);
561  const std::string port_name = curr_port->get_id();
562  {
563  structural_objectRef generated_port;
564  if(curr_port->get_kind() == port_vector_o_K)
565  {
566  generated_port = CM->add_port_vector(port_name, port_o::IN, port_o::PARAMETRIC_PORT, wrapper_top,
567  curr_port->get_typeRef());
568  }
569  else
570  {
571  generated_port = CM->add_port(port_name, port_o::IN, wrapper_top, curr_port->get_typeRef());
572  }
573  curr_port->copy(generated_port);
574  }
575  }
576  for(unsigned int currentPort = 0; currentPort < inPortSize; ++currentPort)
577  {
578  structural_objectRef curr_port = fu_module->get_in_port(currentPort);
579  if(!is_other_port(curr_port))
580  {
581  const std::string port_name = curr_port->get_id();
582  if(port_name != CLOCK_PORT_NAME && port_name != RESET_PORT_NAME)
583  {
584  structural_objectRef proxy_generated_port;
585  const std::string proxy_port_name = PROXY_PREFIX + port_name;
586  if(curr_port->get_kind() == port_vector_o_K)
587  {
588  proxy_generated_port = CM->add_port_vector(proxy_port_name, port_o::IN, port_o::PARAMETRIC_PORT,
589  wrapper_top, curr_port->get_typeRef());
590  }
591  else
592  {
593  proxy_generated_port = CM->add_port(proxy_port_name, port_o::IN, wrapper_top, curr_port->get_typeRef());
594  }
595  curr_port->copy(proxy_generated_port);
596  GetPointer<port_o>(proxy_generated_port)->set_id(proxy_port_name);
597  }
598  }
599  }
600  // handle output ports
601  auto outPortSize = static_cast<unsigned int>(fu_module->get_out_port_size());
602  for(unsigned int currentPort = 0; currentPort < outPortSize; ++currentPort)
603  {
604  structural_objectRef curr_port = fu_module->get_out_port(currentPort);
605  const std::string port_name = curr_port->get_id();
606  {
607  structural_objectRef generated_port;
608  if(curr_port->get_kind() == port_vector_o_K)
609  {
610  generated_port = CM->add_port_vector(port_name, port_o::OUT, port_o::PARAMETRIC_PORT, wrapper_top,
611  curr_port->get_typeRef());
612  }
613  else
614  {
615  generated_port = CM->add_port(port_name, port_o::OUT, wrapper_top, curr_port->get_typeRef());
616  }
617  curr_port->copy(generated_port);
618  }
619  }
620  for(unsigned int currentPort = 0; currentPort < outPortSize; ++currentPort)
621  {
622  structural_objectRef curr_port = fu_module->get_out_port(currentPort);
623  if(!is_other_port(curr_port))
624  {
625  structural_objectRef proxy_generated_port;
626  const std::string proxy_port_name = PROXY_PREFIX + curr_port->get_id();
627  if(curr_port->get_kind() == port_vector_o_K)
628  {
629  proxy_generated_port = CM->add_port_vector(proxy_port_name, port_o::OUT, port_o::PARAMETRIC_PORT,
630  wrapper_top, curr_port->get_typeRef());
631  }
632  else
633  {
634  proxy_generated_port = CM->add_port(proxy_port_name, port_o::OUT, wrapper_top, curr_port->get_typeRef());
635  }
636  curr_port->copy(proxy_generated_port);
637  GetPointer<port_o>(proxy_generated_port)->set_id(proxy_port_name);
638  }
639  }
640 
641  const NP_functionalityRef& np = fu_module->get_NP_functionality();
642  std::string orig_np_library = np->get_NP_functionality(NP_functionality::LIBRARY);
643  orig_np_library.replace(0, orig_fun_name.size(), wrapped_fu_name);
644  CM->add_NP_functionality(wrapper_top, NP_functionality::LIBRARY, orig_np_library);
645  TechM->add_resource(PROXY_LIBRARY, wrapped_fu_name, CM);
646  fu_obj->set_owner(wrapper_top);
647  GetPointer<module>(wrapper_top)->add_internal_object(fu_obj);
649  " - Created proxy wrapper " + wrapped_fu_name + " and added to library " + PROXY_LIBRARY);
650 
651  auto wrapper_tn = TechM->get_fu(wrapped_fu_name, PROXY_LIBRARY);
652  auto* wrapper_fu = GetPointer<functional_unit>(wrapper_tn);
653  auto* orig_fu = GetPointer<functional_unit>(techNode_obj);
654  wrapper_fu->ordered_attributes = orig_fu->ordered_attributes;
655  wrapper_fu->attributes = orig_fu->attributes;
656  wrapper_fu->clock_period = orig_fu->clock_period;
657  wrapper_fu->clock_period_resource_fraction = orig_fu->clock_period_resource_fraction;
658  wrapper_fu->area_m = orig_fu->area_m;
659  wrapper_fu->fu_template_name = orig_fu->fu_template_name;
660  wrapper_fu->fu_template_parameters = orig_fu->fu_template_parameters;
661  wrapper_fu->characterizing_constant_value = orig_fu->characterizing_constant_value;
662  wrapper_fu->memory_type = orig_fu->memory_type;
663  wrapper_fu->channels_type = orig_fu->channels_type;
664  wrapper_fu->memory_ctrl_type = orig_fu->memory_ctrl_type;
665  wrapper_fu->bram_load_latency = orig_fu->bram_load_latency;
666  const functional_unit::operation_vec& ops = orig_fu->get_operations();
667  for(const auto& op : ops)
668  {
669  auto* current_op = GetPointer<operation>(op);
670  std::string op_name = current_op->get_name();
671  TechM->add_operation(PROXY_LIBRARY, wrapped_fu_name, op_name);
672  auto* proxy_op = GetPointer<operation>(wrapper_fu->get_operation(op_name));
673  proxy_op->time_m = current_op->time_m;
674  proxy_op->commutative = current_op->commutative;
675  proxy_op->bounded = current_op->bounded;
676  proxy_op->supported_types = current_op->supported_types;
677  proxy_op->pipe_parameters = current_op->pipe_parameters;
678  }
680  TechM->add_operation(PROXY_LIBRARY, wrapped_fu_name, wrapped_fu_name);
681  auto* wrapper_fictious_op = GetPointer<operation>(wrapper_fu->get_operation(wrapped_fu_name));
682  wrapper_fictious_op->time_m = time_info::factory(parameters);
683 
685  BuildProxyWrapper(wrapper_fu, orig_fu->get_name(), library_name);
686 }
687 
689 {
690  const functional_unit::operation_vec& ops = current_fu->get_operations();
691  structural_managerRef CM = current_fu->CM;
693  auto* fu_module = GetPointer<module>(top);
694  auto inPortSize = static_cast<unsigned int>(fu_module->get_in_port_size());
695  auto outPortSize = static_cast<unsigned int>(fu_module->get_out_port_size());
697  HDLWriter_Language::VERILOG, HLSMgr->get_HLS_device()->get_technology_manager(), parameters);
698 
700  std::string sel_guard;
701  for(const auto& op : ops)
702  {
703  auto* current_op = GetPointer<operation>(op);
704  std::string op_name = current_op->get_name();
705  if(starts_with(op_name, PROXY_PREFIX))
706  {
707  continue;
708  }
709  std::string sel_port_name = "sel_" + op_name;
710  structural_objectRef sel_port = fu_module->find_member(sel_port_name, port_o_K, top);
711  if(!sel_port)
712  {
713  CM->add_port(sel_port_name, port_o::IN, top, b_type);
714  }
715  if(sel_guard.empty())
716  {
717  sel_guard = sel_port_name;
718  }
719  else
720  {
721  sel_guard = "(" + sel_guard + "|" + sel_port_name + ")";
722  }
723  }
724 
725  std::string verilog_description;
726  for(unsigned int currentPort = 0; currentPort < inPortSize; ++currentPort)
727  {
728  structural_objectRef curr_port = fu_module->get_in_port(currentPort);
729  if(is_other_port(curr_port))
730  {
731  continue;
732  }
733  std::string port_name = curr_port->get_id();
734  if(port_name != CLOCK_PORT_NAME && port_name != RESET_PORT_NAME)
735  {
736  if(verilog_description.size())
737  {
738  verilog_description += "\n";
739  }
740  if(port_name == START_PORT_NAME)
741  {
742  verilog_description = verilog_description + "assign " + PROXY_PREFIX + port_name + " = " +
743  fix_identifier(port_name, writer) + ";";
744  }
745  else if(fu_module->find_member(PROXY_PREFIX + port_name, port_o_K, top))
746  {
747  verilog_description = verilog_description + "assign " + PROXY_PREFIX + port_name + " = " + sel_guard +
748  " ? " + fix_identifier(port_name, writer) + " : 0;";
749  }
750  }
751  }
752  for(unsigned int currentPort = 0; currentPort < outPortSize; ++currentPort)
753  {
754  structural_objectRef curr_port = fu_module->get_out_port(currentPort);
755  if(is_other_port(curr_port))
756  {
757  continue;
758  }
759  std::string port_name = curr_port->get_id();
760  if(verilog_description.size())
761  {
762  verilog_description += "\n";
763  }
764  verilog_description =
765  verilog_description + "assign " + fix_identifier(port_name, writer) + " = " + PROXY_PREFIX + port_name + ";";
766  }
767  CM->add_NP_functionality(top, NP_functionality::VERILOG_PROVIDED, verilog_description);
768 }
769 
771 {
772  const functional_unit::operation_vec& ops = current_fu->get_operations();
773  structural_managerRef CM = current_fu->CM;
775  auto* fu_module = GetPointer<module>(top);
776  auto inPortSize = static_cast<unsigned int>(fu_module->get_in_port_size());
777  auto outPortSize = static_cast<unsigned int>(fu_module->get_out_port_size());
779  HDLWriter_Language::VHDL, HLSMgr->get_HLS_device()->get_technology_manager(), parameters);
780 
782  std::string sel_guard;
783  for(const auto& op : ops)
784  {
785  auto* current_op = GetPointer<operation>(op);
786  std::string op_name = current_op->get_name();
787  if(starts_with(op_name, PROXY_PREFIX))
788  {
789  continue;
790  }
791  std::string sel_port_name = "sel_" + op_name;
792  structural_objectRef sel_port = fu_module->find_member(sel_port_name, port_o_K, top);
793  if(!sel_port)
794  {
795  CM->add_port(sel_port_name, port_o::IN, top, b_type);
796  }
797  if(sel_guard.empty())
798  {
799  sel_guard = fix_identifier(sel_port_name, writer);
800  }
801  else
802  {
803  sel_guard = sel_guard + " or " + fix_identifier(sel_port_name, writer);
804  }
805  }
806 
807  sel_guard = "(" + sel_guard + ") = '1'";
808 
809  std::string VHDL_description;
810  VHDL_description += "begin";
811  for(unsigned int currentPort = 0; currentPort < inPortSize; ++currentPort)
812  {
813  structural_objectRef curr_port = fu_module->get_in_port(currentPort);
814  if(is_other_port(curr_port))
815  {
816  continue;
817  }
818  std::string port_name = curr_port->get_id();
819  if(port_name != CLOCK_PORT_NAME && port_name != RESET_PORT_NAME)
820  {
821  if(VHDL_description.size())
822  {
823  VHDL_description += "\n";
824  }
825  if(port_name == START_PORT_NAME)
826  {
827  VHDL_description = VHDL_description + fix_identifier(PROXY_PREFIX + port_name, writer) +
828  " <= " + fix_identifier(port_name, writer) + ";";
829  }
830  else if(fu_module->find_member(PROXY_PREFIX + port_name, port_o_K, top))
831  {
832  VHDL_description =
833  VHDL_description + fix_identifier(PROXY_PREFIX + port_name, writer) +
834  " <= " + fix_identifier(port_name, writer) + " when (" + sel_guard + ") else " +
835  (curr_port->get_typeRef()->type == structural_type_descriptor::BOOL ? "'0'" : "(others => '0')") + ";";
836  }
837  }
838  }
839  for(unsigned int currentPort = 0; currentPort < outPortSize; ++currentPort)
840  {
841  structural_objectRef curr_port = fu_module->get_out_port(currentPort);
842  if(is_other_port(curr_port))
843  {
844  continue;
845  }
846  std::string port_name = curr_port->get_id();
847  if(VHDL_description.size())
848  {
849  VHDL_description += "\n";
850  }
851  VHDL_description = VHDL_description + fix_identifier(port_name, writer) +
852  " <= " + fix_identifier(PROXY_PREFIX + port_name, writer) + ";";
853  }
854  CM->add_NP_functionality(top, NP_functionality::VHDL_PROVIDED, VHDL_description);
855 }
856 
858 {
859  const auto writer = static_cast<HDLWriter_Language>(parameters->getOption<unsigned int>(OPT_writer_language));
860  switch(writer)
861  {
863  {
864  BuildProxyFunctionVHDL(current_fu);
865  break;
866  }
868  {
869  BuildProxyFunctionVerilog(current_fu);
870  break;
871  }
873  default:
874  THROW_UNREACHABLE("");
875  }
876 }
877 
879  const std::string& orig_fun_name)
880 {
881  const std::string proxied_fu_name = PROXY_PREFIX + orig_fun_name;
882  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, " - adding proxied function " + proxied_fu_name);
883  structural_managerRef structManager_obj = GetPointer<functional_unit>(techNode_obj)->CM;
884  structural_objectRef fu_obj = structManager_obj->get_circ();
885  auto* fu_module = GetPointer<module>(fu_obj);
886 
889  structural_type_descriptorRef module_type =
891  CM->set_top_info(proxied_fu_name, module_type);
892  top = CM->get_circ();
894  GetPointer<module>(top)->set_description("Proxy module for function: " + proxied_fu_name);
895  GetPointer<module>(top)->set_copyright(fu_module->get_copyright());
896  GetPointer<module>(top)->set_authors(fu_module->get_authors());
897  GetPointer<module>(top)->set_license(fu_module->get_license());
898  GetPointer<module>(top)->set_multi_unit_multiplicity(fu_module->get_multi_unit_multiplicity());
899 
900  /*
901  * The proxy is a module instantiated in the datapath of the caller.
902  * It is used to call a shared function module that is allocated in one of
903  * the dominators of the caller.
904  * We can imagine this with three layers
905  *
906  * CALLER LAYER
907  *
908  * ^
909  * ----|----|---------
910  * v
911  *
912  * PROXY LAYER
913  *
914  * ^
915  * ----|----|---------
916  * v
917  *
918  * CALLED LAYER
919  * (proxied function)
920  *
921  * The called layer connects the signals from the proxy to the real
922  * instance of the called function, wherever it was allocated.
923  * It is not handled here.
924  * Here we're building the component that implements the proxy layer and we
925  * have to add the ports for communication with the caller layer and the
926  * called layer.
927  */
928  auto inPortSize = static_cast<unsigned int>(fu_module->get_in_port_size());
929  auto outPortSize = static_cast<unsigned int>(fu_module->get_out_port_size());
930  // analyze the input signals of the proxed function, i.e. the function called through the proxy
931  for(unsigned int currentPort = 0; currentPort < inPortSize; ++currentPort)
932  {
933  structural_objectRef curr_port = fu_module->get_in_port(currentPort);
934  if(is_other_port(curr_port))
935  {
936  continue;
937  }
938 
939  const std::string port_name = curr_port->get_id();
940  // clock and reset are not propagated because the proxied functions have their own
941  if(port_name != CLOCK_PORT_NAME and port_name != RESET_PORT_NAME)
942  {
943  /*
944  * add an input port to the proxy for every input port of the proxied function.
945  * This connects the caller layer to the proxy
946  */
947  structural_objectRef generated_port;
948  if(curr_port->get_kind() == port_vector_o_K)
949  {
950  generated_port =
951  CM->add_port_vector(port_name, port_o::IN, port_o::PARAMETRIC_PORT, top, curr_port->get_typeRef());
952  }
953  else
954  {
955  generated_port = CM->add_port(port_name, port_o::IN, top, curr_port->get_typeRef());
956  }
957  curr_port->copy(generated_port);
958  }
959  }
960  // analyze the output signals of the proxied function
961  for(unsigned int currentPort = 0; currentPort < outPortSize; ++currentPort)
962  {
963  structural_objectRef curr_port = fu_module->get_out_port(currentPort);
964  if(is_other_port(curr_port))
965  {
966  continue;
967  }
968  /*
969  * Add an output port to the proxy for every output port of the proxied function.
970  * These connect the proxy to the caller layer
971  */
972  structural_objectRef generated_port;
973  const std::string port_name = curr_port->get_id();
974  if(curr_port->get_kind() == port_vector_o_K)
975  {
976  generated_port =
977  CM->add_port_vector(port_name, port_o::OUT, port_o::PARAMETRIC_PORT, top, curr_port->get_typeRef());
978  }
979  else
980  {
981  generated_port = CM->add_port(port_name, port_o::OUT, top, curr_port->get_typeRef());
982  }
983  curr_port->copy(generated_port);
984  }
985  // analyze the input signals of the proxied function, i.e. the function called through the proxy
986  for(unsigned int currentPort = 0; currentPort < inPortSize; ++currentPort)
987  {
988  structural_objectRef curr_port = fu_module->get_in_port(currentPort);
989  if(is_other_port(curr_port))
990  {
991  continue;
992  }
993 
994  const std::string port_name = curr_port->get_id();
995  // clock and reset are not propagated because the proxied functions have their own
996  if(port_name != CLOCK_PORT_NAME and port_name != RESET_PORT_NAME)
997  {
998  /*
999  * add an output port to the proxy for every input port of the proxied function.
1000  * This connects the proxy to the called layer.
1001  * The connection is outgoing from the proxy to the called proxied function.
1002  */
1003  structural_objectRef proxy_generated_port;
1004  const std::string proxied_port_name = PROXY_PREFIX + port_name;
1005  if(curr_port->get_kind() == port_vector_o_K)
1006  {
1007  proxy_generated_port = CM->add_port_vector(proxied_port_name, port_o::OUT, port_o::PARAMETRIC_PORT, top,
1008  curr_port->get_typeRef());
1009  }
1010  else
1011  {
1012  proxy_generated_port = CM->add_port(proxied_port_name, port_o::OUT, top, curr_port->get_typeRef());
1013  }
1014  curr_port->copy(proxy_generated_port);
1015  GetPointer<port_o>(proxy_generated_port)->set_port_direction(port_o::OUT);
1016  GetPointer<port_o>(proxy_generated_port)->set_is_memory(true);
1017  GetPointer<port_o>(proxy_generated_port)->set_id(proxied_port_name);
1018  }
1019  }
1020  // analyze the output signals of the proxied function
1021  for(unsigned int currentPort = 0; currentPort < outPortSize; ++currentPort)
1022  {
1023  structural_objectRef curr_port = fu_module->get_out_port(currentPort);
1024  if(is_other_port(curr_port))
1025  {
1026  continue;
1027  }
1028  /*
1029  * add an input port to the proxy for every output port of the proxied function.
1030  * This connects the proxy to the called layer.
1031  * The connection is incoming from the called proxied function to the proxy itself
1032  */
1033  const std::string proxied_port_name = PROXY_PREFIX + curr_port->get_id();
1034  structural_objectRef proxy_generated_port;
1035  if(curr_port->get_kind() == port_vector_o_K)
1036  {
1037  proxy_generated_port =
1038  CM->add_port_vector(proxied_port_name, port_o::IN, port_o::PARAMETRIC_PORT, top, curr_port->get_typeRef());
1039  }
1040  else
1041  {
1042  proxy_generated_port = CM->add_port(proxied_port_name, port_o::IN, top, curr_port->get_typeRef());
1043  }
1044  curr_port->copy(proxy_generated_port);
1045  GetPointer<port_o>(proxy_generated_port)->set_port_direction(port_o::IN);
1046  GetPointer<port_o>(proxy_generated_port)->set_is_memory(true);
1047  GetPointer<port_o>(proxy_generated_port)->set_id(proxied_port_name);
1048  }
1049 
1050  const NP_functionalityRef& np = fu_module->get_NP_functionality();
1051  std::string orig_np_library = np->get_NP_functionality(NP_functionality::LIBRARY);
1052  orig_np_library.replace(0, orig_fun_name.size(), proxied_fu_name);
1053  CM->add_NP_functionality(top, NP_functionality::LIBRARY, orig_np_library);
1054  TechM->add_resource(PROXY_LIBRARY, proxied_fu_name, CM);
1056  " - Created proxy module " + proxied_fu_name + " and added to library " + PROXY_LIBRARY);
1057 
1058  auto proxy_tn = TechM->get_fu(proxied_fu_name, PROXY_LIBRARY);
1059  auto* proxy_fu = GetPointer<functional_unit>(proxy_tn);
1060  auto* orig_fu = GetPointer<functional_unit>(techNode_obj);
1061  proxy_fu->ordered_attributes = orig_fu->ordered_attributes;
1062  proxy_fu->attributes = orig_fu->attributes;
1063  proxy_fu->clock_period = orig_fu->clock_period;
1064  proxy_fu->clock_period_resource_fraction = orig_fu->clock_period_resource_fraction;
1065  proxy_fu->area_m = orig_fu->area_m;
1066  proxy_fu->fu_template_name = orig_fu->fu_template_name;
1067  proxy_fu->fu_template_parameters = orig_fu->fu_template_parameters;
1068  proxy_fu->characterizing_constant_value = orig_fu->characterizing_constant_value;
1069  proxy_fu->memory_type = orig_fu->memory_type;
1070  proxy_fu->channels_type = orig_fu->channels_type;
1071  proxy_fu->memory_ctrl_type = orig_fu->memory_ctrl_type;
1072  proxy_fu->bram_load_latency = orig_fu->bram_load_latency;
1073  const functional_unit::operation_vec& ops = orig_fu->get_operations();
1074  for(const auto& op : ops)
1075  {
1076  auto* current_op = GetPointer<operation>(op);
1077  std::string op_name = current_op->get_name();
1078  TechM->add_operation(PROXY_LIBRARY, proxied_fu_name, op_name);
1079  auto* proxy_op = GetPointer<operation>(proxy_fu->get_operation(op_name));
1080  proxy_op->time_m = current_op->time_m;
1081  proxy_op->commutative = current_op->commutative;
1082  proxy_op->bounded = current_op->bounded;
1083  proxy_op->supported_types = current_op->supported_types;
1084  proxy_op->pipe_parameters = current_op->pipe_parameters;
1085  }
1087  TechM->add_operation(PROXY_LIBRARY, proxied_fu_name, proxied_fu_name);
1088  auto* proxy_fictious_op = GetPointer<operation>(proxy_fu->get_operation(proxied_fu_name));
1089  proxy_fictious_op->time_m = time_info::factory(parameters);
1090 
1092  BuildProxyFunction(proxy_fu);
1093 
1094  HLS_C->set_number_fu(proxied_fu_name, PROXY_LIBRARY, 1);
1095 }
1096 
1097 void allocation::add_tech_constraint(technology_nodeRef cur_fu, unsigned int tech_constrain_value, unsigned int pos,
1098  bool proxy_constrained)
1099 {
1101  "Specialized unit: " + (cur_fu->get_name()) + " in position: " + STR(pos) +
1102  (proxy_constrained ? "(proxy)" : ""));
1104  auto last_fu = static_cast<unsigned int>(allocation_information->list_of_FU.size());
1105  allocation_information->list_of_FU.push_back(cur_fu);
1106  bool is_memory_ctrl = allocation_information->is_indirect_access_memory_unit(last_fu);
1107  if(is_memory_ctrl || allocation_information->get_number_channels(pos) >= 1)
1108  {
1110  }
1111  else if(proxy_constrained)
1112  {
1114  }
1115  else
1116  {
1118  "Constrained " + STR(pos) + "=" + cur_fu->get_name() + "->" + STR(tech_constrain_value));
1119  allocation_information->tech_constraints.push_back(tech_constrain_value);
1120  }
1121 }
1122 
1123 bool allocation::check_templated_units(double clock_period, node_kind_prec_infoRef node_info,
1124  const library_managerRef library, technology_nodeRef current_fu,
1125  operation* curr_op)
1126 {
1127  std::string required_prec = "";
1128  std::string template_suffix = "";
1129  const size_t n_ins = node_info->input_prec.size();
1130  for(size_t ind = 0; ind < n_ins; ++ind)
1131  {
1132  if(node_info->base128_input_nelem[ind] == 0)
1133  {
1134  required_prec += STR(node_info->input_prec[ind]) + " ";
1135  template_suffix += STR(node_info->input_prec[ind]) + "_";
1136  }
1137  else
1138  {
1139  required_prec += STR(node_info->input_prec[ind]) + " " + STR(node_info->base128_input_nelem[ind]) + " ";
1140  template_suffix += STR(node_info->input_prec[ind]) + "_" + STR(node_info->base128_input_nelem[ind]) + "_";
1141  }
1142  }
1143  if(node_info->base128_output_nelem == 0)
1144  {
1145  required_prec += STR(node_info->output_prec);
1146  template_suffix += STR(node_info->output_prec);
1147  }
1148  else
1149  {
1150  required_prec += STR(node_info->output_prec) + " " + STR(node_info->base128_output_nelem);
1151  template_suffix += STR(node_info->output_prec) + "_" + STR(node_info->base128_output_nelem);
1152  }
1153  std::string fu_template_parameters = GetPointer<functional_unit>(current_fu)->fu_template_parameters;
1154  if(!starts_with(fu_template_parameters, required_prec))
1155  {
1157  "---Not support required precision " + STR(required_prec) + "(" + fu_template_parameters + ")");
1158  return true;
1159  }
1160  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "- required_prec: \"" + required_prec);
1161  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "- template_suffix: \"" + template_suffix + "\"");
1163  "- fu_template_parameters: \"" + fu_template_parameters + "\"");
1164  std::string pipeline_id = get_compliant_pipelined_unit(
1165  clock_period, curr_op->pipe_parameters, current_fu, curr_op->get_name(), library->get_library_name(),
1166  template_suffix, node_info->input_prec.size() > 1 ? node_info->input_prec[1] : node_info->input_prec[0]);
1167  if(!curr_op->pipe_parameters.empty())
1168  {
1169  if(pipeline_id.size())
1170  {
1171  required_prec += " " + pipeline_id;
1172  }
1173  // if the computed parameters is different from what was used to build this specialization skip it.
1174  if(required_prec != fu_template_parameters)
1175  {
1177  "---" + required_prec + " vs. " + fu_template_parameters);
1178  return true;
1179  }
1180  }
1181  if(pipeline_id.empty())
1182  {
1183  if(curr_op->time_m->get_cycles() == 0 && allocation_information->time_m_execution_time(curr_op) > clock_period)
1184  {
1185  THROW_WARNING("No functional unit exists for the given clock period: the fastest unit will be used as "
1186  "multi-cycle unit (" +
1187  GetPointer<functional_unit>(current_fu)->fu_template_name +
1188  "): " + STR(allocation_information->time_m_execution_time(curr_op)));
1189  }
1190  }
1191  return false;
1192 }
1193 
1194 bool allocation::check_for_memory_compliancy(bool Has_extern_allocated_data, technology_nodeRef current_fu,
1195  const std::string& memory_ctrl_type, const std::string& channels_type)
1196 {
1197  const auto& memory_type = GetPointer<functional_unit>(current_fu)->memory_type;
1198  const auto& bram_load_latency = GetPointer<functional_unit>(current_fu)->bram_load_latency;
1199 
1201  if(memory_type.size())
1202  {
1203  return true;
1204  }
1205 
1207  if(channels_type.size() &&
1208  (memory_ctrl_type == MEMORY_CTRL_TYPE_PROXY || memory_ctrl_type == MEMORY_CTRL_TYPE_PROXYN ||
1209  memory_ctrl_type == MEMORY_CTRL_TYPE_DPROXY || memory_ctrl_type == MEMORY_CTRL_TYPE_DPROXYN ||
1210  memory_ctrl_type == MEMORY_CTRL_TYPE_SPROXY || memory_ctrl_type == MEMORY_CTRL_TYPE_SPROXYN))
1211  {
1212  return true;
1213  }
1214 #if !HAVE_EXPERIMENTAL
1215  if(GetPointer<functional_unit>(current_fu)->functional_unit_name == "MEMORY_CTRL_P1N")
1216  {
1217  return true;
1218  }
1219 #endif
1220 
1221  const auto channel_type_to_be_used = HLSMgr->CGetFunctionBehavior(funId)->GetChannelsType();
1222  if(channels_type.size())
1223  {
1224  switch(channel_type_to_be_used)
1225  {
1228  {
1229  if(channels_type.find(CHANNELS_TYPE_MEM_ACC_NN) != std::string::npos ||
1230  channels_type.find(CHANNELS_TYPE_MEM_ACC_P1N) != std::string::npos ||
1231  channels_type.find(CHANNELS_TYPE_MEM_ACC_CS) != std::string::npos)
1232  {
1233  return true;
1234  }
1235  break;
1236  }
1238  {
1239  if(channels_type.find(CHANNELS_TYPE_MEM_ACC_NN) == std::string::npos)
1240  {
1241  return true;
1242  }
1243  break;
1244  }
1246  {
1247  if(channels_type.find(CHANNELS_TYPE_MEM_ACC_P1N) == std::string::npos)
1248  {
1249  return true;
1250  }
1251  break;
1252  }
1254  {
1255  if(channels_type.find(CHANNELS_TYPE_MEM_ACC_CS) == std::string::npos)
1256  {
1257  return true;
1258  }
1259  break;
1260  }
1261  default:
1262  THROW_UNREACHABLE("");
1263  }
1264  }
1265  bool are_operations_bounded = memory_ctrl_type.size();
1266  const functional_unit::operation_vec& Operations = GetPointer<functional_unit>(current_fu)->get_operations();
1267  const auto it_o_end = Operations.end();
1268  for(auto it_o = Operations.begin(); it_o_end != it_o && are_operations_bounded; ++it_o)
1269  {
1270  if(!GetPointer<operation>(*it_o)->is_bounded())
1271  {
1272  are_operations_bounded = false;
1273  }
1274  }
1275 
1276  if(Has_extern_allocated_data && are_operations_bounded && memory_ctrl_type.size())
1277  {
1278  return true;
1279  }
1280  if(!Has_extern_allocated_data && !are_operations_bounded && memory_ctrl_type.size())
1281  {
1282  return true;
1283  }
1284 
1285  if(memory_ctrl_type.size() && parameters->getOption<std::string>(OPT_memory_controller_type) != memory_ctrl_type)
1286  {
1287  return true;
1288  }
1289  if(bram_load_latency.size())
1290  {
1291  if(bram_load_latency == "2" && parameters->getOption<std::string>(OPT_bram_high_latency).size())
1292  {
1293  return true;
1294  }
1295  if(bram_load_latency == "3" && parameters->getOption<std::string>(OPT_bram_high_latency) != "_3")
1296  {
1297  return true;
1298  }
1299  if(bram_load_latency == "4" && parameters->getOption<std::string>(OPT_bram_high_latency) != "_4")
1300  {
1301  return true;
1302  }
1303  if(bram_load_latency != "2" && bram_load_latency != "3" && bram_load_latency != "4")
1304  {
1305  THROW_ERROR("unexpected bram_load_latency");
1306  }
1307  }
1308  return false;
1309 }
1310 
1311 bool allocation::check_type_and_precision(operation* curr_op, node_kind_prec_infoRef node_info)
1312 {
1313  if(node_info->node_kind.size() && !curr_op->is_type_supported(node_info->node_kind))
1314  {
1315  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Not supported type " + node_info->node_kind);
1316  return true; // FU does not support the operation type
1317  }
1318  // Check for correct precision
1319  if(!curr_op->is_type_supported(node_info->node_kind, node_info->input_prec, node_info->base128_input_nelem))
1320  {
1321  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Not supported precision");
1322  return true; // FU does support the operation type, but does not support correct precision
1323  }
1324  return false;
1325 }
1326 
1327 bool allocation::check_proxies(const library_managerRef library, const std::string& fu_name)
1328 {
1329  if(HLSMgr->Rfuns->is_a_proxied_function(fu_name))
1330  {
1331  return true;
1332  }
1333  if(library->get_library_name() == PROXY_LIBRARY)
1334  {
1335  if(starts_with(fu_name, WRAPPED_PROXY_PREFIX))
1336  {
1337  const auto original_function_name = fu_name.substr(sizeof(WRAPPED_PROXY_PREFIX) - 1);
1338  if(!HLSMgr->Rfuns->is_a_shared_function(funId, original_function_name))
1339  {
1340  return true;
1341  }
1342  }
1343  else
1344  {
1345  THROW_ASSERT(starts_with(fu_name, PROXY_PREFIX), "expected a proxy module");
1346  const auto original_function_name = fu_name.substr(sizeof(PROXY_PREFIX) - 1);
1347  if(!HLSMgr->Rfuns->is_a_proxied_shared_function(funId, original_function_name))
1348  {
1349  return true;
1350  }
1351  }
1352  }
1353  return false;
1354 }
1355 
1356 bool allocation::check_generated_bambu_flopoco(bool skip_softfloat_resources, structural_managerRef structManager_obj,
1357  std::string& bambu_provided_resource, bool skip_flopoco_resources,
1358  technology_nodeRef current_fu)
1359 {
1360  if(structManager_obj)
1361  {
1362  structural_objectRef modobj = structManager_obj->get_circ();
1363  auto* mod = GetPointer<module>(modobj);
1364 
1365  if(mod->get_generated())
1366  {
1367  return true;
1368  }
1369 
1370  const NP_functionalityRef& np = mod->get_NP_functionality();
1371  if(skip_flopoco_resources)
1372  {
1374  {
1375  return true;
1376  }
1377  }
1378  if(skip_softfloat_resources)
1379  {
1381  {
1382  return true;
1383  }
1384  }
1385  else if(np)
1386  {
1387  bambu_provided_resource = np->get_NP_functionality(NP_functionality::BAMBU_PROVIDED);
1388  }
1389  }
1390  else if(GetPointer<functional_unit>(current_fu)->fu_template_name.size())
1391  {
1392  std::string tfname = GetPointer<functional_unit>(current_fu)->fu_template_name;
1393  technology_nodeRef tfu = get_fu(tfname);
1394  if(!tfu || !GetPointer<functional_unit_template>(tfu) || !GetPointer<functional_unit_template>(tfu)->FU ||
1395  !GetPointer<functional_unit>(GetPointer<functional_unit_template>(tfu)->FU)->CM)
1396  {
1397  return true;
1398  }
1399  structural_managerRef tcm = GetPointer<functional_unit>(GetPointer<functional_unit_template>(tfu)->FU)->CM;
1400  structural_objectRef tmodobj = tcm->get_circ();
1401  auto* tmod = GetPointer<module>(tmodobj);
1402  const NP_functionalityRef& tnp = tmod->get_NP_functionality();
1403  if(tnp && skip_flopoco_resources && tnp->get_NP_functionality(NP_functionality::FLOPOCO_PROVIDED).size())
1404  {
1405  return true;
1406  }
1407  if(tnp && skip_softfloat_resources && tnp->get_NP_functionality(NP_functionality::BAMBU_PROVIDED).size())
1408  {
1409  return true;
1410  }
1411  else if(tnp)
1412  {
1413  bambu_provided_resource = tnp->get_NP_functionality(NP_functionality::BAMBU_PROVIDED);
1414  }
1415  }
1416  return false;
1417 }
1418 
1420 {
1421  const auto& HLS_C = HLS->HLS_C;
1422  const auto FB = HLSMgr->CGetFunctionBehavior(funId);
1423  const auto TM = HLSMgr->get_tree_manager();
1424  const auto function_vars = HLSMgr->Rmem->get_function_vars(funId);
1425  const auto clock_period = HLS_C->get_clock_period_resource_fraction() * HLS_C->get_clock_period();
1426  const auto channels_number = FB->GetChannelsNumber();
1427  const auto memory_allocation_policy = FB->GetMemoryAllocationPolicy();
1428  long step_time = 0;
1430  {
1431  START_TIME(step_time);
1432  }
1434  {
1436  }
1438  "-->Module allocation information for function " +
1439  HLSMgr->CGetFunctionBehavior(funId)->CGetBehavioralHelper()->get_function_name() + ":");
1440  unsigned long long int base_address = HLSMgr->base_address;
1441  const auto Has_extern_allocated_data =
1442  ((HLSMgr->Rmem->get_memory_address() - base_address) > 0 &&
1443  memory_allocation_policy != MemoryAllocation_Policy::EXT_PIPELINED_BRAM) ||
1444  (HLSMgr->Rmem->has_unknown_addresses() && memory_allocation_policy != MemoryAllocation_Policy::ALL_BRAM &&
1445  memory_allocation_policy != MemoryAllocation_Policy::EXT_PIPELINED_BRAM);
1447 
1448 #if HAVE_FLOPOCO
1449  bool skip_flopoco_resources = false;
1450 #else
1451  bool skip_flopoco_resources = true;
1452 #endif
1453  bool skip_softfloat_resources = true;
1454  if(parameters->isOption(OPT_soft_float) && parameters->getOption<bool>(OPT_soft_float))
1455  {
1456  skip_flopoco_resources = true;
1457  skip_softfloat_resources = false;
1458  }
1459  auto& tech_vec = HLS_C->tech_constraints;
1460  const auto& binding_constraints = HLS_C->binding_constraints;
1462  CustomOrderedSet<vertex> vertex_analysed;
1463  const auto cfg = FB->CGetOpGraph(FunctionBehavior::CFG);
1464  OpVertexSet support_ops(cfg);
1465  const auto op_graph_size = boost::num_vertices(*cfg);
1466  if(op_graph_size != HLS->operations.size())
1467  {
1468  support_ops.insert(HLS->operations.begin(), HLS->operations.end());
1469  }
1470  const auto g = op_graph_size != HLS->operations.size() ? FB->CGetOpGraph(FunctionBehavior::CFG, support_ops) : cfg;
1471  CustomUnorderedMap<std::string, OpVertexSet> vertex_to_analyse_partition;
1472  std::map<std::string, technology_nodeRef> new_fu;
1473  bool gimple_return_allocated_p = false;
1474  unsigned int gimple_return_current_id = 0;
1475  BOOST_FOREACH(vertex v, boost::vertices(*g))
1476  {
1477  std::string current_op = tree_helper::NormalizeTypename(g->CGetOpNodeInfo(v)->GetOperation());
1478  const auto node_id = g->CGetOpNodeInfo(v)->GetNodeId();
1479  const auto node_operation = [&]() -> std::string {
1480  if(node_id == ENTRY_ID)
1481  {
1482  return "Entry";
1483  }
1484  if(node_id == EXIT_ID)
1485  {
1486  return "Exit";
1487  }
1488  return GetPointer<const gimple_node>(TM->CGetTreeNode(node_id))->operation;
1489  }();
1491  "-->Processing operation: " + current_op + " - " + GET_NAME(g, v) +
1492  (node_id && node_id != ENTRY_ID && node_id != EXIT_ID ?
1493  " - " + TM->CGetTreeNode(node_id)->ToString() :
1494  ""));
1495  technology_nodeRef current_fu;
1496  if(GET_TYPE(g, v) & (TYPE_STORE | TYPE_LOAD))
1497  {
1498  const auto curr_tn = TM->CGetTreeNode(node_id);
1499  const auto me = GetPointer<const gimple_assign>(curr_tn);
1500  THROW_ASSERT(me, "only gimple_assign's are allowed as memory operations");
1501  tree_nodeConstRef var;
1502  if(GET_TYPE(g, v) & TYPE_STORE)
1503  {
1504  var = tree_helper::GetBaseVariable(me->op0);
1505  }
1506  else
1507  {
1508  var = tree_helper::GetBaseVariable(me->op1);
1509  }
1510  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Variable is " + (var ? STR(var) : "0"));
1511  if(!var || (!function_vars.count(var->index) &&
1512  (!HLSMgr->Rmem->has_proxied_internal_variables(funId) ||
1513  !HLSMgr->Rmem->get_proxied_internal_variables(funId).count(var->index))))
1514  {
1515  if(vertex_to_analyse_partition.find(current_op) == vertex_to_analyse_partition.end())
1516  {
1517  vertex_to_analyse_partition.insert(std::make_pair(current_op, OpVertexSet(g)));
1518  }
1519  vertex_to_analyse_partition.at(current_op).insert(v);
1521  "<--Operation " + current_op + " queued for allocation");
1522  continue;
1523  }
1525  "Not existing memory unit associated with the variable");
1526  allocation_information->binding[node_id] =
1527  std::make_pair(current_op, allocation_information->vars_to_memory_units[var->index]);
1528  allocation_information->node_id_to_fus[std::make_pair(node_id, node_operation)].insert(
1532  "---Operation " + current_op + " named " + GET_NAME(g, v) + " mapped onto " +
1533  current_fu->get_name() + ", found in library " + TechM->get_library(current_op) +
1534  " in position " + STR(allocation_information->vars_to_memory_units[var->index]));
1535  }
1536  else if(GIMPLE_RETURN == current_op)
1537  {
1538  if(!gimple_return_allocated_p)
1539  {
1540  unsigned int current_size = allocation_information->get_number_fu_types();
1541  gimple_return_current_id = current_size;
1542  current_fu = get_fu(GIMPLE_RETURN_STD);
1543  allocation_information->list_of_FU.push_back(current_fu);
1545  allocation_information->id_to_fu_names[gimple_return_current_id] =
1546  std::make_pair(current_fu->get_name(), TechM->get_library(current_fu->get_name()));
1547  allocation_information->is_vertex_bounded_rel.insert(gimple_return_current_id);
1548  allocation_information->precision_map[gimple_return_current_id] = 0;
1549  gimple_return_allocated_p = true;
1550  }
1551  else
1552  {
1553  current_fu = allocation_information->list_of_FU[gimple_return_current_id];
1554  }
1555  allocation_information->binding[node_id] = std::make_pair(current_op, gimple_return_current_id);
1556  allocation_information->node_id_to_fus[std::make_pair(node_id, node_operation)].insert(
1557  gimple_return_current_id);
1559  "---Operation " + current_op + " named " + GET_NAME(g, v) + " mapped onto " +
1560  current_fu->get_name() + ", found in library " + TechM->get_library(current_op) +
1561  " in position " + STR(gimple_return_current_id));
1562  }
1563  // direct mapping FUs
1564  else if(ASSIGN == current_op || ASSERT_EXPR == current_op || ADDR_EXPR == current_op || READ_COND == current_op ||
1565  MULTI_READ_COND == current_op || NOP_EXPR == current_op || CONVERT_EXPR == current_op ||
1566  SWITCH_COND == current_op || GIMPLE_LABEL == current_op || GIMPLE_GOTO == current_op ||
1567  GIMPLE_PRAGMA == current_op || ENTRY == current_op || EXIT == current_op || NOP == current_op ||
1568  GIMPLE_PHI == current_op || GIMPLE_NOP == current_op || VIEW_CONVERT_EXPR == current_op ||
1569  EXTRACT_BIT_EXPR == current_op || LUT_EXPR == current_op)
1570  {
1571  const auto current_size = allocation_information->get_number_fu_types();
1572  if(current_op == ASSIGN)
1573  {
1574  const auto& modify_node = g->CGetOpNodeInfo(v)->node;
1575  const auto gms = GetPointerS<const gimple_assign>(GET_CONST_NODE(modify_node));
1576  const auto left_type = tree_helper::CGetType(gms->op0);
1577  if(tree_helper::IsComplexType(left_type))
1578  {
1579  current_fu = get_fu(ASSIGN_VECTOR_BOOL_STD);
1580  }
1581  else if(tree_helper::IsSignedIntegerType(left_type))
1582  {
1583  current_fu = get_fu(ASSIGN_SIGNED_STD);
1584  }
1585  else if(tree_helper::IsRealType(left_type))
1586  {
1587  current_fu = get_fu(ASSIGN_REAL_STD);
1588  }
1589  else if(tree_helper::IsVectorType(left_type))
1590  {
1591  const auto element_type = tree_helper::CGetElements(left_type);
1592  if(tree_helper::IsSignedIntegerType(element_type))
1593  {
1594  current_fu = get_fu(ASSIGN_VEC_SIGNED_STD);
1595  }
1596  else if(tree_helper::IsUnsignedIntegerType(element_type))
1597  {
1598  current_fu = get_fu(ASSIGN_VEC_UNSIGNED_STD);
1599  }
1600  else
1601  {
1602  THROW_ERROR("unexpected type");
1603  }
1604  }
1605  else
1606  {
1607  current_fu = get_fu(ASSIGN_UNSIGNED_STD);
1608  }
1609  }
1610  else if(current_op == ASSERT_EXPR)
1611  {
1612  const auto& modify_node = g->CGetOpNodeInfo(v)->node;
1613  const auto gms = GetPointerS<const gimple_assign>(GET_CONST_NODE(modify_node));
1614  const auto left_type = tree_helper::CGetType(gms->op0);
1615  if(tree_helper::IsSignedIntegerType(left_type))
1616  {
1617  current_fu = get_fu(ASSERT_EXPR_SIGNED_STD);
1618  }
1619  else if(tree_helper::IsRealType(left_type))
1620  {
1621  current_fu = get_fu(ASSERT_EXPR_REAL_STD);
1622  }
1623  else
1624  {
1625  current_fu = get_fu(ASSERT_EXPR_UNSIGNED_STD);
1626  }
1627  }
1628  else if(current_op == EXTRACT_BIT_EXPR)
1629  {
1630  const auto& modify_node = g->CGetOpNodeInfo(v)->node;
1631  const auto gms = GetPointerS<const gimple_assign>(GET_CONST_NODE(modify_node));
1632  const auto ebe = GetPointerS<const extract_bit_expr>(GET_CONST_NODE(gms->op1));
1633  const auto intOP0 = tree_helper::IsSignedIntegerType(ebe->op0);
1634  if(intOP0)
1635  {
1636  current_fu = get_fu(EXTRACT_BIT_EXPR_SIGNED_STD);
1637  }
1638  else
1639  {
1640  current_fu = get_fu(EXTRACT_BIT_EXPR_UNSIGNED_STD);
1641  }
1642  }
1643  else if(current_op == LUT_EXPR)
1644  {
1645  current_fu = get_fu(LUT_EXPR_STD);
1646  }
1647  else if(current_op == ADDR_EXPR)
1648  {
1649  current_fu = get_fu(ADDR_EXPR_STD);
1650  }
1651  else if(current_op == NOP_EXPR)
1652  {
1653  const auto modify_node = g->CGetOpNodeInfo(v)->node;
1654  const auto gms = GetPointerS<const gimple_assign>(GET_CONST_NODE(modify_node));
1655  const auto ne = GetPointerS<const nop_expr>(GET_CONST_NODE(gms->op1));
1656  const auto left_type = tree_helper::CGetType(gms->op0);
1657  const auto right_type = tree_helper::CGetType(ne->op);
1658 
1659  const auto unsignedR = tree_helper::IsUnsignedIntegerType(right_type);
1660  const auto unsignedL = tree_helper::IsUnsignedIntegerType(left_type);
1661  const auto intR = tree_helper::IsSignedIntegerType(right_type);
1662  const auto intL = tree_helper::IsSignedIntegerType(left_type);
1663  const auto enumR = tree_helper::IsEnumType(right_type);
1664  const auto enumL = tree_helper::IsEnumType(left_type);
1665  const auto boolR = tree_helper::IsBooleanType(right_type);
1666  const auto boolL = tree_helper::IsBooleanType(left_type);
1667  const auto is_a_pointerR = tree_helper::IsPointerType(right_type);
1668  const auto is_a_pointerL = tree_helper::IsPointerType(left_type);
1669  const auto is_realR = tree_helper::IsRealType(right_type);
1670  const auto is_realL = tree_helper::IsRealType(left_type);
1671 
1672  const auto vector_boolR =
1673  tree_helper::IsVectorType(right_type) &&
1675  const auto vector_boolL =
1676  tree_helper::IsVectorType(left_type) &&
1678  const auto vector_intL =
1679  tree_helper::IsVectorType(left_type) &&
1681  const auto vector_unsignedL =
1682  tree_helper::IsVectorType(left_type) &&
1684  const auto vector_intR =
1685  tree_helper::IsVectorType(right_type) &&
1687  const auto vector_unsignedR =
1688  tree_helper::IsVectorType(right_type) &&
1690 
1691  if((unsignedR || is_a_pointerR || boolR) && (unsignedL || is_a_pointerL || boolL))
1692  {
1693  current_fu = get_fu(UUDATA_CONVERTER_STD);
1694  }
1695  else if((intR || enumR) && (unsignedL || is_a_pointerL || boolL))
1696  {
1697  current_fu = get_fu(IUDATA_CONVERTER_STD);
1698  }
1699  else if((unsignedR || is_a_pointerR || boolR) && (intL || enumL))
1700  {
1701  current_fu = get_fu(UIDATA_CONVERTER_STD);
1702  }
1703  else if((intR || enumR) && (intL || enumL))
1704  {
1705  current_fu = get_fu(IIDATA_CONVERTER_STD);
1706  }
1707  else if(is_realR && is_realL)
1708  {
1709  if(!skip_flopoco_resources)
1710  {
1711  current_fu = get_fu(FFDATA_CONVERTER_STD);
1712  }
1713  else if(!skip_softfloat_resources)
1714  {
1715  const auto prec_in = tree_helper::Size(right_type);
1716  const auto prec_out = tree_helper::Size(left_type);
1717  allocation_information->extract_bambu_provided_name(prec_in, prec_out, HLSMgr, current_fu);
1718  }
1719  else
1720  {
1721  THROW_ERROR("missing resource for floating point to floating point conversion");
1722  }
1723  }
1724  else if(vector_boolR && vector_intL)
1725  {
1726  current_fu = get_fu(BIVECTOR_CONVERTER_STD);
1727  }
1728  else if(vector_boolR && vector_unsignedL)
1729  {
1730  current_fu = get_fu(BUVECTOR_CONVERTER_STD);
1731  }
1732  else if(vector_unsignedR && vector_boolL)
1733  {
1734  current_fu = get_fu(UBVECTOR_CONVERTER_STD);
1735  }
1736  else if(vector_unsignedR && vector_unsignedL)
1737  {
1738  current_fu = get_fu(UUVECTOR_CONVERTER_STD);
1739  }
1740  else if(vector_intR && vector_unsignedL)
1741  {
1742  current_fu = get_fu(IUVECTOR_CONVERTER_STD);
1743  }
1744  else if(vector_unsignedR && vector_intL)
1745  {
1746  current_fu = get_fu(UIVECTOR_CONVERTER_STD);
1747  }
1748  else if(vector_intR && vector_intL)
1749  {
1750  current_fu = get_fu(IIVECTOR_CONVERTER_STD);
1751  }
1752  else
1753  {
1754  THROW_ERROR(std::string("Nop_Expr pattern not supported ") + STR(modify_node) + " - Left type is " +
1755  STR(left_type) + " - Right type is " + STR(right_type));
1756  }
1757  }
1758  else if(current_op == CONVERT_EXPR)
1759  {
1760  const auto modify_node = g->CGetOpNodeInfo(v)->node;
1761  const auto gms = GetPointerS<const gimple_assign>(GET_CONST_NODE(modify_node));
1762  const auto ce = GetPointerS<const convert_expr>(GET_CONST_NODE(gms->op1));
1763  const auto left_type = tree_helper::CGetType(gms->op0);
1764  const auto right_type = tree_helper::CGetType(ce->op);
1765 
1766  const auto unsignedR = tree_helper::IsUnsignedIntegerType(right_type);
1767  const auto unsignedL = tree_helper::IsUnsignedIntegerType(left_type);
1768  const auto intR = tree_helper::IsSignedIntegerType(right_type);
1769  const auto intL = tree_helper::IsSignedIntegerType(left_type);
1770  const auto boolR = tree_helper::IsBooleanType(right_type);
1771  const auto boolL = tree_helper::IsBooleanType(left_type);
1772  const auto is_a_pointerR = tree_helper::IsPointerType(right_type);
1773  const auto is_a_pointerL = tree_helper::IsPointerType(left_type);
1774 
1775  if((unsignedR || is_a_pointerR || boolR) && (unsignedL || is_a_pointerL || boolL))
1776  {
1777  current_fu = get_fu(UUCONVERTER_EXPR_STD);
1778  }
1779  else if(intR && (unsignedL || is_a_pointerL || boolL))
1780  {
1781  current_fu = get_fu(IUCONVERTER_EXPR_STD);
1782  }
1783  else if((unsignedR || is_a_pointerR || boolR) && intL)
1784  {
1785  current_fu = get_fu(UICONVERTER_EXPR_STD);
1786  }
1787  else if(intR && intL)
1788  {
1789  current_fu = get_fu(IICONVERTER_EXPR_STD);
1790  }
1791  else
1792  {
1793  THROW_UNREACHABLE("CONVERT_EXPR pattern not supported in statement " + STR(modify_node) +
1794  ". Left type is " + STR(left_type) + " - Right type is " + STR(right_type));
1795  }
1796  }
1797  else if(current_op == READ_COND)
1798  {
1799  current_fu = get_fu(READ_COND_STD);
1800  }
1801  else if(current_op == MULTI_READ_COND)
1802  {
1803  current_fu = get_fu(MULTI_READ_COND_STD);
1804  }
1805  else if(current_op == SWITCH_COND)
1806  {
1807  current_fu = get_fu(SWITCH_COND_STD);
1808  }
1809  else if(current_op == GIMPLE_LABEL)
1810  {
1811  current_fu = get_fu(GIMPLE_LABEL_STD);
1812  }
1813  else if(current_op == GIMPLE_GOTO)
1814  {
1815  current_fu = get_fu(GIMPLE_GOTO_STD);
1816  }
1817  else if(current_op == GIMPLE_PRAGMA)
1818  {
1819  current_fu = get_fu(GIMPLE_PRAGMA_STD);
1820  }
1821  else if(current_op == ENTRY)
1822  {
1823  current_fu = get_fu(ENTRY_STD);
1824  }
1825  else if(current_op == EXIT)
1826  {
1827  current_fu = get_fu(EXIT_STD);
1828  }
1829  else if(current_op == NOP)
1830  {
1831  current_fu = get_fu(NOP_STD);
1832  }
1833  else if(current_op == GIMPLE_PHI)
1834  {
1835  current_fu = get_fu(GIMPLE_PHI_STD);
1836  }
1837  else if(current_op == GIMPLE_NOP)
1838  {
1839  current_fu = get_fu(GIMPLE_NOP_STD);
1840  }
1841  else if(current_op == VIEW_CONVERT_EXPR)
1842  {
1843  const auto& modify_node = g->CGetOpNodeInfo(v)->node;
1844  const auto gms = GetPointerS<const gimple_assign>(GET_CONST_NODE(modify_node));
1845  const auto vce = GetPointerS<const view_convert_expr>(GET_CONST_NODE(gms->op1));
1846  const auto right_type = tree_helper::CGetType(vce->op);
1847  if(tree_helper::IsSignedIntegerType(right_type))
1848  {
1849  current_fu = get_fu(VIEW_CONVERT_STD_INT);
1850  }
1851  else if(tree_helper::IsRealType(right_type))
1852  {
1853  current_fu = get_fu(VIEW_CONVERT_STD_REAL);
1854  }
1855  else
1856  {
1857  current_fu = get_fu(VIEW_CONVERT_STD_UINT);
1858  }
1859  }
1860  else
1861  {
1862  THROW_ERROR("Unexpected operation");
1863  }
1864  // FU must exist
1865  THROW_ASSERT(current_fu,
1866  std::string("Not found ") + current_op + " in library " + TechM->get_library(current_op));
1867 
1868  allocation_information->list_of_FU.push_back(current_fu);
1870  const auto current_id = current_size;
1872  "Something of wrong happen");
1873  allocation_information->is_vertex_bounded_rel.insert(current_id);
1874  allocation_information->binding[node_id] = std::pair<std::string, unsigned int>(current_op, current_id);
1875  allocation_information->node_id_to_fus[std::pair<unsigned int, std::string>(node_id, node_operation)].insert(
1876  current_id);
1877  allocation_information->id_to_fu_names[current_id] =
1878  std::make_pair(current_fu->get_name(), TechM->get_library(current_op));
1879  unsigned int out_var = HLSMgr->get_produced_value(HLS->functionId, v);
1880  if(out_var)
1881  {
1882  const auto type = tree_helper::CGetType(TM->CGetTreeReindex(out_var));
1884  {
1885  const auto element_type = tree_helper::CGetElements(type);
1886  const auto element_size = tree_helper::Size(element_type);
1887  allocation_information->precision_map[current_size] = element_size;
1888  }
1889  else
1890  {
1892  }
1893  }
1894  else
1895  {
1896  allocation_information->precision_map[current_size] = 0;
1897  }
1899  " . Operation " + current_op + " mapped onto " + current_fu->get_name() +
1900  ", found in library " + TechM->get_library(current_op));
1901  }
1902  // Constrained FUs
1903  else if(binding_constraints.find(GET_NAME(g, v)) != binding_constraints.end())
1904  {
1905  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, " . Current node is under constraints");
1906  const auto& [fu_name, constraint] = binding_constraints.at(GET_NAME(g, v));
1907  const auto& [fu_library, fu_index] = constraint;
1908  const auto key = ENCODE_FU_LIB(fu_name, fu_library);
1909  if(fu_name_to_id.find(key) != fu_name_to_id.end())
1910  {
1911  if(fu_name_to_id[key].find(fu_index) != fu_name_to_id[key].end())
1912  {
1913  allocation_information->binding[node_id] =
1914  std::pair<std::string, unsigned int>(current_op, fu_name_to_id[key][fu_index]);
1915  }
1916  else
1917  {
1918  unsigned int current_size = allocation_information->get_number_fu_types();
1919  fu_name_to_id[key][fu_index] = current_size;
1920  current_fu = TechM->get_fu(fu_name, fu_library);
1921  THROW_ASSERT(current_fu, std::string("Not found") + fu_name + " in library " + fu_library);
1922  allocation_information->list_of_FU.push_back(current_fu);
1924  allocation_information->binding[node_id] =
1925  std::pair<std::string, unsigned int>(current_op, current_size);
1926  allocation_information->node_id_to_fus[std::pair<unsigned int, std::string>(node_id, node_operation)]
1927  .insert(current_size);
1928  allocation_information->id_to_fu_names[current_size] = std::make_pair(fu_name, fu_library);
1929  if(tech_vec.find(key) != tech_vec.end())
1930  {
1931  tech_vec[key]--;
1932  }
1933  const auto out_var = HLSMgr->get_produced_value(HLS->functionId, v);
1934  if(out_var)
1935  {
1936  const auto type = tree_helper::CGetType(TM->CGetTreeReindex(out_var));
1938  {
1939  const auto element_type = tree_helper::CGetElements(type);
1940  const auto element_size = tree_helper::Size(element_type);
1941  allocation_information->precision_map[current_size] = element_size;
1942  }
1943  else
1944  {
1946  }
1947  }
1948  else
1949  {
1950  allocation_information->precision_map[current_size] = 0;
1951  }
1952  }
1953  }
1954  else
1955  {
1956  const auto current_size = allocation_information->get_number_fu_types();
1957  fu_name_to_id[key][fu_index] = current_size;
1958  current_fu = TechM->get_fu(fu_name, fu_library);
1959  THROW_ASSERT(current_fu, std::string("Not found") + fu_name + " in library " + fu_library);
1960  allocation_information->list_of_FU.push_back(current_fu);
1962  allocation_information->binding[node_id] = std::pair<std::string, unsigned int>(current_op, current_size);
1963  allocation_information->node_id_to_fus[std::pair<unsigned int, std::string>(node_id, node_operation)]
1964  .insert(current_size);
1965  allocation_information->id_to_fu_names[current_size] = std::make_pair(fu_name, fu_library);
1966  if(tech_vec.find(key) != tech_vec.end())
1967  {
1968  tech_vec[key]--;
1969  }
1970  unsigned int out_var = HLSMgr->get_produced_value(HLS->functionId, v);
1971  if(out_var)
1972  {
1973  const auto type = tree_helper::CGetType(TM->CGetTreeReindex(out_var));
1975  {
1976  const auto element_type = tree_helper::CGetElements(type);
1977  const auto element_size = tree_helper::Size(element_type);
1978  allocation_information->precision_map[current_size] = element_size;
1979  }
1980  else
1981  {
1983  }
1984  }
1985  else
1986  {
1987  allocation_information->precision_map[current_size] = 0;
1988  }
1989  }
1990  }
1991  else
1992  {
1993  if(vertex_to_analyse_partition.find(current_op) == vertex_to_analyse_partition.end())
1994  {
1995  vertex_to_analyse_partition.insert(std::pair<std::string, OpVertexSet>(current_op, OpVertexSet(g)));
1996  }
1997  vertex_to_analyse_partition.at(current_op).insert(v);
1999  "---Operation " + current_op + " queued for allocation");
2000  }
2002  }
2003 
2004  INDENT_DBG_MEX(DEBUG_LEVEL_VERBOSE, debug_level, "---Starting allocation of operations in queued vertices");
2005 
2006  for(const auto& tv : tech_vec)
2007  {
2009  "---Resource constraint on " + tv.first + ": " + STR(tv.second));
2010  }
2011 
2012  std::string bambu_provided_resource;
2013  for(const auto& lib_name : TechM->get_library_list())
2014  {
2015  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Considering library " + lib_name);
2016  const auto library = TechM->get_library_manager(lib_name);
2018  if(lib_name == "STD_COMMON")
2019  {
2020  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Considered library " + lib_name);
2021  continue;
2022  }
2023  for(const auto& fu : library->get_library_fu())
2024  {
2025  technology_nodeRef current_fu = fu.second;
2026  if(GetPointer<functional_unit_template>(current_fu))
2027  {
2028  continue;
2029  }
2030 
2031  const auto& fu_channels_type = GetPointer<functional_unit>(current_fu)->channels_type;
2032  const auto& fu_memory_ctrl_type = GetPointer<functional_unit>(current_fu)->memory_ctrl_type;
2034  "-->Considering functional unit: " + current_fu->get_name());
2035  if(check_for_memory_compliancy(Has_extern_allocated_data, current_fu, fu_memory_ctrl_type, fu_channels_type))
2036  {
2037  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Skipped for memory compliance");
2038  continue;
2039  }
2040 
2042  if((HLSMgr->Rfuns->has_shared_functions(HLS->functionId) ||
2043  HLSMgr->Rfuns->has_proxied_shared_functions(HLS->functionId)))
2044  {
2045  if(check_proxies(library, fu.first))
2046  {
2047  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Skipped because proxy");
2048  continue;
2049  }
2050  }
2051  else if(lib_name == PROXY_LIBRARY)
2052  {
2053  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Skipped because proxy library");
2054  continue;
2055  }
2056 
2057  const auto tech_constrain_it =
2058  GetPointer<functional_unit>(current_fu)->fu_template_name.size() ?
2059  tech_vec.find(ENCODE_FU_LIB(GetPointer<functional_unit>(current_fu)->fu_template_name, lib_name)) :
2060  tech_vec.find(ENCODE_FU_LIB(current_fu->get_name(), lib_name));
2061 
2062  if(tech_constrain_it != tech_vec.end() && tech_constrain_it->second == 0)
2063  {
2064  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Skipped because of constraint");
2065  continue; // forced to use 0 FUs of current ones
2066  }
2067 
2068  const auto tech_constrain_value =
2069  tech_constrain_it == tech_vec.end() ? INFINITE_UINT : tech_constrain_it->second;
2070 
2071  const auto structManager_obj = GetPointer<functional_unit>(current_fu)->CM;
2072 
2074  if(check_generated_bambu_flopoco(skip_softfloat_resources, structManager_obj, bambu_provided_resource,
2075  skip_flopoco_resources, current_fu))
2076  {
2077  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Skipped because of generated module");
2078  continue;
2079  }
2080 
2081  unsigned int current_fu_id = allocation_information->get_number_fu_types();
2082 
2083  unsigned int current_id = current_fu_id;
2084 
2085  const auto lib_is_proxy_or_work =
2086  lib_name == WORK_LIBRARY || lib_name == PROXY_LIBRARY || lib_name == INTERFACE_LIBRARY;
2087  for(const auto& ops : GetPointer<functional_unit>(current_fu)->get_operations())
2088  {
2089  const auto curr_op = GetPointer<operation>(ops);
2090  const auto& curr_op_name = curr_op->get_name();
2091  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Considering operation: " + curr_op_name);
2092  if(vertex_to_analyse_partition.find(curr_op_name) == vertex_to_analyse_partition.end())
2093  {
2094  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Considered operation: " + curr_op_name);
2095  continue;
2096  }
2097  for(const auto vert : vertex_to_analyse_partition.at(curr_op_name))
2098  {
2099  const auto vert_node_id = g->CGetOpNodeInfo(vert)->GetNodeId();
2100  const auto vert_node_operation = [&]() -> std::string {
2101  if(vert_node_id == ENTRY_ID)
2102  {
2103  return "Entry";
2104  }
2105  if(vert_node_id == EXIT_ID)
2106  {
2107  return "Exit";
2108  }
2109  return GetPointer<const gimple_node>(TM->CGetTreeNode(vert_node_id))->operation;
2110  }();
2111  if(tree_helper::NormalizeTypename(g->CGetOpNodeInfo(vert)->GetOperation()) != curr_op_name)
2112  {
2113  continue;
2114  }
2115  else if((!lib_is_proxy_or_work) &&
2116  TechM->get_fu(tree_helper::NormalizeTypename(g->CGetOpNodeInfo(vert)->GetOperation()),
2117  WORK_LIBRARY) &&
2118  GET_TYPE(g, vert) != TYPE_MEMCPY)
2119  {
2120  continue;
2121  }
2122  // else if(lib_is_proxy_or_work && GET_TYPE(g, vert) == TYPE_MEMCPY) continue;
2123 
2124  node_kind_prec_infoRef node_info(new node_kind_prec_info());
2125  HLS_manager::io_binding_type constant_id;
2126  bool isMemory = fu_memory_ctrl_type.size();
2127  THROW_ASSERT((GET_TYPE(g, vert) & (TYPE_LOAD | TYPE_STORE)) == 0 or isMemory,
2128  "unexpected condition: " + g->CGetOpNodeInfo(vert)->GetOperation());
2129 
2130  if(!isMemory)
2131  {
2132  allocation_information->GetNodeTypePrec(vert, g, node_info, constant_id,
2133  tech_constrain_value != INFINITE_UINT);
2134  }
2135  else
2136  {
2137  node_info->node_kind = "VECTOR_BOOL";
2138  }
2139 
2140  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Considering vertex " + GET_NAME(g, vert));
2142  if(check_type_and_precision(curr_op, node_info))
2143  {
2144  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Skipped because of type and precision");
2145  continue;
2146  }
2147 
2149  THROW_ASSERT(curr_op->time_m,
2150  "expected a time model for " + current_fu->get_name() + " for operation " + curr_op_name);
2151  if(curr_op->time_m->get_cycles() >= 1 &&
2152  allocation_information->time_m_stage_period(curr_op) > clock_period && fu_memory_ctrl_type.empty() &&
2153  GetPointer<functional_unit>(current_fu)->fu_template_name.empty())
2154  {
2155  THROW_ERROR("Functional unit " + current_fu->get_name() +
2156  " not compliant with the given clock period " + STR(clock_period));
2157  // continue;
2158  }
2159  else if(curr_op->time_m->get_cycles() >= 1)
2160  {
2162  "Functional unit " + current_fu->get_name() +
2163  " compliant with the given clock period " + STR(clock_period) + " stage period " +
2165  }
2166 
2167  if(GetPointer<functional_unit>(current_fu)->fu_template_name.size())
2168  {
2169  // check if specialized unit is compliant with the vertex
2170  if(check_templated_units(clock_period, node_info, library, current_fu, curr_op))
2171  {
2172  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Skipped because of template");
2173  continue;
2174  }
2175  }
2176 
2177  std::string current_op;
2178  std::string specialized_fuName = "";
2179 
2180  const auto has_to_be_generated =
2181  structManager_obj && (GetPointer<module>(structManager_obj->get_circ())
2182  ->get_NP_functionality()
2183  ->exist_NP_functionality(NP_functionality::VERILOG_GENERATOR) ||
2184  GetPointer<module>(structManager_obj->get_circ())
2185  ->get_NP_functionality()
2186  ->exist_NP_functionality(NP_functionality::VHDL_GENERATOR));
2187  if(has_to_be_generated)
2188  {
2189  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "Unit has to be specialized.");
2191  const auto varargs_fu = GetPointer<module>(structManager_obj->get_circ())->is_var_args();
2192  if(varargs_fu)
2193  {
2194  const auto required_variables = HLSMgr->get_required_values(funId, vert);
2195  std::string unique_id;
2196  if(g->CGetOpNodeInfo(vert)->GetOperation() == GIMPLE_ASM)
2197  {
2198  unique_id = STR(g->CGetOpNodeInfo(vert)->GetNodeId());
2199  }
2200  auto firstIndexToSpecialize = 0U;
2201  const auto mod = GetPointer<module>(structManager_obj->get_circ());
2202  for(auto Pindex = 0U; Pindex < mod->get_in_port_size(); ++Pindex)
2203  {
2204  const auto& port_obj = mod->get_in_port(Pindex);
2205  const auto& port_name = port_obj->get_id();
2206  if(GetPointer<port_o>(port_obj)->get_is_var_args())
2207  {
2208  break;
2209  }
2210  if(port_name != CLOCK_PORT_NAME && port_name != RESET_PORT_NAME && port_name != START_PORT_NAME)
2211  {
2212  ++firstIndexToSpecialize;
2213  }
2214  }
2215  THROW_ASSERT(required_variables.size() >= firstIndexToSpecialize,
2216  "unexpected condition:" + STR(required_variables.size()) + " " +
2217  STR(firstIndexToSpecialize));
2218  current_op = current_fu->get_name() + unique_id +
2219  modGen->get_specialized_name(firstIndexToSpecialize, required_variables, FB);
2220  }
2221  else
2222  {
2223  current_op = current_fu->get_name() + "_modgen";
2224  }
2225  specialized_fuName = current_op;
2226  const auto& fu_name = current_fu->get_name();
2227 
2228  const auto check_lib = TechM->get_library(specialized_fuName);
2229  if(check_lib == lib_name)
2230  {
2231  new_fu[specialized_fuName] = get_fu(specialized_fuName);
2232  }
2233  else if(new_fu.find(specialized_fuName) == new_fu.end())
2234  {
2235  if(varargs_fu)
2236  {
2237  modGen->specialize_fu(fu_name, vert, FB, lib_name, specialized_fuName, new_fu);
2238  }
2239  else
2240  {
2241  modGen->create_generic_module(fu_name, vert, FB, lib_name, specialized_fuName);
2242  const auto libraryManager = TechM->get_library_manager(lib_name);
2243  const auto new_techNode_obj = libraryManager->get_fu(specialized_fuName);
2244  THROW_ASSERT(new_techNode_obj, "not expected");
2245  new_fu.insert(std::make_pair(specialized_fuName, new_techNode_obj));
2246  }
2247  }
2248  }
2249  else if(node_info->node_kind.size() && !isMemory)
2250  {
2251  current_op = encode_op_type_prec(curr_op_name, curr_op->get_type_supported_string(), node_info);
2252  }
2253  else if(node_info->node_kind.size())
2254  {
2255  current_op = encode_op_type(curr_op_name, curr_op->get_type_supported_string());
2256  }
2257  else
2258  {
2259  current_op = curr_op_name;
2260  }
2261 
2262  std::string library_name = lib_name;
2263  if(bambu_provided_resource.size())
2264  {
2265  if(HLSMgr->Rfuns->is_a_proxied_function(functions::GetFUName(bambu_provided_resource, HLSMgr)))
2266  {
2267  library_name = PROXY_LIBRARY;
2268  }
2269  else
2270  {
2271  library_name = WORK_LIBRARY;
2272  }
2273 
2274  current_fu = extract_bambu_provided(library_name, curr_op, bambu_provided_resource);
2275  }
2276 
2277  auto max_prec = node_info->input_prec.empty() ?
2278  0ULL :
2279  *std::max_element(node_info->input_prec.begin(), node_info->input_prec.end());
2280  if(isMemory || lib_is_proxy_or_work || tech_constrain_value != INFINITE_UINT ||
2281  bambu_provided_resource.size())
2282  {
2283  constant_id = HLS_manager::io_binding_type(0, 0);
2284  max_prec = 0U;
2285  }
2286 
2287  decltype(fu_list)::iterator techMap;
2288  std::string functionalUnitName = "";
2289  auto specializedId = current_id;
2290  const auto libraryManager = TechM->get_library_manager(library_name);
2291  if(has_to_be_generated)
2292  {
2293  functionalUnitName = specialized_fuName;
2294  techMap = fu_list.find(new_fu.at(functionalUnitName));
2295  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "Specialized unit: " + functionalUnitName);
2296  if(techMap != fu_list.end() && techMap->second.find(max_prec) != techMap->second.end() &&
2297  techMap->second.find(max_prec)->second.find(constant_id) !=
2298  techMap->second.find(max_prec)->second.end())
2299  {
2300  specializedId = techMap->second.find(max_prec)->second.find(constant_id)->second;
2301  }
2302  else
2303  {
2305  "Insert into list of unit to add: " + functionalUnitName +
2306  " prec=" + STR(max_prec) + " constant_id=" + STR(std::get<0>(constant_id)) +
2307  "-" + STR(std::get<1>(constant_id)));
2308  fu_list[new_fu.find(functionalUnitName)->second][max_prec][constant_id] = current_id;
2309  allocation_information->precision_map[current_id] = max_prec;
2310  if(fu_channels_type == CHANNELS_TYPE_MEM_ACC_NN && fu_memory_ctrl_type.size())
2311  {
2312  set_number_channels(specializedId, channels_number);
2313  }
2314  else if(fu_memory_ctrl_type.size())
2315  {
2316  set_number_channels(specializedId, 1);
2317  }
2318  auto fuUnit = new_fu.find(functionalUnitName)->second;
2319  if(fuUnit->get_kind() == functional_unit_K)
2320  {
2321  auto fuUnitModule = GetPointer<functional_unit>(fuUnit)->CM->get_circ();
2322  if(GetPointer<module>(fuUnitModule))
2323  {
2324  auto multiplicity = GetPointer<module>(fuUnitModule)->get_multi_unit_multiplicity();
2325  if(multiplicity)
2326  {
2328  "Added multiplicity of " + STR(multiplicity) + " to " +
2329  functionalUnitName);
2330  set_number_channels(specializedId, multiplicity);
2331  }
2332  }
2333  }
2334  add_tech_constraint(fuUnit, tech_constrain_value, current_id, library_name == PROXY_LIBRARY);
2335  current_id++;
2336  }
2337  }
2338  else
2339  {
2340  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---Not generated functional unit");
2341  functionalUnitName = current_fu->get_name();
2343  "---Functional unit name is " + functionalUnitName);
2344  techMap = fu_list.find(libraryManager->get_fu(functionalUnitName));
2345  if(techMap != fu_list.end() && techMap->second.find(max_prec) != techMap->second.end() &&
2346  techMap->second.find(max_prec)->second.find(constant_id) !=
2347  techMap->second.find(max_prec)->second.end())
2348  {
2349  specializedId = techMap->second.find(max_prec)->second.find(constant_id)->second;
2350  }
2351  else
2352  {
2353  fu_list[libraryManager->get_fu(functionalUnitName)][max_prec][constant_id] = current_id;
2354  allocation_information->precision_map[current_id] = max_prec;
2355  if(fu_channels_type == CHANNELS_TYPE_MEM_ACC_P1N and fu_memory_ctrl_type.size())
2356  {
2357  auto n_ports = parameters->getOption<unsigned int>(OPT_memory_banks_number);
2358  set_number_channels(specializedId, n_ports);
2359  }
2360  else if(fu_channels_type == CHANNELS_TYPE_MEM_ACC_NN && fu_memory_ctrl_type.size())
2361  {
2362  set_number_channels(specializedId, channels_number);
2363  }
2364  else if(fu_memory_ctrl_type.size())
2365  {
2366  set_number_channels(specializedId, 1);
2367  }
2368  add_tech_constraint(libraryManager->get_fu(functionalUnitName), tech_constrain_value, current_id,
2369  library_name == PROXY_LIBRARY);
2370  current_id++;
2371  }
2372  }
2373 
2374  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, " . Match found for vertex: " + GET_NAME(g, vert));
2376  " . Adding candidate FU: " + functionalUnitName + " for operation: " + current_op +
2377  " in position " + STR(specializedId));
2378  vertex_analysed.insert(vert);
2380  ->node_id_to_fus[std::pair<unsigned int, std::string>(vert_node_id, vert_node_operation)]
2381  .insert(specializedId);
2382  allocation_information->id_to_fu_names[specializedId] = std::make_pair(functionalUnitName, library_name);
2383  if(node_info->is_single_bool_test_cond_expr)
2384  {
2386  }
2387  if(node_info->is_simple_pointer_plus_expr)
2388  {
2389  allocation_information->simple_pointer_plus_expr.insert(specializedId);
2390  }
2391  if(library_name == PROXY_LIBRARY)
2392  {
2393  if(starts_with(functionalUnitName, WRAPPED_PROXY_PREFIX))
2394  {
2395  const auto original_function_name = functionalUnitName.substr(sizeof(WRAPPED_PROXY_PREFIX) - 1);
2396  allocation_information->proxy_wrapped_units[specializedId] = original_function_name;
2397  }
2398  else
2399  {
2400  THROW_ASSERT(starts_with(functionalUnitName, PROXY_PREFIX), "expected a proxy module");
2401  const auto original_function_name = functionalUnitName.substr(sizeof(PROXY_PREFIX) - 1);
2402  allocation_information->proxy_function_units[specializedId] = original_function_name;
2403  }
2404  }
2405  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Considered vertex " + GET_NAME(g, vert));
2406  }
2407  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Considered operation: " + curr_op_name);
2408  }
2410  "<--Considered functional unit: " + current_fu->get_name());
2411  }
2412  for(auto& iter_new_fu : new_fu)
2413  {
2415  "Adding functional unit: " + iter_new_fu.first + " in " + lib_name);
2416  TechM->add(iter_new_fu.second, lib_name);
2417  }
2418  new_fu.clear();
2419  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Considered library " + lib_name);
2420  }
2421 
2422 #ifndef NDEBUG
2423  // For debug purpose
2425 #endif
2426 
2427  // Check if each operation has been analysed
2428  bool completely_analyzed = true;
2429  for(const auto& ve_op : vertex_to_analyse_partition)
2430  {
2431  for(const auto& ve : ve_op.second)
2432  {
2433  if(vertex_analysed.count(ve))
2434  {
2435  continue;
2436  }
2437  node_kind_prec_infoRef node_info(new node_kind_prec_info());
2438  HLS_manager::io_binding_type constant_id;
2439  allocation_information->GetNodeTypePrec(ve, g, node_info, constant_id, false);
2440  std::string precisions;
2441  const size_t n_ins = node_info->input_prec.size();
2442  for(size_t ind = 0; ind < n_ins; ++ind)
2443  {
2444  if(node_info->real_input_nelem[ind] == 0)
2445  {
2446  precisions += " " + STR(node_info->input_prec[ind]);
2447  }
2448  else
2449  {
2450  precisions += " " + STR(node_info->input_prec[ind]) + ":" + STR(node_info->real_input_nelem[ind]);
2451  }
2452  }
2453  if(node_info->real_output_nelem == 0)
2454  {
2455  precisions += " " + STR(node_info->output_prec);
2456  }
2457  else
2458  {
2459  precisions += " " + STR(node_info->output_prec) + ":" + STR(node_info->real_output_nelem);
2460  }
2462  "---Operation for which does not exist a functional unit in the resource library: " +
2463  tree_helper::NormalizeTypename(g->CGetOpNodeInfo(ve)->GetOperation()) +
2464  " in vertex: " + GET_NAME(g, ve) + " with vertex type: " + node_info->node_kind +
2465  " and vertex prec:" + precisions);
2466  completely_analyzed = false;
2467  }
2468  }
2469  if(!completely_analyzed)
2470  {
2471  THROW_ERROR("Vertices not completely allocated");
2472  }
2475  {
2476  for(const auto& op : allocation_information->node_id_to_fus)
2477  {
2478  for(auto fu_unit : op.second)
2479  {
2480  allocation_information->fus_to_node_id[fu_unit].insert(op.first.first);
2481  if(op.first.first != ENTRY_ID && op.first.first != EXIT_ID)
2482  {
2483  if(!allocation_information->is_operation_bounded(op.first.first, fu_unit) ||
2484  allocation_information->get_cycles(fu_unit, op.first.first) > 1 ||
2485  allocation_information->get_DSPs(fu_unit) > 0 ||
2488  {
2490  }
2491  }
2492  }
2493  }
2495  "---Number of complex operations: " + STR(allocation_information->n_complex_operations));
2496  }
2497  if(!allocation_information->node_id_to_fus.empty() and bb_version == 0)
2498  {
2499  for(const auto& op : allocation_information->node_id_to_fus)
2500  {
2501  for(auto fu_unit : op.second)
2502  {
2504  {
2505  HLSMgr->Rmem->increment_n_mem_operations(allocation_information->memory_units.find(fu_unit)->second);
2506  }
2507  else if(allocation_information->proxy_memory_units.find(fu_unit) !=
2509  {
2510  HLSMgr->Rmem->increment_n_mem_operations(
2511  allocation_information->proxy_memory_units.find(fu_unit)->second);
2512  }
2513  }
2514  }
2516  "---Number of complex operations: " + STR(allocation_information->n_complex_operations));
2517  }
2519  {
2520  STOP_TIME(step_time);
2521  }
2523  {
2525  "Time to perform module allocation: " + print_cpu_time(step_time) + " seconds");
2526  }
2529  {
2531  }
2532 
2534 }
2535 
2536 std::string allocation::get_compliant_pipelined_unit(double clock, const std::string& pipe_parameter,
2537  const technology_nodeRef current_fu, const std::string& curr_op,
2538  const std::string& library_name,
2539  const std::string& template_suffix, unsigned long long module_prec)
2540 {
2541  if(pipe_parameter.empty())
2542  {
2543  return "";
2544  }
2545  THROW_ASSERT(GetPointer<functional_unit>(current_fu), "expected a functional unit object");
2546  auto* fu = GetPointer<functional_unit>(current_fu);
2547 
2548  THROW_ASSERT(fu->fu_template_name.size(), "expected a template_name for a pipelined unit");
2549  if(precomputed_pipeline_unit.find(fu->fu_template_name + "_" + template_suffix) != precomputed_pipeline_unit.end())
2550  {
2551  std::string compliant_id = precomputed_pipeline_unit.find(fu->fu_template_name + "_" + template_suffix)->second;
2552  if(pipe_parameter == compliant_id)
2553  {
2554  return pipe_parameter;
2555  }
2556  else
2557  {
2558  return "";
2559  }
2560  }
2561  const technology_nodeRef fu_template = HLS_D->get_technology_manager()->get_fu(fu->fu_template_name, library_name);
2562  const functional_unit_template* fu_temp = GetPointer<functional_unit_template>(fu_template);
2563  THROW_ASSERT(fu_temp, "expected a template functional unit for a pipelined unit");
2564  bool is_flopoco_provided = false;
2565  structural_managerRef tcm = GetPointer<functional_unit>(fu_temp->FU)->CM;
2566  if(tcm)
2567  {
2568  structural_objectRef tmodobj = tcm->get_circ();
2569  auto* tmod = GetPointer<module>(tmodobj);
2570  const NP_functionalityRef& np = tmod->get_NP_functionality();
2571  if(np->get_NP_functionality(NP_functionality::FLOPOCO_PROVIDED).size())
2572  {
2573  is_flopoco_provided = true;
2574  }
2575  }
2576  technology_nodeRef fun_temp_operation = GetPointer<functional_unit>(fu_temp->FU)->get_operation(curr_op);
2577  THROW_ASSERT(fun_temp_operation, "operation not present in the template description");
2578  auto* template_op = GetPointer<operation>(fun_temp_operation);
2579  std::string temp_pipe_parameters = template_op->pipe_parameters;
2580  std::vector<std::string> parameters_split = SplitString(temp_pipe_parameters, "|");
2581  THROW_ASSERT(parameters_split.size() > 0, "unexpected pipe_parameter format");
2582  for(auto& el_indx : parameters_split)
2583  {
2584  std::vector<std::string> parameters_pairs = SplitString(el_indx, ":");
2585  if(parameters_pairs[0] == "*")
2586  {
2587  temp_pipe_parameters = parameters_pairs[1];
2588  break;
2589  }
2590  else if(parameters_pairs[0] == "DSPs_y_sizes" and
2592  module_prec) != allocation_information->DSP_y_db.end())
2593  {
2594  temp_pipe_parameters = parameters_pairs[1];
2595  break;
2596  }
2597  else if(std::stoull(parameters_pairs[0]) == module_prec)
2598  {
2599  temp_pipe_parameters = parameters_pairs[1];
2600  break;
2601  }
2602  }
2603  THROW_ASSERT(temp_pipe_parameters.size(), "expected some pipe_parameters for the the template operation");
2604  std::string fastest_pipe_parameter = "0";
2605  double fastest_stage_period = std::numeric_limits<double>::max();
2606  std::vector<std::string> pipe_parameters = SplitString(temp_pipe_parameters, ",");
2607  const auto st_end = pipe_parameters.end();
2608  std::vector<std::string>::const_iterator st_next;
2609  unsigned int skip_pipe_parameter = 0;
2610  if(is_flopoco_provided)
2611  {
2612  skip_pipe_parameter = std::max(1u, parameters->getOption<unsigned int>(OPT_skip_pipe_parameter));
2613  }
2614  else if(is_a_skip_operation(curr_op))
2615  {
2616  skip_pipe_parameter = parameters->getOption<unsigned int>(OPT_skip_pipe_parameter);
2617  }
2618  for(auto st = st_next = pipe_parameters.begin(); st != st_end; ++st)
2619  {
2620  ++st_next;
2621  const technology_nodeRef fu_cur_obj = HLS_D->get_technology_manager()->get_fu(
2622  fu->fu_template_name + "_" + template_suffix + "_" + *st, library_name);
2623  if(fu_cur_obj)
2624  {
2625  area_infoRef a_m = GetPointer<functional_unit>(fu_cur_obj)->area_m;
2626  THROW_ASSERT(a_m, "Area information not specified for unit " + fu->fu_template_name + "_" + template_suffix +
2627  "_" + *st);
2628  bool has_DSPs = (a_m && a_m->get_resource_value(area_info::DSP) > 0);
2629  double DSP_allocation_coefficient = allocation_information->DSP_allocation_coefficient;
2630  double dsp_multiplier = has_DSPs ? allocation_information->DSPs_margin * DSP_allocation_coefficient : 1.0;
2631  double dsp_multiplier_stage =
2632  has_DSPs ? allocation_information->DSPs_margin_stage * DSP_allocation_coefficient : 1.0;
2633 
2634  if(fu_cur_obj)
2635  {
2636  const functional_unit* fu_cur = GetPointer<functional_unit>(fu_cur_obj);
2637  auto* fu_cur_operation = GetPointer<operation>(fu_cur->get_operation(curr_op));
2638  if(fu_cur_operation->time_m->get_cycles() >= 1 &&
2639  allocation_information->time_m_stage_period(fu_cur_operation) < fastest_stage_period)
2640  {
2641  fastest_pipe_parameter = *st;
2642  fastest_stage_period = allocation_information->time_m_stage_period(fu_cur_operation);
2643  }
2644  if((*st == "0" &&
2645  dsp_multiplier * allocation_information->time_m_execution_time(fu_cur_operation) < clock &&
2646  allocation_information->time_m_execution_time(fu_cur_operation) != 0.0) ||
2647  (fu_cur_operation->time_m->get_cycles() >= 1 &&
2648  dsp_multiplier_stage * allocation_information->time_m_stage_period(fu_cur_operation) < clock &&
2649  *st != "0"))
2650  {
2651  if(skip_pipe_parameter && st_next != st_end)
2652  {
2653  --skip_pipe_parameter;
2654  }
2655  else
2656  {
2657  precomputed_pipeline_unit[fu->fu_template_name + "_" + template_suffix] = *st;
2658  if(*st == pipe_parameter)
2659  {
2660  return pipe_parameter;
2661  }
2662  else
2663  {
2664  return "";
2665  }
2666  }
2667  }
2668  }
2669  }
2670  }
2671  if(fastest_pipe_parameter == "0")
2672  {
2673  precomputed_pipeline_unit[fu->fu_template_name + "_" + template_suffix] = fastest_pipe_parameter;
2674  }
2675  else
2676  {
2679  THROW_WARNING("No functional unit exists for the given clock period: the fastest pipelined unit will be used (" +
2680  fu->fu_template_name + "): " + STR(fastest_stage_period));
2681  precomputed_pipeline_unit[fu->fu_template_name + "_" + template_suffix] = fastest_pipe_parameter;
2682  }
2683  if(pipe_parameter == fastest_pipe_parameter)
2684  {
2685  return fastest_pipe_parameter;
2686  }
2687  else
2688  {
2689  return "";
2690  }
2691 }
2692 
2693 void allocation::set_number_channels(unsigned int fu_name, unsigned int n_ports)
2694 {
2695  allocation_information->nports_map[fu_name] = n_ports;
2696 }
2697 
2698 technology_nodeRef allocation::get_fu(const std::string& fu_name)
2699 {
2700  std::string library_name = HLS_D->get_technology_manager()->get_library(fu_name);
2701  if(library_name.empty())
2702  {
2703  return technology_nodeRef();
2704  }
2705  return HLS_D->get_technology_manager()->get_fu(fu_name, library_name);
2706 }
2707 
2709  technology_nodeRef current_fu)
2710 {
2711  if(!parameters->IsParameter("variable-mem-lat") || parameters->GetParameter<int>("variable-mem-lat") == 0)
2712  {
2713  return false;
2714  }
2715  if(HLSMgr->Rmem->is_read_only_variable(var))
2716  {
2717  return false;
2718  }
2719  const auto n_ref = static_cast<unsigned int>(HLSMgr->Rmem->get_maximum_references(var));
2720  const auto clock_period = HLS_C->get_clock_period_resource_fraction() * HLS_C->get_clock_period();
2721  const auto controller_delay = 0; // too overestimated allocation_information->EstimateControllerDelay();
2722  const auto fu_cur = GetPointerS<functional_unit>(current_fu);
2723  const auto load_operation = GetPointerS<operation>(fu_cur->get_operation("STORE"));
2724  const auto ex_time = allocation_information->time_m_execution_time(load_operation);
2725  const auto FB = HLSMgr->CGetFunctionBehavior(funId);
2726  const auto n_channels = FB->GetChannelsNumber() ? FB->GetChannelsNumber() : 1U;
2727  const auto mux_delay = allocation_information->estimate_muxNto1_delay(32, n_ref / n_channels);
2728  const auto setup = allocation_information->get_setup_hold_time(); // for the PHIs
2729  return n_ref / n_channels > 1 && (controller_delay + ex_time + mux_delay + setup) > clock_period;
2730 }
2731 
2732 std::string allocation::get_synch_ram_latency(const std::string& ram_template, const std::string& latency_postfix,
2733  const HLS_constraintsRef HLS_C, unsigned int var)
2734 {
2735  std::string new_lat;
2736  technology_nodeRef current_fu = get_fu(ram_template + latency_postfix);
2737  bool is_synchronous_ram_not_timing_compliant = is_ram_not_timing_compliant(HLS_C, var, current_fu);
2738  if(is_synchronous_ram_not_timing_compliant)
2739  {
2740  new_lat = latency_postfix.empty() ? std::string("3") : std::string("4");
2741  current_fu = get_fu(ram_template + allocation_information->get_latency_string(new_lat));
2743  }
2744  else
2745  {
2746  new_lat = latency_postfix.empty() ? "2" : (latency_postfix == "_3" ? "3" : "4");
2748  }
2749  return new_lat;
2750 }
2751 
2753 {
2754  const auto TM = HLSMgr->get_tree_manager();
2755  const auto FB = HLSMgr->CGetFunctionBehavior(funId);
2756  const auto channels_number = FB->GetChannelsNumber();
2757  const auto channels_type = FB->GetChannelsType();
2758  const auto& HLS_C = HLS->HLS_C;
2759  const auto clock_period = HLS_C->get_clock_period_resource_fraction() * HLS_C->get_clock_period();
2760 
2761  std::string latency_postfix = "";
2762  if(parameters->getOption<std::string>(OPT_bram_high_latency).size())
2763  {
2764  latency_postfix = parameters->getOption<std::string>(OPT_bram_high_latency);
2765  }
2766  for(const auto& l : HLSMgr->Rmem->get_function_vars(funId))
2767  {
2768  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, " - analyzing variable " + STR(l.first));
2769  const auto& var = l.first;
2770  technology_nodeRef current_fu;
2771  unsigned int n_ports = 1;
2772 
2773  if(HLSMgr->Rmem->has_callSite_base_address(var))
2774  {
2775  continue;
2776  }
2777 
2778  bool is_async_var = false;
2779 
2780  THROW_ASSERT(channels_type != MemoryAllocation_ChannelsType::MEM_ACC_P1N, "unexpected condition");
2781  if(channels_type == MemoryAllocation_ChannelsType::MEM_ACC_11)
2782  {
2783  if(HLSMgr->Rmem->is_sds_var(var))
2784  {
2785  if((HLSMgr->Rmem->has_all_pointers_resolved() && HLSMgr->Rmem->does_need_addr(var)) ||
2786  (!HLSMgr->Rmem->has_all_pointers_resolved() && !HLSMgr->Rmem->is_private_memory(var)))
2787  {
2788  current_fu = get_fu(ARRAY_1D_STD_BRAM_SDS_BUS + latency_postfix);
2789  }
2790  else
2791  {
2792  if(parameters->getOption<bool>(OPT_use_asynchronous_memories) &&
2794  TM, var, parameters->getOption<unsigned int>(OPT_distram_threshold),
2795  HLSMgr->Rmem->is_read_only_variable(var), 1)))
2796  {
2797  current_fu = get_fu(ARRAY_1D_STD_DISTRAM_SDS);
2798  bool is_asynchronous_ram_not_timing_compliant = is_ram_not_timing_compliant(HLS_C, var, current_fu);
2799  if(is_asynchronous_ram_not_timing_compliant)
2800  {
2801  current_fu = get_fu(ARRAY_1D_STD_BRAM_SDS +
2803  ARRAY_1D_STD_BRAM_SDS, latency_postfix, HLS_C, var)));
2804  }
2805  else
2806  {
2807  is_async_var = true;
2808  }
2809  }
2810  else
2811  {
2812  current_fu =
2814  ARRAY_1D_STD_BRAM_SDS, latency_postfix, HLS_C, var)));
2815  }
2816  }
2817  }
2818  else
2819  {
2820  current_fu = get_fu(ARRAY_1D_STD_BRAM + latency_postfix);
2821  }
2822  }
2823  else if(channels_type == MemoryAllocation_ChannelsType::MEM_ACC_N1)
2824  {
2825  if(HLSMgr->Rmem->is_sds_var(var))
2826  {
2827  if((HLSMgr->Rmem->has_all_pointers_resolved() && HLSMgr->Rmem->does_need_addr(var)) ||
2828  (!HLSMgr->Rmem->has_all_pointers_resolved() && !HLSMgr->Rmem->is_private_memory(var)))
2829  {
2830  current_fu = get_fu(ARRAY_1D_STD_BRAM_N1_SDS_BUS + latency_postfix);
2831  }
2832  else
2833  {
2834  if(parameters->getOption<bool>(OPT_use_asynchronous_memories) &&
2836  TM, var, parameters->getOption<unsigned int>(OPT_distram_threshold),
2837  HLSMgr->Rmem->is_read_only_variable(var), channels_number))
2838  {
2839  current_fu = get_fu(ARRAY_1D_STD_DISTRAM_N1_SDS);
2840  bool is_asynchronous_ram_not_timing_compliant = is_ram_not_timing_compliant(HLS_C, var, current_fu);
2841  if(is_asynchronous_ram_not_timing_compliant)
2842  {
2843  current_fu = get_fu(ARRAY_1D_STD_BRAM_N1_SDS +
2845  ARRAY_1D_STD_BRAM_N1_SDS, latency_postfix, HLS_C, var)));
2846  }
2847  else
2848  {
2849  is_async_var = true;
2850  }
2851  }
2852  else
2853  {
2854  current_fu = get_fu(ARRAY_1D_STD_BRAM_N1_SDS +
2856  ARRAY_1D_STD_BRAM_N1_SDS, latency_postfix, HLS_C, var)));
2857  }
2858  }
2859  }
2860  else
2861  {
2862  current_fu = get_fu(ARRAY_1D_STD_BRAM_N1 + latency_postfix);
2863  }
2864  n_ports = channels_number;
2865  }
2866  else if(channels_type == MemoryAllocation_ChannelsType::MEM_ACC_NN)
2867  {
2868  if(HLSMgr->Rmem->is_sds_var(var))
2869  {
2870  if((HLSMgr->Rmem->has_all_pointers_resolved() && HLSMgr->Rmem->does_need_addr(var)) ||
2871  (!HLSMgr->Rmem->has_all_pointers_resolved() && !HLSMgr->Rmem->is_private_memory(var)))
2872  {
2873  current_fu = get_fu(ARRAY_1D_STD_BRAM_NN_SDS_BUS + latency_postfix);
2874  }
2875  else
2876  {
2877  if(parameters->getOption<bool>(OPT_use_asynchronous_memories) &&
2879  TM, var, parameters->getOption<unsigned int>(OPT_distram_threshold),
2880  HLSMgr->Rmem->is_read_only_variable(var), channels_number))
2881  {
2882  current_fu = get_fu(ARRAY_1D_STD_DISTRAM_NN_SDS);
2883  bool is_asynchronous_ram_not_timing_compliant = is_ram_not_timing_compliant(HLS_C, var, current_fu);
2884  if(is_asynchronous_ram_not_timing_compliant)
2885  {
2886  current_fu = get_fu(ARRAY_1D_STD_BRAM_NN_SDS +
2888  ARRAY_1D_STD_BRAM_NN_SDS, latency_postfix, HLS_C, var)));
2889  }
2890  else
2891  {
2892  is_async_var = true;
2893  }
2894  }
2895  else
2896  {
2897  current_fu = get_fu(ARRAY_1D_STD_BRAM_NN_SDS +
2899  ARRAY_1D_STD_BRAM_NN_SDS, latency_postfix, HLS_C, var)));
2900  }
2901  }
2902  }
2903  else
2904  {
2905  current_fu = get_fu(ARRAY_1D_STD_BRAM_NN + latency_postfix);
2906  }
2907  n_ports = channels_number;
2908  }
2909  else
2910  {
2911  THROW_ERROR("type of channel based organization not yet supported");
2912  }
2913 
2914  unsigned int current_size = allocation_information->get_number_fu_types();
2916  " - allocating unit " + current_fu->get_name() + " for variable " +
2917  FB->CGetBehavioralHelper()->PrintVariable(l.first) + " in position " + STR(current_size));
2918  allocation_information->list_of_FU.push_back(current_fu);
2919  if(HLSMgr->Rmem->is_sds_var(var) && HLSMgr->Rmem->is_read_only_variable(var) &&
2920  (is_async_var ||
2921  (parameters->isOption(OPT_rom_duplication) && parameters->getOption<bool>(OPT_rom_duplication))))
2922  {
2924  set_number_channels(current_size, n_ports);
2925  }
2926  else
2927  {
2928  allocation_information->tech_constraints.push_back(n_ports);
2929  set_number_channels(current_size, n_ports);
2930  }
2931  allocation_information->id_to_fu_names[current_size] =
2932  std::make_pair(current_fu->get_name(), TechM->get_library(current_fu->get_name()));
2934  "Something of wrong happened");
2935  allocation_information->vars_to_memory_units[var] = current_size;
2936  allocation_information->memory_units[current_size] = var;
2937  allocation_information->memory_units_sizes[current_size] = tree_helper::Size(TM->CGetTreeReindex(var)) / 8;
2938  allocation_information->precision_map[current_size] = 0;
2940  auto* fu_br = GetPointer<functional_unit>(current_fu);
2941  technology_nodeRef op_store_node = fu_br->get_operation("STORE");
2942  auto* op_store = GetPointer<operation>(op_store_node);
2943  double store_delay = allocation_information->time_m_execution_time(op_store) -
2944  allocation_information->get_correction_time(current_size, "STORE", 0) +
2946  if(store_delay > clock_period)
2947  {
2948  THROW_ERROR("clock constraint too tight: BRAMs for this device cannot run so fast... (" +
2949  current_fu->get_name() + ":" + STR(store_delay) + ">" + STR(clock_period) + ")");
2950  }
2951  }
2952 
2954  if(HLSMgr->Rmem->has_proxied_internal_variables(funId))
2955  {
2956  for(const auto& proxied_var_id : HLSMgr->Rmem->get_proxied_internal_variables(funId))
2957  {
2958  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, " - analyzing proxied variable " + STR(proxied_var_id));
2959  technology_nodeRef current_fu;
2960  unsigned int n_ports = 1;
2961  if(channels_type == MemoryAllocation_ChannelsType::MEM_ACC_11)
2962  {
2963  if(HLSMgr->Rmem->is_sds_var(proxied_var_id))
2964  {
2965  if((HLSMgr->Rmem->has_all_pointers_resolved() && HLSMgr->Rmem->does_need_addr(proxied_var_id)) ||
2966  (!HLSMgr->Rmem->has_all_pointers_resolved() && !HLSMgr->Rmem->is_private_memory(proxied_var_id)))
2967  {
2968  current_fu = get_fu(PROXY_CTRL + latency_postfix);
2969  }
2970  else
2971  {
2972  if(parameters->getOption<bool>(OPT_use_asynchronous_memories) &&
2974  TM, proxied_var_id, parameters->getOption<unsigned int>(OPT_distram_threshold),
2975  HLSMgr->Rmem->is_read_only_variable(proxied_var_id), 1))
2976  {
2978  bool is_asynchronous_ram_not_timing_compliant =
2979  is_ram_not_timing_compliant(HLS_C, proxied_var_id, a_fu);
2980  if(is_asynchronous_ram_not_timing_compliant)
2981  {
2982  current_fu =
2984  ARRAY_1D_STD_BRAM_SDS, latency_postfix, HLS_C, proxied_var_id)));
2985  }
2986  else
2987  {
2988  current_fu = get_fu(DPROXY_CTRL);
2989  }
2990  }
2991  else
2992  {
2993  current_fu =
2995  ARRAY_1D_STD_BRAM_SDS, latency_postfix, HLS_C, proxied_var_id)));
2996  }
2997  }
2998  }
2999  else
3000  {
3001  current_fu = get_fu(PROXY_CTRL + latency_postfix);
3002  }
3003  }
3004  else if(channels_type == MemoryAllocation_ChannelsType::MEM_ACC_N1 ||
3006  {
3007  if(HLSMgr->Rmem->is_sds_var(proxied_var_id))
3008  {
3009  if((HLSMgr->Rmem->has_all_pointers_resolved() && HLSMgr->Rmem->does_need_addr(proxied_var_id)) ||
3010  (!HLSMgr->Rmem->has_all_pointers_resolved() && !HLSMgr->Rmem->is_private_memory(proxied_var_id)))
3011  {
3012  current_fu = get_fu(PROXY_CTRLN + latency_postfix);
3013  }
3014  else
3015  {
3016  bool is_nn = channels_type == MemoryAllocation_ChannelsType::MEM_ACC_NN;
3017  if(parameters->getOption<bool>(OPT_use_asynchronous_memories) &&
3019  TM, proxied_var_id, parameters->getOption<unsigned int>(OPT_distram_threshold),
3020  HLSMgr->Rmem->is_read_only_variable(proxied_var_id), channels_number))
3021  {
3022  technology_nodeRef a_fu =
3024  bool is_asynchronous_ram_not_timing_compliant =
3025  is_ram_not_timing_compliant(HLS_C, proxied_var_id, a_fu);
3026  if(is_asynchronous_ram_not_timing_compliant)
3027  {
3028  current_fu =
3031  latency_postfix, HLS_C, proxied_var_id)));
3032  }
3033  else
3034  {
3035  current_fu = get_fu(DPROXY_CTRLN);
3036  }
3037  }
3038  else
3039  {
3040  current_fu =
3043  latency_postfix, HLS_C, proxied_var_id)));
3044  }
3045  }
3046  }
3047  else
3048  {
3049  current_fu = get_fu(PROXY_CTRLN + latency_postfix);
3050  }
3051  n_ports = channels_number;
3052  }
3053  else
3054  {
3055  THROW_ERROR("type of channel based organization not yet supported");
3056  }
3057  unsigned int current_size = allocation_information->get_number_fu_types();
3059  " - allocating unit " + current_fu->get_name() + " for variable " +
3060  FB->CGetBehavioralHelper()->PrintVariable(proxied_var_id) + " in position " +
3061  STR(current_size));
3062  allocation_information->list_of_FU.push_back(current_fu);
3063  allocation_information->tech_constraints.push_back(n_ports);
3064  set_number_channels(current_size, n_ports);
3065  allocation_information->id_to_fu_names[current_size] =
3066  std::make_pair(current_fu->get_name(), TechM->get_library(current_fu->get_name()));
3068  "Something of wrong happened");
3069  allocation_information->vars_to_memory_units[proxied_var_id] = current_size;
3070  allocation_information->proxy_memory_units[current_size] = proxied_var_id;
3071  allocation_information->precision_map[current_size] = 0;
3072  }
3073  }
3074 
3076  if(HLSMgr->Rfuns->has_shared_functions(funId))
3077  {
3078  for(const auto& shared_fu_name : HLSMgr->Rfuns->get_shared_functions(funId))
3079  {
3080  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, " - adding proxy function wrapper " + shared_fu_name);
3081  const auto library_name = TechM->get_library(shared_fu_name);
3082  if(library_name.size())
3083  {
3084  const auto libraryManager = TechM->get_library_manager(library_name);
3085  auto techNode_obj = libraryManager->get_fu(shared_fu_name);
3086  THROW_ASSERT(techNode_obj, "function not yet built: " + shared_fu_name);
3087  const auto wrapped_fu_name = WRAPPED_PROXY_PREFIX + shared_fu_name;
3088  auto wrapper_tn = TechM->get_fu(wrapped_fu_name, PROXY_LIBRARY);
3089  if(!wrapper_tn)
3090  {
3091  structural_managerRef structManager_obj = GetPointer<functional_unit>(techNode_obj)->CM;
3092  if(structManager_obj && (GetPointer<module>(structManager_obj->get_circ())
3093  ->get_NP_functionality()
3094  ->exist_NP_functionality(NP_functionality::VERILOG_GENERATOR) or
3095  GetPointer<module>(structManager_obj->get_circ())
3096  ->get_NP_functionality()
3097  ->exist_NP_functionality(NP_functionality::VHDL_GENERATOR)))
3098  {
3100  std::string new_shared_fu_name = shared_fu_name + "_modgen";
3101  const auto fnode = [&]() -> tree_nodeRef {
3102  const auto fu = GetPointer<const functional_unit>(techNode_obj);
3103  for(const auto& op : fu->get_operations())
3104  {
3105  const auto op_fnode = HLSMgr->get_tree_manager()->GetFunction(op->get_name());
3106  if(op_fnode)
3107  {
3108  return op_fnode;
3109  }
3110  }
3111  return nullptr;
3112  }();
3113  THROW_ASSERT(fnode, "Expected valid function node");
3114  modGen->create_generic_module(shared_fu_name, nullptr,
3115  HLSMgr->CGetFunctionBehavior(GET_INDEX_CONST_NODE(fnode)),
3116  libraryManager->get_library_name(), new_shared_fu_name);
3117  techNode_obj = libraryManager->get_fu(new_shared_fu_name);
3118  THROW_ASSERT(techNode_obj, "function not yet built: " + new_shared_fu_name);
3119  }
3120  add_proxy_function_wrapper(library_name, techNode_obj, shared_fu_name);
3121  wrapper_tn = TechM->get_fu(wrapped_fu_name, PROXY_LIBRARY);
3122  }
3123  THROW_ASSERT(wrapper_tn, "Module not added");
3124  HLS_C->set_number_fu(shared_fu_name, PROXY_LIBRARY, 1);
3126  unsigned int current_size = allocation_information->get_number_fu_types();
3128  " - allocating unit " + wrapper_tn->get_name() + " in position " + STR(current_size));
3129  allocation_information->list_of_FU.push_back(wrapper_tn);
3131  allocation_information->id_to_fu_names[current_size] =
3132  std::make_pair(wrapper_tn->get_name(), PROXY_LIBRARY);
3134  "Something of wrong happened");
3135  allocation_information->precision_map[current_size] = 0;
3136  fu_list[wrapper_tn][0][HLS_manager::io_binding_type(0, 0)] = current_size;
3137  allocation_information->proxy_wrapped_units[current_size] = shared_fu_name;
3138  }
3139  }
3140  }
3141 
3143  if(HLSMgr->Rfuns->has_proxied_shared_functions(funId))
3144  {
3145  for(const auto& original_proxied_fu_name : HLSMgr->Rfuns->get_proxied_shared_functions(funId))
3146  {
3148  " - adding proxy function module " + original_proxied_fu_name);
3149  const std::string library_name = TechM->get_library(original_proxied_fu_name);
3150  if(library_name.size())
3151  {
3152  const library_managerRef libraryManager = TechM->get_library_manager(library_name);
3153  technology_nodeRef techNode_obj = libraryManager->get_fu(original_proxied_fu_name);
3154  THROW_ASSERT(techNode_obj, "function not yet built: " + original_proxied_fu_name);
3155  technology_nodeRef proxy_tn = TechM->get_fu(PROXY_PREFIX + original_proxied_fu_name, PROXY_LIBRARY);
3156  if(!proxy_tn)
3157  {
3158  add_proxy_function_module(HLS_C, techNode_obj, original_proxied_fu_name);
3159  }
3160  }
3161  }
3162  }
3163 }
3164 
3166 {
3167  const std::string file_name =
3168  parameters->getOption<std::string>(OPT_output_temporary_directory) + "before_" + GetName() + ".tm";
3169  std::ofstream raw_file(file_name);
3170  TechM->print(raw_file);
3171  raw_file.close();
3172 }
#define READ_COND_STD
static void propagate_memory_parameters(const structural_objectRef src, const structural_managerRef tgt)
Propagates the memory parameters from the source (innermost) module to the target (outermost) one...
Definition: memory.cpp:654
void print_allocated_resources() const
Prints the actual allocation.
#define IUDATA_CONVERTER_STD
void Initialize() override
Initialize the step (i.e., like a constructor, but executed just before exec.
void add_connection(structural_objectRef src, structural_objectRef dest)
Create a connection between a source structural object and a destination structural object...
#define MEMORY_CTRL_TYPE_DPROXY
#define EXIT
Definition: global.h:46
std::map< std::string, std::vector< unsigned int > > supported_types
supported types and precision of the operation, in form (name, list_of_prec).
bool check_generated_bambu_flopoco(bool skip_softfloat_resources, structural_managerRef structManager_obj, std::string &bambu_provided_resource, bool skip_flopoco_resources, technology_nodeRef current_fu)
#define IICONVERTER_EXPR_STD
#define DEBUG_LEVEL_VERY_PEDANTIC
extremely verbose debugging print is performed.
const HLS_managerRef HLSMgr
information about all the HLS synthesis
Definition: hls_step.hpp:205
static bool IsComplexType(const tree_nodeConstRef &type)
Return if treenode is a complex.
#define OR_GATE_STD
#define INDENT_DBG_MEX(dbgLevel, curDbgLevel, mex)
We are producing a debug version of the program, so the message is printed;.
void * top(node_stack *head)
Definition: tree.c:75
Collect information about resource area.
double get_correction_time(unsigned int fu, const std::string &operation_name, unsigned int n_ins) const
return a time to be subtracted to the execution time/stage period
#define GET_TYPE(data, vertex_index)
Helper macro returning the type associated with a node.
static std::string convert_to_identifier(const language_writer *writer, const std::string &id)
Converts a generic string to a language compliant identifier.
refcount< structural_type_descriptor > structural_type_descriptorRef
RefCount type definition of the structural_type_descriptor class structure.
File containing functions and utilities to support the printing of debug messagges.
#define EXTRACT_BIT_EXPR_UNSIGNED_STD
#define DEBUG_LEVEL_PEDANTIC
very verbose debugging print is performed.
This structure collect the information of input and output precision of nodes and the node kind...
#define CHANNELS_TYPE_MEM_ACC_NN
#define START_PORT_NAME
technology_nodeRef get_fu(const std::string &fu_name, const std::string &Library) const
Return the reference to a component given its name.
Structure representing the most relevant information about the type of a structural object...
#define GIMPLE_RETURN
constant string identifying the operation performed by a gimple_return.
Definition: op_graph.hpp:285
const std::string & get_id() const
Return the identifier associated with the structural_object.
refcount< AllocationInformation > AllocationInformationRef
#define GET_CLASS(obj)
Macro returning the actual type of an object.
static const unsigned int PARAMETRIC_PORT
std::string pipe_parameters
comma separated string with the parameter for the different implementation of the pipeline...
#define LUT_EXPR_STD
const structural_objectRef get_circ() const
Get a reference to circ field.
const int output_level
The output level.
const std::vector< std::string > SplitString(const std::string &input, const std::string &separators)
Function which splits a string into tokens.
#define ARRAY_1D_STD_BRAM_NN_SDS_BUS
technology_nodeRef get_fu(const std::string &name) const
only external memory access Datapath see only 1 memory port, while the bus manage parallel accesses ...
void reset()
Definition: adpcm.c:540
#define GIMPLE_PRAGMA_STD
#define UUDATA_CONVERTER_STD
#define CHANNELS_TYPE_MEM_ACC_CS
void print(std::ostream &os) const
Function that prints the class technology_manager.
CustomUnorderedMap< unsigned int, std::pair< std::string, std::string > > id_to_fu_names
map between the functional unit identifier and the pair (library, fu) of names for the unit ...
unsigned int get_out_port_size() const
Return the number of output ports.
#define ASSIGN_VEC_SIGNED_STD
RelationshipType
The relationship type.
#define EXTRACT_BIT_EXPR_SIGNED_STD
Source must be executed to satisfy target.
#define INDENT_OUT_MEX(outLevel, curOutLevel, mex)
std::string get_NP_functionality(NP_functionaly_type type) const
Return the description provided the type.
static void connectClockAndReset(structural_managerRef &SM, structural_objectRef &interfaceObj, structural_objectRef &component)
Definition: allocation.cpp:318
const unsigned int funId
identifier of the function to be processed (0 means that it is a global step)
static tree_nodeConstRef CGetElements(const tree_nodeConstRef &type)
Given an array or a vector return the element type.
#define GET_NAME(data, vertex_index)
Helper macro returning the name associated with a node.
const std::vector< std::string > & get_library_list() const
Return the list of the libraries.
#define MEMORY_PARAMETER
technology_nodeRef get_fu(const std::string &fu_name)
Returns the technology_node associated with the given operation.
technology_nodeRef extract_bambu_provided(const std::string &library_name, operation *curr_op, const std::string &bambu_provided_resource_)
Definition: allocation.cpp:227
#define SPROXY_CTRL
void set_number_channels(unsigned int fu_name, unsigned int n_ports)
set the number of ports associated with the functional unit
#define IIVECTOR_CONVERTER_STD
#define ARRAY_1D_STD_BRAM_NN_SDS
This class manages the circuit structures.
const HLS_deviceRef HLS_D
reference to the information representing the target for the synthesis
Definition: hls.hpp:107
#define READ_COND
constant string identifying the operation performed by a READ_COND.
Definition: op_graph.hpp:255
exceptions managed by PandA
bool check_type_and_precision(operation *curr_op, node_kind_prec_infoRef node_info)
double DSP_allocation_coefficient
coefficient used to modify pipelining DSPs allocation
double get_DSPs(const unsigned int fu_name) const
return an estimation of the number of DSPs used by the unit
AllocationInformationRef allocation_information
Store the technology information.
Definition: hls.hpp:115
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.
static std::string fix_identifier(std::string port_name, language_writerRef writer)
Definition: allocation.cpp:312
Collect information about resource performance.
const structural_objectRef get_in_port(unsigned int n) const
Return the ith input port.
void add_proxy_function_module(const HLS_constraintsRef HLS_C, technology_nodeRef techNode_obj, const std::string &orig_fun_name)
Add a proxy function to the WORK library.
Definition: allocation.cpp:878
#define ARRAY_1D_STD_BRAM_SDS
static bool is_other_port(const structural_objectRef &port)
Definition: allocation.cpp:95
time_infoRef time_m
class representing the timing information associated with this operation
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...
void BuildProxyFunction(functional_unit *current_fu)
Build the proxy function.
Definition: allocation.cpp:857
OpVertexSet operations
Set representing the subset of operations in the specification to be implemented. ...
Definition: hls.hpp:102
void insert(node_tree **tree, int val)
Definition: tree.c:121
static std::string encode_op_type(const std::string &op_name, const std::string &fu_supported_types)
Definition: allocation.cpp:114
CustomUnorderedMap< unsigned int, CustomOrderedSet< unsigned int > > fus_to_node_id
reverse map putting into relation functional units with the operations that can be mapped on ...
static bool is_a_skip_operation(const std::string &op_name)
Definition: allocation.cpp:102
Class specification of the manager of the technology library data structures.
This class contains the base representation for a generic frontend flow step which works on a single ...
all objects that need to be stored in memory are allocated on an external memory
#define OUTPUT_LEVEL_VERY_VERY_PEDANTIC
verbose debugging print is performed.
static std::string extract_bambu_provided_name(unsigned long long prec_in, unsigned long long prec_out, const HLS_managerConstRef hls_manager, technology_nodeRef &current_fu)
#define DPROXY_CTRLN
This class specifies the characteristic of a particular functional unit.
std::map< unsigned int, std::string > sync_ram_var_latency
put into relation variable and their latency when they are mapped on a private synchronous ram ...
Base class description of data information associated with each node of a graph.
#define ASSIGN_SIGNED_STD
#define INTERFACE_LIBRARY
interface library
#define OUTPUT_LEVEL_MINIMUM
minimum debugging print is performed.
redefinition of map to manage ordered/unordered structures
#define ADDR_EXPR_STD
static bool IsEnumType(const tree_nodeConstRef &type)
Return if treenode index is an enumeral type.
std::tuple< unsigned int, unsigned int > io_binding_type
tuple set used to represent the required values or the constant default value associated with the inp...
void ComputeRelationships(DesignFlowStepSet &design_flow_step_set, const DesignFlowStep::RelationshipType relationship_type) override
Compute the relationships of a step with other steps.
#define VIEW_CONVERT_STD_UINT
Include a set of utilities used to manage CPU time measures.
#define TYPE_LOAD
Constant string identifying a memory load operation.
Definition: op_graph.hpp:172
#define GIMPLE_LABEL_STD
#define EXTRACT_BIT_EXPR
constant string identifying the operation performed by an extract_bit_expr.
Definition: op_graph.hpp:245
#define MEMORY_CTRL_TYPE_PROXY
A set of operation vertices.
Definition: op_graph.hpp:654
technology_nodeRef add_operation(const std::string &Library, const std::string &fu_name, const std::string &operation_name)
Add an operation to the specified functional unit.
std::map< std::string, std::string > precomputed_pipeline_unit
store the precomputed pipeline unit: given a functional unit it return the pipeline id compliant ...
Definition: allocation.hpp:110
DesignFlowStep_Status InternalExec() override
Execute the step.
refcount< technology_node > technology_nodeRef
refcount definition of the class
unsigned int get_cycles() const
Definition: time_info.cpp:95
#define GIMPLE_PHI_STD
#define THROW_WARNING(str_expr)
helper function used to throw a warning in a standard way: though it uses PRINT_DBG_MEX, the debug level used is such that the message is always printed
Definition: exceptions.hpp:300
#define STR(s)
Macro which performs a lexical_cast to a string.
void BuildProxyFunctionVHDL(functional_unit *current_fu)
Build the proxy function in VHDL.
Definition: allocation.cpp:770
Auxiliary methods for manipulating string.
#define MEMORY_CTRL_TYPE_SPROXY
CustomUnorderedMap< std::pair< unsigned int, std::string >, CustomOrderedSet< unsigned int > > node_id_to_fus
for each operation (node-id, operation) return the set of functional unit that can be used ...
int key[32]
Definition: aes.h:67
#define max
Definition: backprop.h:17
HDLWriter_Language
s_type type
The type of the port or the signal.
CustomUnorderedSet< unsigned int > simple_pointer_plus_expr
in case of pointer plus expr between constants: no wire delay
~allocation() override
Destructor.
std::vector< unsigned int > DSP_y_db
store DSP y sizes
void BuildProxyFunctionVerilog(functional_unit *current_fu)
Build the proxy function in Verilog.
Definition: allocation.cpp:688
unsigned int get_cycles(const unsigned int fu_name, const unsigned int v) const
Return the number of cycles for given vertex and a given functional unit.
std::map< unsigned int, std::string > proxy_wrapped_units
put into relation proxy wrapped units with shared functions
#define CLOCK_PORT_NAME
standard name for ports
#define ADDR_EXPR
constant string identifying the addressing operation.
Definition: op_graph.hpp:330
static bool IsUnsignedIntegerType(const tree_nodeConstRef &type)
Return true if the treenode is of unsigned integer type.
void ComputeRelationships(DesignFlowStepSet &relationship, const DesignFlowStep::RelationshipType relationship_type) override
Compute the relationships of a step with other steps.
Definition: allocation.cpp:205
static bool IsSignedIntegerType(const tree_nodeConstRef &type)
Return true if the treenode is of integer type.
#define CHANNELS_TYPE_MEM_ACC_P1N
Pure virtual base class for all the design flow step factory.
#define START_TIME(time_var)
Macro used to store the start time into time_var.
Definition: cpu_time.hpp:133
#define THROW_UNREACHABLE(str_expr)
helper function used to specify that some points should never be reached
Definition: exceptions.hpp:292
bool starts_with(const std::string &str, const std::string &pattern)
#define ARRAY_1D_STD_BRAM_N1_SDS_BUS
static void add_NP_functionality(structural_objectRef cir, NP_functionality::NP_functionaly_type dt, std::string functionality_description)
Add a not-parsed functionality.
Factory for hls flow step.
allocation(const ParameterConstRef _parameters, const HLS_managerRef HLSMgr, unsigned int funId, const DesignFlowManagerConstRef design_flow_manager, const HLSFlowStep_Type=HLSFlowStep_Type::ALLOCATION)
Constructor.
Definition: allocation.cpp:146
#define GIMPLE_PHI
constant string identifying the operation performed by a gimple_phi.
Definition: op_graph.hpp:295
double get_resource_value(value_t val) const
Definition: area_info.cpp:77
#define ASSERT_EXPR_UNSIGNED_STD
CustomUnorderedMap< unsigned int, std::pair< std::string, unsigned int > > binding
Puts into relation operation with type and functional units.
void add(const technology_nodeRef curr, const std::string &Library)
Add the given functional_unit to the specified library.
static unsigned long long Size(const tree_nodeConstRef &tn)
Return the size of a tree object.
#define EXIT_ID
constant used to represent tree node index of exit operation
Definition: op_graph.hpp:81
double estimate_muxNto1_delay(unsigned long long fu_prec, unsigned int mux_ins) const
Return the delay due to mux with n-inputs.
std::string get_latency_string(const std::string &lat) const
void Clear() override
Clear all the data structure.
static bool IsBooleanType(const tree_nodeConstRef &type)
Return true if the treenode is of bool type.
void Initialize() override
Initialize all the data structure.
This class specifies the characteristic of a particular operation working on a given functional unit...
absl::flat_hash_map< T, U, Hash, Eq, Alloc > CustomUnorderedMap
Definition: custom_map.hpp:148
void Initialize() override
Initialize the step (i.e., like a constructor, but executed just before exec.
Definition: allocation.cpp:155
#define ENTRY
Superclass include.
void set_top_info(const std::string &id, const technology_managerRef &LM, const std::string &Library="")
Data structure used to store the schedule of the operations.
#define ASSIGN_REAL_STD
std::string get_synch_ram_latency(const std::string &ram_template, const std::string &latency_postfix, const HLS_constraintsRef HLS_C, unsigned int var)
std::map< technology_nodeRef, std::map< unsigned long long, std::map< HLS_manager::io_binding_type, unsigned int > > > fu_list
Definition: allocation.hpp:113
Control flow graph.
std::vector< technology_nodeRef > list_of_FU
Stores the list of the functional units.
all global variables, static variables and strings are allocated on BRAMs
HLSFlowStep_Type
Definition: hls_step.hpp:95
#define ARRAY_1D_STD_BRAM_N1_SDS
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. ...
#define ARRAY_1D_STD_DISTRAM_SDS
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.
const structural_objectRef get_out_port(unsigned int n) const
Return the ith output port.
unsigned int bb_version
The version of bb intermediate representation on which this step was applied.
const unsigned int index
Represent the index read from the raw file and the index-1 of the vector of tree_node associated to t...
Definition: tree_node.hpp:146
Classes to describe design flow graph.
CustomOrderedSet< unsigned int > is_vertex_bounded_rel
Store the set of functional units (identifiers) uniquely bounded.
redefinition of set to manage ordered/unordered structures
#define GIMPLE_NOP_STD
#define ARRAY_1D_STD_BRAM_NN
#define STOP_TIME(time_var)
Macro used to store the elapsed time into time_var.
Definition: cpu_time.hpp:136
#define UUCONVERTER_EXPR_STD
#define ARRAY_1D_STD_BRAM
Datastructure to describe functions allocation in high-level synthesis.
#define TYPE_STORE
Constant string identifying a memory store operation.
Definition: op_graph.hpp:177
const operation_vec & get_operations() const
Return the operations that the functional unit can handle.
boost::graph_traits< graph >::vertex_descriptor vertex
vertex definition.
Definition: graph.hpp:1303
#define PROXY_PREFIX
const Wrefcount< const DesignFlowManager > design_flow_manager
The design flow manager.
#define VIEW_CONVERT_STD_INT
static bool IsVectorType(const tree_nodeConstRef &type)
Return true if the treenode is a vector.
unsigned offset[NUM_VERTICES+1]
Definition: graph.h:3
static std::string encode_op_type_prec(const std::string &op_name, const std::string &fu_supported_types, node_kind_prec_infoRef node_info)
Definition: allocation.cpp:119
#define IIDATA_CONVERTER_STD
static std::string GetFUName(const std::string &fname, const HLS_managerRef HLSMgr)
Return FU used to implement given function.
Definition: functions.cpp:118
const std::string & get_name() const override
Returns the name of the operation.
std::map< unsigned int, unsigned long long > precision_map
map functional units with their precision
#define GET_CONST_NODE(t)
Definition: tree_node.hpp:347
bool check_proxies(const library_managerRef library, const std::string &fu_name_)
#define UICONVERTER_EXPR_STD
AllocationInformationRef allocation_information
The allocation solution.
Definition: allocation.hpp:106
virtual enum so_kind get_kind() const =0
Virtual function used to find the real type of a structural_object instance.
#define ENTRY_STD
double DSPs_margin_stage
coefficient used to modify DSPs stage period
CustomUnorderedSet< unsigned int > single_bool_test_cond_expr_units
store all cond_expr units having a Boolean condition
Classes specification of the tree_node data structures.
#define FFDATA_CONVERTER_STD
static std::string NormalizeTypename(const std::string &id)
Return normalized name of types and variables.
unsigned int n_complex_operations
number of complex operations
#define GIMPLE_GOTO
constant string identifying the operation performed by a GIMPLE_GOTO.
Definition: op_graph.hpp:275
#define GIMPLE_LABEL
constant string identifying the operation performed by a GIMPLE_LABEL.
Definition: op_graph.hpp:270
const ParameterConstRef parameters
Set of input parameters.
#define UIDATA_CONVERTER_STD
DesignFlowStep_Status
The status of a step.
This package is used by all HLS packages to manage resource constraints and characteristics.
#define SWITCH_COND_STD
This file collects some utility functions and macros.
bool is_type_supported(const std::string &type_name) const
Checks if the specified type name is supported.
Base class to allocate memories in high-level synthesis.
void GetNodeTypePrec(const vertex node, const OpGraphConstRef g, node_kind_prec_infoRef info, HLS_manager::io_binding_type &constant_id, bool is_constrained) const
Extract the node kind and precision, if available.
#define THROW_ERROR(str_expr)
helper function used to throw an error in a standard way
Definition: exceptions.hpp:263
#define VIEW_CONVERT_EXPR
constant string identifying view convert expressions
Definition: op_graph.hpp:355
double time_m_execution_time(operation *op) const
return the execution time of the operation corrected by time_multiplier factor
#define GIMPLE_RETURN_STD
artificial functional units
Wrapper of design_flow.
#define NOP_STD
refcount< structural_manager > structural_managerRef
RefCount type definition of the structural_manager class structure.
Data structure definition for HLS constraints.
#define WRAPPED_PROXY_PREFIX
#define ARRAY_1D_STD_DISTRAM_NN_SDS
bool is_operation_bounded(const OpGraphConstRef g, const vertex &op, unsigned int fu_type) const
Checks if the given operation has a bounded execution time or not.
This file collects some utility functions.
#define SWITCH_COND
constant string identifying the operation performed by a SWITCH_COND.
Definition: op_graph.hpp:265
bool can_be_asynchronous_ram(tree_managerConstRef TM, unsigned int var, unsigned int threshold, bool is_read_only_variable, unsigned int channel_number)
#define MEMORY_CTRL_TYPE_PROXYN
#define SPROXY_CTRLN
std::string print_cpu_time(long int t)
massage a long which represents a time interval in milliseconds, into a string suitable for output ...
Definition: cpu_time.hpp:110
void BuildProxyWrapper(functional_unit *current_fu, const std::string &orig_fun_name, const std::string &orig_library_name)
Build the proxy wrapper.
Definition: allocation.cpp:337
bool commutative
property of commutativity
unsigned int get_in_port_size() const
Return the number of input ports.
std::vector< unsigned int > tech_constraints
For each functional unit (position in the vector), tech_constraints stores the maximum number of reso...
void add_proxy_function_wrapper(const std::string &library_name, technology_nodeRef techNode_obj, const std::string &orig_fun_name)
Add a proxy wrapper to the WORK library.
Definition: allocation.cpp:530
refcount< T > lock() const
Definition: refcount.hpp:212
This class describe a functional unit template.
for each memory at maximum n parallel direct accesses and one indirect access
#define LUT_EXPR
constant string identifying the operation performed by an extract_bit_expr.
Definition: op_graph.hpp:250
std::map< unsigned int, unsigned int > proxy_memory_units
put into relation proxy memory units with variables
void add(int accelnum, int startidx, int endidx)
Definition: add.c:11
#define TYPE_MEMCPY
A vertex is of type TYPE_MEMCPY when it is associated with a assignment between struct/union.
Definition: op_graph.hpp:182
technology_managerRef TechM
The technology manager.
Definition: allocation.hpp:119
static tree_nodeConstRef GetBaseVariable(const tree_nodeConstRef &mem)
Retrun the base variable of a memory access.
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.
bool is_fu(const std::string &name) const
#define OUTPUT_LEVEL_PEDANTIC
verbose debugging print is performed.
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.
Definition: allocation.cpp:174
#define ASSIGN_VEC_UNSIGNED_STD
#define ASSERT_EXPR_REAL_STD
#define ASSIGN_UNSIGNED_STD
technology_nodeRef get_operation(const std::string &op_name) const
This method returns the operationRef from its name if the functional unit contains an operation of ty...
Class specification of the tree_reindex support class.
#define ENTRY_ID
constant used to represent tree node index of entry operation
Definition: op_graph.hpp:79
#define ASSIGN
constant string identifying the operation performed by an assignment.
Definition: op_graph.hpp:224
void set_id(const std::string &s)
Set the identifier associated with the structural_object.
#define PROXY_CTRL
unsigned int get_number_channels(unsigned int fu_name) const
return the number of channels available for the functional unit
bool check_for_memory_compliancy(bool Has_extern_allocated_data, technology_nodeRef current_fu, const std::string &memory_ctrl_type, const std::string &channels_type)
std::map< unsigned int, std::string > proxy_function_units
put into relation proxy function units with shared functions
virtual const std::string & get_name() const =0
Return the name of the technology node.
#define WORK_LIBRARY
working library.
#define MEMORY_CTRL_TYPE_DPROXYN
#define INFINITE_UINT
UNSIGNED INT representing infinite.
Definition: utility.hpp:70
#define GIMPLE_PRAGMA
constant string identifying the operation performed by a GIMPLE_PRAGMA.
Definition: op_graph.hpp:305
#define ARRAY_1D_STD_BRAM_SDS_BUS
void PrintInitialIR() const override
Dump the initial intermediate representation.
technology_managerRef get_technology_manager() const
Returns the technology manager.
virtual void copy(structural_objectRef dest) const
Perform a copy of the structural object.
std::string GetName() const final
Return the name of this design step.
#define ASSERT_EXPR
constant string identifying the operation performed by an assignment.
Definition: op_graph.hpp:240
hlsRef HLS
HLS data structure of the function to be analyzed.
#define NOP
constant string identifying a no operation.
Definition: op_graph.hpp:280
for each memory at maximum n parallel direct accesses and n parallel indirect accesses ...
This class contains the methods to create a frontend flow step.
Data structures used in operations graph.
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.
for each memory at maximum one direct access and one indirect access
std::map< unsigned int, unsigned int > vars_to_memory_units
map between variables and associated memory_units
#define MEMORY_CTRL_TYPE_SPROXYN
virtual void IntegrateTechnologyLibraries()
Integrate technology libraries with special functional units.
#define DPROXY_CTRL
#define EXIT_STD
#define GIMPLE_GOTO_STD
this class is used to manage the command-line or XML options.
#define IUCONVERTER_EXPR_STD
double time_m_stage_period(operation *op) const
return the stage time of the operation corrected by time_multiplier factor
#define MUX_GATE_STD
#define MULTI_READ_COND_STD
std::string get_compliant_pipelined_unit(double clock, const std::string &pipe_parameter, const technology_nodeRef current_fu, const std::string &curr_op, const std::string &library_name, const std::string &template_suffix, unsigned long long module_prec)
In case the current functional unit has pipelined operations then it return an id identifying the mos...
bool check_templated_units(double clock_period, node_kind_prec_infoRef node_info, const library_managerRef library, technology_nodeRef current_fu, operation *curr_op)
#define ASSIGN_VECTOR_BOOL_STD
unsigned int functionId
this is the identifier of the function to be implemented
Definition: hls.hpp:87
Not parsed functionality manager.
std::map< unsigned int, unsigned long long > memory_units_sizes
size of each memory unit in bytes
#define PROXY_CTRLN
#define RESET_PORT_NAME
double DSPs_margin
coefficient used to modify DSPs execution time
#define ARRAY_1D_STD_DISTRAM_N1_SDS
Wrapper to call graph.
bool is_ram_not_timing_compliant(const HLS_constraintsRef HLS_C, unsigned int var, technology_nodeRef current_fu)
Class implementation of the structural_manager.
bool is_memory_unit(const unsigned int fu_name) const
Returns true if the fu_name is a memory unit.
#define GIMPLE_ASM
constant string identifying the operation performed by a gimple_asm.
Definition: op_graph.hpp:300
bool is_indirect_access_memory_unit(unsigned int fu) const
return true in case fu type is a resource unit performing an indirect access to memory ...
Generic device description.
std::string get_library_name() const
const HLS_constraintsRef HLS_C
store the HLS constraints
Definition: hls.hpp:110
Class specification of the manager for each library.
int debug_level
The debug level.
#define BUVECTOR_CONVERTER_STD
This package is used by all HLS packages to manage resource constraints and characteristics.
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
std::vector< technology_nodeRef > operation_vec
Type definition of a vector of functional_unit.
#define UIVECTOR_CONVERTER_STD
#define GET_INDEX_CONST_NODE(t)
Definition: tree_node.hpp:363
HLS_deviceRef HLS_D
The HLS target.
Definition: allocation.hpp:116
#define ARRAY_1D_STD_BRAM_N1
#define NOP_EXPR
constant string identifying some conversion expressions
Definition: op_graph.hpp:335
#define DEBUG_LEVEL_VERBOSE
verbose debugging print is performed.
static bool IsPointerType(const tree_nodeConstRef &type)
Return true if treenode index is a pointer.
#define BIVECTOR_CONVERTER_STD
#define VIEW_CONVERT_STD_REAL
technology_nodeRef FU
Functional Unit.
Data structure definition for high-level synthesis flow.
This class describes a generic module.
Superclass include.
static structural_objectRef add_port_vector(std::string id, port_o::port_direction pdir, unsigned int n_ports, structural_objectRef owner, structural_type_descriptorRef type_descr, unsigned int treenode=0)
Create a new port_vector.
This class contains the base representation for a generic frontend flow step which works on the whole...
#define GIMPLE_NOP
constant string identifying the operation performed by a gimple_return.
Definition: op_graph.hpp:290
#define NULL_VERTEX
null vertex definition
Definition: graph.hpp:1305
#define ENCODE_FU_LIB(fu_name, library)
macro used to convert the functional unit name and the library in an unique string.
static time_infoRef factory(const ParameterConstRef Param)
Definition: time_info.cpp:110
Datastructure to represent memory information in high-level synthesis.
#define PROXY_LIBRARY
proxy library
#define MULTI_READ_COND
constant string identifying the operation performed by a MULTI_READ_COND.
Definition: op_graph.hpp:260
std::map< unsigned int, unsigned int > nports_map
define the number of ports associated with the functional unit
library_managerRef get_library_manager(const std::string &Name) const
Return the library data structure corresponding to the given library id.
Class specification of the manager of the tree structures extracted from the raw file.
#define ASSERT_EXPR_SIGNED_STD
HLS specialization of generic_device.
std::string get_library(const std::string &Name) const
Return the higher priority library where the given component is stored.
std::map< unsigned int, unsigned int > memory_units
map between memory units and the associated variables
#define UUVECTOR_CONVERTER_STD
#define UBVECTOR_CONVERTER_STD
#define IUVECTOR_CONVERTER_STD
static bool IsRealType(const tree_nodeConstRef &type)
Return true if the treenode is of real type.
void add_tech_constraint(technology_nodeRef cur_fu, unsigned int tech_constrain_value, unsigned int pos, bool proxy_constrained)
#define CONVERT_EXPR
constant string identifying some conversion expressions
Definition: op_graph.hpp:350
unsigned int get_number_fu_types() const
Returns the number of functional units types.
#define STD_GET_SIZE(structural_obj)
Macro returning the size of a type.
static const std::string ComputeSignature(const FrontendFlowStepType frontend_flow_step_type, const unsigned int function_id)
Compute the signature of a function frontend flow step.
#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