PandA-2024.02
vcd_utility.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) 2015-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  */
36 #include "vcd_utility.hpp"
37 
38 #include "Discrepancy.hpp"
39 #include "Parameter.hpp"
41 #include "behavioral_helper.hpp"
44 #include "call_graph.hpp"
45 #include "call_graph_manager.hpp"
46 #include "control_flow_checker.hpp"
47 #include "cpu_stats.hpp"
48 #include "cpu_time.hpp"
49 #include "design_flow_graph.hpp"
50 #include "design_flow_manager.hpp"
52 #include "function_behavior.hpp"
53 #include "hls.hpp"
54 #include "hls_device.hpp"
55 #include "hls_manager.hpp"
56 #include "language_writer.hpp"
57 #include "memory.hpp"
58 #include "parse_discrepancy.hpp"
59 #include "reg_binding.hpp"
62 #include "string_manipulation.hpp"
63 #include "structural_manager.hpp"
64 #include "tree_helper.hpp"
65 #include "tree_manager.hpp"
66 #include "tree_node.hpp"
67 #include "tree_reindex.hpp"
68 #include "vcd_trace_head.hpp"
69 
70 #include <boost/algorithm/string/case_conv.hpp>
71 #include <cfloat>
72 #include <filesystem>
73 #include <fstream>
74 #include <iterator>
75 #include <utility>
76 
77 DiscrepancyLog::DiscrepancyLog(const HLS_managerConstRef HLSMgr, const vcd_trace_head& t, const uint64_t c_context,
78  std::string _c_val, const unsigned int _el_idx,
79  const std::string::size_type _first_c_bit, const std::string::size_type _c_size,
80  const unsigned int _b)
81  : op_start_time(t.op_start_time),
82  op_end_time(t.op_end_time),
83  type(t.op_info.type),
84  op_id(t.op_info.op_id),
85  ssa_id(t.op_info.ssa_name_node_id),
86  fun_id(t.op_info.stg_fun_id),
87  op_start_state(t.fsm_ss_it->value),
88  fu_name(HLSMgr->CGetFunctionBehavior(t.op_info.stg_fun_id)->CGetBehavioralHelper()->get_function_name()),
89  stmt_string(HLSMgr->get_tree_manager()->CGetTreeNode(t.op_info.op_id)->ToString()),
90  c_val(std::move(_c_val)),
91  vcd_val(t.out_var_it->value),
92  fullsigname(t.fullsigname),
93  context(c_context),
94  bitsize(t.op_info.bitsize),
95  el_idx(_el_idx),
96  first_c_bit(_first_c_bit),
97  c_size(_c_size),
98  base_index(_b)
99 {
100 }
101 
103 
105  const DesignFlowManagerConstRef _design_flow_manager)
106  : HLS_step(_parameters, _HLSMgr, _design_flow_manager, HLSFlowStep_Type::VCD_UTILITY),
107  TM(HLSMgr->get_tree_manager()),
108  Discr(_HLSMgr->RDiscr),
109  allow_uninitialized(
110  (parameters->isOption(OPT_discrepancy_force) && parameters->getOption<bool>(OPT_discrepancy_force))),
111  present_state_name(static_cast<HDLWriter_Language>(_parameters->getOption<unsigned int>(OPT_writer_language)) ==
113  "_present_state" :
114  "present_state")
115 {
116  debug_level = parameters->get_class_debug_level(GET_CLASS(*this));
117  THROW_ASSERT(parameters->isOption(OPT_discrepancy) && parameters->getOption<bool>(OPT_discrepancy),
118  "Step " + STR(__PRETTY_FUNCTION__) + " should not be added without discrepancy");
119  THROW_ASSERT(HLSMgr->RDiscr, "Discr data structure is not correctly initialized");
120 }
121 
124 {
126  switch(relationship_type)
127  {
129  {
130  ret.insert(std::make_tuple(HLSFlowStep_Type::SIMULATION_EVALUATION, HLSFlowStepSpecializationConstRef(),
132  ret.insert(std::make_tuple(HLSFlowStep_Type::VCD_SIGNAL_SELECTION, HLSFlowStepSpecializationConstRef(),
134  ret.insert(std::make_tuple(
137  CBackendInformation::CB_DISCREPANCY_ANALYSIS,
138  parameters->getOption<std::string>(OPT_output_directory) + "/simulation/discrepancy.c",
139  parameters->getOption<std::string>(OPT_output_directory) + "/simulation/dynamic_discrepancy_stats")),
141  break;
142  }
144  {
145  break;
146  }
148  {
149  break;
150  }
151  default:
152  THROW_UNREACHABLE("");
153  }
154  return ret;
155 }
156 
157 static const std::list<sig_variation>& get_signal_variations(const vcd_parser::vcd_trace_t& vcd_trace,
158  const std::string& scope, const std::string& signal_name)
159 {
160  const auto scopes_end = vcd_trace.end();
161  const auto scopes_it = vcd_trace.find(scope);
162  if(scopes_it == scopes_end)
163  {
164  THROW_ERROR("cannot find scope: " + scope);
165  }
166  const auto signal_end = scopes_it->second.end();
167  const auto signal_it = scopes_it->second.find(signal_name);
168  if(signal_it == signal_end)
169  {
170  THROW_ERROR("cannot find signal: " + signal_name + " in scope: " + scope);
171  }
172  return signal_it->second;
173 }
174 
175 unsigned long long vcd_utility::GetClockPeriod(const vcd_parser::vcd_trace_t& vcd_trace) const
176 {
177  std::string top_scope = Discr->unfolded_v_to_scope.at(Discr->unfolded_root_v);
178  const std::string controller_scope = top_scope + "Controller_i" + STR(HIERARCHY_SEPARATOR);
179  const auto clock_signal_name = STR(CLOCK_PORT_NAME);
180  const std::list<sig_variation>& clock_sig_variations =
181  get_signal_variations(vcd_trace, controller_scope, clock_signal_name);
182  auto clock_var_it = clock_sig_variations.begin();
183  const auto clock_var_beg = clock_var_it;
184  const auto clock_var_end = clock_sig_variations.end();
185  const auto same_value = [clock_var_beg](const sig_variation& v) { return v.value == clock_var_beg->value; };
186  clock_var_it = std::find_if(std::next(clock_var_it), clock_var_end, same_value);
187  if(clock_var_it == clock_var_end)
188  {
189  THROW_ERROR("clock signal for top function does not complete a cycle");
190  }
191  unsigned long long clock_period = clock_var_it->time_stamp - clock_var_beg->time_stamp;
192  THROW_ASSERT(clock_period > 0, "clock period is 0\n");
193  return clock_period;
194 }
195 
197 {
198  // cleanup member data structures to allow multiple executions of this step
199  THROW_ASSERT(Discr, "Discr data structure is not correctly initialized");
202  // TODO: should we clear the discrepancy lists of the previous executions or
203  // keep them and work incrementally on them??
204  discr_list.clear();
205  soft_discr_list.clear();
206 
207  std::ofstream disc_stat_file;
208  std::string disc_stat_filename =
209  parameters->getOption<std::string>(OPT_output_directory) + "/simulation/dynamic_discrepancy_stats";
210  disc_stat_file.open(disc_stat_filename, std::ofstream::app);
211  if(!disc_stat_file.is_open())
212  {
213  THROW_ERROR("can't open file " + disc_stat_filename);
214  }
215 
216  std::string vcd_filename = parameters->getOption<std::string>(OPT_output_directory) + "/simulation/test.vcd";
217  INDENT_OUT_MEX(OUTPUT_LEVEL_VERBOSE, output_level, "Parsing vcd file " + vcd_filename);
218  long vcd_parse_time = 0;
220  {
221  START_TIME(vcd_parse_time);
222  }
223  /* create vcd parser obj */
225  /* parse the selected signals */
226  vcd_parser::vcd_trace_t vcd_trace = vcd_parser.parse_vcd(vcd_filename, HLSMgr->RDiscr->selected_vcd_signals);
227 
229  {
230  STOP_TIME(vcd_parse_time);
231  }
233  "Parsed vcd file " + vcd_filename + " in " + print_cpu_time(vcd_parse_time) + " seconds");
234  /* parse the discrepancy trace coming from C execution */
235  const std::string& discrepancy_data_filename = HLSMgr->RDiscr->c_trace_filename;
236  INDENT_OUT_MEX(OUTPUT_LEVEL_VERBOSE, output_level, "Parsing C trace file " + discrepancy_data_filename);
237  long ctrace_parse_time = 0;
239  {
240  START_TIME(ctrace_parse_time);
241  }
242  parse_discrepancy(discrepancy_data_filename, Discr);
244  {
245  STOP_TIME(ctrace_parse_time);
246  }
248  "Parsed C trace file " + discrepancy_data_filename + " in " + print_cpu_time(ctrace_parse_time) +
249  " seconds");
250 
251  auto& c_op_trace = Discr->c_op_trace;
252  if(c_op_trace.empty())
253  {
255  "Discrepancy Analysis: the trace of the C execution is empty. Discrepancy Analysis cannot be performed");
256  if(!parameters->isOption(OPT_no_clean) || !parameters->getOption<bool>(OPT_no_clean))
257  {
258  if(!parameters->isOption(OPT_generate_vcd) || !parameters->getOption<bool>(OPT_generate_vcd))
259  {
260  std::filesystem::remove(vcd_filename);
261  }
262  std::filesystem::remove(discrepancy_data_filename);
263  }
264  disc_stat_file << "Possibly lost address checks = 0 (empty trace)\n";
265  disc_stat_file << "Mismatched integers = 0 (empty trace)\n";
266  disc_stat_file.flush();
267  disc_stat_file.close();
269  }
270 
271  std::map<unsigned int, std::map<std::string, struct vcd_trace_head>> op_id_to_scope_to_vcd_head;
273  INDENT_OUT_MEX(OUTPUT_LEVEL_MINIMUM, output_level, "---Starting discrepancy analysis");
274  long discrepancy_time = 0;
276  {
277  START_TIME(discrepancy_time);
278  }
279  for(const auto& c : c_op_trace)
280  {
281  const DiscrepancyOpInfo& op_info = c.first;
282  const std::list<std::pair<uint64_t, std::string>>& optrace = c.second;
283  THROW_ASSERT(HLSMgr->RDiscr->opid_to_outsignal.find(op_info.op_id) != HLSMgr->RDiscr->opid_to_outsignal.end(),
284  "can't find out signal for operation " + STR(op_info.op_id));
285  std::string& outsigname = HLSMgr->RDiscr->opid_to_outsignal.at(op_info.op_id);
286  /*
287  * setup the heads for the multiple vcd traces in hw related to an
288  * operation in C
289  */
290  THROW_ASSERT(Discr->f_id_to_scope.find(op_info.stg_fun_id) != Discr->f_id_to_scope.end(),
291  "no scope for function " + STR(op_info.stg_fun_id));
292  const auto& scope_set = Discr->f_id_to_scope.at(op_info.stg_fun_id);
293  if(!scope_set.empty())
294  {
295  op_id_to_scope_to_vcd_head[op_info.op_id];
296  }
297  for(const std::string& scope : scope_set)
298  {
299  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "-->Analyzing scope " + scope);
300  const std::string controller_scope = scope + "Controller_i" + STR(HIERARCHY_SEPARATOR);
301  const std::string datapath_scope = scope + "Datapath_i" + STR(HIERARCHY_SEPARATOR);
302  std::string fullsigname = datapath_scope + outsigname;
303  /* select the variations of the output sign&l */
304  const std::list<sig_variation>& op_out_vars = get_signal_variations(vcd_trace, datapath_scope, outsigname);
305  /* select the variations of state signal of the state machine */
306  const std::list<sig_variation>& present_state_vars =
307  get_signal_variations(vcd_trace, controller_scope, present_state_name);
308  /* select the variations of the start port signals */
309  const std::list<sig_variation>& start_vars =
310  get_signal_variations(vcd_trace, controller_scope, STR(START_PORT_NAME));
311  /*
312  * calculate the initial state of the FSM. this is used by the
313  * vcd_trace_head to compute the exact starting time for the operation,
314  * when the initial state of the FSM is a starting state for this operation
315  */
316  const auto stg_man = HLSMgr->get_HLS(op_info.stg_fun_id)->STG;
317  const auto entry = stg_man->get_entry_state();
318  const auto stg = stg_man->CGetStg();
319  THROW_ASSERT(boost::out_degree(entry, *stg) == 1, "Non deterministic initial state");
320  OutEdgeIterator oe, oend;
321  tie(oe, oend) = boost::out_edges(entry, *stg);
322  const auto first_state = boost::target(*oe, *stg);
323  const auto initial_state_id = stg->CGetStateTransitionGraphInfo()->vertex_to_state_id.at(first_state);
324 
325  op_id_to_scope_to_vcd_head.at(op_info.op_id)
326  .insert(
327  std::make_pair(scope, vcd_trace_head(op_info, fullsigname, present_state_vars, op_out_vars, start_vars,
328  initial_state_id, GetClockPeriod(vcd_trace), HLSMgr, TM,
330  INDENT_DBG_MEX(DEBUG_LEVEL_VERY_PEDANTIC, debug_level, "<--Analyzed scope " + scope);
331  }
332 
333  /*
334  * Start looking for discrepancies. The analysis is performed on the trace
335  * of one C operation at a time, with multiple heads analyzing the vcd
336  * traces. Indeed when using duplicated modules for a single C function
337  * there may be many vcd traces for every single C trace, one for every
338  * duplicated module. Every vcd_trace_head has its own state. The
339  * comparison works iterating on the C trace, for every assignment in C
340  * the corresponding vcd_trace_head is retrieved and it is processed
341  * according to its state.
342  */
343  auto ct_it = optrace.begin();
344  const auto ct_end = optrace.cend();
345  while(ct_it != ct_end)
346  {
347  struct vcd_trace_head& vcd_head =
348  op_id_to_scope_to_vcd_head.at(op_info.op_id).at(Discr->context_to_scope.at(ct_it->first));
349  switch(vcd_head.state)
350  {
352  {
353  if(vcd_head.more_executions_in_this_hw_state())
354  {
355  vcd_head.state = vcd_trace_head::suspended;
356  }
357  else
358  {
359  vcd_head.state = vcd_trace_head::running;
360  }
361  ct_it++;
362  break;
363  }
367  {
368  vcd_head.advance();
369  if(vcd_head.state == vcd_trace_head::init_fail)
370  {
373  }
374  break;
375  }
377  {
378  if((!discr_list.empty()) && vcd_head.ends_after(discr_list.front().op_end_time))
379  {
381  break;
382  }
383  if(detect_mismatch(vcd_head, ct_it->first, ct_it->second))
384  {
386  }
387  else
388  {
389  vcd_head.exec_times_in_current_state++;
390  vcd_head.state = vcd_trace_head::checked;
391  }
392  break;
393  }
397  {
398  ct_it++;
399  break;
400  }
401  default:
402  {
403  THROW_UNREACHABLE("invalid state for vcd_trace_head");
404  break;
405  }
406  }
407  }
408  }
409 
411  {
412  STOP_TIME(discrepancy_time);
413  }
415  "---Discrepancy analysis executed in " + print_cpu_time(discrepancy_time) + " seconds");
417  "---Possibly lost address checks = " + STR(possibly_lost_address));
418 
419  disc_stat_file << "Possibly lost address checks = ";
420  disc_stat_file << possibly_lost_address << "\n";
421  disc_stat_file << "Mismatched integers = ";
422  disc_stat_file << mismatched_integers << "\n";
423  disc_stat_file.flush();
424  disc_stat_file.close();
425 
427  "---DISCREPANCY CHECKS: " + STR(Discr->n_checked_operations) + "/" + STR(Discr->n_total_operations));
428 
429  bool first_discrepancy_print = true;
430  if(!discr_list.empty() || !soft_discr_list.empty())
431  {
433  "\n\n\n"
434  "/====================================\\\n"
435  "| FINAL DISCREPANCY REPORT |\n"
436  "\\====================================/");
437  if(!discr_list.empty())
438  {
440  "\n\n"
441  "/--------------------------------\\\n"
442  "| HARD DISCREPANCIES |\n"
443  "\\--------------------------------/");
444  for(const auto& l : discr_list)
445  {
447  }
448  }
449  if(!soft_discr_list.empty())
450  {
452  "\n\n"
453  "/--------------------------------\\\n"
454  "| SOFT DISCREPANCIES |\n"
455  "\\--------------------------------/");
456  for(const auto& l : soft_discr_list)
457  {
459  }
460  }
461  first_discrepancy_print = false;
462  }
463 
464  bool persisting_warning = false;
465  bool before_discrepancy = false;
466  bool suspended_op_never_ends = false;
467  // print any persisting warning that starts before the first discrepancy
468  for(const auto& id_to_scope_to_head : op_id_to_scope_to_vcd_head)
469  {
470  for(const auto& t : id_to_scope_to_head.second)
471  {
472  before_discrepancy = discr_list.empty() || !t.second.starts_after(discr_list.front().op_start_time);
473 
474  suspended_op_never_ends = t.second.state == vcd_trace_head::suspended &&
475  t.second.consecutive_state_executions !=
476  std::numeric_limits<decltype(t.second.consecutive_state_executions)>::max();
477 
478  if(before_discrepancy && t.second.has_been_initialized &&
479  (t.second.state == vcd_trace_head::init_fail || suspended_op_never_ends))
480  {
481  if(first_discrepancy_print)
482  {
484  "\n\n\n"
485  "/====================================\\\n"
486  "| FINAL DISCREPANCY REPORT |\n"
487  "\\====================================/");
488  first_discrepancy_print = false;
489  }
490  if(!persisting_warning)
491  {
493  "\n\n"
494  "/------------------------------\\\n"
495  "| PERSISTING ERRORS |\n"
496  "\\------------------------------/");
497  }
498  print_failed_vcd_head(t.second, ControlFlowChecker::IsOneHotFSM(t.second.op_info.stg_fun_id, HLSMgr),
500  persisting_warning = true;
501  }
502  }
503  }
504  if(persisting_warning || !discr_list.empty() || !soft_discr_list.empty())
505  {
506  THROW_ERROR("DISCREPANCY FOUND");
507  }
508  else
509  {
510  INDENT_OUT_MEX(OUTPUT_LEVEL_MINIMUM, output_level, "---DISCREPANCY NOT FOUND");
511  if((!parameters->isOption(OPT_no_clean)) || (!parameters->getOption<bool>(OPT_no_clean)))
512  {
513  if((!parameters->isOption(OPT_generate_vcd)) || (!parameters->getOption<bool>(OPT_generate_vcd)))
514  {
515  std::filesystem::remove(vcd_filename);
516  }
517  std::filesystem::remove(discrepancy_data_filename);
518  }
519  }
520 
522 }
523 
525 {
526  return true;
527 }
528 
529 bool vcd_utility::detect_mismatch(const vcd_trace_head& t, const uint64_t c_context, const std::string& c_val)
530 {
531  const std::string& vcd_val = t.out_var_it->value;
532  bool is_mismatch = false;
533  if(parameters->isOption(OPT_discrepancy_force) && parameters->getOption<bool>(OPT_discrepancy_force) &&
534  vcd_val.find_first_not_of("01") != std::string::npos)
535  {
536  /*
537  * The user is saying that he/she guarantees that there are no uninitialized
538  * variables in the original C specification. For this reason any value in
539  * vcd different from 0 or 1 is considered an error, independently of the
540  * values in C.
541  * The last four parameters are set to 0, because they are irrelevant in
542  * case of an error like this.
543  */
544  update_discr_list(t, c_context, c_val, 0, 0, 0, 0);
545  return true;
546  }
547 
548  if(t.op_info.type & DISCR_VECTOR)
549  {
550  THROW_ASSERT(c_val.length() % t.op_info.vec_base_bitsize == 0, "ssa_name = " + STR(t.op_info.ssa_name) +
551  "\n"
552  "ssa node id = " +
554  "\n"
555  "c_val.length() = " +
556  STR(c_val.length()) +
557  "\n"
558  "vec_base_bitsize = " +
559  STR(t.op_info.vec_base_bitsize) + "\n");
560 
561  THROW_ASSERT(vcd_val.length() >= c_val.length(), "ssa_name = " + STR(t.op_info.ssa_name) +
562  "\n"
563  "ssa node id = " +
565  "\n"
566  "c_val.length() = " +
567  STR(c_val.length()) +
568  "\n"
569  "vcd signal = " +
570  t.fullsigname +
571  "\n"
572  "vcd length = " +
573  STR(vcd_val.length()) + "\n");
574 
575  for(unsigned int i = 0u; i < c_val.length() / t.op_info.vec_base_bitsize; i++)
576  {
577  is_mismatch |= detect_mismatch_element(t, c_context, c_val, i);
578  }
579  }
580  else
581  {
582  is_mismatch = detect_mismatch_element(t, c_context, c_val, 0u);
583  }
584  return is_mismatch;
585 }
586 
587 bool vcd_utility::detect_mismatch_element(const vcd_trace_head& t, const uint64_t c_context, const std::string& c_val,
588  const unsigned int el_idx)
589 {
590 #if HAVE_ASSERTS
591  const std::string& vcd_val = t.out_var_it->value;
592 #endif
593 
594  std::string::size_type first_c_bit = el_idx * t.op_info.vec_base_bitsize;
595  std::string::size_type c_elem_size = t.op_info.vec_base_bitsize;
596 
597  THROW_ASSERT(c_val.length() >= first_c_bit + c_elem_size, "ssa_name = " + STR(t.op_info.ssa_name) +
598  "\n"
599  "ssa node id = " +
601  "\n"
602  "c_val.length() = " +
603  STR(c_val.length()) +
604  "\n"
605  "first_c_bit = " +
606  STR(first_c_bit) +
607  "\n"
608  "c_elem_size = " +
609  STR(c_elem_size) + "\n");
610 
611  THROW_ASSERT(t.out_var_it->value.length() > first_c_bit, "ssa_name = " + STR(t.op_info.ssa_name) +
612  "\n"
613  "ssa node id = " +
615  "\n"
616  "c_val.length() = " +
617  STR(c_val.length()) +
618  "\n"
619  "first_c_bit = " +
620  STR(first_c_bit) +
621  "\n"
622  "vcd signal = " +
623  t.fullsigname +
624  "\n"
625  "vcd length = " +
626  STR(vcd_val.length()) + "\n");
627 
628  bool is_mismatch = false;
629  if(t.op_info.type & DISCR_COMPLEX)
630  {
631  THROW_ASSERT(t.out_var_it->value.length() >= c_val.length(), "ssa_name = " + STR(t.op_info.ssa_name) +
632  "\n"
633  "ssa node id = " +
635  "\n"
636  "c_val.length() = " +
637  STR(c_val.length()) +
638  "\n"
639  "first_c_bit = " +
640  STR(first_c_bit) +
641  "\n"
642  "vcd signal = " +
643  t.fullsigname +
644  "\n"
645  "vcd length = " +
646  STR(vcd_val.length()) + "\n");
647 
648  std::string::size_type part_size = c_elem_size / 2;
649 
650  is_mismatch = detect_mismatch_simple(t, c_context, c_val, el_idx, first_c_bit, part_size);
651 
652  is_mismatch |= detect_mismatch_simple(t, c_context, c_val, el_idx, first_c_bit + part_size, part_size);
653  }
654  else
655  {
656  is_mismatch = detect_mismatch_simple(t, c_context, c_val, el_idx, first_c_bit, c_elem_size);
657  }
658  return is_mismatch;
659 }
660 
661 bool vcd_utility::detect_mismatch_simple(const vcd_trace_head& t, const uint64_t c_context, const std::string& c_val,
662  const unsigned int el_idx, const std::string::size_type first_c_bit,
663  const std::string::size_type c_size)
664 {
665  unsigned int base_index = 0; // this is set when an address mismatch is detected
666  const bool resized = c_val.length() != c_size;
667  const std::string& resized_c_val = resized ? c_val.substr(first_c_bit, c_size) : c_val;
668 
669  THROW_ASSERT(!resized || (t.op_info.type & (DISCR_COMPLEX | DISCR_VECTOR)),
670  "operation " + STR(t.op_info.op_id) + " assigns ssa " + STR(t.op_info.ssa_name) +
671  ": only complex or vectors are supposed to be resized for discrepancy analysis");
672 
673  const std::string& vcd = t.out_var_it->value;
674 
675  auto vcd_first_bit = first_c_bit;
676  if(vcd.size() > c_val.size())
677  {
678  vcd_first_bit += vcd.size() - c_val.size();
679  }
680 
681  const std::string& resized_vcd_val = resized ? vcd.substr(vcd_first_bit, c_size) : vcd;
682 
683  bool discrepancy_found = detect_regular_mismatch(t, resized_c_val, resized_vcd_val);
684 
685  if(discrepancy_found && (t.op_info.type & DISCR_ADDR))
686  {
688  "address ssa cannot be real or complex: "
689  "real = " +
690  STR(static_cast<bool>(t.op_info.type & DISCR_VECTOR)) +
691  "complex = " + STR(static_cast<bool>(t.op_info.type & DISCR_COMPLEX)));
693  /*
694  * if the ssa stores an address first we try to find a regular
695  * mismatch. if we find it, this means that the value cannot be
696  * directly compared as an integer, so we have to translate it in
697  * the address space of the hw accelerator.
698  */
699  discrepancy_found = detect_address_mismatch(t.op_info, c_context, resized_c_val, resized_vcd_val, base_index);
700  }
701  if(discrepancy_found)
702  {
703  update_discr_list(t, c_context, c_val, el_idx, first_c_bit, c_size, base_index);
704  }
705  return discrepancy_found;
706 }
707 
708 void vcd_utility::update_discr_list(const vcd_trace_head& t, const uint64_t c_context, const std::string& c_val,
709  const unsigned int el_idx, const std::string::size_type first_c_bit,
710  const std::string::size_type c_size, const unsigned int base_index)
711 {
712  bool hard_discrepancy = true;
713  if(parameters->isOption(OPT_discrepancy_permissive_ptrs) &&
714  parameters->getOption<bool>(OPT_discrepancy_permissive_ptrs) && (t.op_info.type & DISCR_ADDR))
715  {
716  hard_discrepancy = false;
717  }
718 
719  if(hard_discrepancy)
720  {
721  if(!discr_list.empty() && t.op_end_time < discr_list.front().op_end_time)
722  {
723  /*
724  * if the list is not empty look for end times to see if the discrepancy
725  * that we just found is to be considered the first discrepancy happened
726  * in the execution.
727  * if the new end_time is _strictly_ smaller than the previous, then
728  * this is actually the first discrepancy, hence the list of the
729  * discr_list must be clreared before insertion.
730  */
731  discr_list.clear();
732  }
733  discr_list.emplace_back(HLSMgr, t, c_context, c_val, el_idx, first_c_bit, c_size, base_index);
734 
735  /*
736  * remove from the list of soft discrepancies those that happen after the
737  * first hard discrepancy
738  */
739  std::list<decltype(soft_discr_list.begin())> soft_discr_to_remove;
740  auto soft_discr_it = soft_discr_list.begin();
741  const auto soft_discr_end = soft_discr_list.cend();
742 
743  for(; soft_discr_it != soft_discr_end; soft_discr_it++)
744  {
745  if(soft_discr_it->op_end_time > t.op_end_time)
746  {
747  soft_discr_to_remove.push_back(soft_discr_it);
748  }
749  }
750 
751  for(const auto& s : soft_discr_to_remove)
752  {
753  soft_discr_list.erase(s);
754  }
755  }
756  else
757  {
758  if(discr_list.empty() || t.op_end_time <= discr_list.front().op_end_time)
759  {
760  soft_discr_list.emplace_back(HLSMgr, t, c_context, c_val, el_idx, first_c_bit, c_size, base_index);
761  }
762  }
763  return;
764 }
765 
766 bool vcd_utility::detect_binary_float_mismatch(const std::string& c_val, const std::string& resized_vcd_val) const
767 {
768  THROW_ASSERT(c_val.length() == resized_vcd_val.length(),
769  STR(c_val.length()) + " != " + STR(resized_vcd_val.length()));
770  union
771  {
772  float f;
773  unsigned int b;
774  } expected, computed;
775  computed.b = 0;
776  expected.b = 0;
777  size_t len = c_val.length();
778  for(size_t i = 0; i < len; i++)
779  {
780  computed.b |= (resized_vcd_val.at(i) == '1') ? (1u << (len - i - 1)) : 0;
781  expected.b |= (c_val.at(i) == '1') ? (1u << (len - i - 1)) : 0;
782  }
783  float ulp = 0.0;
784  float& c = computed.f;
785  float& e = expected.f;
786  if(std::isnan(c) && std::isnan(e))
787  {
788  return false;
789  }
790  else if(std::isinf(c) && std::isinf(e))
791  {
792  if(std::signbit(c) != std::signbit(e))
793  {
794  return true;
795  }
796  else
797  {
798  return false;
799  }
800  }
801  else if(std::isinf(c) || std::isinf(e) || std::isnan(c) || std::isnan(e))
802  {
803  return false;
804  }
805  else
806  {
807  if(e == 0.0f)
808  {
809  ulp = std::fabs(c - e) / std::ldexp(1.0f, -(FLT_MANT_DIG - 1));
810  }
811  else
812  {
813  ulp = std::fabs(c - e) / std::ldexp(1.0f, std::ilogb(e) - (FLT_MANT_DIG - 1));
814  }
815 
816  return static_cast<double>(ulp) > parameters->getOption<double>(OPT_max_ulp);
817  }
818  return false;
819 }
820 
821 bool vcd_utility::detect_binary_double_mismatch(const std::string& c_val, const std::string& resized_vcd_val) const
822 {
823  THROW_ASSERT(c_val.length() == resized_vcd_val.length(),
824  STR(c_val.length()) + " != " + STR(resized_vcd_val.length()));
825  union
826  {
827  double f;
828  unsigned long long b;
829  } expected, computed;
830  computed.b = 0;
831  expected.b = 0;
832  size_t len = c_val.length();
833  for(size_t i = 0; i < len; i++)
834  {
835  computed.b |= (resized_vcd_val.at(i) == '1') ? (1ULL << (len - i - 1)) : 0;
836  expected.b |= (c_val.at(i) == '1') ? (1ULL << (len - i - 1)) : 0;
837  }
838  double ulp = 0.0;
839  double& c = computed.f;
840  double& e = expected.f;
841  if(std::isnan(c) && std::isnan(e))
842  {
843  return false;
844  }
845  else if(std::isinf(c) && std::isinf(e))
846  {
847  if(std::signbit(c) != std::signbit(e))
848  {
849  return true;
850  }
851  else
852  {
853  return false;
854  }
855  }
856  else if(std::isinf(c) || std::isinf(e) || std::isnan(c) || std::isnan(e))
857  {
858  return false;
859  }
860  else
861  {
862  if(e == 0.0)
863  {
864  ulp = std::fabs(c - e) / std::ldexp(1.0, -(DBL_MANT_DIG - 1));
865  }
866  else
867  {
868  ulp = std::fabs(c - e) / std::ldexp(1.0, std::ilogb(e) - (DBL_MANT_DIG - 1));
869  }
870 
871  return ulp > parameters->getOption<double>(OPT_max_ulp);
872  }
873  return false;
874 }
875 
877  const std::string& c_val, const std::string& vcd_val,
878  const unsigned int base_index) const
879 {
880  const auto context_it = Discr->c_addr_map.find(c_context);
881  THROW_ASSERT(context_it != Discr->c_addr_map.end(), "no address map found for context " + STR(c_context));
882  const auto var_id_to_base_address_it = context_it->second.find(base_index);
883  if(var_id_to_base_address_it == context_it->second.end())
884  {
885  return false;
886  }
887 
888  uint64_t c_addr = std::stoull(c_val.c_str(), nullptr, 2);
889  uint64_t c_base_addr = var_id_to_base_address_it->second;
890  bool c_offset_is_negative = c_addr < c_base_addr;
891  uint64_t c_addr_offset = c_addr - c_base_addr;
892  if(c_offset_is_negative)
893  {
894  c_addr_offset = c_base_addr - c_addr;
895  }
896  /* don't detect mismatch for out of bounds address */
897  const uint64_t memory_area_bitsize =
898  std::max(8ull, tree_helper::Size(tree_helper::CGetType(TM->CGetTreeReindex(base_index))));
899  THROW_ASSERT(memory_area_bitsize % 8 == 0,
900  "bitsize of a variable in memory must be multiple of 8 --> is " + STR(memory_area_bitsize));
901  if(c_offset_is_negative || ((memory_area_bitsize / 8) <= (c_addr - c_base_addr)))
902  {
903  return false;
904  }
905  /*
906  * if the value of the hw address is retrieved with a load, the vcd signal
907  * representing the pointer can be wider than 32 bits. in that case we take
908  * the lowest 32 bits
909  */
910  const std::string& resized_vcd_val =
911  c_val.length() < vcd_val.length() ? vcd_val.substr(vcd_val.length() - c_val.length()) : vcd_val;
912  /*
913  * detect a mismatch if some of the resized address bits are not zeros or ones
914  */
915  if(resized_vcd_val.find_first_not_of("01") != std::string::npos)
916  {
917  return true;
918  }
919  uint64_t vcd_addr = std::stoull(resized_vcd_val.c_str(), nullptr, 2);
920  uint64_t vcd_base_addr = HLSMgr->Rmem->get_base_address(base_index, op_info.stg_fun_id);
921  bool vcd_offset_is_negative = vcd_addr < vcd_base_addr;
922  uint64_t vcd_addr_offset = vcd_addr - vcd_base_addr;
923  if(vcd_offset_is_negative)
924  {
925  vcd_addr_offset = vcd_base_addr - vcd_addr;
926  }
927  /* if the vcd is out of range even if the address in C is in range, we have a mismatch */
928  if(vcd_offset_is_negative || ((memory_area_bitsize / 8) <= (vcd_addr - vcd_base_addr)))
929  {
930  return true;
931  }
932  else
933  {
934  return c_addr_offset != vcd_addr_offset;
935  }
936 }
937 
938 bool vcd_utility::detect_address_mismatch(const DiscrepancyOpInfo& op_info, const uint64_t c_context,
939  const std::string& c_val, const std::string& vcd_val,
940  unsigned int& base_index)
941 {
942  const auto* ssa = GetPointer<const ssa_name>(TM->get_tree_node_const(op_info.ssa_name_node_id));
943  base_index = tree_helper::get_base_index(TM, op_info.ssa_name_node_id);
944  if(base_index != 0 && HLSMgr->Rmem->has_base_address(base_index))
945  {
946  return detect_fixed_address_mismatch(op_info, c_context, c_val, vcd_val, base_index);
947  }
948  else
949  {
950  if(ssa->use_set->is_fully_resolved())
951  {
952 #if HAVE_ASSERTS
953  bool at_least_one_pointed_variable_is_in_scope = false;
954 #endif
955  for(const tree_nodeRef& pointed_var_decl_id : ssa->use_set->variables)
956  {
957  base_index = tree_helper::get_base_index(TM, GET_INDEX_NODE(pointed_var_decl_id));
958  THROW_ASSERT(base_index != 0 && HLSMgr->Rmem->has_base_address(base_index),
959  "opid = " + STR(op_info.op_id) + " base index = " + STR(base_index) + " has no base address");
960  THROW_ASSERT(Discr->c_addr_map.find(c_context) != Discr->c_addr_map.end(),
961  "no address map found for context " + STR(c_context));
962  if(Discr->c_addr_map.at(c_context).find(base_index) != Discr->c_addr_map.at(c_context).end())
963  {
964 #if HAVE_ASSERTS
965  at_least_one_pointed_variable_is_in_scope = true;
966 #endif
967  if(detect_fixed_address_mismatch(op_info, c_context, c_val, vcd_val, base_index))
968  {
969  return true;
970  }
971  }
972  }
973  THROW_ASSERT(at_least_one_pointed_variable_is_in_scope == true,
974  "no pointed variable are in scope for opid = " + STR(op_info.op_id));
975  }
976  else
977  {
978  base_index = 0;
979  const uint64_t c_addr = static_cast<unsigned int>(std::stoull(c_val.c_str(), nullptr, 2));
982  for(const auto& addr : Discr->c_addr_map.at(c_context))
983  {
984  addr2base_index[addr.second] = addr.first;
985  addrSet.insert(addr.second);
986  }
987  for(auto it_set = addrSet.rbegin(); it_set != addrSet.rend(); ++it_set)
988  {
989  if(c_addr <= *it_set)
990  {
991  base_index = addr2base_index.at(*it_set);
992  }
993  }
994 
995  if(base_index)
996  {
997  return detect_fixed_address_mismatch(op_info, c_context, c_val, vcd_val, base_index);
998  }
999  else
1000  {
1002  return false;
1003  }
1004  }
1005  }
1006  return false;
1007 }
1008 
1009 bool vcd_utility::detect_regular_mismatch(const vcd_trace_head& t, const std::string& c_val,
1010  const std::string& vcd_val) const
1011 {
1012  if(t.op_info.type & DISCR_REAL)
1013  {
1014  THROW_ASSERT(c_val.length() <= vcd_val.length(), "ssa_name = " + t.op_info.ssa_name +
1015  "\n"
1016  "vcd signal = " +
1017  t.fullsigname +
1018  "\n"
1019  "c_val.length() = " +
1020  STR(c_val.length()) +
1021  "\n"
1022  "vcd_val.length() = " +
1023  STR(vcd_val.length()) + "\n");
1024 
1025  const bool to_resize = c_val.length() < vcd_val.length();
1026  const std::string resized_vcd_val = to_resize ? (vcd_val.substr(vcd_val.length() - c_val.length())) : vcd_val;
1027 
1028  if(c_val.length() == 32)
1029  {
1030  if(resized_vcd_val.find_first_not_of("01") != std::string::npos)
1031  {
1032  return allow_uninitialized;
1033  }
1034  return detect_binary_float_mismatch(c_val, resized_vcd_val);
1035  }
1036  else if(c_val.length() == 64)
1037  {
1038  if(resized_vcd_val.find_first_not_of("01") != std::string::npos)
1039  {
1040  return allow_uninitialized;
1041  }
1042  return detect_binary_double_mismatch(c_val, resized_vcd_val);
1043  }
1044  else
1045  {
1046  THROW_UNREACHABLE("only floating point with bitsize 32 or 64 are currently supported\n"
1047  "ssa_name = " +
1048  t.op_info.ssa_name +
1049  "\n"
1050  "c_val.length() = " +
1051  STR(c_val.length()) + "\n");
1052  return true;
1053  }
1054  }
1055  else // is an integer
1056  {
1057  std::string bitvalue =
1058  GetPointer<const ssa_name>(GET_NODE(TM->CGetTreeReindex(t.op_info.ssa_name_node_id)))->bit_values;
1059  auto first_not_x_pos = bitvalue.find_first_not_of("xX");
1060  if(first_not_x_pos == std::string::npos)
1061  {
1062  return false;
1063  }
1064  if(bitvalue.size() < vcd_val.size())
1065  {
1066  first_not_x_pos += vcd_val.size() - bitvalue.size();
1067  }
1068  const std::string vcd_trimmed_val = vcd_val.substr(first_not_x_pos);
1069  const std::string& longer = (vcd_trimmed_val.length() <= c_val.length()) ? c_val : vcd_trimmed_val;
1070  const std::string& shorter = (vcd_trimmed_val.length() <= c_val.length()) ? vcd_trimmed_val : c_val;
1071  if(longer.find_first_not_of("01") != std::string::npos || shorter.find_first_not_of("01") != std::string::npos)
1072  {
1073  return allow_uninitialized;
1074  }
1075  return shorter != longer.substr(longer.length() - shorter.length());
1076  }
1077 }
1078 
1079 void vcd_utility::print_discrepancy(const DiscrepancyLog& l, bool one_hot_encoding, const int verbosity) const
1080 {
1081  std::string out_msg = "\n/--------------------------------------------------------------------\n"
1082  "| ERROR in signal " +
1083  l.fullsigname +
1084  "\n"
1085  "| value in vcd: " +
1086  l.vcd_val +
1087  "\n"
1088  "| value in C: " +
1089  l.c_val +
1090  "\n"
1091  "| bitvalue: " +
1092  STR(l.bitsize) +
1093  "\n"
1094  "| operation id: " +
1095  STR(l.fun_id) + "_" + STR(l.op_id) +
1096  "\n"
1097  "| in function: " +
1098  l.fu_name +
1099  "\n"
1100  "| in context: " +
1101  STR(l.context) +
1102  "\n"
1103  "| operation: " +
1104  l.stmt_string +
1105  "\n"
1106  "| discrepancy time = " +
1107  STR(l.op_end_time) +
1108  "\n"
1109  "| failed operation starts at time " +
1110  STR(l.op_start_time) +
1111  "\n"
1112  "| when fsm state is " +
1113  compute_fsm_state_from_vcd_string(l.op_start_state, one_hot_encoding) +
1114  "\n"
1115  "| assigned ssa id " +
1116  STR(GetPointer<const ssa_name>(GET_NODE(TM->CGetTreeReindex(l.ssa_id)))) +
1117  "\n"
1118  "| bitvalue string for ssa id is " +
1119  STR(l.ssa_id) + " " +
1120  GetPointer<const ssa_name>(GET_NODE(TM->CGetTreeReindex(l.ssa_id)))->bit_values + "\n";
1121 
1122  if(l.type & DISCR_ADDR)
1123  {
1124  out_msg += "| THE DISCREPANCY IS ON A SIGNAL THAT MAY REPRESENT AN ADDRESS\n";
1125 
1126  const auto context_it = Discr->c_addr_map.find(l.context);
1127  THROW_ASSERT(context_it != Discr->c_addr_map.end(), "context " + STR(l.context) + " not find");
1128  const auto var_id_to_base_address_it = context_it->second.find(l.base_index);
1129  if(var_id_to_base_address_it != context_it->second.end())
1130  {
1131  uint64_t c_base_addr = var_id_to_base_address_it->second;
1132  out_msg += "| referenced variable decl id: " + STR(l.base_index) + "\n";
1133 
1134  out_msg += "| base address in C: " + STR(c_base_addr) + "\n";
1135 
1136  uint64_t c_addr = std::stoull(l.c_val.c_str(), nullptr, 2);
1137  out_msg += "| address in C: " + STR(c_addr) + "\n";
1138 
1139  uint64_t c_addr_offset = c_addr - c_base_addr;
1140  THROW_ASSERT(c_addr >= c_base_addr, "discrepancies for out of range addresses should not be raised:"
1141  " c_addr = " +
1142  STR(c_addr) + " c_base_addr = " + STR(c_base_addr));
1143  out_msg += "| address offset in C: " + STR(c_addr_offset) + "\n";
1144 #if HAVE_ASSERTS
1145  const uint64_t memory_area_bitsize =
1146  std::max(8ull, tree_helper::Size(tree_helper::CGetType(TM->CGetTreeReindex(l.base_index))));
1147  THROW_ASSERT(memory_area_bitsize % 8 == 0, "bitsize of a variable in memory must be multiple of 8 --> is " +
1148  STR(memory_area_bitsize) +
1149  ": this should be catched by an assertion earlier");
1150 #endif
1151  }
1152  else
1153  {
1154  out_msg += "| the address is not in range for any variable in context " + STR(l.context) + "\n";
1155  }
1156 
1157  std::string resized_vcd_val;
1158  if(l.c_val.length() < l.vcd_val.length())
1159  {
1160  resized_vcd_val = l.vcd_val.substr(l.vcd_val.length() - l.c_val.length());
1161  }
1162  const std::string& vcd = resized_vcd_val.empty() ? l.vcd_val : resized_vcd_val;
1163  if(vcd.find_first_not_of("01") == std::string::npos)
1164  {
1165  uint64_t vcd_base_addr = HLSMgr->Rmem->get_base_address(l.base_index, l.fun_id);
1166  out_msg += "| base address in vcd: " + STR(vcd_base_addr) + "\n";
1167 
1168  uint64_t vcd_addr = std::stoull(vcd.c_str(), nullptr, 2);
1169  out_msg += "| address in vcd: " + STR(vcd_addr) + "\n";
1170 
1171  uint64_t vcd_addr_offset = vcd_addr >= vcd_base_addr ? vcd_addr - vcd_base_addr : vcd_base_addr - vcd_addr;
1172  out_msg += "| address offset in vcd: " + (vcd_addr >= vcd_base_addr ? std::string("") : std::string("-")) +
1173  STR(vcd_addr_offset) + "\n";
1174  }
1175  else
1176  {
1177  out_msg += "| address bits in vcd: " + vcd +
1178  "\n"
1179  "| this cannot be converted to a valid address since it contains values different from 0 and 1\n";
1180  }
1181  }
1182  if(l.type & DISCR_VECTOR)
1183  {
1184  out_msg += "| THE DISCREPANCY IS IN A SIGNAL REPRESENTING A VECTORIZED VARIABLE\n";
1185  }
1186  if(l.type & DISCR_COMPLEX)
1187  {
1188  out_msg += "| THE DISCREPANCY IS IN A COMPLEX VARIABLE\n";
1189  }
1190  out_msg += "\\--------------------------------------------------------------------\n";
1191 
1192  INDENT_OUT_MEX(verbosity, output_level, out_msg);
1193  return;
1194 }
1195 
1196 void vcd_utility::print_failed_vcd_head(const vcd_trace_head& t, bool one_hot_encoding, const int verbosity) const
1197 {
1198  std::string out_msg = "\n/--------------------------------------------------------------------\n"
1199  "| ERROR in signal " +
1200  t.fullsigname + "\n";
1201 
1202  const std::string state = compute_fsm_state_from_vcd_string(t.fsm_ss_it->value, one_hot_encoding);
1203  switch(t.failed)
1204  {
1206  {
1207  out_msg += "| operation " + STR(t.op_info.stg_fun_id) + "_" + STR(t.op_info.op_id) +
1208  "\n"
1209  "| is scheduled in the initial state S_0 of a function which does not start\n"
1210  "| failed operation starts at time " +
1211  STR(t.op_start_time) +
1212  "\n"
1213  "| when fsm state is " +
1214  state + "\n";
1215  break;
1216  }
1218  {
1219  out_msg += "| cannot find next start state for operation " + STR(t.op_info.stg_fun_id) + "_" +
1220  STR(t.op_info.op_id) +
1221  "\n"
1222  "| previous execution started at time " +
1223  STR(t.op_start_time) +
1224  "\n"
1225  "| when fsm state was " +
1226  state +
1227  "\n"
1228  "| and ended at time " +
1229  STR(t.op_end_time) + "\n";
1230  break;
1231  }
1233  {
1234  out_msg += "| cannot find next end state for operation " + STR(t.op_info.stg_fun_id) + "_" +
1235  STR(t.op_info.op_id) +
1236  "\n"
1237  "| never reaches an end in HDL simulation\n"
1238  "| failed operation starts at time " +
1239  STR(t.op_start_time) +
1240  "\n"
1241  "| when fsm state is " +
1242  state + "\n";
1243  break;
1244  }
1246  default:
1247  {
1248  THROW_UNREACHABLE("unexpected failure state for vcd head\n");
1249  }
1250  }
1251  out_msg += "\\--------------------------------------------------------------------\n";
1252  INDENT_OUT_MEX(verbosity, output_level, out_msg);
1253 }
1254 
1255 std::string vcd_utility::compute_fsm_state_from_vcd_string(const std::string& vcd_state_string,
1256  bool one_hot_encoding) const
1257 {
1258  if(vcd_state_string.find_first_not_of("01") != std::string::npos)
1259  {
1260  /*
1261  * the vcd state string contains values that are not 0 or 1. something
1262  * went wrong, so we print the raw state string as it was found in vcd
1263  */
1264  return vcd_state_string;
1265  }
1266 
1267  if(one_hot_encoding)
1268  {
1269  const auto first_1_pos = vcd_state_string.find_first_of('1');
1270  const auto last_1_pos = vcd_state_string.find_last_of('1');
1271  if(first_1_pos != last_1_pos)
1272  {
1273  /*
1274  * not really one hot encoding. something went wrong. so print the raw
1275  * state string as it was found in vcd
1276  */
1277  return vcd_state_string;
1278  }
1279  return STR(vcd_state_string.length() - first_1_pos - 1);
1280  }
1281  else
1282  {
1283  return STR(std::stoul(vcd_state_string.c_str(), nullptr, 2));
1284  }
1285 }
#define GET_NODE(t)
Macro used to hide implementation details when accessing a tree_node from another tree_node...
Definition: tree_node.hpp:343
std::string fullsigname
Definition: vcd_utility.hpp:75
DiscrepancyLog(const HLS_managerConstRef HLSMgr, const vcd_trace_head &t, const uint64_t c_context, std::string _c_val, const unsigned int el_idx, const std::string::size_type _first_c_bit, const std::string::size_type _c_size, const unsigned int _b)
Definition: vcd_utility.cpp:77
std::list< DiscrepancyLog > discr_list
#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
vcd_utility(const ParameterConstRef parameters, const HLS_managerRef HLSMgr, const DesignFlowManagerConstRef design_flow_manager)
Constructor.
Data structure representing the entire HLS information.
#define INDENT_DBG_MEX(dbgLevel, curDbgLevel, mex)
We are producing a debug version of the program, so the message is printed;.
Factory class to create c backend.
unsigned int fun_id
Definition: vcd_utility.hpp:69
std::list< DiscrepancyLog > soft_discr_list
boost::graph_traits< graph >::out_edge_iterator OutEdgeIterator
out_edge_iterator definition.
Definition: graph.hpp:1312
unsigned long long GetClockPeriod(const vcd_parser::vcd_trace_t &vcd_trace) const
bool detect_regular_mismatch(const vcd_trace_head &t, const std::string &c_val, const std::string &vcd_val) const
const DiscrepancyRef Discr
#define OUTPUT_LEVEL_NONE
no output print is performed.
#define START_PORT_NAME
enum vcd_head_state state
This file contains the structures needed to manage a graph that will represent the state transition g...
unsigned int bitsize
Definition: vcd_utility.hpp:77
std::string stmt_string
Definition: vcd_utility.hpp:72
string target
Definition: lenet_tvm.py:16
#define GET_CLASS(obj)
Macro returning the actual type of an object.
unsigned long long mismatched_integers
enum vcd_head_failure failed
const int output_level
The output level.
void parse_discrepancy(const std::string &c_trace_filename, DiscrepancyRef Discrepancy)
void update_discr_list(const vcd_trace_head &t, const uint64_t c_context, const std::string &c_val, const unsigned int el_idx, const std::string::size_type first_c_bit, const std::string::size_type c_size, const unsigned int base_index)
std::string fu_name
Definition: vcd_utility.hpp:71
RelationshipType
The relationship type.
Source must be executed to satisfy target.
unsigned long long op_start_time
#define INDENT_OUT_MEX(outLevel, curOutLevel, mex)
bool detect_mismatch_element(const vcd_trace_head &t, const uint64_t c_context, const std::string &c_val, const unsigned int el_idx)
Definition of hash function for EdgeDescriptor.
Definition: graph.hpp:1321
static bool IsOneHotFSM(unsigned int function_id, const HLS_managerRef HLSMgr)
#define GET_INDEX_NODE(t)
Macro used to hide implementation details when accessing a tree_node from another tree_node...
Definition: tree_node.hpp:361
std::string c_val
Definition: vcd_utility.hpp:73
std::list< sig_variation >::const_iterator out_var_it
void print_failed_vcd_head(const vcd_trace_head &t, bool one_hot_encoding, const int verbosity) const
#define OUTPUT_LEVEL_MINIMUM
minimum debugging print is performed.
Include a set of utilities used to manage CPU time measures.
unsigned int vec_base_bitsize
Base class to pass information to a c backend.
bool
Definition: bellmanford.c:29
std::string compute_fsm_state_from_vcd_string(const std::string &vcd_state_string, bool one_hot_encoding) const
unsigned long long op_end_time
unsigned long long op_end_time
Definition: vcd_utility.hpp:65
static const std::list< sig_variation > & get_signal_variations(const vcd_parser::vcd_trace_t &vcd_trace, const std::string &scope, const std::string &signal_name)
#define THROW_WARNING(str_expr)
helper function used to throw a warning in a standard way: though it uses PRINT_DBG_MEX, the debug level used is such that the message is always printed
Definition: exceptions.hpp:300
#define STR(s)
Macro which performs a lexical_cast to a string.
Auxiliary methods for manipulating string.
#define max
Definition: backprop.h:17
HDLWriter_Language
std::string ToString(ActorGraphBackend_Type actor_graph_backend_type)
Header include.
bool allow_uninitialized
const std::string fullsigname
This class models a single variation of a signal in vcd.
#define CLOCK_PORT_NAME
standard name for ports
unsigned int op_id
Definition: vcd_utility.hpp:67
#define START_TIME(time_var)
Macro used to store the start time into time_var.
Definition: cpu_time.hpp:133
#define THROW_UNREACHABLE(str_expr)
helper function used to specify that some points should never be reached
Definition: exceptions.hpp:292
DesignFlowStep_Status Exec() override
Execute the step.
uint64_t context
Definition: vcd_utility.hpp:76
Data structure used to store the register binding of variables.
static unsigned long long Size(const tree_nodeConstRef &tn)
Return the size of a tree object.
absl::flat_hash_map< T, U, Hash, Eq, Alloc > CustomUnorderedMap
Definition: custom_map.hpp:148
HLSFlowStep_Type
Definition: hls_step.hpp:95
This class writes different HDL based descriptions (VHDL, Verilog, SystemC) starting from a structura...
bool ends_after(unsigned long long t) const
Classes to describe design flow graph.
unsigned int ssa_id
Definition: vcd_utility.hpp:68
#define STOP_TIME(time_var)
Macro used to store the elapsed time into time_var.
Definition: cpu_time.hpp:136
unsigned long long possibly_lost_address
bool detect_fixed_address_mismatch(const DiscrepancyOpInfo &op_info, const uint64_t c_context, const std::string &c_val, const std::string &vcd_val, const unsigned int base_index) const
This file contains the structures needed to manage a graph that will represent the state transition g...
Classes specification of the tree_node data structures.
UnorderedMapStd< std::string, CustomUnorderedMapStable< std::string, std::list< sig_variation > >> vcd_trace_t
this type is the result of a parse.
Definition: vcd_parser.hpp:109
const ParameterConstRef parameters
Set of input parameters.
DesignFlowStep_Status
The status of a step.
Call graph hierarchy.
#define THROW_ERROR(str_expr)
helper function used to throw an error in a standard way
Definition: exceptions.hpp:263
Wrapper of design_flow.
#define HIERARCHY_SEPARATOR
bool detect_address_mismatch(const DiscrepancyOpInfo &op_info, const uint64_t c_context, const std::string &c_val, const std::string &vcd_val, unsigned int &base_index)
This file collects some utility functions.
enum discrepancy_type_mask type
Definition: vcd_utility.hpp:66
bool detect_mismatch(const vcd_trace_head &t, const uint64_t c_context, const std::string &c_val)
std::string print_cpu_time(long int t)
massage a long which represents a time interval in milliseconds, into a string suitable for output ...
Definition: cpu_time.hpp:110
std::string present_state_name
The name of the present state signal.
unsigned int ssa_name_node_id
const DiscrepancyOpInfo & op_info
const tree_managerRef TM
Class specification of the tree_reindex support class.
void print_discrepancy(const DiscrepancyLog &l, bool one_hot_encoding, const int verbosity) const
vcd_trace_t parse_vcd(const std::string &vcd_file_to_parse, const vcd_parser::vcd_filter_t &selected_signals)
parses a file selecting only a predefined set of signals.
Definition: vcd_parser.cpp:53
std::string op_start_state
Definition: vcd_utility.hpp:70
bool HasToBeExecuted() const override
Check if this step has actually to be executed.
const CustomUnorderedSet< std::tuple< HLSFlowStep_Type, HLSFlowStepSpecializationConstRef, HLSFlowStep_Relationship > > ComputeHLSRelationships(const DesignFlowStep::RelationshipType relationship_type) const override
Return the set of analyses in relationship with this design step.
unsigned long long op_start_time
Definition: vcd_utility.hpp:64
This class contains the methods to create a frontend flow step.
Template borrowed from the ANTLR library by Terence Parr (http://www.jGuru.com - Software rights: htt...
Definition: refcount.hpp:94
static tree_nodeConstRef CGetType(const tree_nodeConstRef &node)
Return the treenode of the type of node.
bool detect_binary_double_mismatch(const std::string &c_val, const std::string &resized_vcd_val) const
this class is used to manage the command-line or XML options.
static unsigned int get_base_index(const tree_managerConstRef &TM, const unsigned int index)
Retrun the base address of a memory access.
std::string vcd_val
Definition: vcd_utility.hpp:74
Wrapper to call graph.
Class implementation of the structural_manager.
bool detect_binary_float_mismatch(const std::string &c_val, const std::string &resized_vcd_val) const
int debug_level
The debug level.
#define OUTPUT_LEVEL_VERBOSE
verbose debugging print is performed.
refcount< const HLSFlowStepSpecialization > HLSFlowStepSpecializationConstRef
const refcount definition of the class
Definition: hls_step.hpp:93
Utility managing CPU statistics.
unsigned long long exec_times_in_current_state
std::list< sig_variation >::const_iterator fsm_ss_it
Base class to pass information to a c backend.
bool more_executions_in_this_hw_state() const
Data structure definition for high-level synthesis flow.
This class contains the base representation for a generic frontend flow step which works on the whole...
enum discrepancy_type_mask type
bool detect_mismatch_simple(const vcd_trace_head &t, const uint64_t c_context, const std::string &c_val, const unsigned int el_idx, const std::string::size_type first_c_bit, const std::string::size_type c_size)
Datastructure to represent memory information in high-level synthesis.
Class specification of the manager of the tree structures extracted from the raw file.
HLS specialization of generic_device.
A brief description of the C++ Header File.
unsigned int base_index
valid only if type is DISCR_ADDR.
Definition: vcd_utility.hpp:87
#define THROW_ASSERT(cond, str_expr)
helper function used to check an assert and if needed to throw an error in a standard way ...
Definition: exceptions.hpp:289

Generated on Mon Feb 12 2024 13:02:54 for PandA-2024.02 by doxygen 1.8.13