PandA-2024.02
conn_binding.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  */
46 #include "conn_binding.hpp"
47 
48 #include "Parameter.hpp"
49 #include "adder_conn_obj.hpp"
50 #include "allocation.hpp"
52 #include "behavioral_helper.hpp"
53 #include "commandport_obj.hpp"
54 #include "conn_binding_creator.hpp"
55 #include "conn_binding_cs.hpp"
56 #include "connection_obj.hpp"
57 #include "conv_conn_obj.hpp"
58 #include "dataport_obj.hpp"
59 #include "dbgPrintHelper.hpp"
60 #include "fu_binding.hpp"
61 #include "funit_obj.hpp"
62 #include "generic_obj.hpp"
63 #include "hls.hpp"
64 #include "hls_device.hpp"
65 #include "hls_manager.hpp"
66 #include "multi_unbounded_obj.hpp"
67 #include "mux_conn.hpp"
68 #include "mux_obj.hpp"
69 #include "omp_functions.hpp"
71 #include "string_manipulation.hpp"
72 #include "structural_manager.hpp"
73 #include "technology_manager.hpp"
74 #include "technology_node.hpp"
75 #include "tree_helper.hpp"
76 #include "tree_manager.hpp"
77 
78 #include "custom_set.hpp"
79 #include <algorithm>
80 #include <list>
81 #include <tuple>
82 #include <utility>
83 #include <vector>
84 
85 #define CONN_COLUMN_SIZE 40
86 
87 unsigned conn_binding::unique_id = 0;
88 
90  : parameters(_parameters),
91  debug_level(_parameters->get_class_debug_level(GET_CLASS(*this))),
92  output_level(_parameters->getOption<int>(OPT_output_level)),
93  BH(_BH)
94 {
95 }
96 
98  const BehavioralHelperConstRef _BH,
99  const ParameterConstRef _parameters)
100 {
101  if(_parameters->isOption(OPT_context_switch))
102  {
103  auto omp_functions = GetPointer<OmpFunctions>(_HLSMgr->Rfuns);
104  bool found = false;
105  if(omp_functions->kernel_functions.find(_HLS->functionId) != omp_functions->kernel_functions.end())
106  {
107  found = true;
108  }
109  if(omp_functions->parallelized_functions.find(_HLS->functionId) != omp_functions->parallelized_functions.end())
110  {
111  found = true;
112  }
113  if(omp_functions->atomic_functions.find(_HLS->functionId) != omp_functions->atomic_functions.end())
114  {
115  found = true;
116  }
117  if(found)
118  {
119  return conn_bindingRef(new conn_binding_cs(_BH, _parameters));
120  }
121  else
122  {
123  return conn_bindingRef(new conn_binding(_BH, _parameters));
124  }
125  }
126  else
127  {
128  return conn_bindingRef(new conn_binding(_BH, _parameters));
129  }
130 }
131 
132 conn_binding::~conn_binding() = default;
133 
135 {
136  switch(dir)
137  {
138  case IN:
139  THROW_ASSERT(input_ports.count(var), "Data port not stored into conn_binding class");
140  return input_ports[var];
141  case OUT:
142  THROW_ASSERT(output_ports.count(var), "Data port not stored into conn_binding class");
143  return output_ports[var];
144  default:
145  THROW_ERROR("Port kind not allowed");
146  }
147  return generic_objRef();
148 }
149 
150 void conn_binding::add_data_transfer(const generic_objRef op1, const generic_objRef op2, unsigned int operand,
151  unsigned int port_index, data_transfer data)
152 {
153  conn_variables[ConnectionTarget(op2, operand, port_index)][op1].insert(data);
154 }
155 
156 const std::map<conn_binding::ConnectionTarget, conn_binding::ConnectionSources>&
158 {
159  return conn_variables;
160 }
161 
162 void conn_binding::AddConnectionCB(const generic_objRef op1, const generic_objRef op2, unsigned int operand,
163  unsigned int port_index, connection_objRef conn)
164 {
166  "---Adding connection " + op1->get_string() + " " + op2->get_string() + " " + STR(operand) + " " +
167  STR(port_index));
168  conn_implementation[connection(op1, op2, operand, port_index)] = conn;
169 }
170 
172 {
173  switch(dir)
174  {
175  case IN:
176  {
177  if(input_ports.count(var) == 0)
178  {
179  input_ports[var] = generic_objRef(new dataport_obj("IN_PORT_" + BH->PrintVariable(var), 0));
180  }
181  return input_ports[var];
182  }
183  case OUT:
184  {
185  if(output_ports.count(var) == 0)
186  {
187  output_ports[var] = generic_objRef(new dataport_obj("OUT_PORT_" + BH->PrintVariable(var), 0));
188  }
189  return output_ports[var];
190  }
191  default:
192  THROW_ERROR("Port kind not allowed");
193  }
194  return generic_objRef();
195 }
196 
198  const OpGraphConstRef g)
199 {
200  switch(dir)
201  {
202  case IN:
203  {
204  if(command_input_ports.count(std::make_pair(ver, mode)) == 0)
205  {
206  command_input_ports[std::make_pair(ver, mode)] = generic_objRef(new commandport_obj(
207  ver, mode, "IN_" + commandport_obj::get_mode_string(mode) + "_" + GET_NAME(g, ver)));
208  }
209  return command_input_ports[std::make_pair(ver, mode)];
210  }
211  case OUT:
212  {
213  if(command_output_ports.count(ver) == 0)
214  {
216  ver, mode, "OUT_" + commandport_obj::get_mode_string(mode) + "_" + GET_NAME(g, ver)));
217  }
218  return command_output_ports[ver];
219  }
220  default:
221  THROW_ERROR("Port kind not allowed");
222  }
223  return generic_objRef();
224 }
225 
227  const generic_objRef elem, unsigned int op)
228 {
229  if(selectors.find(dir) == selectors.end() or selectors[dir].find(std::make_pair(elem, op)) == selectors[dir].end())
230  {
231  selectors[dir][std::make_pair(elem, op)] =
232  generic_objRef(new commandport_obj(elem, mode,
233  (dir == IN ? "IN_" : "OUT_") + elem->get_string() + "_" +
234  commandport_obj::get_mode_string(mode) + "_" + STR(op)));
235  }
236  return selectors[dir][std::make_pair(elem, op)];
237 }
238 
240  const OpGraphConstRef data)
241 {
242  if(activation_ports.find(cond) != activation_ports.end() and
243  activation_ports[cond].find(dir) != activation_ports[cond].end())
244  {
245  return activation_ports[cond][dir];
246  }
248  cond, mode, (dir == IN ? "IN_" : "OUT_") + commandport_obj::get_mode_string(mode) + "_" + GET_NAME(data, cond)));
249  activation_ports[cond][dir] = port;
250  return selectors[dir][std::make_pair(port, 0)] = port;
251 }
252 
254 {
255  bool allconnected = true;
256  for(unsigned int p = 0; p < GetPointer<port_o>(port_i)->get_ports_size() && allconnected; ++p)
257  {
258  structural_objectRef port_d = GetPointer<port_o>(port_i)->get_port(p);
259  if(!GetPointer<port_o>(port_d)->find_bounded_object())
260  {
261  allconnected = false;
262  }
263  }
264 
265  return allconnected;
266 }
267 
269 {
271  add_command_ports(HLSMgr, HLS, SM);
272 
274  INDENT_DBG_MEX(DEBUG_LEVEL_VERBOSE, debug_level, "-->Adding sparse logic to the datapath");
275  add_sparse_logic_dp(HLS, SM, HLSMgr);
277 
278 #ifndef NDEBUG
279  const auto connection_type = HLS->Param->getOption<HLSFlowStep_Type>(OPT_datapath_interconnection_algorithm);
281  THROW_ASSERT(connection_type == HLSFlowStep_Type::MUX_INTERCONNECTION_BINDING, "Unexpected interconnection binding");
282 #endif
283  INDENT_DBG_MEX(DEBUG_LEVEL_VERBOSE, debug_level, "-->Datapath interconnection using mux architecture");
284  mux_connection(HLS, SM);
286 
287  const auto circuit = SM->get_circ();
288  std::map<unsigned long long, structural_objectRef> null_values;
289  for(unsigned int i = 0; i < GetPointer<module>(circuit)->get_internal_objects_size(); i++)
290  {
291  auto curr_gate = GetPointer<module>(circuit)->get_internal_object(i);
292  if(!GetPointer<module>(curr_gate) || GetPointer<module>(curr_gate)->get_id() == "scheduler_kernel")
293  {
294  continue;
295  }
296  for(unsigned int j = 0; j < GetPointer<module>(curr_gate)->get_in_port_size(); j++)
297  {
298  structural_objectRef port_i = GetPointer<module>(curr_gate)->get_in_port(j);
299  if((port_i->get_kind() == port_o_K || port_i->get_kind() == port_vector_o_K) &&
300  GetPointer<port_o>(port_i)->find_bounded_object())
301  {
302  continue;
303  }
304  if(port_i->get_kind() == port_vector_o_K && check_pv_allconnected(port_i))
305  {
306  continue;
307  }
308  if(port_i->get_kind() == port_vector_o_K)
309  {
310  for(unsigned int p = 0; p < GetPointer<port_o>(port_i)->get_ports_size(); ++p)
311  {
312  const auto port_d = GetPointer<port_o>(port_i)->get_port(p);
313  const auto bw = GET_TYPE_SIZE(port_d);
314  if(null_values.find(bw) == null_values.end())
315  {
317  const auto const_obj = SM->add_constant("null_value_" + STR(bw), circuit, bool_type, STR(0));
318  null_values[bw] = const_obj;
319  }
320  if(!GetPointer<port_o>(port_d)->find_bounded_object())
321  {
322  SM->add_connection(port_d, null_values[bw]);
323  }
324  }
325  }
326  else
327  {
328  auto bw = GET_TYPE_SIZE(port_i);
329  if(null_values.find(bw) == null_values.end())
330  {
332  const auto const_obj = SM->add_constant("null_value_" + STR(bw), circuit, bool_type, STR(0));
333  null_values[bw] = const_obj;
334  }
335  SM->add_connection(port_i, null_values[bw]);
336  }
337  }
338  for(unsigned int j = 0; j < GetPointer<module>(curr_gate)->get_out_port_size(); j++)
339  {
340  const auto port_out = GetPointer<module>(curr_gate)->get_out_port(j);
341  if((port_out->get_kind() == port_o_K || port_out->get_kind() == port_vector_o_K) &&
342  GetPointer<port_o>(port_out)->find_bounded_object())
343  {
344  continue;
345  }
346  if(port_out->get_kind() == port_vector_o_K && check_pv_allconnected(port_out))
347  {
348  continue;
349  }
350 
351  if(port_out->get_kind() == port_vector_o_K)
352  {
353  for(unsigned int p = 0; p < GetPointer<port_o>(port_out)->get_ports_size(); ++p)
354  {
355  const auto port_d = GetPointer<port_o>(port_out)->get_port(p);
356  if(!GetPointer<port_o>(port_d)->find_bounded_object())
357  {
358  const auto name = "null_out_signal_" + port_out->get_owner()->get_id() + "_" + port_out->get_id() +
359  "_" + port_d->get_id();
360  const auto sign = SM->add_sign(name, circuit, port_d->get_typeRef());
361  SM->add_connection(port_d, sign);
362  }
363  }
364  }
365  }
366  }
367 }
368 
370 {
371  structural_objectRef circuit = SM->get_circ();
372 
373  // CustomOrderedSet<std::pair<std::string, std::string> > already_considered;
374  for(auto i = conn_implementation.begin(); i != conn_implementation.end(); ++i)
375  {
376  generic_objRef src = std::get<0>(i->first);
377  generic_objRef tgt = std::get<1>(i->first);
378 
379  THROW_ASSERT(src, "a NULL src may come from uninitialized variables. Target: " + tgt->get_string());
380  unsigned int operand = std::get<2>(i->first);
381  unsigned int port_index = std::get<3>(i->first);
383  "-->Creating CONNECTION between " + src->get_string() + " and " + tgt->get_string() + "(" +
384  STR(operand) + ":" + STR(port_index) + ")");
385 
386  structural_objectRef src_module = src->get_structural_obj();
387  structural_objectRef tgt_module = tgt->get_structural_obj();
388  THROW_ASSERT(src, "No source signal to " + tgt->get_string());
389  structural_objectRef port_src, port_tgt;
390  THROW_ASSERT(src_module, "No object associated to " + src->get_string());
391  if(src_module->get_kind() == component_o_K)
392  {
393  auto* src_obj = GetPointer<module>(src_module);
394  for(unsigned int ind = 0; ind < src_obj->get_out_port_size(); ind++)
395  {
396  auto curr_port = src_obj->get_out_port(ind);
397  if(curr_port->get_id() == DONE_PORT_NAME)
398  {
399  continue;
400  }
401  if(GetPointer<port_o>(curr_port)->get_is_memory() || GetPointer<port_o>(curr_port)->get_is_global() ||
402  GetPointer<port_o>(curr_port)->get_is_extern())
403  {
404  continue;
405  }
406  port_src = curr_port;
407  if(port_src->get_kind() == port_vector_o_K)
408  {
409  port_src = GetPointer<port_o>(port_src)->get_port(GetPointer<funit_obj>(src)->get_index() %
410  GetPointer<port_o>(port_src)->get_ports_size());
411  }
412  break;
413  }
414  }
415  else if(src_module->get_kind() == port_o_K || src_module->get_kind() == port_vector_o_K)
416  {
417  port_src = src_module;
418  }
419  if(!port_src)
420  {
421  src_module->print(std::cerr);
422  THROW_ERROR("source module does not have the expected return_port: " + src_module->get_id() + " - " +
423  src_module->get_path() + "\nCheck the module specification");
424  }
425 
426  THROW_ASSERT(tgt_module, "No object associated to " + tgt->get_string());
427  if(tgt_module->get_kind() == component_o_K)
428  {
429  auto* tgt_obj = GetPointer<module>(tgt_module);
430  unsigned int num = 0;
431 
432  for(unsigned int ind = 0; ind < tgt_obj->get_in_port_size(); ind++)
433  {
434  auto curr_port = tgt_obj->get_in_port(ind);
435  if(curr_port->get_id() == CLOCK_PORT_NAME || curr_port->get_id() == RESET_PORT_NAME ||
436  curr_port->get_id() == START_PORT_NAME)
437  {
438  continue;
439  }
440  if(GetPointer<port_o>(curr_port)->get_is_memory() || GetPointer<port_o>(curr_port)->get_is_global() ||
441  GetPointer<port_o>(curr_port)->get_is_extern())
442  {
443  continue;
444  }
445  if(num == operand)
446  {
447  port_tgt = curr_port;
448  if(port_tgt->get_kind() == port_vector_o_K)
449  {
450  port_tgt = GetPointer<port_o>(port_tgt)->get_port(port_index);
451  }
452  else
453  {
454  THROW_ASSERT(port_index == 0, "expected 0 as port index");
455  }
456  break;
457  }
458  num++;
459  }
460  }
461  else if(tgt_module->get_kind() == port_o_K || tgt_module->get_kind() == port_vector_o_K)
462  {
463  port_tgt = tgt_module;
464  }
465  if(!port_tgt)
466  {
467  tgt_module->print(std::cerr);
468  THROW_ERROR("target module does not have the expected input port: " + tgt_module->get_id() + " - " +
469  tgt_module->get_path() + "\nCheck the module specification");
470  }
471 
472  structural_type_descriptorRef port_src_type = port_src->get_typeRef();
474  if(!sign)
475  {
476  std::string name = "out_" + src->get_string() + "_" + src->get_structural_obj()->get_id();
477  sign = SM->add_sign(name, circuit, port_src_type);
478  THROW_ASSERT(port_src_type->size, "size greater than one expected");
479  src->set_out_sign(sign);
480  SM->add_connection(port_src, sign);
481  }
482 
483  switch(i->second->get_type())
484  {
485  case connection_obj::DIRECT_CONN:
486  {
487  INDENT_DBG_MEX(DEBUG_LEVEL_VERBOSE, debug_level, "---Creating DIRECTED CONNECTION");
488  THROW_ASSERT(sign, "");
489  THROW_ASSERT(port_tgt, tgt_module->get_path());
490  auto bits_src = GET_TYPE_SIZE(sign);
491  auto bits_tgt = GET_TYPE_SIZE(port_tgt);
493 
494  if(bits_src != bits_tgt)
495  {
496  if(port_tgt->get_typeRef()->type == structural_type_descriptor::INT)
497  {
499  }
500  else if(port_tgt->get_typeRef()->type == structural_type_descriptor::UINT)
501  {
503  }
504  else if(port_tgt->get_typeRef()->type == structural_type_descriptor::REAL)
505  {
507  }
508  else
509  {
511  }
512  }
513  add_datapath_connection(HLS->HLS_D->get_technology_manager(), SM, sign, port_tgt, conn_type);
514  break;
515  }
516  case connection_obj::BY_MUX:
517  {
518  INDENT_DBG_MEX(DEBUG_LEVEL_VERBOSE, debug_level, "---Creating MUX TREE");
519  mux_allocation(HLS, SM, sign, port_tgt, i->second);
520  break;
521  }
522  default:
523  THROW_ERROR("Connection type not allowed: " + STR(i->second->get_type()));
524  }
526  }
527 }
528 
529 void conn_binding::specialise_mux(const generic_objRef mux, unsigned int bits_tgt) const
530 {
531  auto data_size = GetPointer<mux_obj>(mux)->get_bitsize();
532  data_size = std::max(data_size, bits_tgt);
533 
535  const module* mux_module = GetPointer<module>(mux_obj);
536 
538  "---Specializing " + mux_obj->get_path() + ": " + STR(data_size));
540  mux_module->get_in_port(1)->type_resize(data_size);
541  mux_module->get_in_port(2)->type_resize(data_size);
542  mux_module->get_out_port(0)->type_resize(data_size);
543 }
544 
547 {
548  THROW_ASSERT(src, "mux_allocation - No source object");
549  THROW_ASSERT(tgt, "mux_allocation - No target object");
550  unsigned long long bits_tgt = 0;
553  {
554  bits_tgt = GET_TYPE_SIZE(tgt);
556  }
558  {
559  bits_tgt = GET_TYPE_SIZE(tgt);
561  }
563  {
564  bits_tgt = GET_TYPE_SIZE(tgt);
566  }
567  else
568  {
569  bits_tgt = GET_TYPE_SIZE(tgt);
571  }
573  "---conn_binding::mux_allocation between " + src->get_path() + " and " + tgt->get_path());
574 
575  THROW_ASSERT(GetPointer<mux_conn>(conn), "The connection is not implemented through multiplexers");
576  auto* mux_alloc = GetPointer<mux_conn>(conn);
577  const std::vector<std::pair<generic_objRef, unsigned int>>& mux_tree = mux_alloc->get_mux_tree();
578  THROW_ASSERT(mux_tree.size() > 0, "no mux into a mux connection");
579 
580  const structural_objectRef circuit = SM->get_circ();
581  for(const auto& i : mux_tree)
582  {
583  structural_objectRef mux = i.first->get_structural_obj();
584  auto in_mux = i.second == T_COND ? 1u : 2u;
585 
586  if(mux)
587  {
589  auto* mux_object = GetPointer<module>(mux);
590 
592  auto mux_input = mux_object->get_in_port(in_mux);
593  THROW_ASSERT(mux_input, "classic_datapath::mux_allocation - In port does not exist");
594  add_datapath_connection(HLS->HLS_D->get_technology_manager(), SM, src, mux_input, conn_type);
595 
596  return;
597  }
598  else
599  {
600  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "---MUX must be allocated");
601  std::string name = i.first->get_string();
603  HLS->HLS_D->get_technology_manager()->get_library(MUX_GATE_STD),
604  circuit, HLS->HLS_D->get_technology_manager());
605  i.first->set_structural_obj(mux);
606 
608  generic_objRef selector = GetPointer<mux_obj>(i.first)->GetSelector();
609  structural_objectRef sel_obj = selector->get_structural_obj();
610  THROW_ASSERT(sel_obj, "Selector obj not created");
612  structural_objectRef mux_sel = mux->find_member("sel", port_o_K, mux);
613  THROW_ASSERT(mux_sel, "Mux selector not yet created");
614  SM->add_connection(sel_obj, mux_sel);
615 
617  HLS_manager::check_bitwidth(bits_tgt);
618  specialise_mux(i.first, static_cast<unsigned>(bits_tgt));
619 
620  auto* mux_object = GetPointer<module>(mux);
621 
623  auto mux_input = mux_object->get_in_port(in_mux);
624  THROW_ASSERT(mux_input, "classic_datapath::mux_allocation - In port does not exist");
625  add_datapath_connection(HLS->HLS_D->get_technology_manager(), SM, src, mux_input, conn_type);
626 
628  structural_objectRef port_out_mux = mux_object->get_out_port(0);
629  THROW_ASSERT(port_out_mux, "classic_datapath::mux_allocation - Out port does not exist");
630  structural_type_descriptorRef out_type = port_out_mux->get_typeRef();
631  THROW_ASSERT(out_type->size, "size greater than zero expected");
632  std::string sig_name = "out_" + name;
633  structural_objectRef sign = SM->add_sign(sig_name, circuit, out_type);
634  i.first->set_out_sign(sign);
635  SM->add_connection(sign, port_out_mux);
636  src = sign;
637  }
638  }
639  add_datapath_connection(HLS->HLS_D->get_technology_manager(), SM, src, tgt, conn_type);
640 }
641 
643  const structural_objectRef src, const structural_objectRef tgt,
644  unsigned int conn_type)
645 {
646  auto bits_src = GET_TYPE_SIZE(src);
647  auto bits_tgt = GET_TYPE_SIZE(tgt);
649  "-->Adding datapath connections " + src->get_path() + "(" + STR(bits_src) + " bits)-->" +
650  tgt->get_path() + "(" + STR(bits_tgt) + " bits)");
651  // std::cerr << "adding connection between " << src->get_path() << " and " << tgt->get_path() << " conn type " <<
652  // conn_type << std::endl;
653  if(bits_src == bits_tgt)
654  {
655  THROW_ASSERT(src->get_owner(), "expected an owner for src: " + src->get_path());
656  THROW_ASSERT(tgt->get_owner(), "expected an owner for tgt: " + tgt->get_path());
657  if(src->get_owner() == tgt->get_owner() && src->get_kind() == port_o_K && tgt->get_kind() == port_o_K)
658  {
659  std::string name = "io_signal_" + src->get_id() + "_" + tgt->get_id();
660  structural_type_descriptorRef sign_type = tgt->get_typeRef();
661  structural_objectRef sign = SM->add_sign(name, src->get_owner(), sign_type);
662  SM->add_connection(src, sign);
663  SM->add_connection(sign, tgt);
664  }
665  else
666  {
667  SM->add_connection(src, tgt);
668  }
669  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Added datapath connections (same bitsize)");
670  return;
671  }
672  structural_objectRef circuit = SM->get_circ();
673  bool is_src_int = src->get_typeRef()->type == structural_type_descriptor::INT ||
674  (conn_type == structural_type_descriptor::INT &&
676  bool is_tgt_int = tgt->get_typeRef()->type == structural_type_descriptor::INT ||
677  (conn_type == structural_type_descriptor::INT &&
679  bool is_src_real = src->get_typeRef()->type == structural_type_descriptor::REAL ||
680  (conn_type == structural_type_descriptor::REAL &&
682  bool is_tgt_real = tgt->get_typeRef()->type == structural_type_descriptor::REAL ||
683  (conn_type == structural_type_descriptor::REAL &&
685 
686  std::string name = "conv_" + src->get_id() + (is_src_int ? "_I" : (is_src_real ? "_R" : "")) + "_" + STR(bits_src) +
687  (is_tgt_int ? "_I" : (is_tgt_real ? "_R" : "")) + "_" + STR(bits_tgt);
688  if(converters.find(name) == converters.end())
689  {
690  // std::cerr << "name: " << name << std::endl;
691  // std::cerr << src->get_typeRef()->get_name() << "--" << tgt->get_typeRef()->get_name() << std::endl;
692  structural_objectRef c_obj;
693  unsigned int offset = 0;
694  if(!is_src_int && !is_tgt_int && !is_src_real && !is_tgt_real)
695  {
696  std::string library_name = TM->get_library(UUDATA_CONVERTER_STD);
697  c_obj = SM->add_module_from_technology_library(name, UUDATA_CONVERTER_STD, library_name, circuit, TM);
698  }
699  else if(!is_src_int && !is_src_real && is_tgt_int)
700  {
701  std::string library_name = TM->get_library(UIDATA_CONVERTER_STD);
702  c_obj = SM->add_module_from_technology_library(name, UIDATA_CONVERTER_STD, library_name, circuit, TM);
703  }
704  else if(is_src_int && !is_tgt_int && !is_tgt_real)
705  {
706  std::string library_name = TM->get_library(IUDATA_CONVERTER_STD);
707  c_obj = SM->add_module_from_technology_library(name, IUDATA_CONVERTER_STD, library_name, circuit, TM);
708  }
709  else if(is_src_int && is_tgt_int)
710  {
711  std::string library_name = TM->get_library(IIDATA_CONVERTER_STD);
712  c_obj = SM->add_module_from_technology_library(name, IIDATA_CONVERTER_STD, library_name, circuit, TM);
713  }
714  else if(is_src_real && is_tgt_real)
715  {
716  std::string library_name = TM->get_library(UUDATA_CONVERTER_STD);
717  c_obj = SM->add_module_from_technology_library(name, UUDATA_CONVERTER_STD, library_name, circuit, TM);
718 #if 0
719  std::string library_name = TM->get_library(FFDATA_CONVERTER_STD);
720  c_obj = SM->add_module_from_technology_library(name, FFDATA_CONVERTER_STD, library_name, circuit, TM);
721  offset = 2;
722 #endif
723  }
724  else
725  {
726  THROW_UNREACHABLE("Conversion not expected from " + src->get_path() + "(" + src->get_typeRef()->get_name() +
727  ") to " + tgt->get_path() + "(" + tgt->get_typeRef()->get_name() + ")(" + STR(is_src_int) +
728  " " + STR(is_tgt_int) + " " + STR(is_src_real) + " " + STR(is_tgt_real) + " " +
729  STR(bits_src) + " " + STR(bits_tgt) + ")");
730  }
731 
733  structural_objectRef in1 = GetPointer<module>(c_obj)->get_in_port(offset);
734  in1->type_resize(bits_src);
735  SM->add_connection(src, in1);
736 
738  structural_objectRef out0 = GetPointer<module>(c_obj)->get_out_port(0);
739  out0->type_resize(bits_tgt);
740  THROW_ASSERT(out0->get_typeRef()->size, "size greater than one expected");
741 
742  structural_objectRef sign = SM->add_sign("out_" + c_obj->get_id(), circuit, out0->get_typeRef());
743  SM->add_connection(out0, sign);
744  converters[name] = sign;
745  }
746  SM->add_connection(converters[name], tgt);
747  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Added datapath connections");
748 }
749 
750 generic_objRef conn_binding::get_constant_obj(const std::string& value, const std::string& param,
751  unsigned int precision)
752 {
753  THROW_ASSERT(value != "", "value expected");
754  if(constant_values.find(const_param(value, param)) == constant_values.end())
755  {
756  constant_values[const_param(value, param)] =
757  generic_objRef(new dataport_obj("CONSTANT_" + value, param, precision));
758  }
759  return constant_values[const_param(value, param)];
760 }
761 
762 const std::map<conn_binding::const_param, generic_objRef>& conn_binding::get_constant_objs() const
763 {
764  return constant_values;
765 }
766 
768 {
769  const structural_objectRef circuit = SM->get_circ();
770  structural_objectRef sparse_component;
771  std::string resource_name, resource_instance_name;
772  unsigned int resource_index = 0;
773  unsigned long long bitsize = 0;
774  for(const auto& component : sparse_logic)
775  {
776  switch(component->get_type())
777  {
779  {
780  resource_name = GetPointer<adder_conn_obj>(component)->is_align_adder() ? UI_ALIGN_ADDER_STD : UI_ADDER_STD;
781  resource_instance_name = resource_name + "_adder_" + STR(resource_index);
782  bitsize = GetPointer<adder_conn_obj>(component)->get_bitsize();
783  break;
784  }
786  {
787  resource_name = UUDATA_CONVERTER_STD;
788  resource_instance_name = resource_name + "_uu_conv_" + STR(resource_index);
789  bitsize = GetPointer<uu_conv_conn_obj>(component)->get_bitsize();
790  break;
791  }
793  {
794  resource_name = UIDATA_CONVERTER_STD;
795  resource_instance_name = resource_name + "_ui_conv_" + STR(resource_index);
796  bitsize = GetPointer<ui_conv_conn_obj>(component)->get_bitsize();
797  break;
798  }
800  {
801  resource_name = IUDATA_CONVERTER_STD;
802  resource_instance_name = resource_name + "_iu_conv_" + STR(resource_index);
803  bitsize = GetPointer<iu_conv_conn_obj>(component)->get_bitsize();
804  break;
805  }
807  {
808  resource_name = IIDATA_CONVERTER_STD;
809  resource_instance_name = resource_name + "_ii_conv_" + STR(resource_index);
810  bitsize = GetPointer<ii_conv_conn_obj>(component)->get_bitsize();
811  break;
812  }
814  {
815  bitsize = GetPointer<ff_conv_conn_obj>(component)->get_bitsize_out();
816  if(HLS->Param->isOption(OPT_soft_float) && HLS->Param->getOption<bool>(OPT_soft_float))
817  {
818  technology_nodeRef current_fu;
820  GetPointer<ff_conv_conn_obj>(component)->get_bitsize_in(),
821  GetPointer<ff_conv_conn_obj>(component)->get_bitsize_out(), HLSMgr, current_fu);
822  }
823  else
824  {
825  resource_name = FFDATA_CONVERTER_STD;
826  }
827  resource_instance_name = resource_name + "_ff_conv_" + STR(resource_index);
828  break;
829  }
831  {
832  resource_name = ASSIGN_SIGNED_STD;
833  resource_instance_name = resource_name + "_i_assign_" + STR(resource_index);
834  bitsize = GetPointer<i_assign_conn_obj>(component)->get_bitsize();
835  break;
836  }
838  {
839  resource_name = ASSIGN_UNSIGNED_STD;
840  resource_instance_name = resource_name + "_u_assign_" + STR(resource_index);
841  bitsize = GetPointer<u_assign_conn_obj>(component)->get_bitsize();
842  break;
843  }
845  {
846  resource_name = ASSIGN_REAL_STD;
847  resource_instance_name = resource_name + "_f_assign_" + STR(resource_index);
848  bitsize = GetPointer<f_assign_conn_obj>(component)->get_bitsize();
849  break;
850  }
851  default:
852  {
853  THROW_ERROR("sparse component not yet considered " + component->get_string());
854  }
855  }
856  ++resource_index;
857  sparse_component = SM->add_module_from_technology_library(
858  resource_instance_name, resource_name, HLS->HLS_D->get_technology_manager()->get_library(resource_name),
859  circuit, HLS->HLS_D->get_technology_manager());
860  component->set_structural_obj(sparse_component);
861  auto* sparse_module = GetPointer<module>(sparse_component);
862 
864  "---Specializing " + sparse_component->get_path() + ": " + STR(bitsize));
866  unsigned int shift_index = 0;
867  if(component->get_type() == generic_obj::ADDER_CONN_OBJ &&
868  GetPointer<adder_conn_obj>(component)->is_align_adder())
869  {
870  sparse_module->SetParameter(VALUE_PARAMETER, STR(GetPointer<adder_conn_obj>(component)->get_trimmed_bits()));
871  }
872  else if(GetPointer<port_o>(sparse_module->get_in_port(shift_index)) &&
873  GetPointer<port_o>(sparse_module->get_in_port(shift_index))->get_is_clock())
874  {
875  ++shift_index;
876  }
877  if(!HLS->Param->isOption(OPT_soft_float) || !HLS->Param->getOption<bool>(OPT_soft_float) ||
878  component->get_type() != generic_obj::FF_CONV_CONN_OBJ)
879  {
880  if(component->get_type() == generic_obj::FF_CONV_CONN_OBJ)
881  {
882  ++shift_index;
883  sparse_module->get_in_port(shift_index)
884  ->type_resize(GetPointer<ff_conv_conn_obj>(component)->get_bitsize_in());
885  }
886  else
887  {
888  sparse_module->get_in_port(shift_index)->type_resize(bitsize);
889  }
890  }
891  if(component->get_type() != generic_obj::UU_CONV_CONN_OBJ &&
892  component->get_type() != generic_obj::UI_CONV_CONN_OBJ &&
893  component->get_type() != generic_obj::IU_CONV_CONN_OBJ &&
894  component->get_type() != generic_obj::II_CONV_CONN_OBJ &&
895  component->get_type() != generic_obj::FF_CONV_CONN_OBJ &&
896  component->get_type() != generic_obj::I_ASSIGN_CONN_OBJ &&
897  component->get_type() != generic_obj::U_ASSIGN_CONN_OBJ &&
898  component->get_type() != generic_obj::F_ASSIGN_CONN_OBJ)
899  {
900  sparse_module->get_in_port(shift_index + 1)->type_resize(bitsize);
901  }
902  if(!HLS->Param->isOption(OPT_soft_float) || !HLS->Param->getOption<bool>(OPT_soft_float) ||
903  component->get_type() != generic_obj::FF_CONV_CONN_OBJ)
904  {
905  sparse_module->get_out_port(0)->type_resize(bitsize);
906  }
907  }
908 }
909 
911 {
912  for(const auto& conn : conn_implementation)
913  {
914  generic_objRef src = std::get<0>(conn.first);
915  generic_objRef tgt = std::get<1>(conn.first);
916  auto op = std::get<2>(conn.first);
917  std::string str = conn.second->get_string();
918  if(conn.second->get_type() == connection_obj::BY_MUX)
919  {
920  str = "MUX_TREE [" + STR(GetPointer<mux_conn>(conn.second)->get_mux_tree_size()) + "] => " + str;
921  }
923  "---Source: " + src->get_string() + " Target: " + tgt->get_string() + "(" + STR(op) + ") " +
924  " connected by: " + str);
925  }
926 }
927 
928 unsigned long long conn_binding::determine_bit_level_mux() const
929 {
931  for(const auto& it : conn_implementation)
932  {
933  if(!GetPointer<mux_conn>(it.second))
934  {
935  continue;
936  }
937  const std::vector<std::pair<generic_objRef, unsigned int>>& tree =
938  GetPointer<mux_conn>(it.second)->get_mux_tree();
939  for(const auto& v : tree)
940  {
941  mux.insert(v.first);
942  }
943  }
944  auto bit_mux = 0ull;
945  for(const auto& m : mux)
946  {
947  bit_mux += GetPointer<mux_obj>(m)->get_bitsize();
948  }
949  return bit_mux;
950 }
951 
953 {
954  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Adding command ports");
955  structural_objectRef circuit = SM->get_circ();
956 
957  const FunctionBehaviorConstRef FB = HLSMgr->CGetFunctionBehavior(HLS->functionId);
959 
961  structural_type_descriptorRef boolean_port_type =
963 
964  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Adding starting ports");
965  const OpVertexSet& operations = HLS->operations;
966  for(auto j : operations)
967  {
969  technology_nodeRef op_tn = GetPointer<functional_unit>(tn)->get_operation(
970  tree_helper::NormalizeTypename(data->CGetOpNodeInfo(j)->GetOperation()));
971  THROW_ASSERT(GetPointer<operation>(op_tn)->time_m,
972  "Time model not available for operation: " + GET_NAME(data, j));
974  structural_managerRef CM = GetPointer<functional_unit>(tn)->CM;
975  if(!CM)
976  {
977  continue;
978  }
980  THROW_ASSERT(top, "expected");
981  auto* fu_module = GetPointer<module>(top);
982  THROW_ASSERT(fu_module, "expected");
983  structural_objectRef start_port_i = fu_module->find_member(START_PORT_NAME, port_o_K, top);
984  if(((GET_TYPE(data, j) & TYPE_EXTERNAL) && start_port_i) || !GetPointer<operation>(op_tn)->is_bounded() ||
985  start_port_i)
986  {
987  bind_selector_port(conn_binding::IN, commandport_obj::UNBOUNDED, j, data);
988  bind_selector_port(conn_binding::OUT, commandport_obj::UNBOUNDED, j, data);
989  }
990  }
991  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Added starting ports");
992 
994  std::map<structural_objectRef, std::list<structural_objectRef>> calls;
995  std::map<structural_objectRef, std::list<vertex>> start_to_vertex;
996  if(selectors.find(conn_binding::IN) != selectors.end())
997  {
998  auto connection_binding_sets = selectors.find(conn_binding::IN)->second;
999  for(auto j = connection_binding_sets.begin(); j != connection_binding_sets.end(); ++j)
1000  {
1001  // unit associate with selector
1002  const generic_objRef elem = j->first.first;
1003  // operation's index
1004  auto oper = j->first.second;
1007  switch(elem->get_type())
1008  {
1010  {
1011  auto type_fu = GetPointer<funit_obj>(elem)->get_fu();
1012  std::vector<technology_nodeRef> tmp_ops_node =
1013  GetPointer<functional_unit>(HLS->allocation_information->get_fu(type_fu))->get_operations();
1014  THROW_ASSERT(GetPointer<commandport_obj>(j->second), "Not valid command port");
1015  structural_objectRef sel_obj =
1016  SM->add_port("fuselector_" + elem->get_string() + "_" + tmp_ops_node[oper]->get_name(), port_o::IN,
1017  circuit, boolean_port_type);
1018  (j->second)->set_structural_obj(sel_obj);
1019  structural_objectRef fu_mod = elem->get_structural_obj();
1020  THROW_ASSERT(fu_mod, "not correct module");
1021  structural_objectRef port_selector =
1022  fu_mod->find_member("sel_" + tmp_ops_node[oper]->get_name(), port_o_K, fu_mod);
1025  if(port_selector)
1026  {
1027  if(port_selector->get_kind() == port_vector_o_K)
1028  {
1029  THROW_ASSERT(GetPointer<port_o>(port_selector)->get_ports_size() != 0,
1030  "port not correctly initialized" + port_selector->get_path());
1031  port_selector = GetPointer<port_o>(port_selector)
1032  ->get_port(GetPointer<funit_obj>(elem)->get_index() %
1033  GetPointer<port_o>(port_selector)->get_ports_size());
1034  }
1035  SM->add_connection(port_selector, sel_obj);
1036  }
1037  break;
1038  }
1039  case generic_obj::REGISTER:
1040  {
1041  structural_objectRef reg_mod = elem->get_structural_obj();
1042 
1043  THROW_ASSERT(GetPointer<commandport_obj>(j->second), "Not valid command port");
1044  structural_objectRef sel_obj =
1045  SM->add_port("wrenable_" + reg_mod->get_id(), port_o::IN, circuit, boolean_port_type);
1046  (j->second)->set_structural_obj(sel_obj);
1047 
1048  structural_objectRef port_wenable = reg_mod->find_member(WENABLE_PORT_NAME, port_o_K, reg_mod);
1049  SM->add_connection(port_wenable, sel_obj);
1050  break;
1051  }
1053  {
1054  structural_objectRef mu_mod = elem->get_structural_obj();
1055 
1056  THROW_ASSERT(GetPointer<commandport_obj>(j->second), "Not valid command port");
1057  structural_objectRef sel_obj =
1058  SM->add_port("muenable_" + mu_mod->get_id(), port_o::IN, circuit, boolean_port_type);
1059  (j->second)->set_structural_obj(sel_obj);
1060 
1061  structural_objectRef port_enable = mu_mod->find_member("enable", port_o_K, mu_mod);
1062  SM->add_connection(port_enable, sel_obj);
1063  break;
1064  }
1067  {
1068  THROW_ASSERT(GetPointer<commandport_obj>(j->second), "Not valid command port");
1070  "---Adding selector_" + elem->get_string() + " " + STR(elem->get_type()));
1071  structural_objectRef sel_obj =
1072  SM->add_port("selector_" + elem->get_string(), port_o::IN, circuit, boolean_port_type);
1073  (j->second)->set_structural_obj(sel_obj);
1074 
1075  if(GetPointer<commandport_obj>(j->second)->get_command_type() == commandport_obj::UNBOUNDED)
1076  {
1077  vertex op = GetPointer<commandport_obj>(j->second)->get_vertex();
1078  generic_objRef fu_unit = HLS->Rfu->get(op);
1079  structural_objectRef fu_obj = fu_unit->get_structural_obj();
1080  structural_objectRef start = fu_obj->find_member(START_PORT_NAME, port_o_K, fu_obj);
1081  THROW_ASSERT(start, fu_obj->get_path());
1082  calls[start].push_back(sel_obj);
1083  start_to_vertex[start].push_back(op);
1084  }
1085  break;
1086  }
1087  default:
1088  {
1089  THROW_ERROR("Not supported generic_obj " + STR(elem->get_type()));
1090  }
1091  }
1092  }
1093  }
1095  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Adding calls connections");
1096  for(auto& call : calls)
1097  {
1098  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Adding connections of " + call.first->get_path());
1099  const auto isMultipleModule = GetPointer<module>(call.first->get_owner()) &&
1100  GetPointer<module>(call.first->get_owner())->get_multi_unit_multiplicity();
1101  if(call.second.size() == 1 && !isMultipleModule)
1102  {
1103  SM->add_connection(call.first, call.second.front());
1104  }
1105  else
1106  {
1107  if(isMultipleModule)
1108  {
1109  THROW_ASSERT(start_to_vertex.find(call.first) != start_to_vertex.end(), "unexpected condition");
1110  THROW_ASSERT(call.first->get_kind() == port_vector_o_K, "unexpected condition");
1111  std::map<structural_objectRef, std::list<structural_objectRef>> toOred;
1112  auto ports_it = call.second.begin();
1113  for(auto v : start_to_vertex.at(call.first))
1114  {
1115  const auto tn = HLS->allocation_information->get_fu(HLS->Rfu->get_assign(v));
1116  const auto index = HLS->Rfu->get_index(v);
1117 #if HAVE_ASSERTS
1118  const auto multiplicity = GetPointer<module>(call.first->get_owner())->get_multi_unit_multiplicity();
1119 #endif
1120  THROW_ASSERT(multiplicity == GetPointer<port_o>(call.first)->get_ports_size(), "unexpected condition");
1121  THROW_ASSERT(index < multiplicity,
1122  "unexpected condition: index: " + STR(index) + ", multiplicity: " + STR(multiplicity));
1123  auto sp_i = GetPointer<port_o>(call.first)->get_port(index);
1124  toOred[sp_i].push_back(*ports_it);
1125 
1126  THROW_ASSERT(ports_it != call.second.end(), "unexpected condition");
1127  ++ports_it;
1128  }
1129  for(const auto& pp_pair : toOred)
1130  {
1131  if(pp_pair.second.size() == 1)
1132  {
1133  SM->add_connection(pp_pair.first, pp_pair.second.front());
1134  }
1135  else
1136  {
1137  const auto TM = HLS->HLS_D->get_technology_manager();
1138  const auto library = TM->get_library(OR_GATE_STD);
1139  const auto or_gate = SM->add_module_from_technology_library(
1140  "or_" + pp_pair.first->get_owner()->get_id() + STR(unique_id), OR_GATE_STD, library,
1141  SM->get_circ(), TM);
1142  const auto sig = SM->add_sign("s_" + pp_pair.first->get_owner()->get_id() + STR(unique_id),
1143  SM->get_circ(), boolean_port_type);
1144  ++unique_id;
1145  SM->add_connection(sig, or_gate->find_member("out1", port_o_K, or_gate));
1146  SM->add_connection(sig, pp_pair.first);
1147  const auto in = or_gate->find_member("in", port_vector_o_K, or_gate);
1148  auto port = GetPointer<port_o>(in);
1149  port->add_n_ports(static_cast<unsigned int>(pp_pair.second.size()), in);
1150  unsigned int num = 0;
1151  for(auto a = pp_pair.second.begin(); a != pp_pair.second.end(); ++a, ++num)
1152  {
1153  SM->add_connection(*a, port->get_port(num));
1154  }
1155  }
1156  }
1157  }
1158  else
1159  {
1160  const auto TM = HLS->HLS_D->get_technology_manager();
1161  const auto library = TM->get_library(OR_GATE_STD);
1162  const auto or_gate = SM->add_module_from_technology_library(
1163  "or_" + call.first->get_owner()->get_id() + STR(unique_id), OR_GATE_STD, library, SM->get_circ(), TM);
1164  const auto sig = SM->add_sign("s_" + call.first->get_owner()->get_id() + STR(unique_id), SM->get_circ(),
1165  boolean_port_type);
1166  ++unique_id;
1167  SM->add_connection(sig, or_gate->find_member("out1", port_o_K, or_gate));
1168  SM->add_connection(sig, call.first);
1169  const auto in = or_gate->find_member("in", port_vector_o_K, or_gate);
1170  auto port = GetPointer<port_o>(in);
1171  port->add_n_ports(static_cast<unsigned int>(call.second.size()), in);
1172  unsigned int num = 0;
1173  for(auto a = call.second.begin(); a != call.second.end(); ++a, ++num)
1174  {
1175  SM->add_connection(*a, port->get_port(num));
1176  }
1177  }
1178  }
1179  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Added connections of " + call.first->get_path());
1180  }
1181  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Added calls connections");
1182  std::map<structural_objectRef, structural_objectRef> sig;
1183  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Adding multi-unbounded controllers connections");
1184  for(const auto& state2mu : HLS->STG->get_mu_ctrls())
1185  {
1186  auto mu = state2mu.second;
1187  structural_objectRef mu_mod = mu->get_structural_obj();
1188  auto mut = GetPointer<multi_unbounded_obj>(mu);
1189  const auto& ops = mut->get_ops();
1190  structural_objectRef inOps = mu_mod->find_member("ops", port_vector_o_K, mu_mod);
1191  auto* port = GetPointer<port_o>(inOps);
1192  auto j = 0u;
1193  for(const auto& op : ops)
1194  {
1195  generic_objRef fu_unit = HLS->Rfu->get(op);
1196  structural_objectRef fu_obj = fu_unit->get_structural_obj();
1197  structural_objectRef done = fu_obj->find_member(DONE_PORT_NAME, port_o_K, fu_obj);
1198  std::string sign_owner_id = done->get_owner()->get_id();
1199  if(done->get_kind() == port_vector_o_K)
1200  {
1201  THROW_ASSERT(GetPointer<port_o>(done)->get_ports_size() != 0,
1202  "port not correctly initialized" + done->get_path());
1203  THROW_ASSERT(GetPointer<funit_obj>(fu_unit), "unexpected port configuration");
1204  done = GetPointer<port_o>(done)->get_port(GetPointer<funit_obj>(fu_unit)->get_index() %
1205  GetPointer<port_o>(done)->get_ports_size());
1206  sign_owner_id = sign_owner_id + "_P" + done->get_id();
1207  THROW_ASSERT(done, "Missing done_port from function call " + fu_unit->get_string());
1208  }
1209  if(sig.find(done) == sig.end())
1210  {
1211  sig[done] = SM->add_sign("s_done_" + sign_owner_id, SM->get_circ(), boolean_port_type);
1212  SM->add_connection(done, sig[done]);
1213  }
1214  THROW_ASSERT(port->get_port(j), "port->get_port(j) not found");
1215  const auto& port_obj = port->get_port(j);
1216  SM->add_connection(port_obj, sig[done]);
1217  ++j;
1218  }
1219  HLS->Rconn->bind_selector_port(conn_binding::OUT, commandport_obj::MULTI_UNBOUNDED, mu, 0);
1220  }
1221  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Added multi-unbounded controllers connections");
1222 
1223  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Adding outputs");
1225  if(selectors.find(conn_binding::OUT) != selectors.end())
1226  {
1227  auto connection_binding_sets = selectors.find(conn_binding::OUT)->second;
1228  for(auto j = connection_binding_sets.begin(); j != connection_binding_sets.end(); ++j)
1229  {
1230  THROW_ASSERT(GetPointer<commandport_obj>(j->second), "Not valid command port");
1231  if(GetPointer<commandport_obj>(j->second)->get_command_type() == commandport_obj::SWITCH)
1232  {
1233  vertex op = GetPointer<commandport_obj>(j->second)->get_vertex();
1234  auto var_written = HLSMgr->get_produced_value(HLS->functionId, op);
1235  structural_type_descriptorRef switch_port_type =
1237  structural_objectRef sel_obj = SM->add_port(GetPointer<commandport_obj>(j->second)->get_string(),
1238  port_o::OUT, circuit, switch_port_type);
1239  (j->second)->set_structural_obj(sel_obj);
1240  }
1241  else if(GetPointer<commandport_obj>(j->second)->get_command_type() == commandport_obj::MULTIIF)
1242  {
1243  vertex op = GetPointer<commandport_obj>(j->second)->get_vertex();
1244  std::vector<HLS_manager::io_binding_type> var_read = HLSMgr->get_required_values(HLS->functionId, op);
1245  auto vect_size = static_cast<unsigned int>(var_read.size());
1246  structural_type_descriptorRef multiif_port_type =
1248  structural_objectRef sel_obj = SM->add_port(GetPointer<commandport_obj>(j->second)->get_string(),
1249  port_o::OUT, circuit, multiif_port_type);
1250  (j->second)->set_structural_obj(sel_obj);
1251  }
1252  else if(GetPointer<commandport_obj>(j->second)->get_command_type() == commandport_obj::MULTI_UNBOUNDED)
1253  {
1254  structural_objectRef mu_mod = j->second->get_structural_obj();
1255  auto mu_obj = j->first.first;
1256  structural_objectRef alldone_command_port = SM->add_port(
1257  GetPointer<commandport_obj>(j->second)->get_string(), port_o::OUT, circuit, boolean_port_type);
1258  THROW_ASSERT(GetPointer<multi_unbounded_obj>(mu_obj), "unexpected condition");
1259  SM->add_connection(GetPointer<multi_unbounded_obj>(mu_obj)->get_out_sign(), alldone_command_port);
1260  (j->second)->set_structural_obj(alldone_command_port);
1261  }
1262  else
1263  {
1264  structural_objectRef sel_obj = SM->add_port(GetPointer<commandport_obj>(j->second)->get_string(),
1265  port_o::OUT, circuit, boolean_port_type);
1266  (j->second)->set_structural_obj(sel_obj);
1267 
1268  if(GetPointer<commandport_obj>(j->second)->get_command_type() == commandport_obj::UNBOUNDED)
1269  {
1270  vertex op = GetPointer<commandport_obj>(j->second)->get_vertex();
1271  generic_objRef fu_unit = HLS->Rfu->get(op);
1272  structural_objectRef fu_obj = fu_unit->get_structural_obj();
1273  structural_objectRef done = fu_obj->find_member(DONE_PORT_NAME, port_o_K, fu_obj);
1274  if(done)
1275  {
1276  std::string sign_owner_id = done->get_owner()->get_id();
1277  if(done->get_kind() == port_vector_o_K)
1278  {
1279  THROW_ASSERT(GetPointer<port_o>(done)->get_ports_size() != 0,
1280  "port not correctly initialized" + done->get_path());
1281  THROW_ASSERT(GetPointer<funit_obj>(fu_unit), "unexpected port configuration");
1282  done = GetPointer<port_o>(done)->get_port(GetPointer<funit_obj>(fu_unit)->get_index() %
1283  GetPointer<port_o>(done)->get_ports_size());
1284  THROW_ASSERT(done, "Missing done_port from function call " + fu_unit->get_string());
1285  sign_owner_id = sign_owner_id + "_P" + done->get_id();
1286  }
1287  if(sig.find(done) == sig.end())
1288  {
1289  sig[done] = SM->add_sign("s_done_" + sign_owner_id, SM->get_circ(), boolean_port_type);
1290  SM->add_connection(done, sig[done]);
1291  }
1292  SM->add_connection(sig[done], sel_obj);
1293  }
1294  }
1295  }
1296  }
1297  }
1299 
1300  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Added command ports");
1301 }
1302 
1304 {
1305  command_input_ports.clear();
1306  command_output_ports.clear();
1307  conn_variables.clear();
1308 }
1309 conn_binding::ConnectionTarget::ConnectionTarget(generic_objRef tgt, unsigned int tgt_port, unsigned int tgt_port_index)
1310  : std::tuple<generic_objRef, unsigned int, unsigned int>(std::make_tuple(tgt, tgt_port, tgt_port_index))
1311 {
1312 }
1313 #if !HAVE_UNORDERED
1315 {
1317  if((std::get<0>(*this)) != (std::get<0>(other)))
1318  {
1319  THROW_ASSERT(std::get<0>(*this)->get_string() != std::get<0>(other)->get_string(),
1320  "Found generic object with same name " + std::get<0>(*this)->get_string());
1321  return std::get<0>(*this)->get_string() < std::get<0>(other)->get_string();
1322  }
1323  if(std::get<1>(*this) != std::get<1>(other))
1324  {
1325  return std::get<1>(*this) < std::get<1>(other);
1326  }
1327  if(std::get<2>(*this) != std::get<2>(other))
1328  {
1329  return std::get<2>(*this) < std::get<2>(other);
1330  }
1331  return false;
1332 }
1333 
1335 {
1336  if(*(std::get<0>(x)) < *(std::get<0>(y)))
1337  {
1338  return true;
1339  }
1340  if(*(std::get<0>(y)) < *(std::get<0>(x)))
1341  {
1342  return false;
1343  }
1344  if(*(std::get<1>(x)) < *(std::get<1>(y)))
1345  {
1346  return true;
1347  }
1348  if(*(std::get<1>(y)) < *(std::get<1>(x)))
1349  {
1350  return false;
1351  }
1352  if(std::get<2>(x) < std::get<2>(y))
1353  {
1354  return true;
1355  }
1356  if(std::get<2>(y) < std::get<2>(x))
1357  {
1358  return false;
1359  }
1360  if(std::get<3>(x) < std::get<3>(y))
1361  {
1362  return true;
1363  }
1364  if(std::get<3>(y) < std::get<3>(x))
1365  {
1366  return false;
1367  }
1368  return false;
1369 }
1370 #endif
#define IUDATA_CONVERTER_STD
void add_connection(structural_objectRef src, structural_objectRef dest)
Create a connection between a source structural object and a destination structural object...
#define DEBUG_LEVEL_VERY_PEDANTIC
extremely verbose debugging print is performed.
a multi unbounded controller
Definition: generic_obj.hpp:75
#define OR_GATE_STD
Data structure representing the entire HLS information.
#define INDENT_DBG_MEX(dbgLevel, curDbgLevel, mex)
We are producing a debug version of the program, so the message is printed;.
Class implementation of the connection module converting the type and the size of connection objects...
TVMValue param[3]
void * top(node_stack *head)
Definition: tree.c:75
#define GET_TYPE(data, vertex_index)
Helper macro returning the type associated with a node.
an element used for connecting the resources (e.g., muxes)
Definition: generic_obj.hpp:78
definition of target of a connection
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.
Base class for all unbounded objects added to datapath.
generic_objRef get(const vertex v) const
Returns reference to funit object associated with this vertex.
#define DEBUG_LEVEL_PEDANTIC
very verbose debugging print is performed.
#define START_PORT_NAME
This file contains the structures needed to manage a graph that will represent the state transition g...
Structure representing the most relevant information about the type of a structural object...
const std::string & get_id() const
Return the identifier associated with the structural_object.
const ParameterConstRef Param
class containing all the parameters
Definition: hls.hpp:169
Base class for all command ports into datapath.
unsigned int get_type() const
Return generic_obj type.
#define GET_CLASS(obj)
Macro returning the actual type of an object.
void AddConnectionCB(const generic_objRef op1, const generic_objRef op2, unsigned int operand, unsigned int port_index, connection_objRef conn)
Creates a connection between two objects.
specify the type of a connection object: UINT
Definition: generic_obj.hpp:86
const structural_objectRef get_circ() const
Get a reference to circ field.
generic_objRef bind_selector_port(direction_type dir, unsigned int mode, const vertex &cond, const OpGraphConstRef data)
#define UUDATA_CONVERTER_STD
std::map< unsigned int, generic_objRef > input_ports
map between input port variable and generic object
a data port (in/out data)
Definition: generic_obj.hpp:77
#define INDENT_OUT_MEX(outLevel, curOutLevel, mex)
virtual void add_to_SM(const HLS_managerRef HLSMgr, const hlsRef HLS, const structural_managerRef SM)
Add the interconnection to the structural representation of the datapath.
generic_objRef get_port(unsigned int var, direction_type dir)
Returns reference to generic object associated to a given variable, for a specific port direction...
unsigned int get_assign(const vertex &v) const
Returns the functional unit assigned to the vertex.
Definition: fu_binding.cpp:242
const std::map< const_param, generic_objRef > & get_constant_objs() const
#define GET_NAME(data, vertex_index)
Helper macro returning the name associated with a node.
const structural_objectRef get_out_sign() const
Gets structural_object of output signal associated to this object.
const HLS_deviceRef HLS_D
reference to the information representing the target for the synthesis
Definition: hls.hpp:107
This class manages command ports into datapath.
std::tuple< std::string, std::string > const_param
definition of the key to deal with constant parameters
AllocationInformationRef allocation_information
Store the technology information.
Definition: hls.hpp:115
const structural_objectRef get_in_port(unsigned int n) const
Return the ith input port.
a converter from signed to signed int
Definition: generic_obj.hpp:83
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...
generic_objRef bind_port(unsigned int var, direction_type dir)
Bind variable to a port object.
unsigned long long determine_bit_level_mux() const
Returns the number of bit-level multiplexers.
Definition of hash function for EdgeDescriptor.
Definition: graph.hpp:1321
virtual void print() const
Function that prints the interconnection binding.
OpVertexSet operations
Set representing the subset of operations in the specification to be implemented. ...
Definition: hls.hpp:102
#define VALUE_PARAMETER
#define UI_ALIGN_ADDER_STD
#define WENABLE_PORT_NAME
Class specification of the manager of the technology library data structures.
ConnectionTarget(generic_objRef tgt, unsigned int tgt_port, unsigned int tgt_port_index)
Constructor.
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)
static technology_nodeRef get_fu(const std::string &fu_name, const HLS_managerConstRef hls_manager)
Returns the technology_node associated with the given operation.
#define ASSIGN_SIGNED_STD
refcount< conn_binding > conn_bindingRef
Refcount definition of the class.
static const std::string get_mode_string(unsigned int _mode)
generic_objRef get_constant_obj(const std::string &value, const std::string &param, unsigned int precision)
Class adopt to represent a mux connection.
bool check_pv_allconnected(structural_objectRef port_i)
check if a port vector has its port bounded to something
a converter from unsigned to unsigned int
Definition: generic_obj.hpp:80
std::map< unsigned int, Selectors > selectors
A set of operation vertices.
Definition: op_graph.hpp:654
void add_data_transfer(const generic_objRef op1, const generic_objRef op2, unsigned int operand, unsigned int port_index, data_transfer data)
Adds a data transfer between two objects.
std::map< const_param, generic_objRef > constant_values
constant values
#define STR(s)
Macro which performs a lexical_cast to a string.
void add_command_ports(const HLS_managerRef HLSMgr, const hlsRef HLS, const structural_managerRef SM)
Add signals from/to controller.
Auxiliary methods for manipulating string.
#define max
Definition: backprop.h:17
s_type type
The type of the port or the signal.
Base class for all interconnection binding algorithms.
unsigned long long size
The size of the object (in bit). The objects having a size are: ports, signals, channels, data, and actions.
Base class for all resources into datapath.
#define CLOCK_PORT_NAME
standard name for ports
const structural_objectRef get_structural_obj() const
Gets structural_object associated to this object.
const OpNodeInfoConstRef CGetOpNodeInfo(const vertex node) const
Returns the info associated with a node.
Definition: op_graph.hpp:843
#define THROW_UNREACHABLE(str_expr)
helper function used to specify that some points should never be reached
Definition: exceptions.hpp:292
fu_bindingRef Rfu
Store the refcounted functional unit binding of the operations.
Definition: hls.hpp:121
const std::string get_string() const
Returns the name associated with the element.
s_type
Define the possible type of a structural object.
Base class for multiplexer into datapath.
Data structure used to store the interconnection binding of datapath elements.
#define ASSIGN_REAL_STD
#define DONE_PORT_NAME
std::map< std::pair< vertex, unsigned int >, generic_objRef > command_input_ports
map between command input port (operation vertex and command type) and generic object ...
void print(std::ostream &os) const
Prints elements into given stream.
a functional resource
Definition: generic_obj.hpp:73
std::map< unsigned int, generic_objRef > output_ports
map between output port variable and generic object
HLSFlowStep_Type
Definition: hls_step.hpp:95
Class specification of the data structures used to manage technology information. ...
const std::string get_path() const
Return a unique identifier of the structural object.
#define TYPE_EXTERNAL
constant identifying the node type of a EXTERNAL operation (a function call)
Definition: op_graph.hpp:95
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.
a converter from real to real int
Definition: generic_obj.hpp:84
virtual void print(std::ostream &os) const
Print the structural_object (for debug purpose)
std::tuple< unsigned int, unsigned int, vertex, vertex, vertex > data_transfer
definition of the data transfer (tree_node, precision, from, to, data_transferred, current_op).
#define index(x, y)
Definition: Keccak.c:74
redefinition of set to manage ordered/unordered structures
static unsigned unique_id
const std::map< vertex, generic_objRef > & get_mu_ctrls() const
boost::graph_traits< graph >::vertex_descriptor vertex
vertex definition.
Definition: graph.hpp:1303
unsigned offset[NUM_VERTICES+1]
Definition: graph.h:3
#define IIDATA_CONVERTER_STD
#define T_COND
constant used to represent control edges representing a true edge of a conditional statement...
std::map< vertex, generic_objRef > command_output_ports
map between output port variable and generic object
bool operator<(const ConnectionTarget &other) const
virtual ~conn_binding()
Destructor.
virtual enum so_kind get_kind() const =0
Virtual function used to find the real type of a structural_object instance.
Base class for all dataports into datapath.
#define FFDATA_CONVERTER_STD
static std::string NormalizeTypename(const std::string &id)
Return normalized name of types and variables.
#define UIDATA_CONVERTER_STD
primary ports of datapath.
This package is used by all HLS packages to manage resource constraints and characteristics.
void specialise_mux(const generic_objRef mux, unsigned int bits_tgt) const
Specialize a multiplexer according to the type of the variables crossing it.
conn_binding(const BehavioralHelperConstRef BH, const ParameterConstRef parameters)
Constructor.
void mux_connection(const hlsRef HLS, const structural_managerRef SM)
Add the mux-based interconnection.
static conn_bindingRef create_conn_binding(const HLS_managerRef _HLSMgr, const hlsRef _HLS, const BehavioralHelperConstRef _BH, const ParameterConstRef _parameters)
factory method to create the right conn_binding depending on the flow
#define THROW_ERROR(str_expr)
helper function used to throw an error in a standard way
Definition: exceptions.hpp:263
void type_resize(unsigned long long new_bit_size)
Just resize the size of the bits of the object.
std::map< ConnectionTarget, ConnectionSources > conn_variables
map between the input of the unit and the corresponding incoming connections.
static void check_bitwidth(unsigned long long prec)
check if the maximum bitwidth used for registers, busses, muxes, etc. is compatible with prec ...
This file collects some utility functions.
std::map< vertex, std::map< unsigned int, generic_objRef > > activation_ports
map between a vertex and the corresponding activation signal
structural_objectRef add_constant(std::string id, structural_objectRef owner, structural_type_descriptorRef type, std::string value, unsigned int treenode=0)
Create a new constant;.
structural_objectRef add_module_from_technology_library(const std::string &id, const std::string &fu_name, const std::string &library_name, const structural_objectRef owner, const technology_managerConstRef TM)
Create a new object starting from a library component.
conn_implementation_map conn_implementation
map between the connection <src, tgt, tgt_port, tgt_port_index> and the corresponding object ...
bool operator()(const connection &x, const connection &y) const
Compare position of two connections.
void set_out_sign(const structural_objectRef &out_sign_)
Sets structural_object of output signal associated to this object.
std::tuple< generic_objRef, generic_objRef, unsigned int, unsigned int > connection
connection between two objects (<src, tgt, tgt_port, tgt_port_index>)
Class implementation of the adder connection module.
#define GET_TYPE_SIZE(structural_obj)
Macro returning the size of the type of a structural object.
const structural_type_descriptorRef & get_typeRef() const
Return the type descriptor of the structural_object.
#define ASSIGN_UNSIGNED_STD
static structural_objectRef add_sign(std::string id, structural_objectRef owner, structural_type_descriptorRef sign_type, unsigned int treenode=0)
Create a new signal.
#define UI_ADDER_STD
const structural_objectRef get_owner() const
Return the owner.
#define OUTPUT_LEVEL_VERY_PEDANTIC
verbose debugging print is performed.
Data structure used to store the functional-unit binding of the vertexes.
const OpGraphConstRef CGetOpGraph(FunctionBehavior::graph_type gt) const
This method returns the operation graphs.
const std::map< ConnectionTarget, ConnectionSources > & get_data_transfers() const
Returns the map containing all the data transfers.
void add_sparse_logic_dp(const hlsRef HLS, const structural_managerRef SM, const HLS_managerRef HLSMgr)
Add sparse logic to the datapath.
Template borrowed from the ANTLR library by Terence Parr (http://www.jGuru.com - Software rights: htt...
Definition: refcount.hpp:94
char str[25]
Definition: fixedptc.c:8
a converter from signed to unsigned int
Definition: generic_obj.hpp:82
this class is used to manage the command-line or XML options.
void add_datapath_connection(const technology_managerRef TM, const structural_managerRef SM, const structural_objectRef src, const structural_objectRef port_tgt, unsigned int conn_type)
Add a data converter, if needed, between two objects of the structural representation of the datapath...
const BehavioralHelperConstRef BH
reference to the behavioral helper associated with the specification
CustomOrderedSet< generic_objRef, GenericObjSorter > sparse_logic
set containing all the sparse logic contained into the datapath
#define MUX_GATE_STD
unsigned int functionId
this is the identifier of the function to be implemented
Definition: hls.hpp:87
an adder object representation used to compute some addresses
Definition: generic_obj.hpp:79
#define RESET_PORT_NAME
Class implementation of the structural_manager.
uint32_t sign
StateTransitionGraphManagerRef STG
Store the refcounted state transition graph.
Definition: hls.hpp:124
enum { IN=0, OUT } direction_type
direction port identifier
x
Return the smallest n such that 2^n >= _x.
This package is used by all HLS packages to manage resource constraints and characteristics.
generic_objRef bind_command_port(const vertex &ver, direction_type dir, unsigned int mode, const OpGraphConstRef g)
Bind vertex to a command port object.
virtual void mux_allocation(const hlsRef HLS, const structural_managerRef SM, structural_objectRef src, structural_objectRef tgt, connection_objRef conn)
Add multiplexers to the structural representation of the datapath.
int debug_level
control the verbosity during the debugging
Datastructure to describe functions allocation in high-level synthesis.
Base class for all register into datapath.
specify the type of a connection object: INT
Definition: generic_obj.hpp:85
#define DEBUG_LEVEL_VERBOSE
verbose debugging print is performed.
std::map< std::string, structural_objectRef > converters
data type converters
Data structure definition for high-level synthesis flow.
This class describes a generic module.
const std::string get_name() const
Returns the name of the type descriptor.
int output_level
control the output verbosity
conn_bindingRef Rconn
Store the refcounted interconnection of datapath elements.
Definition: hls.hpp:139
unsigned int get_index(const vertex &v) const
Returns the index of functional unit assigned to the vertex.
Definition: fu_binding.cpp:261
a converter from unsigned to signed int
Definition: generic_obj.hpp:81
Class specification of the manager of the tree structures extracted from the raw file.
refcount< generic_obj > generic_objRef
RefCount definition for generic_obj class.
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.
void cleanInternals()
This class is a specialization of generic_obj class to represent a multiplexer into the datapath...
Definition: mux_obj.hpp:57
#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:53 for PandA-2024.02 by doxygen 1.8.13