HAL  v4.5.0-254-g8f9f6a423
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
module_identification.cpp
Go to the documentation of this file.
2 
16 
17 #include <deque>
18 #include <mutex>
19 
20 // #define PRINT_THREAD_INFO
21 
22 namespace hal
23 {
24  namespace module_identification
25  {
26  hal::Result<std::vector<std::pair<std::unique_ptr<BaseCandidate>, std::vector<std::unique_ptr<StructuralCandidate>>>>> generate_structural_candidates(const Netlist* nl,
27  const Configuration& config)
28  {
29  auto gl_name = nl->get_gate_library()->get_name();
30  std::vector<std::pair<std::unique_ptr<BaseCandidate>, std::vector<std::unique_ptr<StructuralCandidate>>>> candidates;
31 
32  if (gl_name == "ICE40ULTRA" || gl_name == "ICE40ULTRA_iPhone" || gl_name == "ICE40ULTRA_WITH_HAL_TYPES")
33  {
34  log_info("module_identification", "generate arithmetic structures for {}", gl_name);
36  }
37  else if (gl_name == "XILINX_UNISIM_WITH_HAL_TYPES" || gl_name == "XILINX_UNISIM")
38  {
39  log_info("module_identification", "generate arithmetic structures for {}", gl_name);
41  }
42  else
43  {
44  return ERR("arithmetic structure generation not available for gate_lib: " + gl_name);
45  }
46 
47  // filter out already classified modules or blocked base candidates
48  std::vector<u32> filtered_indices;
49  std::vector<std::pair<std::unique_ptr<BaseCandidate>, std::vector<std::unique_ptr<StructuralCandidate>>>> filtered_candidates;
50 
51  for (u32 idx = 0; idx < candidates.size(); idx++)
52  {
53  auto& [base_candidate, structural_candidates] = candidates.at(idx);
54  bool filtered_out = false;
55 
56  for (const auto& blocked_base_candidate : config.m_blocked_base_candidates)
57  {
58  const std::set<Gate*> base_candidate_set = {base_candidate->m_gates.begin(), base_candidate->m_gates.end()};
59 
60  if (base_candidate_set == blocked_base_candidate)
61  {
62  filtered_out = true;
63  break;
64  }
65  }
66 
67  for (const auto& already_classified_candidates : config.m_already_classified_candidates)
68  {
69  const std::set<Gate*> already_classified_candidates_set = {already_classified_candidates.begin(), already_classified_candidates.end()};
70 
71  for (const auto& g : base_candidate->m_gates)
72  {
73  if (already_classified_candidates_set.find(g) != already_classified_candidates_set.end())
74  {
75  filtered_out = true;
76  break;
77  }
78  }
79 
80  if (filtered_out)
81  {
82  break;
83  }
84  }
85 
86  if (!filtered_out)
87  {
88  filtered_indices.push_back(idx);
89  }
90  }
91 
92  log_info("module_identification", "Filtered out already classified candidates. Left with {} / {} base candidates", filtered_indices.size(), candidates.size());
93 
94  for (const auto& idx : filtered_indices)
95  {
96  auto& [base_candidate, structural_candidates] = candidates.at(idx);
97  filtered_candidates.push_back({std::move(base_candidate), std::move(structural_candidates)});
98  }
99 
100  for (const auto& [bc, sc_vec] : filtered_candidates)
101  {
102  for (const auto& sc : sc_vec)
103  {
104  // TODO: this is an ugly fix
105  sc->ctx.m_gates = sc->m_gates;
106  }
107  }
108 
109  return OK(std::move(filtered_candidates));
110  }
111 
113  {
114  std::vector<FunctionalCandidate> result;
115 
116  Netlist* nl = sc->m_gates.front()->get_netlist();
117  auto output_nets = get_output_nets(sc->m_gates, false);
118 
119  // TODO make this a config parameter
120  const u32 max_inputs = 130;
121  bool found_oversized_boolean_function = false;
122 
123  // the cache shares the inputs of the logic that the output nets have in common between them
124  const auto subgraph_dec = SubgraphNetlistDecorator(*nl);
125  auto cache_res = subgraph_dec.make_subgraph_function_cache(sc->m_gates);
126  if (cache_res.is_error())
127  {
128  return ERR_APPEND(cache_res.get_error(), "cannot generate functional candidates for " + sc->m_gates.front()->get_name() + ": failed to create subgraph function cache");
129  }
130  auto cache = cache_res.get();
131 
132  for (const auto& o_net : output_nets)
133  {
134  const auto input_nets_res = subgraph_dec.get_subgraph_function_inputs(o_net, cache);
135  if (input_nets_res.is_error())
136  {
137  return ERR_APPEND(input_nets_res.get_error(),
138  "cannot generate functional candidates for " + sc->m_gates.front()->get_name() + ": failed to get subgrapg inputs for net " + o_net->get_name() + " with ID "
139  + std::to_string(o_net->get_id()));
140  }
141  const auto input_net_count = input_nets_res.get().size();
142 
143  if (input_net_count > max_inputs)
144  {
145  found_oversized_boolean_function = true;
146  break;
147  }
148  }
149 
150  if (found_oversized_boolean_function)
151  {
152  return OK({});
153  }
154 
155  // TODO this should not happen, but exists as a safety meassure
156  if (sc->m_gates != sc->ctx.m_gates)
157  {
158  return ERR("cannot generate functional candidates: candiate and context gates are not identical!");
159  }
160 
161  const auto res = sc->ctx.populate_boolean_function_cache(output_nets);
162  if (res.is_error())
163  {
164  return ERR_APPEND(res.get_error(), "cannot generate functional candidates: failed to populate Boolean context cache");
165  }
166 
167  for (const auto& type : config.m_types_to_check)
168  {
169  const auto it = std::find(all_checkable_candidate_types.begin(), all_checkable_candidate_types.end(), type);
170 
171  if (it == all_checkable_candidate_types.end())
172  {
173  log_error("module_identification", "no candidate generation available for type {}", enum_to_string(type));
174  continue;
175  }
176 
177  const auto start_pre_processing = std::chrono::steady_clock::now();
178  auto new_candidates_res = FunctionalCandidate::create_candidates(sc, config.m_max_control_signals, sc->ctx, type, config.m_known_registers);
179  const u64 duration = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start_pre_processing).count();
180 
181  if (new_candidates_res.is_error())
182  {
183  return ERR(new_candidates_res.get_error().get());
184  }
185  auto new_candidates = new_candidates_res.get();
186 
187  std::map<std::string, std::map<std::string, std::map<std::string, std::map<std::string, u64>>>> new_entries = {};
188  new_entries["PRE_PROCESSING"][enum_to_string(type)]["CANDIDATE_CREATION"]["DURATION"] += duration;
189  new_entries["PRE_PROCESSING"][enum_to_string(type)]["CANDIDATE_CREATION"]["AMOUNT"] += new_candidates.size();
190  stats.add_stat(sc->base_candidate, new_entries);
191 
192  for (auto& nc : new_candidates)
193  {
194  result.push_back(nc);
195  }
196  }
197 
198  return OK(result);
199  }
200 
201  namespace
202  {
203  // TODO this is a mess of multi threading and needs cleaning up badly at some point
204  void work(std::vector<StructuralCandidate*>& structural_candidates_work_queque,
205  std::vector<std::unique_ptr<StructuralCandidate>>& structural_candidates,
206  std::vector<std::unique_ptr<StructuralCandidate>>& done_structural_candidates,
207  std::atomic<u32>& structural_workload,
208  std::deque<std::pair<std::unique_ptr<StructuralCandidate>, std::vector<FunctionalCandidate>>>& functional_candidates,
209  std::map<BaseCandidate*, std::vector<VerifiedCandidate>>& verified_candidates,
210  const Configuration& config,
211  Statistics& stats,
212  std::vector<std::string>& status,
213  std::vector<std::string>& candidate_info,
214  std::mutex& thread_sync,
215  const u32 thread_idx)
216  {
217  std::map<BaseCandidate*, std::vector<VerifiedCandidate>> verified_candidates_cache;
218 
219  const auto work_structural =
220  [&config, &structural_candidates_work_queque, &structural_candidates, &structural_workload, &functional_candidates, &stats, &status, &candidate_info, &thread_sync, &thread_idx]()
221  -> bool {
222  // check for structural OverarchingCandidate workloads
223  if (!structural_candidates_work_queque.empty())
224  {
225  // const auto sc = structural_candidates_work_queque.back();
226  structural_candidates_work_queque.pop_back();
227 
228  auto unique_sc = std::move(structural_candidates.back());
229  structural_candidates.pop_back();
230 
231  thread_sync.unlock();
232 
233  candidate_info.at(thread_idx) = "S_" + unique_sc->base_candidate->m_gates.front()->get_name();
234 
235  auto new_functional_candidates_res = generate_functional_candidates(unique_sc.get(), config, stats);
236  if (new_functional_candidates_res.is_error())
237  {
238  log_error("module_identification",
239  "failed to generate functional candidates for carry chain {}: {}",
240  unique_sc.get()->m_gates.front()->get_name(),
241  new_functional_candidates_res.get_error().get());
242  return true;
243  }
244  std::vector<FunctionalCandidate> new_functional_candidates = new_functional_candidates_res.get();
245 
246  for (const auto& fc : new_functional_candidates)
247  {
248  const auto _bfs = unique_sc.get()->ctx.get_boolean_functions(fc.m_output_nets, fc.m_control_mapping);
249  }
250 
251  structural_workload -= 1;
252  if (!new_functional_candidates.empty())
253  {
254  thread_sync.lock();
255  status.at(thread_idx) = "LOCKING STRUCTUAL at " + std::to_string(thread_idx);
256  functional_candidates.push_back({std::move(unique_sc), new_functional_candidates});
257  thread_sync.unlock();
258  }
259 
260  return true;
261  }
262 
263  return false;
264  };
265 
266  const auto work_functional = [&config, &functional_candidates, &done_structural_candidates, &verified_candidates_cache, &candidate_info, &thread_sync, &thread_idx, &stats]() -> bool {
267  // check for functional OverarchingCandidate workloads
268  if (!functional_candidates.empty())
269  {
270  auto& [sc, f_candidates] = functional_candidates.front();
271 
272  auto sc_ptr = functional_candidates.front().first.get();
273  auto bc = sc->base_candidate;
274  auto fc = f_candidates.back();
275 
276  if (f_candidates.size() == 1)
277  {
278  // if this was the last functional candidate from this structural candidate pop the pair from the deque
279  done_structural_candidates.push_back(std::move(sc));
280  sc_ptr = done_structural_candidates.back().get();
281 
282  functional_candidates.pop_front();
283  }
284  else
285  {
286  // ... otherwise just pop one candidate from the vector
287  f_candidates.pop_back();
288  }
289  thread_sync.unlock();
290 
291  candidate_info.at(thread_idx) = "F_" + fc.m_base_gates.front()->get_name();
292 
293  const auto output_functions_res = sc_ptr->ctx.get_boolean_functions_const(fc.m_output_nets, fc.m_control_mapping);
294  if (output_functions_res.is_error())
295  {
296  log_error("module_identification", "cannot check candidate: failed to get Boolean output functions before check.\n {}", output_functions_res.get_error().get());
297  }
298  const auto output_functions = output_functions_res.get();
299 
300  const auto res = fc.check(output_functions, config.m_known_registers);
301  if (res.is_error())
302  {
303  log_error("module_identification",
304  "failed to check current overaching candidate at carry chain {} of type {}:\n{}",
305  fc.m_gates.front()->get_name(),
306  enum_to_string(fc.m_candidate_type),
307  res.get_error().get());
308  return true;
309  }
310  stats.add_stat(bc, fc);
311 
312  auto vc = res.get();
313  vc.m_base_gates = bc->m_gates;
314 
315  if (vc.is_verified())
316  {
317  verified_candidates_cache[bc].push_back(vc);
318  }
319  return true;
320  }
321 
322  return false;
323  };
324 
325  status.at(thread_idx) = "INIT";
326  while (true)
327  {
328  // getting workload
329  candidate_info.at(thread_idx) = "NONE";
330  status.at(thread_idx) = "LOCKED";
331  thread_sync.lock();
332 
333  // all work is done, now return results
334  if ((structural_workload == 0) && functional_candidates.empty())
335  {
336  for (auto [bc, vc] : verified_candidates_cache)
337  {
338  verified_candidates.at(bc).insert(verified_candidates.at(bc).end(), vc.begin(), vc.end());
339  }
340  thread_sync.unlock();
341 
342  status.at(thread_idx) = "FINISHED";
343  return;
344  }
345 
346  if (config.m_multithreading_priority == MultithreadingPriority::time_priority)
347  {
348  status.at(thread_idx) = "RUNNING STRUCTURAL";
349  if (work_structural())
350  {
351  continue;
352  }
353 
354  status.at(thread_idx) = "RUNNING FUNCTIONAL";
355  if (work_functional())
356  {
357  continue;
358  }
359  }
360  else
361  {
362  status.at(thread_idx) = "RUNNING FUNCTIONAL";
363  if (work_functional())
364  {
365  continue;
366  }
367 
368  status.at(thread_idx) = "RUNNING STRUCTURAL";
369  if (work_structural())
370  {
371  continue;
372  }
373  }
374 
375  thread_sync.unlock();
376 
377  status.at(thread_idx) = "WAITING";
378  std::this_thread::sleep_for(std::chrono::milliseconds(200));
379  }
380  }
381 
383  execute_on_structural_candidates(std::vector<std::pair<std::unique_ptr<BaseCandidate>, std::vector<std::unique_ptr<StructuralCandidate>>>>& base_to_structural_candidates,
384  const Configuration& config)
385  {
386  Netlist* nl = config.m_netlist;
387 
388  // contains a list of verified candidates for each base candidate
389  std::map<BaseCandidate*, std::vector<VerifiedCandidate>> verified_candidates;
390 
391  std::vector<StructuralCandidate*> structural_candidates_work_queque;
392  std::vector<std::unique_ptr<StructuralCandidate>> structural_candidates;
393  std::vector<std::unique_ptr<StructuralCandidate>> done_structural_candidates;
394  std::deque<std::pair<std::unique_ptr<StructuralCandidate>, std::vector<FunctionalCandidate>>> functional_candidates;
395 
396  for (auto& [base_cand, struct_cands] : base_to_structural_candidates)
397  {
398  // initialize verified candidate list with pointer of base candidates
399  verified_candidates.insert(std::make_pair(base_cand.get(), std::vector<VerifiedCandidate>()));
400 
401  // create a vector with all base candidates
402  for (auto& sc : struct_cands)
403  {
404  structural_candidates_work_queque.push_back(sc.get());
405  structural_candidates.push_back(std::move(sc));
406  }
407  }
408 
409  std::atomic<u32> structural_workload = structural_candidates.size();
410 
411  if (structural_candidates.empty())
412  {
413  Result(nl, std::vector<std::pair<BaseCandidate, VerifiedCandidate>>());
414  }
415 
416  const u32 num_threads = std::min(config.m_max_thread_count, std::thread::hardware_concurrency() - 1);
417 
418  log_info("module_identification", "running with {} threads and {} multithreading priority", num_threads, static_cast<int>(config.m_multithreading_priority));
419 
420  auto stats = Statistics();
421 
422  // create hal GND and VCC nets as they might be needed for the operand creation
423  const auto gnd_res = NetlistModificationDecorator(*nl).create_gnd_net();
424  if (gnd_res.is_error())
425  {
426  log_error("module_identification", "failed to create GND net: {}", gnd_res.get_error().get());
427  }
428 
429  const auto vcc_res = NetlistModificationDecorator(*nl).create_vcc_net();
430  if (vcc_res.is_error())
431  {
432  log_error("module_identification", "failed to create VCC net: {}", vcc_res.get_error().get());
433  }
434 
435  // creating workloads
436  log_info("module_identification", "running checks for {} possible candidates...", structural_candidates.size());
437  std::vector<std::thread> workers;
438  std::vector<std::string> status = {num_threads + 1, "NOT STARTED"};
439  std::vector<std::string> candidate_info = {num_threads + 1, "NONE"};
440 
441  std::mutex thread_sync;
442 
443  for (u32 i = 0; i < num_threads; ++i)
444  {
445  workers.emplace_back([&, i]() {
446  return work(structural_candidates_work_queque,
447  structural_candidates,
448  done_structural_candidates,
449  structural_workload,
450  functional_candidates,
451  verified_candidates,
452  config,
453  stats,
454  status,
455  candidate_info,
456  thread_sync,
457  i);
458  });
459  }
460 
461 #ifdef PRINT_THREAD_INFO
462  while ((structural_workload != 0) || !functional_candidates.empty())
463  {
464  std::cout << "WORKLOAD: " << structural_workload << std::endl;
465 
466  std::map<std::string, u32> status_collection;
467  for (u32 i = 0; i < num_threads; i++)
468  {
469  status_collection[status.at(i)] += 1;
470  }
471 
472  std::cout << "Thread status: " << std::endl;
473  for (const auto& [sn, sc] : status_collection)
474  {
475  std::cout << "\t" << sn << ": " << sc << std::endl;
476  }
477 
478  std::map<std::string, u32> candidate_collection;
479  for (u32 i = 0; i < num_threads; i++)
480  {
481  candidate_collection[candidate_info.at(i)] += 1;
482  }
483 
484  if (candidate_collection.size() < 10)
485  {
486  std::cout << "Candidate Info: " << std::endl;
487  for (const auto& [sn, sc] : candidate_collection)
488  {
489  std::cout << "\t" << sn << ": " << sc << std::endl;
490  }
491  }
492 
493  std::this_thread::sleep_for(std::chrono::milliseconds(500));
494  }
495 #endif
496 
497  // wait for threads to finish
498  for (auto& worker : workers)
499  {
500  worker.join();
501  }
502 
503  // if (config.s_progress_indicator_function)
504  // {
505  // // TODO use string formatter to make this pretty
506  // config.s_progress_indicator_function(100, "module identification finished\ndoing postprocessing");
507  // }
508 
509  // post processing
510  std::map<std::string, u32> type_counter;
511  std::vector<std::vector<hal::Gate*>> known_registers = config.m_known_registers;
512  std::vector<std::pair<BaseCandidate, VerifiedCandidate>> result_input;
513 
514  log_info("module_identification", "Done with module identification, now doing post processing");
515 
516  const auto start_post_processing = std::chrono::steady_clock::now();
517  for (auto& [bc, vc] : verified_candidates)
518  {
519  auto post_processing_result = post_processing(vc, nl, known_registers);
520 
521  if (!post_processing_result.is_verified())
522  {
523  post_processing_result = VerifiedCandidate({}, {}, {}, {}, {}, {}, bc->m_gates, {}, {});
524  }
525 
526  result_input.push_back(std::make_pair(*bc, post_processing_result));
527  }
528  const auto duration_post_processing = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start_post_processing);
529  log_info("module_identification", "Post processing took {} ms", duration_post_processing.count());
530 
531  return OK(Result(nl, result_input, stats.to_json()));
532  }
533  } // namespace
534 
536  {
537  const Netlist* nl = config.m_netlist;
538 
539  log_info("module_identification",
540  "Executing on netlist {} / {} / {} and gatelib {}",
541  nl->get_top_module()->get_name(),
542  nl->get_design_name(),
543  nl->get_device_name(),
544  nl->get_gate_library()->get_name());
545 
546  auto res = generate_structural_candidates(nl, config);
547  if (res.is_error())
548  {
549  return ERR_APPEND(res.get_error(), "cannot execute plugin: failed structural candidate generation");
550  }
551 
552  auto base_to_structural_candidates = res.get();
553  return execute_on_structural_candidates(base_to_structural_candidates, config);
554  }
555 
556  hal::Result<Result> execute_on_gates(const std::vector<Gate*>& gates, const Configuration& config)
557  {
558  if (gates.empty())
559  {
560  return ERR("cannot execute plugin: provided gates are empty");
561  }
562 
563  std::unique_ptr<BaseCandidate> bc = std::make_unique<BaseCandidate>(gates);
564 
565  std::vector<std::unique_ptr<StructuralCandidate>> structural_vector;
566  structural_vector.emplace_back(std::make_unique<StructuralCandidate>(bc.get(), gates));
567  std::vector<std::pair<std::unique_ptr<BaseCandidate>, std::vector<std::unique_ptr<StructuralCandidate>>>> base_to_structural_candidates;
568  base_to_structural_candidates.emplace_back(std::make_pair<std::unique_ptr<BaseCandidate>, std::vector<std::unique_ptr<StructuralCandidate>>>(std::move(bc), std::move(structural_vector)));
569 
570  return execute_on_structural_candidates(base_to_structural_candidates, config);
571  }
572  } // namespace module_identification
573 } // namespace hal
This file contains the definition of the BaseCandidate class, which represents a base candidate in th...
This file contains the enumeration and constants for the candidate types used in the module identific...
std::string get_name() const
std::string get_name() const
Definition: module.cpp:88
Module * get_top_module() const
Definition: netlist.cpp:610
const std::string & get_device_name() const
Definition: netlist.cpp:120
const std::string & get_design_name() const
Definition: netlist.cpp:106
const GateLibrary * get_gate_library() const
Definition: netlist.cpp:134
static hal::Result< std::vector< FunctionalCandidate > > create_candidates(StructuralCandidate *sc, u32 max_control_signal, CandidateContext &ctx, module_identification::CandidateType candidate_type, const std::vector< std::vector< Gate * >> &registers)
Create functional candidates from a structural candidate.
A class representing a structural candidate for module identification.
BaseCandidate * base_candidate
Pointer to the base candidate.
std::vector< Gate * > m_gates
Vector of gates that form the structural candidate.
CandidateContext ctx
Candidate context for the structural candidate.
uint64_t u64
Definition: defines.h:42
uint32_t u32
Definition: defines.h:41
This file contains the class and functions for handling functional candidates within the module ident...
#define log_error(channel,...)
Definition: log.h:78
#define log_info(channel,...)
Definition: log.h:70
#define ERR(message)
Definition: result.h:60
#define OK(...)
Definition: result.h:56
#define ERR_APPEND(prev_error, message)
Definition: result.h:64
This file contains the function to generate structural candidates for Lattice iCE40 FPGAs.
This file contains the struct Configuration for module identification analysis.
This file contains the function declarations for the Module Identification plugin in hal.
std::vector< std::pair< std::unique_ptr< BaseCandidate >, std::vector< std::unique_ptr< StructuralCandidate > > > > generate_structural_candidates(const Netlist *nl)
Generate structural candidates for a given netlist.
std::vector< std::pair< std::unique_ptr< BaseCandidate >, std::vector< std::unique_ptr< StructuralCandidate > > > > generate_structural_candidates(const Netlist *nl)
Generate structural candidates for a given netlist.
hal::Result< std::vector< FunctionalCandidate > > generate_functional_candidates(StructuralCandidate *sc, const Configuration &config, Statistics &stats)
const std::vector< CandidateType > all_checkable_candidate_types
A list of all candidate types that are selectable to be checked.
hal::Result< std::vector< std::pair< std::unique_ptr< BaseCandidate >, std::vector< std::unique_ptr< StructuralCandidate > > > > > generate_structural_candidates(const Netlist *nl, const Configuration &config)
hal::Result< Result > execute(const Configuration &config)
Perform a full run of the module identification process on the given netlist with the provided config...
VerifiedCandidate post_processing(const std::vector< VerifiedCandidate > &verified_candidates, const Netlist *nl, const std::vector< std::vector< Gate * >> &dana_cache)
Performs post-processing on a set of verified candidates to identify the best candidate for module id...
hal::Result< Result > execute_on_gates(const std::vector< Gate * > &gates, const Configuration &config)
Perform a module identification run on the specified gates with the provided configuration.
std::vector< Net * > get_output_nets(const std::vector< Gate * > &gates, bool only_external_destinations=true)
Get output nets from a list of gates.
Definition: utils.cpp:61
@ time_priority
Prioritize time efficiency in multithreading.
Definition: defines.h:45
std::string enum_to_string(T e)
Definition: enums.h:53
PinType type
This file contains the structures and functions related to module identification results.
This file contains helper functions for module identification in the HAL framework.
This file contains the function to perform post-processing on verified candidates to identify the bes...
std::vector< Gate * > m_gates
The gates of the corresponding structural candidate.
hal::Result< std::monostate > populate_boolean_function_cache(const std::vector< Net * > nets)
Populates the boolean function cache for a set of nets.
Configuration for the module identification analysis.
Definition: configuration.h:55
Netlist * m_netlist
The netlist to be analyzed.
Definition: configuration.h:71
std::vector< std::set< Gate * > > m_blocked_base_candidates
Base candidates to block during analysis.
std::vector< module_identification::CandidateType > m_types_to_check
CandidateTypes that shall be checked. Defaults to all checkable candidate types.
Definition: configuration.h:81
std::vector< std::vector< Gate * > > m_known_registers
A vector handling possibly known registers.
Definition: configuration.h:76
u32 m_max_control_signals
Maximum number of control signals to be tested. Defaults to 3.
Definition: configuration.h:91
std::vector< std::vector< Gate * > > m_already_classified_candidates
Gates to ignore during processing.
Definition: configuration.h:96
void add_stat(const BaseCandidate *bc, const FunctionalCandidate &oc)
Definition: statistics.h:28
This file contains the class for defining and managing structural candidates within the module identi...
This file contains the function to generate structural candidates for Xilinx Unisim libraries.