PandA-2024.02
fsm_controller.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 "fsm_controller.hpp"
42 #include "BambuParameter.hpp"
44 #include "basic_block.hpp"
45 #include "behavioral_helper.hpp"
46 #include "commandport_obj.hpp"
47 #include "conn_binding.hpp"
48 #include "connection_obj.hpp"
49 #include "copyrights_strings.hpp"
50 #include "custom_map.hpp"
51 #include "custom_set.hpp"
52 #include "dbgPrintHelper.hpp"
53 #include "exceptions.hpp"
54 #include "fu_binding.hpp"
55 #include "function_behavior.hpp"
56 #include "funit_obj.hpp"
57 #include "hls.hpp"
58 #include "hls_manager.hpp"
59 #include "liveness.hpp"
60 #include "multi_unbounded_obj.hpp"
61 #include "mux_obj.hpp"
62 #include "op_graph.hpp"
63 #include "reg_binding.hpp"
64 #include "register_obj.hpp"
65 #include "schedule.hpp"
69 #include "string_manipulation.hpp" // for GET_CLASS
70 #include "structural_manager.hpp"
71 #include "structural_objects.hpp"
72 #include "technology_manager.hpp"
73 #include "technology_node.hpp"
74 #include "tree_helper.hpp"
75 #include "tree_manager.hpp"
76 #include "tree_node.hpp"
77 #include "tree_reindex.hpp"
78 #include <deque>
79 #include <iosfwd>
80 #include <list>
81 #include <utility>
82 #include <vector>
83 
84 fsm_controller::fsm_controller(const ParameterConstRef _Param, const HLS_managerRef _HLSMgr, unsigned int _funId,
85  const DesignFlowManagerConstRef _design_flow_manager,
86  const HLSFlowStep_Type _hls_flow_step_type)
87  : ControllerCreatorBaseStep(_Param, _HLSMgr, _funId, _design_flow_manager, _hls_flow_step_type)
88 {
89  debug_level = parameters->get_class_debug_level(GET_CLASS(*this), DEBUG_LEVEL_NONE);
90 }
91 
93 
95 {
96  THROW_ASSERT(HLS->STG, "State transition graph not created");
97 
99  PRINT_DBG_MEX(DEBUG_LEVEL_VERBOSE, debug_level, "FSM based controller creation");
100  const FunctionBehaviorConstRef FB = HLSMgr->CGetFunctionBehavior(funId);
101 
102  const std::string function_name = FB->CGetBehavioralHelper()->get_function_name();
104  structural_type_descriptorRef module_type =
105  structural_type_descriptorRef(new structural_type_descriptor("controller_" + function_name));
107 
108  SM->set_top_info("Controller_i", module_type);
109  structural_objectRef circuit = SM->get_circ();
110  // Now the top circuit is created, just as an empty box. <circuit> is a reference to the structural object that
111  // will contain all the circuit components
112 
113  circuit->set_black_box(false);
114 
116  GetPointer<module>(circuit)->set_description("FSM based controller description for " + function_name);
117  GetPointer<module>(circuit)->set_copyright(GENERATED_COPYRIGHT);
118  GetPointer<module>(circuit)->set_authors("Component automatically generated by bambu");
119  GetPointer<module>(circuit)->set_license(GENERATED_LICENSE);
120 
121  // Add clock, reset, done and command ports
122  this->add_common_ports(circuit, SM);
123 
124  PRINT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "Creating state machine representations...");
125  std::string state_representation;
126  this->create_state_machine(state_representation);
127  add_correct_transition_memory(state_representation, SM); // if CS is activated some register are memory
128 
129  PRINT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "Machine encoding");
130  PRINT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, state_representation);
132 
133  PRINT_DBG_MEX(DEBUG_LEVEL_VERBOSE, debug_level, "Circuit created without errors!");
134  out_ports.clear();
135  mu_ports.clear();
136  cond_ports.clear();
138 }
139 
140 static std::string input_vector_to_string(const std::vector<long long int>& to_be_printed, bool with_comma)
141 {
142  std::string output;
143  for(unsigned int i = 0; i < to_be_printed.size(); i++)
144  {
145  output += (to_be_printed[i] == default_COND ? "-" : std::to_string(to_be_printed[i]));
146  if(i != (to_be_printed.size() - 1) && with_comma)
147  {
148  output += ",";
149  }
150  }
151  return output;
152 }
153 
154 void fsm_controller::create_state_machine(std::string& parse)
155 {
156  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "-->Create state machine");
157  const auto stg = HLS->STG->CGetStg();
158  const auto astg = HLS->STG->CGetAstg();
159  const auto FB = HLSMgr->CGetFunctionBehavior(funId);
160  const auto data = FB->CGetOpGraph(FunctionBehavior::CFG);
161  const auto fsymbol = FB->CGetBehavioralHelper()->GetMangledFunctionName();
162  const auto func_arch = HLSMgr->module_arch->GetArchitecture(fsymbol);
163  const auto is_dataflow_top = func_arch &&
164  func_arch->attrs.find(FunctionArchitecture::func_dataflow) != func_arch->attrs.end() &&
165  func_arch->attrs.find(FunctionArchitecture::func_dataflow)->second == "top";
166 
167  const auto entry = HLS->STG->get_entry_state();
168  THROW_ASSERT(boost::out_degree(entry, *stg) == 1, "Non deterministic initial state");
170  const auto first_state = boost::target(*boost::out_edges(entry, *stg).first, *stg);
172  parse += stg->CGetStateInfo(first_state)->name + " " + RESET_PORT_NAME + " " + START_PORT_NAME + " " +
173  CLOCK_PORT_NAME + ";\n";
174 
175  const auto& selectors = HLS->Rconn->GetSelectors();
176 
177  std::map<vertex, std::vector<long long int>> present_state;
178  CustomOrderedSet<unsigned int> unbounded_ports;
179 
181  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "-->Computation of default output of each state");
182  std::list<vertex> working_list;
183  astg->TopologicalSort(working_list);
184  THROW_ASSERT(std::find(working_list.begin(), working_list.end(), first_state) != working_list.end(),
185  "unexpected case");
186  working_list.erase(std::find(working_list.begin(), working_list.end(), first_state));
187  working_list.push_front(first_state);
188 
189  std::map<vertex, std::vector<bool>> state_Xregs;
190  std::map<unsigned int, unsigned int> wren_list;
191  std::map<unsigned int, unsigned int> register_selectors;
192 
193  std::map<unsigned int, CustomUnorderedSet<vertex>> loop_map;
194  std::map<unsigned int, std::list<vertex>> loop_executing_ops;
195  std::map<unsigned int, std::list<vertex>> loop_starting_ops;
196  CustomUnorderedSet<unsigned int> analyzed_loops;
197  std::map<unsigned int, vertex> loop_last_state;
198 
199  // group vertices under their respective loopId
200  if(FB->is_pipeline_enabled())
201  {
202  for(const auto& v : working_list)
203  {
204  auto info = astg->CGetStateInfo(v);
205  // checking only the pipeline_enabled condition is sufficient
206  // since this step is taken only for stallable pipelines
207  if(info->loopId != 0)
208  {
209  loop_map[info->loopId].insert(v);
210  }
211  }
212  }
213 
214  // detect entry and exit node for each loop
215  for(auto loop : loop_map)
216  {
217  auto loop_first_state = first_state;
218 
219 #if HAVE_ASSERTS
220  bool found_first = false;
221  bool found_last = false;
222 #endif
223 
224  for(auto v : loop_map[get<0>(loop)])
225  {
226  BOOST_FOREACH(EdgeDescriptor ie, boost::in_edges(v, *astg))
227  {
228  if(stg->CGetStateInfo(boost::source(ie, *astg))->loopId != std::get<0>(loop))
229  {
230  THROW_ASSERT(not found_first, "A loop has multiple first states");
231 #if HAVE_ASSERTS
232  found_first = true;
233 #endif
234  loop_first_state = v;
235  }
236  }
237  bool all_external = true;
238  BOOST_FOREACH(EdgeDescriptor lst, boost::out_edges(v, *astg))
239  {
240  all_external = all_external && astg->CGetStateInfo(boost::target(lst, *astg))->loopId != std::get<0>(loop);
241  if(!all_external)
242  {
243  break;
244  }
245  }
246  if(all_external)
247  {
248  THROW_ASSERT(!found_last, "A loop has multiple outgoing edges");
249 #if HAVE_ASSERTS
250  found_last = true;
251 #endif
252  loop_last_state[std::get<0>(loop)] = v;
253  }
254  for(auto op : stg->CGetStateInfo(v)->executing_operations)
255  {
256  loop_executing_ops[get<0>(loop)].push_front(op);
257  }
258  }
259  THROW_ASSERT(found_last, "No last state was detected for loop " + std::to_string(get<0>(loop)));
260  THROW_ASSERT(found_first, "No first state was detected for loop " + std::to_string(get<0>(loop)));
261  loop_starting_ops[get<0>(loop)] = stg->CGetStateInfo(loop_first_state)->starting_operations;
262  }
263 
264  std::map<unsigned int, std::map<vertex, std::set<unsigned int>>> bypass_signals;
265  for(const auto& v : working_list)
266  {
267  state_Xregs[v] = std::vector<bool>(HLS->Rreg->get_used_regs(), true);
268  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "-->Analyzing state " + astg->CGetStateInfo(v)->name);
269 
270  if(analyzed_loops.find(stg->CGetStateInfo(v)->loopId) == analyzed_loops.end())
271  {
273  "Analyzing loop " + std::to_string(stg->CGetStateInfo(v)->loopId));
274  present_state[v] = std::vector<long long int>(out_num, 0);
275  if(stg->CGetStateInfo(v)->loopId != 0 && FB->is_pipeline_enabled())
276  {
277  analyzed_loops.insert(stg->CGetStateInfo(v)->loopId);
278  }
279  if(selectors.find(conn_binding::IN) != selectors.end())
280  {
281  for(const auto& s : selectors.at(conn_binding::IN))
282  {
283 #ifndef NDEBUG
284  std::map<vertex, CustomOrderedSet<vertex>> activations_check;
285 #endif
286  const auto& activations = GetPointer<commandport_obj>(s.second)->get_activations();
287  for(const auto& a : activations)
288  {
289 #ifndef NDEBUG
290  if(activations_check.find(std::get<0>(a)) != activations_check.end())
291  {
292  THROW_ASSERT(!activations_check.find(std::get<0>(a))->second.empty(),
293  "empty set not expected here");
294  if(activations_check.at(std::get<0>(a)).find(std::get<1>(a)) ==
295  activations_check.at(std::get<0>(a)).end())
296  {
297  if(std::get<1>(a) == NULL_VERTEX)
298  {
299  THROW_ERROR("non compatible transitions added");
300  }
301  else if(activations_check.at(std::get<0>(a)).find(NULL_VERTEX) !=
302  activations_check.at(std::get<0>(a)).end())
303  {
304  THROW_ERROR("non compatible transitions added");
305  }
306  else
307  {
308  activations_check[std::get<0>(a)].insert(std::get<1>(a));
309  }
310  }
311  else
312  {
313  THROW_ERROR("activation already added");
314  }
315  }
316  else
317  {
318  activations_check[std::get<0>(a)].insert(std::get<1>(a));
319  }
320 #endif
321  if(std::get<0>(a) == v && (stg->CGetStateInfo(v)->loopId == 0 || !FB->is_pipeline_enabled()))
322  {
323  present_state[v][out_ports[s.second]] = 1;
324  }
325  else if(loop_map[stg->CGetStateInfo(v)->loopId].find(std::get<0>(a)) !=
326  loop_map[stg->CGetStateInfo(v)->loopId].end() &&
327  stg->CGetStateInfo(v)->loopId != 0 && FB->is_pipeline_enabled())
328  {
329  present_state[v][out_ports[s.second]] = 1;
330  }
331  }
332  }
333  }
334 
336  const auto TreeM = HLSMgr->get_tree_manager();
337  const auto& operations = (stg->CGetStateInfo(v)->loopId == 0 || !FB->is_pipeline_enabled()) ?
338  astg->CGetStateInfo(v)->executing_operations :
339  loop_executing_ops[stg->CGetStateInfo(v)->loopId];
340  for(const auto& op : operations)
341  {
342  active_fu.insert(HLS->Rfu->get(op));
343  const auto tn = HLS->allocation_information->get_fu(HLS->Rfu->get_assign(op));
344  const auto op_tn = GetPointer<functional_unit>(tn)->get_operation(
345  tree_helper::NormalizeTypename(data->CGetOpNodeInfo(op)->GetOperation()));
346  THROW_ASSERT(GetPointer<operation>(op_tn)->time_m,
347  "Time model not available for operation: " + GET_NAME(data, op));
348  const auto& CM = GetPointer<functional_unit>(tn)->CM;
349  if(!CM)
350  {
351  continue;
352  }
353  const auto top = CM->get_circ();
354  THROW_ASSERT(top, "expected");
355  const auto fu_module = GetPointer<module>(top);
356  THROW_ASSERT(fu_module, "expected");
357  const auto start_port_i = fu_module->find_member(START_PORT_NAME, port_o_K, top);
358  const auto done_port_i = fu_module->find_member(DONE_PORT_NAME, port_o_K, top);
360  if(!GetPointer<operation>(op_tn)->is_bounded() && (!start_port_i || !done_port_i))
361  {
362  THROW_ERROR("Unbounded operations have to have both done_port and start_port ports!" +
363  STR(TreeM->CGetTreeNode(data->CGetOpNodeInfo(op)->GetNodeId())));
364  }
365 
366  // since v now has to wait for loop completion, every operation will be unbounded
367  bool is_starting_operation = true;
368  if(!is_dataflow_top && (stg->CGetStateInfo(v)->loopId == 0 || !FB->is_pipeline_enabled()))
369  {
370  const auto& starting_ops = stg->CGetStateInfo(v)->starting_operations;
371  is_starting_operation = std::find(starting_ops.begin(), starting_ops.end(), op) != starting_ops.end();
372  }
373 
374  if((!GetPointer<operation>(op_tn)->is_bounded()))
375  {
376  auto node = TreeM->CGetTreeNode(data->CGetOpNodeInfo(op)->GetNodeId());
377  if(node->get_kind() == gimple_assign_K)
378  {
379  const auto nodeGA = GetPointerS<const gimple_assign>(node);
380  const auto ssaIndex = GET_INDEX_CONST_NODE(nodeGA->op0);
382  {
383  const auto storage_value_index =
385  const auto written_reg = HLS->Rreg->get_register(storage_value_index);
386  const auto doneCommand =
387  HLS->Rconn->bind_selector_port(conn_binding::OUT, commandport_obj::UNBOUNDED, op, data);
388  const auto doneVertex = GetPointer<commandport_obj>(doneCommand)->get_vertex();
389  THROW_ASSERT(cond_ports.find(doneVertex) != cond_ports.end(), "unexpected condition");
390  const auto reg_obj = HLS->Rreg->get(written_reg);
391  const auto sel_port = HLS->Rconn->bind_selector_port(conn_binding::IN, commandport_obj::WRENABLE,
392  reg_obj, written_reg);
393  THROW_ASSERT(out_ports.find(sel_port) != out_ports.end(), "");
394  bypass_signals[1 + out_ports.find(sel_port)->second][v].insert(
395  cond_ports.find(doneVertex)->second);
396  }
397  }
398  }
399 
400  if((!GetPointer<operation>(op_tn)->is_bounded() || start_port_i) &&
401  (!stg->CGetStateInfo(v)->is_dummy || is_dataflow_top) && is_starting_operation)
402  {
403  const auto unbounded_port =
404  out_ports[HLS->Rconn->bind_selector_port(conn_binding::IN, commandport_obj::UNBOUNDED, op, data)];
405  unbounded_ports.insert(unbounded_port);
406  present_state[v][unbounded_port] = 1;
407  }
408  }
409 
410  if(stg->CGetStateInfo(v)->loopId == 0 || !FB->is_pipeline_enabled())
411  {
412  for(auto in0 : HLS->Rliv->get_live_in(v))
413  {
415  {
416  const auto storage_value_index = HLS->storage_value_information->get_storage_value_index(v, in0);
417  const auto accessed_reg = HLS->Rreg->get_register(storage_value_index);
418  state_Xregs[v][accessed_reg] = false;
419  }
420  }
421 
422  if(selectors.find(conn_binding::IN) != selectors.end())
423  {
424  for(const auto& s : selectors.at(conn_binding::IN))
425  {
426  if(s.second->get_type() == generic_obj::COMMAND_PORT)
427  {
428  const auto current_port = GetPointer<commandport_obj>(s.second);
429  // compute X values for wr_enable signals
430  if(current_port->get_command_type() == commandport_obj::command_type::WRENABLE)
431  {
432  const auto reg_obj = GetPointer<register_obj>(current_port->get_elem());
433  wren_list.insert(std::make_pair(reg_obj->get_register_index(), out_ports[s.second]));
434  if(parameters->IsParameter("enable-FSMX") && parameters->GetParameter<int>("enable-FSMX") == 1)
435  {
436  if(state_Xregs[v][reg_obj->get_register_index()] && v != first_state)
437  {
438  present_state[v][out_ports[s.second]] = 2;
440  "Set X value for wr_en on register reg_" +
441  std::to_string(reg_obj->get_register_index()));
442  }
443  }
444  }
445  else if(current_port->get_command_type() == commandport_obj::command_type::SELECTOR)
446  {
447  const auto selector_slave = current_port->get_elem();
448  if(GetPointer<mux_obj>(selector_slave))
449  {
450  auto mux_slave = GetPointer<mux_obj>(selector_slave)->get_final_target();
451  if(mux_slave->get_type() == generic_obj::resource_type::REGISTER)
452  {
453  const auto reg_index = GetPointer<register_obj>(mux_slave)->get_register_index();
454  register_selectors[out_ports[s.second]] = reg_index;
455  }
456  else if(mux_slave->get_type() == generic_obj::resource_type::FUNCTIONAL_UNIT &&
457  active_fu.find(mux_slave) == active_fu.end())
458  {
459  if(parameters->IsParameter("enable-FSMX") &&
460  parameters->GetParameter<int>("enable-FSMX") == 1)
461  {
462  present_state[v][out_ports[s.second]] = 2;
463  }
464  }
465  }
466  }
467  }
468  }
469  }
470  }
471  }
472 
474  "---default output after considering unbounded: " + container_to_string(present_state[v], " "));
476  }
477  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "<--Computed default output of each state");
478 
480  bool first_io = true;
481  for(const auto& vio : bypass_signals)
482  {
483  if(first_io)
484  {
485  first_io = false;
486  }
487  else
488  {
489  parse += ":";
490  }
491  parse += STR(vio.first) + "=";
492  bool first_vi = true;
493  for(const auto& vi : vio.second)
494  {
495  if(first_vi)
496  {
497  first_vi = false;
498  }
499  else
500  {
501  parse += ",";
502  }
503  parse += stg->CGetStateInfo(vi.first)->name + ">";
504  bool first_i = true;
505  for(const auto& i : vi.second)
506  {
507  if(first_i)
508  {
509  first_i = false;
510  }
511  else
512  {
513  parse += "<";
514  }
515  parse += STR(i);
516  }
517  }
518  }
519  parse += ";\n";
520 
521  analyzed_loops.clear();
522 
523  const tree_managerRef TreeM = HLSMgr->get_tree_manager();
524  for(const auto& v : working_list)
525  {
526  // for every loop controller set the proper transition depending on the done port
527  if(HLS->STG->get_entry_state() == v or HLS->STG->get_exit_state() == v)
528  {
529  continue;
530  }
531 
532  // skip all but one state per loop
533  if(analyzed_loops.find(stg->CGetStateInfo(v)->loopId) == analyzed_loops.end())
534  {
535  if(stg->CGetStateInfo(v)->loopId != 0 && FB->is_pipeline_enabled())
536  {
537  analyzed_loops.insert(stg->CGetStateInfo(v)->loopId);
538  }
539  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "-->Analyzing state " + stg->CGetStateInfo(v)->name);
540 
541  parse += stg->CGetStateInfo(v)->name + " 0" + input_vector_to_string(present_state[v], false);
542 
543  std::list<EdgeDescriptor> sorted;
544  EdgeDescriptor default_edge;
545  bool found_default = false;
546  vertex ver;
547  if(stg->CGetStateInfo(v)->loopId == 0 || !FB->is_pipeline_enabled())
548  {
549  ver = v;
550  }
551  else
552  {
553  ver = loop_last_state[stg->CGetStateInfo(v)->loopId];
554  }
555  BOOST_FOREACH(EdgeDescriptor oe, boost::out_edges(ver, *stg))
556  {
557  if(!found_default)
558  {
559  if(stg->CGetTransitionInfo(oe)->get_has_default())
560  {
561  found_default = true;
562  default_edge = oe;
563  }
564  if(!found_default)
565  {
566  sorted.push_back(oe);
567  }
568  }
569  else
570  {
571  sorted.push_back(oe);
572  }
573  }
574  if(found_default)
575  {
576  sorted.push_back(default_edge);
577  }
578  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "---Sorted next states");
579 
580  bool done_port_is_registered = HLS->registered_done_port;
581  for(const auto e : sorted)
582  {
584  "-->Considering successor state " + stg->CGetStateInfo(boost::target(e, *stg))->name);
585  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "---Number of inputs is " + std::to_string(in_num));
586  std::vector<std::string> in(in_num, "-");
587 
588  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Analyzing condition");
589  auto transitionType = stg->CGetTransitionInfo(e)->get_type();
590  if(transitionType == DONTCARE_COND)
591  {
592  ; // do nothing
593  }
594  else if(transitionType == TRUE_COND)
595  {
596  auto op = stg->CGetTransitionInfo(e)->get_operation();
597  THROW_ASSERT(cond_ports.find(op) != cond_ports.end(), "the port is missing");
598  THROW_ASSERT(in[cond_ports.find(op)->second] == "-", "two different values for the same condition port");
599  in[cond_ports.find(op)->second] = "1";
600  }
601  else if(transitionType == FALSE_COND)
602  {
603  auto op = stg->CGetTransitionInfo(e)->get_operation();
604  THROW_ASSERT(cond_ports.find(op) != cond_ports.end(), "the port is missing");
605  THROW_ASSERT(in[cond_ports.find(op)->second] == "-", "two different values for the same condition port");
606  in[cond_ports.find(op)->second] = "0";
607  }
608  else if(transitionType == ALL_FINISHED)
609  {
610  auto ops = stg->CGetTransitionInfo(e)->get_operations();
611  if(ops.size() == 1)
612  {
613  auto op = *(ops.begin());
614  THROW_ASSERT(cond_ports.find(op) != cond_ports.end(), "the port is missing");
615  THROW_ASSERT(in[cond_ports.find(op)->second] == "-",
616  "two different values for the same condition port");
617  in[cond_ports.find(op)->second] = "1";
618  }
619  else
620  {
621  auto state = stg->CGetTransitionInfo(e)->get_ref_state();
622  THROW_ASSERT(mu_ports.find(state) != mu_ports.end(), "the port is missing");
623  THROW_ASSERT(in[mu_ports.find(state)->second] == "-",
624  "two different values for the same condition port");
625  in[mu_ports.find(state)->second] = "1";
626  }
627  }
628  else if(transitionType == NOT_ALL_FINISHED)
629  {
630  auto ops = stg->CGetTransitionInfo(e)->get_operations();
631  if(ops.size() == 1)
632  {
633  auto op = *(ops.begin());
634  THROW_ASSERT(cond_ports.find(op) != cond_ports.end(), "the port is missing");
635  THROW_ASSERT(in[cond_ports.find(op)->second] == "-",
636  "two different values for the same condition port");
637  in[cond_ports.find(op)->second] = "0";
638  }
639  else
640  {
641  auto state = stg->CGetTransitionInfo(e)->get_ref_state();
642  THROW_ASSERT(mu_ports.find(state) != mu_ports.end(), "the port is missing");
643  THROW_ASSERT(in[mu_ports.find(state)->second] == "-",
644  "two different values for the same condition port");
645  in[mu_ports.find(state)->second] = "0";
646  }
647  }
648  else if(transitionType == CASE_COND)
649  {
650  auto op = stg->CGetTransitionInfo(e)->get_operation();
651  THROW_ASSERT(cond_ports.find(op) != cond_ports.end(), "the port is missing");
652  THROW_ASSERT(in[cond_ports.find(op)->second] == "-", "two different values for the same condition port");
653  std::string value = in[cond_ports.find(op)->second];
654  THROW_ASSERT(value == "-", "two different values for the same condition port");
655  auto labels = stg->CGetTransitionInfo(e)->get_labels();
656  for(auto label : labels)
657  {
658  if(value == "-")
659  {
660  value = get_guard_value(TreeM, label, op, data);
661  }
662  else
663  {
664  value += "|" + get_guard_value(TreeM, label, op, data);
665  }
666  }
667  if(stg->CGetTransitionInfo(e)->get_has_default())
668  {
669  if(value == "-")
670  {
671  value = STR(default_COND);
672  }
673  else
674  {
675  value += "|" + STR(default_COND);
676  }
677  }
678  in[cond_ports.find(op)->second] = value;
679  }
680  else
681  {
682  THROW_ERROR("transition type not supported yet");
683  }
684  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "<--Analyzed conditions");
685 
686  parse += " : ";
687  for(auto in_it = in.begin(); in_it != in.end(); ++in_it)
688  {
689  if(in_it == in.begin())
690  {
691  parse += *in_it;
692  }
693  else
694  {
695  parse += "," + *in_it;
696  }
697  }
698 
699  vertex tgt = boost::target(e, *stg);
700  bool last_transition = tgt == HLS->STG->get_exit_state();
701  vertex next_state = last_transition ? first_state : tgt;
702  bool assert_done_port = false;
703  if(done_port_is_registered)
704  {
705  BOOST_FOREACH(EdgeDescriptor os, boost::out_edges(tgt, *stg))
706  {
707  if(boost::target(os, *stg) == HLS->STG->get_exit_state())
708  {
709  assert_done_port = true;
710  break;
711  }
712  }
713  }
714  else
715  {
716  assert_done_port = last_transition;
717  }
718 
719  std::vector<long long int> transition_outputs(out_num, default_COND);
720  for(unsigned int k = 0; k < out_num; k++)
721  {
722  if(present_state[v][k] == 1 && unbounded_ports.find(k) == unbounded_ports.end())
723  {
724  transition_outputs[k] = 0;
725  }
726  }
727 
728  if(selectors.find(conn_binding::IN) != selectors.end())
729  {
730  for(const auto& s : selectors.at(conn_binding::IN))
731  {
732  auto current_port = GetPointer<commandport_obj>(s.second);
733  if(current_port->get_command_type() == commandport_obj::command_type::MULTI_UNBOUNDED_ENABLE)
734  {
735  auto mu_obj = GetPointer<multi_unbounded_obj>(current_port->get_elem());
736  if(v == mu_obj->get_fsm_state())
737  {
738  transition_outputs[out_ports[s.second]] = 1;
739  }
740  }
741  const auto& activations = current_port->get_activations();
742  for(const auto& a : activations)
743  {
744  THROW_ASSERT(v != NULL_VERTEX && std::get<0>(a) != NULL_VERTEX, "error on source vertex");
745  bool source_activation = false;
746  if(stg->CGetStateInfo(v)->loopId == 0 || !FB->is_pipeline_enabled())
747  {
748  source_activation = std::get<0>(a) == v;
749  }
750  else
751  {
752  source_activation = loop_map[stg->CGetStateInfo(v)->loopId].find(std::get<0>(a)) !=
753  loop_map[stg->CGetStateInfo(v)->loopId].end();
754  }
755  if(source_activation && (std::get<1>(a) == tgt || std::get<1>(a) == NULL_VERTEX))
756  {
757  THROW_ASSERT(present_state[v][out_ports[s.second]] != 0, "unexpected condition");
758  transition_outputs[out_ports[s.second]] = 1;
759  }
760  }
761  }
762 
763  for(auto const& sel : register_selectors)
764  {
765  if(parameters->IsParameter("enable-FSMX") && parameters->GetParameter<int>("enable-FSMX") == 1)
766  {
767  if(wren_list.find(sel.second) != wren_list.end() &&
768  ((transition_outputs[wren_list[sel.second]] == 0) ||
769  (transition_outputs[wren_list[sel.second]] == default_COND &&
770  present_state[v][wren_list[sel.second]] != 1)))
771  {
772  transition_outputs[sel.first] = 2;
773  }
774  }
775  }
776  }
777 
778  for(unsigned int k = 0; k < out_num; k++)
779  {
780  if(present_state[v][k] == transition_outputs[k])
781  {
782  transition_outputs[k] = default_COND;
783  }
784  else if(present_state[v][k] != transition_outputs[k] && present_state[v][k] == 1 &&
785  transition_outputs[k] == 0)
786  {
787  // std::cerr << "k " << k << " to " << HLS->STG->get_state_name(tgt)<< std::endl;
788  // abort();
789  }
790  }
791 
792  parse += " " + stg->CGetStateInfo(next_state)->name + " " + (assert_done_port ? "1" : "-") +
793  input_vector_to_string(transition_outputs, false);
795  }
796 
797  parse += "; ";
798 
799  parse += "\n";
800  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "<--Analyzed state " + stg->CGetStateInfo(v)->name);
801  }
802  }
803 
804  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "<--Created state machine");
805  INDENT_DBG_MEX(DEBUG_LEVEL_PEDANTIC, debug_level, "---Finite_state_machine representation\n" + parse);
806 }
807 
808 std::string fsm_controller::get_guard_value(const tree_managerRef TM, const unsigned int index, vertex op,
809  const OpGraphConstRef data)
810 {
811  if((GET_TYPE(data, op) & TYPE_MULTIIF) != 0)
812  {
813  unsigned int node_id = data->CGetOpNodeInfo(op)->GetNodeId();
814  unsigned int pos = tree_helper::get_multi_way_if_pos(TM, node_id, index);
815  return "&" + STR(pos);
816  }
817  else
818  {
819  tree_nodeRef node = TM->get_tree_node_const(index);
820  THROW_ASSERT(node->get_kind() == case_label_expr_K, "case_label_expr expected " + GET_NAME(data, op));
821  auto cle = GetPointer<case_label_expr>(node);
822  THROW_ASSERT(cle->op0, "guard expected in a case_label_expr");
823  THROW_ASSERT(GetPointer<integer_cst>(GET_NODE(cle->op0)),
824  "expected integer_cst object as guard in a case_label_expr");
825  const auto low_result = tree_helper::GetConstValue(cle->op0);
826  integer_cst_t high_result = 0;
827  if(cle->op1)
828  {
829  THROW_ASSERT(GetPointer<integer_cst>(GET_NODE(cle->op1)),
830  "expected integer_cst object as guard in a case_label_expr");
831  high_result = tree_helper::GetConstValue(cle->op1);
832  }
833  if(high_result == 0)
834  {
835  return STR(low_result);
836  }
837  else
838  {
839  std::string res_string;
840  for(auto current_value = low_result; current_value <= high_result; ++current_value)
841  {
842  if(current_value == low_result)
843  {
844  res_string = STR(current_value);
845  }
846  else
847  {
848  res_string += "|" + STR(current_value);
849  }
850  }
851  return res_string;
852  }
853  }
854 }
855 
856 void fsm_controller::add_correct_transition_memory(const std::string& state_representation, structural_managerRef SM)
857 {
858  structural_objectRef circuit = SM->get_circ();
859  SM->add_NP_functionality(circuit, NP_functionality::FSM, state_representation);
860 }
#define GET_NODE(t)
Macro used to hide implementation details when accessing a tree_node from another tree_node...
Definition: tree_node.hpp:343
Class specification to contain liveness information.
virtual void add_correct_transition_memory(const std::string &state_representation, structural_managerRef SM)
Set the correct NP functionality.
unsigned int get_register(unsigned int sv) const
return the register index where the storage value is stored
#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
a multi unbounded controller
Definition: generic_obj.hpp:75
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;.
void * top(node_stack *head)
Definition: tree.c:75
#define GET_TYPE(data, vertex_index)
Helper macro returning the type associated with a node.
void create_state_machine(std::string &parse)
Generates the string representation of the FSM.
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.
#define PRINT_DBG_MEX(dbgLevel, curDbgLevel, mex)
We are producing a debug version of the program, so the message is printed;.
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...
Base class for all command ports into datapath.
#define TYPE_MULTIIF
constant identifying the a multi-way if
Definition: op_graph.hpp:202
string target
Definition: lenet_tvm.py:16
#define GET_CLASS(obj)
Macro returning the actual type of an object.
std::string get_function_name() const
Return the name of the function.
#define GENERATED_LICENSE
const structural_objectRef get_circ() const
Get a reference to circ field.
vertex get_entry_state() const
Gets vertex that represents state that contains entry node.
generic_objRef bind_selector_port(direction_type dir, unsigned int mode, const vertex &cond, const OpGraphConstRef data)
virtual void add_common_ports(structural_objectRef circuit, structural_managerRef SM)
This member function adds the standard ports (clock, reset, done and command ones) to a circuit...
DesignFlowStep_Status InternalExec() override
Execute the step.
const std::map< unsigned int, Selectors > & GetSelectors() const
Header class for the creation of the classical FSM controller.
static std::string input_vector_to_string(const std::vector< long long int > &to_be_printed, bool with_comma)
unsigned int get_assign(const vertex &v) const
Returns the functional unit assigned to the vertex.
Definition: fu_binding.cpp:242
const unsigned int funId
identifier of the function to be processed (0 means that it is a global step)
#define GET_NAME(data, vertex_index)
Helper macro returning the name associated with a node.
exceptions managed by PandA
AllocationInformationRef allocation_information
Store the technology information.
Definition: hls.hpp:115
vertex get_exit_state() const
Gets vertex that represents state that contains exit node.
void insert(node_tree **tree, int val)
Definition: tree.c:121
Class specification of the manager of the technology library data structures.
std::map< vertex, unsigned int > cond_ports
This is the same as in_ports except that the first element is of type vertex.
static technology_nodeRef get_fu(const std::string &fu_name, const HLS_managerConstRef hls_manager)
Returns the technology_node associated with the given operation.
static unsigned int get_multi_way_if_pos(const tree_managerConstRef &TM, unsigned int node_id, unsigned int cond)
return the position of con in the gimple_multi_way_if conditions
virtual bool is_a_storage_value(vertex curr_vertex, unsigned int var_index)=0
return true in case a storage value exist for the pair vertex variable
redefinition of map to manage ordered/unordered structures
volatile int output[DIM_Y][DIM_X]
Definition: los.h:1
virtual enum kind get_kind() const =0
Virtual function returning the type of the actual class.
#define STR(s)
Macro which performs a lexical_cast to a string.
Auxiliary methods for manipulating string.
#define CLOCK_PORT_NAME
standard name for ports
const tree_nodeRef get_tree_node_const(unsigned int i) const
Return the reference to the i-th tree_node Constant version of get_tree_node.
const OpNodeInfoConstRef CGetOpNodeInfo(const vertex node) const
Returns the info associated with a node.
Definition: op_graph.hpp:843
unsigned int in_num
Initialized after add_common_ports is called. It represents the current number of input ports...
fu_bindingRef Rfu
Store the refcounted functional unit binding of the operations.
Definition: hls.hpp:121
static void add_NP_functionality(structural_objectRef cir, NP_functionality::NP_functionaly_type dt, std::string functionality_description)
Add a not-parsed functionality.
std::string get_guard_value(const tree_managerRef TM, const unsigned int index, vertex op, const OpGraphConstRef data)
Returns the value of the guard value of a case_label_expr default is not managed. ...
Data structure used to store the register binding of variables.
StorageValueInformationRef storage_value_information
data-structure for storage values
Definition: hls.hpp:130
Base class for multiplexer into datapath.
void set_top_info(const std::string &id, const technology_managerRef &LM, const std::string &Library="")
Data structure used to store the interconnection binding of datapath elements.
Data structure used to store the schedule of the operations.
#define DONE_PORT_NAME
Control flow graph.
static const uint32_t k[]
Definition: sha-256.c:22
unsigned int out_num
Initialized after add_common_ports is called. It represents the current number of output ports...
HLSFlowStep_Type
Definition: hls_step.hpp:95
Class specification of the data structures used to manage technology information. ...
generic_objRef get(const unsigned int &r) const
Returns reference to register object associated to a given index.
fsm_controller(const ParameterConstRef Param, const HLS_managerRef HLSMgr, unsigned int funId, const DesignFlowManagerConstRef design_flow_manager, const HLSFlowStep_Type hls_flow_step_type=HLSFlowStep_Type::FSM_CONTROLLER_CREATOR)
Constructor.
#define default_COND
constant used to represent label "default" of a switch construct
#define index(x, y)
Definition: Keccak.c:74
redefinition of set to manage ordered/unordered structures
boost::graph_traits< graph >::vertex_descriptor vertex
vertex definition.
Definition: graph.hpp:1303
void set_black_box(bool bb)
Set the black box property associated with the structural_object.
Base class for all register into datapath.
This file contains the structures needed to manage a graph that will represent the state transition g...
const BehavioralHelperConstRef CGetBehavioralHelper() const
Returns the helper associated with the function.
Classes specification of the tree_node data structures.
static std::string NormalizeTypename(const std::string &id)
Return normalized name of types and variables.
const ParameterConstRef parameters
Set of input parameters.
DesignFlowStep_Status
The status of a step.
This package is used by all HLS packages to manage resource constraints and characteristics.
std::map< generic_objRef, unsigned int > out_ports
This contains all the ports that go from the controller to the datapath, used to enable the registers...
#define DEBUG_LEVEL_NONE
no debugging print is performed.
reg_bindingRef Rreg
Store the refcounted register binding of the variables.
Definition: hls.hpp:133
#define THROW_ERROR(str_expr)
helper function used to throw an error in a standard way
Definition: exceptions.hpp:263
This package is used to define the storage value scheme adopted by the register allocation algorithms...
const StateTransitionGraphConstRef CGetAstg() const
Returns pointer to state transition graph created.
livenessRef Rliv
data-structure containing the variable liveness
Definition: hls.hpp:127
This file collects some utility functions.
structural_managerRef controller
Store the controller description.
Definition: hls.hpp:158
Definition: APInt.hpp:53
bool registered_done_port
true when the done port is registered
Definition: hls.hpp:149
This class describes all classes used to represent a structural object.
Class specification of the tree_reindex support class.
Generic class managing controller creation algorithms.
Data structure used to store the functional-unit binding of the vertexes.
Class specification of the basic_block structure.
hlsRef HLS
HLS data structure of the function to be analyzed.
virtual unsigned int get_storage_value_index(vertex curr_vertex, unsigned int var_index)=0
Returns the index of the storage value associated with the variable in a given vertex.
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
unsigned int get_used_regs() const
returns number of used register
It collects all the common strings covering PandA copyrights issues.
~fsm_controller() override
Destructor.
std::string container_to_string(_InputIt first, _InputIt last, const std::string &separator, bool trim_empty=true)
Definition: utility.hpp:122
#define RESET_PORT_NAME
Class implementation of the structural_manager.
StateTransitionGraphManagerRef STG
Store the refcounted state transition graph.
Definition: hls.hpp:124
static integer_cst_t GetConstValue(const tree_nodeConstRef &tn, bool is_signed=true)
Get value from integer constant.
int debug_level
The debug level.
#define GET_INDEX_CONST_NODE(t)
Definition: tree_node.hpp:363
Base class for all register into datapath.
#define DEBUG_LEVEL_VERBOSE
verbose debugging print is performed.
Data structure definition for high-level synthesis flow.
const StateTransitionGraphConstRef CGetStg() const
Returns pointer to state transition graph created.
conn_bindingRef Rconn
Store the refcounted interconnection of datapath elements.
Definition: hls.hpp:139
#define GENERATED_COPYRIGHT
#define NULL_VERTEX
null vertex definition
Definition: graph.hpp:1305
Class specification of the manager of the tree structures extracted from the raw file.
A brief description of the C++ Header File.
std::map< vertex, unsigned int > mu_ports
This map put into relation fsm states and alldone multi_unbounded ports.
const CustomOrderedSet< unsigned int > & get_live_in(const vertex &v) const
Get the set of variables live at the input of a vertex.
Definition: liveness.cpp:109
boost::graph_traits< graph >::edge_descriptor EdgeDescriptor
edge definition.
Definition: graph.hpp:1316
#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