HAL  v4.5.0-83-g30c8f0afc
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
result.cpp
Go to the documentation of this file.
2 
8 
9 #include <algorithm>
10 #include <iterator>
11 #include <tuple>
12 #include <vector>
13 
14 namespace hal
15 {
16  namespace module_identification
17  {
18  Result::Result(Netlist* nl, const std::vector<std::pair<BaseCandidate, VerifiedCandidate>>& result, const std::string& timing_stats_json)
19  : m_netlist{nl}, m_candidates{result}, m_timing_stats_json{timing_stats_json}
20  {
21  }
22 
24  {
25  return m_netlist;
26  }
27 
28  std::map<u32, std::vector<Gate*>> Result::get_verified_candidate_gates() const
29  {
30  std::map<u32, std::vector<Gate*>> result;
31 
32  for (u32 idx = 0; idx < m_candidates.size(); idx++)
33  {
34  const auto& [base_candidate, verified_candidate] = m_candidates[idx];
35  if (verified_candidate.is_verified())
36  {
37  result.insert(std::make_pair(idx, verified_candidate.m_gates));
38  }
39  }
40  return result;
41  }
42 
43  std::map<u32, VerifiedCandidate> Result::get_verified_candidates() const
44  {
45  std::map<u32, VerifiedCandidate> result;
46  for (u32 idx = 0; idx < m_candidates.size(); idx++)
47  {
48  const auto& [base_candidate, verified_candidate] = m_candidates[idx];
49  if (verified_candidate.is_verified())
50  {
51  result.insert(std::make_pair(idx, verified_candidate));
52  }
53  }
54  return result;
55  }
56 
57  std::map<u32, std::vector<Gate*>> Result::get_candidate_gates() const
58  {
59  std::map<u32, std::vector<Gate*>> result;
60  for (u32 idx = 0; idx < m_candidates.size(); idx++)
61  {
62  const auto& [base_candidate, verified_candidate] = m_candidates[idx];
63  result.insert(std::make_pair(idx, verified_candidate.m_gates));
64  }
65  return result;
66  }
67 
68  std::map<u32, VerifiedCandidate> Result::get_candidates() const
69  {
70  std::map<u32, VerifiedCandidate> result;
71  for (u32 idx = 0; idx < m_candidates.size(); idx++)
72  {
73  const auto& [base_candidate, verified_candidate] = m_candidates[idx];
74  result.insert(std::make_pair(idx, verified_candidate));
75  }
76  return result;
77  }
78 
80  {
81  if (id >= m_candidates.size())
82  {
83  return ERR("cannot get candidate with id " + std::to_string(id));
84  }
85 
86  const auto& [base_candidate, verified_candidate] = m_candidates[id];
87  if (verified_candidate.is_verified())
88  {
89  return OK(verified_candidate.m_gates);
90  }
91  else
92  {
93  return OK(base_candidate.m_gates);
94  }
95  }
96 
98  {
99  if (id >= m_candidates.size())
100  {
101  return ERR("cannot get candidate with id " + std::to_string(id));
102  }
103  auto [base_candidate, verified_candidate] = m_candidates[id];
104  return OK(verified_candidate);
105  }
106 
107  std::set<Gate*> Result::get_all_gates() const
108  {
109  std::set<Gate*> result;
110  for (const auto& [base_candidate, verified_candidate] : m_candidates)
111  {
112  if (verified_candidate.is_verified())
113  {
114  std::copy(verified_candidate.m_gates.begin(), verified_candidate.m_gates.end(), std::inserter(result, result.end()));
115  }
116  else
117  {
118  std::copy(base_candidate.m_gates.begin(), base_candidate.m_gates.end(), std::inserter(result, result.end()));
119  }
120  }
121  return result;
122  }
123 
124  std::set<Gate*> Result::get_all_verified_gates() const
125  {
126  std::set<Gate*> result;
127  for (const auto& [base_candidate, verified_candidate] : m_candidates)
128  {
129  if (verified_candidate.is_verified())
130  {
131  std::copy(verified_candidate.m_gates.begin(), verified_candidate.m_gates.end(), std::inserter(result, result.end()));
132  }
133  }
134  return result;
135  }
136 
137  namespace
138  {
139  std::pair<std::map<Gate*, std::vector<u32>>, std::map<Gate*, std::vector<u32>>> check_for_conflicting_gates(const std::vector<std::pair<BaseCandidate, VerifiedCandidate>>& candidates)
140  {
141  std::map<Gate*, std::vector<u32>> gate_to_candidates;
142  std::map<Gate*, std::vector<u32>> conflicts;
143 
144  u32 candidate_id = 0;
145  for (auto [base_cand, verified_cand] : candidates)
146  {
147  if (verified_cand.is_verified())
148  {
149  for (auto gate : verified_cand.m_gates)
150  {
151  if (gate_to_candidates.find(gate) == gate_to_candidates.end())
152  {
153  gate_to_candidates.insert(std::make_pair(gate, std::vector<u32>()));
154  }
155  gate_to_candidates[gate].push_back(candidate_id);
156  }
157  }
158  else
159  {
160  for (auto cur_gate : base_cand.m_gates)
161  {
162  if (gate_to_candidates.find(cur_gate) == gate_to_candidates.end())
163  {
164  gate_to_candidates.insert(std::make_pair(cur_gate, std::vector<u32>()));
165  }
166  gate_to_candidates[cur_gate].push_back(candidate_id);
167  }
168  }
169  candidate_id++;
170  }
171 
172  for (auto [gate, list] : gate_to_candidates)
173  {
174  if (list.size() > 1)
175  {
176  conflicts.insert(std::make_pair(gate, list));
177  }
178  }
179 
180  return {gate_to_candidates, conflicts};
181  }
182 
183  std::pair<Gate*, u32> get_possible_conflict(const std::map<Gate*, std::vector<u32>>& conflicts)
184  {
185  // NOTE: naming, both times they are called current follwoer oder current conflict, there might be better names
186  for (auto [gate, conflicting_candidates] : conflicts)
187  {
188  std::set<u32> successor_conflicts;
189  for (const auto& ep : gate->get_fan_out_endpoints())
190  {
191  for (const auto& dest : ep->get_net()->get_destinations())
192  {
193  if (dest->get_gate() == nullptr)
194  {
195  continue;
196  }
197  if (conflicts.find(dest->get_gate()) == conflicts.end())
198  {
199  continue;
200  }
201  const auto& dest_conflicts = conflicts.at(dest->get_gate());
202  for (u32 dest_conflict : dest_conflicts)
203  {
204  successor_conflicts.insert(dest_conflict);
205  }
206  }
207  }
208 
209  // check whether there is a candidate where this gate causes a conflict that does not also include a conflicting successor of the gate
210  for (u32 conflict_id : conflicting_candidates)
211  {
212  if (std::find(successor_conflicts.begin(), successor_conflicts.end(), conflict_id) == successor_conflicts.end())
213  {
214  // found free id without conflicts
215  return std::make_pair(gate, conflict_id);
216  }
217  }
218  }
219  // couldnt find a free follower
220  log_error("module_identification",
221  "could not resolve conflicts in duplicate gates due to cyclic dependency. Continuing with following broken gate: {}",
222  conflicts.begin()->first->get_name());
223 
224  return std::make_pair(conflicts.begin()->first, conflicts.begin()->second[0]);
225  }
226 
227  void resolve_conflicts_by_cloning(Netlist* nl,
228  std::map<Gate*, std::vector<u32>>& conflicts,
229  std::map<Gate*, std::vector<u32>>& gate_to_candidates,
230  std::vector<std::pair<BaseCandidate, VerifiedCandidate>>& candidates)
231  {
232  // find an order for gates that prioritizes gates at the end
233  while (conflicts.size() > 0)
234  {
235  std::pair<Gate*, u32> available_conflict = get_possible_conflict(conflicts);
236 
237  // TODO remove debug printing
238  // std::cout << "Dealing with conflict " << available_conflict.first->get_name() << " in candidate " << available_conflict.second << std::endl;
239 
240  auto gate = available_conflict.first;
241  auto current_candidate = available_conflict.second;
242 
243  u32 new_gate_id = nl->get_unique_gate_id();
244  std::string new_gate_name = gate->get_name() + "_CLONE_" + std::to_string(gate->get_id()) + "_" + std::to_string(new_gate_id);
245  Gate* new_gate = nl->create_gate(new_gate_id, gate->get_type(), new_gate_name);
246 
247  // copy boolean functions
248  for (const auto& [pin, bf] : gate->get_boolean_functions())
249  {
250  new_gate->add_boolean_function(pin, bf);
251  }
252 
253  // copy all sources from the conflicting gate to the new_gate
254  for (const auto& ep : gate->get_fan_in_endpoints())
255  {
256  ep->get_net()->add_destination(new_gate, ep->get_pin());
257  }
258 
259  // copy data container
260  new_gate->set_data_map(gate->get_data_map());
261 
262  // remove old gate from module and replace with new one
263  std::vector<Gate*>* relevant_vector;
264  auto& [base_candidate, verified_candidate] = candidates[current_candidate];
265  if (verified_candidate.is_verified())
266  {
267  relevant_vector = &(verified_candidate.m_gates);
268  }
269  else
270  {
271  relevant_vector = &(base_candidate.m_gates);
272  }
273  std::vector<Gate*>::iterator position = std::find(relevant_vector->begin(), relevant_vector->end(), gate);
274  if (position != relevant_vector->end())
275  {
276  relevant_vector->erase(position);
277  }
278  else
279  {
280  log_error("module_identification", "trying to erase gate {} / {} from candidate that the gate is not part of", gate->get_id(), gate->get_name());
281  }
282  relevant_vector->push_back(new_gate);
283 
284  gate_to_candidates.insert({new_gate, {current_candidate}});
285 
286  // remove candidate id from old gate
287  std::vector<u32>::iterator old_id_position = std::find(gate_to_candidates[gate].begin(), gate_to_candidates[gate].end(), current_candidate);
288  if (old_id_position != gate_to_candidates[gate].end())
289  {
290  gate_to_candidates[gate].erase(old_id_position);
291  }
292  else
293  {
294  log_error("module_identification", "trying to erase gate {} / {} from candidate that the gate is not part of", gate->get_id(), gate->get_name());
295  }
296 
297  // find all destinations of the conflicting gate that lead to a gate inside the candidate
298  std::map<GatePin*, std::map<Gate*, std::vector<GatePin*>>> new_destinations;
299  for (const auto& ep : gate->get_fan_out_endpoints())
300  {
301  for (const auto& dest : ep->get_net()->get_destinations())
302  {
303  if (dest->get_gate() == nullptr)
304  {
305  continue;
306  }
307 
308  // Check whether destination is part of the candidate where we are cloning in
309  auto dest_gate_mod = gate_to_candidates.find(dest->get_gate());
310  if (dest_gate_mod == gate_to_candidates.end())
311  {
312  // destination is not part of any module
313  // what do we do here?
314  // NOTE: For now we do nothing, that way only the orignal gate keeps this connection.
315 
316  // TODO remove debug printing
317  // std::cout << dest->get_gate()->get_name() << " not part of any module" << std::endl;
318 
319  continue;
320  }
321 
322  const auto& dest_mod_vec = dest_gate_mod->second;
323  if (std::find(dest_mod_vec.begin(), dest_mod_vec.end(), current_candidate) == dest_mod_vec.end())
324  {
325  // dest is outside this module so no need to attach
326  // TODO remove debug printing
327  // std::cout << dest->get_gate()->get_name() << " not part of conflict module" << std::endl;
328  continue;
329  }
330 
331  // safe destination inside the same candidate to later add to the cloned net/gate
332  new_destinations[ep->get_pin()][dest->get_gate()].push_back(dest->get_pin());
333 
334  // TODO remove debug printing
335  // std::cout << "Adding dst " << dest->get_gate()->get_name() << " / " << dest->get_pin()->get_name() << std::endl;
336 
337  // remove the new destination from the conflicting gate
338  ep->get_net()->remove_destination(dest);
339  }
340 
341  // NOTE "!=" instead of "=="
342  // NOTE naming, we usually use camel_case for variables
343  // substitute net in verified cand if it is an output net
344  if (verified_candidate.is_verified()
345  && (std::find(verified_candidate.m_output_nets.begin(), verified_candidate.m_output_nets.end(), ep->get_net()) != verified_candidate.m_output_nets.end()))
346  {
347  // net is output net
348 
349  // create new net
350  u32 new_net_id = nl->get_unique_net_id();
351  std::string new_net_name = "n" + std::to_string(new_net_id) + "_OUTPUT";
352  Net* new_net = nl->create_net(new_net_id, new_net_name);
353 
354  // add source to new net
355  new_net->add_source(new_gate, ep->get_pin());
356  // replace relevant net
357  std::replace(verified_candidate.m_output_nets.begin(), verified_candidate.m_output_nets.end(), ep->get_net(), new_net);
358  }
359  }
360 
361  // create new_nets and connect to new_gate and new_destinations
362  for (const auto& [src_pin, destinations] : new_destinations)
363  {
364  Net* new_net;
365  if (auto fan_out_net = new_gate->get_fan_out_net(src_pin); fan_out_net != nullptr)
366  {
367  new_net = fan_out_net;
368  }
369  else
370  {
371  u32 new_net_id = nl->get_unique_net_id();
372  std::string new_net_name = "n" + std::to_string(new_net_id) + "_CLONED";
373  new_net = nl->create_net(new_net_id, new_net_name);
374 
375  if (!new_net->add_source(new_gate, src_pin))
376  {
377  log_error("module_identification",
378  "failed to add source to net {} with ID {} at gate {} with ID {} and pin {}",
379  new_net->get_name(),
380  new_net->get_id(),
381  new_gate->get_name(),
382  new_gate->get_id(),
383  src_pin->get_name());
384  }
385  }
386 
387  // TODO remove
388  // std::cout << "Created output net " << new_net->get_name() << " with ID " << new_net->get_id() << " at gate " << new_gate->get_name() << " with ID " << new_gate()->get_id()
389  // << " and pin " << src_pin->get_name() << std::endl;
390 
391  for (const auto& [dest_gate, dest_pins] : destinations)
392  {
393  for (const auto& dest_pin : dest_pins)
394  {
395  if (!new_net->add_destination(dest_gate, dest_pin))
396  {
397  log_error("module_identification",
398  "failed to add destination to net {} with ID {} at gate {} with ID {} and pin {}",
399  new_net->get_name(),
400  new_net->get_id(),
401  dest_gate->get_name(),
402  dest_gate->get_id(),
403  dest_pin->get_name());
404  }
405  }
406  }
407  }
408 
409  // remove the resolved conflict
410  std::vector<u32>::iterator conflict_position = std::find(conflicts[gate].begin(), conflicts[gate].end(), current_candidate);
411  if (conflict_position != conflicts[gate].end())
412  {
413  conflicts[gate].erase(conflict_position);
414  }
415  if (conflicts[gate].size() <= 1)
416  {
417  conflicts.erase(gate);
418  }
419  }
420 
421  return;
422  }
423 
424  } // namespace
425 
427  {
428  // search for base candidates that were not verified but are a subset of another verified candidate
429  // these candidates do not need to have a own module and therefore dont have to be cloned
430  std::vector<std::pair<BaseCandidate, VerifiedCandidate>> filtered_candidates;
431 
432  for (u32 i = 0; i < m_candidates.size(); i++)
433  {
434  const auto& [bi, vi] = m_candidates.at(i);
435  if (vi.is_verified())
436  {
437  filtered_candidates.push_back(m_candidates.at(i));
438  continue;
439  }
440 
441  bool is_subset = false;
442  for (u32 j = 0; i < m_candidates.size(); j++)
443  {
444  if (i == j)
445  {
446  continue;
447  }
448 
449  const auto& [bj, vj] = m_candidates.at(j);
450 
451  if (!vj.is_verified())
452  {
453  continue;
454  }
455 
456  if (utils::is_subset(bi.m_gates, vj.m_gates))
457  {
458  is_subset = true;
459  break;
460  }
461  }
462 
463  if (!is_subset)
464  {
465  filtered_candidates.push_back(m_candidates.at(i));
466  }
467  }
468 
469  auto [gate_to_candidates, conflicts] = check_for_conflicting_gates(filtered_candidates);
470 
471  resolve_conflicts_by_cloning(m_netlist, conflicts, gate_to_candidates, filtered_candidates);
472 
473  std::map<std::string, u32> type_counter;
474 
475  for (u32 candidate_idx = 0; candidate_idx < filtered_candidates.size(); candidate_idx++)
476  {
477  auto& [base_candidate, selected_candidate] = filtered_candidates.at(candidate_idx);
478 
479  const std::string candidate_name = selected_candidate.get_name();
480 
481  if (type_counter.find(candidate_name) == type_counter.end())
482  {
483  type_counter.insert(std::make_pair(candidate_name, 0));
484  }
485 
486  const auto mod_gates = selected_candidate.is_verified() ? selected_candidate.m_gates : selected_candidate.m_base_gates;
487 
488  auto mod = m_netlist->create_module(candidate_name + "_" + std::to_string(type_counter[candidate_name]), m_netlist->get_top_module(), mod_gates);
489  type_counter[candidate_name]++;
490 
491  std::set<u32> ctrl_mapping_values;
492  for (const auto& cm : selected_candidate.m_control_signal_mappings)
493  {
494  u32 ctrl_val = 0;
495  for (const auto& [net, val] : cm)
496  {
497  ctrl_val = (ctrl_val << 1) + ((val == BooleanFunction::ONE) ? 1 : 0);
498  }
499 
500  ctrl_mapping_values.insert(ctrl_val);
501  }
502 
503  mod->set_data("ModuleIdentification", "VERIFIED_CANDIDATE_ID", "String", std::to_string(candidate_idx));
504 
505  mod->set_data("ModuleIdentification", "VERIFIED_TYPES", "String", utils::join(", ", selected_candidate.m_types));
506 
507  mod->set_data("ModuleIdentification", "CTRL_MAPPINGS", "String", utils::join(", ", ctrl_mapping_values));
508 
509  std::string word_level_operation_str = "";
510  for (const auto& [cm, bf] : selected_candidate.m_word_level_operations)
511  {
512  u32 ctrl_val = 0;
513  for (const auto& [net, val] : cm)
514  {
515  ctrl_val = (ctrl_val << 1) + ((val == BooleanFunction::ONE) ? 1 : 0);
516  }
517 
518  word_level_operation_str += std::to_string(ctrl_val) + ": " + bf.to_string() + "\n";
519  }
520 
521  mod->set_data("ModuleIdentification", "OPERATIONS", "String", word_level_operation_str);
522 
523  // add operands to module
524 
525  const std::vector<std::string> op_names = {"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W"};
526 
527  if (selected_candidate.m_operands.size() > op_names.size())
528  {
529  return ERR("cannot create modules: encountered candidate with more operands than operand names");
530  }
531 
532  std::map<std::string, std::vector<Net*>> named_operands;
533  for (u32 op_idx = 0; op_idx < selected_candidate.m_operands.size(); op_idx++)
534  {
535  named_operands.insert({op_names.at(op_idx), selected_candidate.m_operands.at(op_idx)});
536  }
537 
538  // NOTE: this is a work around since modules do not allow for a net to lead to multiple pins
539  std::map<Net*, std::map<std::string, std::vector<u32>>> nets_to_indices;
540  for (const auto& [name, nets] : named_operands)
541  {
542  for (u32 idx = 0; idx < nets.size(); idx++)
543  {
544  const auto& net = nets.at(idx);
545  nets_to_indices[net][name].push_back(idx);
546  }
547  }
548 
549  // TODO remove debug printing
550  // for (const auto& [net, names] : nets_to_indices)
551  // {
552  // std::cout << "Net: " << net->get_id() << " / " << net->get_name() << std::endl;
553  // for (const auto& [name, indices] : names)
554  // {
555  // std::cout << "\t" << name << std::endl;
556  // for (const auto& index : indices)
557  // {
558  // std::cout << "\t\t" << index << std::endl;
559  // }
560  // }
561  // }
562 
563  std::set<Net*> visited;
564  for (const auto& [name, nets] : named_operands)
565  {
566  std::vector<hal::ModulePin*> operand_pins;
567  for (const auto& net : nets)
568  {
569  auto pin = mod->get_pin_by_net(net);
570  if (pin == nullptr)
571  {
572  log_error("module_identification", "module {} / {} does not have a pin connected to net {} / {}", mod->get_name(), mod->get_id(), net->get_name(), net->get_id());
573  continue;
574  }
575 
576  // if the net/pin already belongs to the group we dont try to add it again
577  if (std::find(visited.begin(), visited.end(), net) != visited.end())
578  {
579  continue;
580  }
581  visited.insert(net);
582 
583  // NOTE this is a way to build an ugly pin name containing all the pins that a net is connected to but for now i dont know of any better solution
584  std::vector<std::string> operand_pin_names;
585  for (const auto& [op_name, indices] : nets_to_indices.at(net))
586  {
587  operand_pin_names.push_back(op_name + "_" + utils::join(", ", indices));
588  }
589  std::string new_pin_name = utils::join(" | ", operand_pin_names);
590 
591  mod->set_pin_name(pin, new_pin_name);
592  operand_pins.push_back(pin);
593  }
594 
595  std::reverse(operand_pins.begin(), operand_pins.end());
596  auto res = mod->create_pin_group(name, operand_pins, hal::PinDirection::input, hal::PinType::data, false, operand_pins.size() - 1, true);
597  if (res.is_error())
598  {
599  log_error("module_identification", "could not create input pin group: {}", res.get_error().get());
600  }
601  }
602 
603  // add outputs
604  std::vector<hal::ModulePin*> output_pins;
605  u32 counter = 0;
606  for (const auto& out_net : selected_candidate.m_output_nets)
607  {
608  auto pin = mod->get_pin_by_net(out_net);
609  if (pin == nullptr)
610  {
611  log_error("module_identification", "module {} / {} does not have a pin connected to net {} / {}", mod->get_name(), mod->get_id(), out_net->get_name(), out_net->get_id());
612  continue;
613  }
614 
615  std::string pin_name = "OUT_" + std::to_string(counter++);
616  mod->set_pin_name(pin, pin_name);
617  output_pins.push_back(pin);
618  }
619 
620  std::reverse(output_pins.begin(), output_pins.end());
621  auto output_res = mod->create_pin_group("OUT", output_pins, hal::PinDirection::output, hal::PinType::data, false, output_pins.size() - 1, true);
622  if (output_res.is_error())
623  {
624  hal::log_error("module_identification", "could not create output pin group: {}", output_res.get_error().get());
625  }
626 
627  // add controls
628  counter = 0;
629  std::vector<hal::ModulePin*> ctrl_pins;
630  for (const auto& ctrl_net : selected_candidate.m_control_signals)
631  {
632  auto pin = mod->get_pin_by_net(ctrl_net);
633  if (pin == nullptr)
634  {
635  log_error("module_identification", "module {} / {} does not have a pin connected to net {} / {}", mod->get_name(), mod->get_id(), ctrl_net->get_name(), ctrl_net->get_id());
636  continue;
637  }
638 
639  std::string pin_name = "CTRL_" + std::to_string(counter++);
640  mod->set_pin_name(pin, pin_name);
641  ctrl_pins.push_back(pin);
642  }
643  if (!ctrl_pins.empty())
644  {
645  std::reverse(ctrl_pins.begin(), ctrl_pins.end());
646  auto ctrl_res = mod->create_pin_group("CTRL", ctrl_pins, hal::PinDirection::input, hal::PinType::control, false, ctrl_pins.size() - 1, true);
647  if (ctrl_res.is_error())
648  {
649  log_info("module_identification", "could not create ctrl pin group: {}", ctrl_res.get_error().get());
650  }
651  }
652 
653  // This creates a more human readable form of the word level operations
654  std::string word_level_operation_hr_str = "";
655  for (const auto& [cm, bf] : selected_candidate.m_word_level_operations)
656  {
657  u32 ctrl_val = 0;
658  for (const auto& [net, val] : cm)
659  {
660  ctrl_val = (ctrl_val << 1) + ((val == BooleanFunction::ONE) ? 1 : 0);
661  }
662 
663  const auto bf_hr_res = BooleanFunctionDecorator(bf).substitute_module_pins({mod});
664  if (bf_hr_res.is_error())
665  {
666  log_warning("module_identification", "{}", bf_hr_res.get_error().get());
667  continue;
668  }
669  const auto bf_hr = bf_hr_res.get().simplify_local();
670 
671  word_level_operation_hr_str += std::to_string(ctrl_val) + ": " + bf_hr.to_string() + "\n";
672  }
673 
674  mod->set_data("ModuleIdentification", "OPERATIONS_HR", "String", word_level_operation_hr_str);
675  }
676 
677  return OK({});
678  }
679 
680  std::string Result::get_timing_stats() const
681  {
682  return m_timing_stats_json;
683  }
684 
685  hal::Result<Result> Result::merge(const Result& other, const std::vector<std::vector<Gate*>>& dana_cache) const
686  {
687  std::unordered_set<Gate*> base_gates;
688  std::map<const std::set<Gate*>, std::vector<VerifiedCandidate>> base_candidate_to_verified_candidate;
689 
690  for (const auto& [bc, vc] : other.m_candidates)
691  {
692  const std::set<Gate*> bc_set = {bc.m_gates.begin(), bc.m_gates.end()};
693 
694  // check whether base candidate is already in map
695  if (auto it = base_candidate_to_verified_candidate.find(bc_set); it != base_candidate_to_verified_candidate.end())
696  {
697  it->second.push_back(vc);
698  continue;
699  }
700 
701  // check whether parts of the base candidate are a nullptr, not in the netlist or already contained in other base candidates
702  for (const auto& g : bc.m_gates)
703  {
704  if (g == nullptr)
705  {
706  return ERR("failed to merge results: other result contains a base candidate with a nullptr gate");
707  }
708 
709  if (!this->m_netlist->get_top_module()->contains_gate(g))
710  {
711  return ERR("failed to merge results: base candidate gate " + std::to_string((u64)(void**)g) + " is not (or no longer) part of the netlist!");
712  }
713 
714  // TODO this should be the case, but it is not, since we have not yet resolved conflicts
715  // if (base_gates.find(g) != base_gates.end())
716  // {
717  // return ERR("failed to merge results: base candidate gate " + g->get_name() + " with ID " + std::to_string(g->get_id()) + " is part of multiple different base candidates!");
718  // }
719 
720  base_gates.insert(g);
721  }
722 
723  // add verfied candidate
724  base_candidate_to_verified_candidate[bc_set].push_back(vc);
725  }
726 
727  for (const auto& [bc, vc] : m_candidates)
728  {
729  const std::set<Gate*> bc_set = {bc.m_gates.begin(), bc.m_gates.end()};
730 
731  // check whether base candidate is already in map
732  if (auto it = base_candidate_to_verified_candidate.find(bc_set); it != base_candidate_to_verified_candidate.end())
733  {
734  it->second.push_back(vc);
735  continue;
736  }
737 
738  // check whether parts of the base candidate are a nullptr, not in the netlist or already contained in other base candidates
739  for (const auto& g : bc.m_gates)
740  {
741  if (g == nullptr)
742  {
743  return ERR("failed to merge results: result contains a base candidate with a nullptr gate");
744  }
745 
746  if (!this->m_netlist->get_top_module()->contains_gate(g))
747  {
748  return ERR("failed to merge results: base candidate gate " + std::to_string((u64)(void**)g) + " is not part of the netlist!");
749  }
750 
751  // TODO this should be the case, but it is not, since we have not yet resolved conflicts
752  // if (base_gates.find(g) != base_gates.end())
753  // {
754  // return ERR("failed to merge results: base candidate gate " + g->get_name() + " with ID " + std::to_string(g->get_id()) + " is part of multiple different base candidates!");
755  // }
756 
757  base_gates.insert(g);
758  }
759 
760  // add verfied candidate
761  base_candidate_to_verified_candidate[bc_set].push_back(vc);
762  }
763 
764  std::vector<std::pair<BaseCandidate, VerifiedCandidate>> result_candidates;
765  for (auto& [bc_set, vc] : base_candidate_to_verified_candidate)
766  {
767  result_candidates.push_back(std::make_pair(BaseCandidate({bc_set.begin(), bc_set.end()}), post_processing(vc, this->m_netlist, dana_cache)));
768  }
769 
770  return OK(Result{this->m_netlist, result_candidates});
771  }
772 
773  namespace
774  {
775  // TODO this is duplicated in the post processing. find a common place for this
776  u64 calculate_ignored_input_signals(const VerifiedCandidate& vc)
777  {
778  // first collect all operand nets
779  std::set<Net*> covered_nets;
780  for (const auto& op : vc.m_operands)
781  {
782  for (const auto& net : op)
783  {
784  if (net->is_gnd_net() || net->is_vcc_net())
785  {
786  continue;
787  }
788  covered_nets.insert(net);
789  }
790  }
791  covered_nets.insert(vc.m_control_signals.begin(), vc.m_control_signals.end());
792 
793  // second collect all nets that are not part of the operands
794  u64 ignored_inputs = 0;
795  for (const auto& input_net : vc.m_total_input_nets)
796  {
797  if (covered_nets.find(input_net) == covered_nets.end())
798  {
799  ignored_inputs++;
800  }
801  }
802 
803  return ignored_inputs;
804  }
805 
806  // calculates the maximum amount of outputs not covered by the candidate output
807  u64 calculate_ignored_output_signals(const VerifiedCandidate& vc)
808  {
809  const auto all_outputs = vc.m_total_output_nets.size();
810  const auto c_outputs = vc.m_output_nets.size();
811  const auto outputs_ignored = (c_outputs > all_outputs) ? 0 : all_outputs - c_outputs;
812 
813  return outputs_ignored;
814  }
815 
816  u64 calculate_ctrl_score(const VerifiedCandidate& vc)
817  {
818  return vc.m_control_signals.size();
819  }
820 
821  u64 compute_total_io_score(const VerifiedCandidate& vc)
822  {
823  std::set<Net*> total_data_io;
824  for (const auto& nets : vc.m_operands)
825  {
826  for (const auto& n : nets)
827  {
828  if (n->is_gnd_net() || n->is_vcc_net())
829  {
830  continue;
831  }
832  total_data_io.insert(n);
833  }
834  }
835  for (const auto& n : vc.m_output_nets)
836  {
837  total_data_io.insert(n);
838  }
839 
840  return (u64)total_data_io.size();
841  }
842 
843  u64 compute_is_verified(const VerifiedCandidate& vc)
844  {
845  return (vc.is_verified() ? 1 : 0);
846  }
847 
848  bool compare_candidates(const VerifiedCandidate& vc1, const VerifiedCandidate& vc2)
849  {
850  const std::vector<std::pair<bool, std::function<u64(const VerifiedCandidate&)>>> metrics = {
851  {false, compute_is_verified}, {false, compute_total_io_score}, {true, calculate_ignored_input_signals}, {true, calculate_ctrl_score}, {true, calculate_ignored_output_signals}};
852 
853  for (const auto& [higher_is_better, metric_func] : metrics)
854  {
855  const auto score_1 = metric_func(vc1);
856  const auto score_2 = metric_func(vc2);
857 
858  if (score_1 < score_2)
859  {
860  return higher_is_better;
861  }
862  else if (score_1 > score_2)
863  {
864  return !higher_is_better;
865  }
866  }
867 
868  return true;
869  }
870  } // namespace
871 
872  std::vector<std::vector<std::set<Gate*>>> Result::assign_base_candidates_to_iterations(const std::vector<Result>& iteration_results, const bool create_block_lists)
873  {
874  // collect all base candidates
875  std::set<std::set<Gate*>> all_base_candidates;
876  for (const auto& res : iteration_results)
877  {
878  for (const auto& [bc, _] : res.m_candidates)
879  {
880  all_base_candidates.insert({bc.m_gates.begin(), bc.m_gates.end()});
881  }
882  }
883 
884  // for each base candidate collect the verified candidates in the iteration results
885  std::map<const std::set<Gate*>, std::vector<std::pair<u32, VerifiedCandidate>>> base_candidate_to_verified_candidates;
886 
887  for (u32 iteration_idx = 0; iteration_idx < iteration_results.size(); iteration_idx++)
888  {
889  const auto& res = iteration_results.at(iteration_idx);
890 
891  for (const auto& bc : all_base_candidates)
892  {
893  const auto it =
894  std::find_if(res.m_candidates.begin(), res.m_candidates.end(), [&bc](const auto& p) { return std::set<Gate*>{p.first.m_gates.begin(), p.first.m_gates.end()} == bc; });
895 
896  if (it == res.m_candidates.end())
897  {
898  base_candidate_to_verified_candidates[bc].push_back({iteration_idx, VerifiedCandidate{}});
899  }
900  else
901  {
902  base_candidate_to_verified_candidates[bc].push_back({iteration_idx, it->second});
903  }
904  }
905  }
906 
907  std::vector<std::vector<std::set<Gate*>>> iteration_assignments{iteration_results.size()};
908 
909  for (const auto& [bc, candidates] : base_candidate_to_verified_candidates)
910  {
911  // select the best result (iteration) for each base candidate
912  auto candidates_sorted = candidates;
913  std::sort(candidates_sorted.begin(), candidates_sorted.end(), [](const auto& p1, const auto& p2) { return compare_candidates(p1.second, p2.second); });
914  const auto best_iteration = candidates_sorted.front().first;
915 
916  // TODO remove debug printing
917  const std::string base_name = candidates_sorted.front().second.m_base_gates.empty() ? "EMPTY" : candidates_sorted.front().second.m_base_gates.front()->get_name();
918  std::cout << "Found the following candidates [" << base_name << "]: " << std::endl;
919  for (const auto& [it_idx, c] : candidates)
920  {
921  const auto c_type = c.m_types.empty() ? CandidateType::none : *(c.m_types.begin());
922  std::cout << it_idx << " - " << c.is_verified() << " " << enum_to_string(c_type) << " [" << compute_total_io_score(c) << " " << calculate_ignored_input_signals(c) << " "
923  << calculate_ctrl_score(c) << " " << calculate_ignored_output_signals(c) << "]" << std::endl;
924  }
925  std::cout << "Chose iteration " << best_iteration << " as best iteration." << std::endl;
926 
927  // create allow/block list for each base candidate containing the base candidates for which it produces the best results
928  for (u32 iteration_idx = 0; iteration_idx < iteration_results.size(); iteration_idx++)
929  {
930  bool assign_to_iteration = create_block_lists ? (iteration_idx != best_iteration) : (iteration_idx == best_iteration);
931  if (assign_to_iteration)
932  {
933  iteration_assignments.at(iteration_idx).push_back(bc);
934  }
935  }
936  }
937 
938  // TODO remove debug printing
939  for (u32 idx = 0; idx < iteration_assignments.size(); idx++)
940  {
941  std::cout << "Iteration Assignment " << idx << ": " << std::endl;
942  for (const auto& gate_vec : iteration_assignments.at(idx))
943  {
944  std::cout << "\t" << (*gate_vec.begin())->get_id() << " - " << (*gate_vec.begin())->get_name() << std::endl;
945  }
946  }
947 
948  return iteration_assignments;
949  }
950 
951  } // namespace module_identification
952 } // namespace hal
u32 size
This file contains the enumeration and constants for the candidate types used in the module identific...
Result< BooleanFunction > substitute_module_pins(const std::vector< Module * > &modules) const
bool set_data(const std::string &category, const std::string &key, const std::string &data_type, const std::string &value, const bool log_with_info_level=false)
bool contains_gate(Gate *gate, bool recursive=false) const
Definition: module.cpp:352
Module * get_top_module() const
Definition: netlist.cpp:608
Module * create_module(const u32 module_id, const std::string &name, Module *parent, const std::vector< Gate * > &gates={})
Definition: netlist.cpp:587
Represents a base candidate in the module identification process.
Represents a verified candidate for module identification.
std::vector< std::vector< Net * > > m_operands
uint64_t u64
Definition: defines.h:42
uint32_t u32
Definition: defines.h:41
#define log_error(channel,...)
Definition: log.h:78
#define log_info(channel,...)
Definition: log.h:70
#define log_warning(channel,...)
Definition: log.h:76
#define ERR(message)
Definition: result.h:60
#define OK(...)
Definition: result.h:56
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...
T replace(const T &str, const T &search, const T &replace)
Definition: utils.h:384
bool is_subset(const T1 &subset, const T2 &superset)
Definition: utils.h:541
std::string join(const std::string &joiner, const Iterator &begin, const Iterator &end, const Transform &transform)
Definition: utils.h:414
Definition: defines.h:45
std::string enum_to_string(T e)
Definition: enums.h:53
Net * net
std::string name
i32 id
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...
The result of a module identification run containing the candidates.
Definition: result.h:55
std::map< u32, std::vector< Gate * > > get_candidate_gates() const
Get a map of the candidate IDs to the gates contained inside the candidate.
Definition: result.cpp:57
std::map< u32, VerifiedCandidate > get_candidates() const
Get a map of the candidate IDs to the candidates.
Definition: result.cpp:68
hal::Result< Result > merge(const Result &other, const std::vector< std::vector< Gate * >> &registers) const
Merges two results by combining the found verified candidates.
Definition: result.cpp:685
std::set< Gate * > get_all_gates() const
Get all gates contained in any of the candidates.
Definition: result.cpp:107
std::map< u32, std::vector< Gate * > > get_verified_candidate_gates() const
Get a map of the candidate IDs to the gates contained inside the verified candidates.
Definition: result.cpp:28
std::set< Gate * > get_all_verified_gates() const
Get all gates contained in any of the verified candidates.
Definition: result.cpp:124
static std::vector< std::vector< std::set< Gate * > > > assign_base_candidates_to_iterations(const std::vector< Result > &iteration_results, const bool create_block_lists=false)
For different runs of the plugin figure out in which iteration the plugin found the highest quality r...
Definition: result.cpp:872
Netlist * get_netlist() const
Get the netlist on which module identification has been performed.
Definition: result.cpp:23
hal::Result< std::monostate > create_modules_in_netlist()
Creates a HAL module for each candidate of the result.
Definition: result.cpp:426
Result(Netlist *nl, const std::vector< std::pair< BaseCandidate, VerifiedCandidate >> &result, const std::string &timing_stats_json="")
Constructor for Result.
Definition: result.cpp:18
hal::Result< std::vector< Gate * > > get_candidate_gates_by_id(const u32 id) const
Get the gates of the candidate with the corresponding ID.
Definition: result.cpp:79
std::string get_timing_stats() const
Get the collected timing information formatted as a JSON string.
Definition: result.cpp:680
hal::Result< VerifiedCandidate > get_candidate_by_id(const u32 id) const
Returns the candidate with the corresponding ID.
Definition: result.cpp:97
std::map< u32, VerifiedCandidate > get_verified_candidates() const
Get a map of the candidate IDs to the verified candidates.
Definition: result.cpp:43