HAL  v4.5.0-133-g64838ea8d
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
xilinx_unisim.cpp
Go to the documentation of this file.
3 
4 #include "hal_core/defines.h"
13 
14 #include <vector>
15 
16 namespace hal
17 {
18  namespace module_identification
19  {
20  namespace xilinx_unisim
21  {
22  namespace
23  {
34  std::vector<std::unique_ptr<BaseCandidate>> find_carry_chains(const Netlist* nl)
35  {
36  std::vector<std::vector<Gate*>> carry_chains;
37 
38  // retrieve all carry gates
39  std::vector<Gate*> carry_gates = nl->get_gates([](const Gate* g) { return g->get_type()->has_property(GateTypeProperty::c_carry); });
40  std::set<Gate*> carry_gates_set = std::set<Gate*>(carry_gates.begin(), carry_gates.end());
41 
42  // collect carry chains until all carry gates have been analyzed
43  while (!carry_gates_set.empty())
44  {
45  Gate* current_gate = *carry_gates_set.begin();
46  const GateType* carry_type = current_gate->get_type();
47 
48  // get carry chains by defining appropriate filter function
49  auto chain_res = NetlistTraversalDecorator(*nl).get_gate_chain(current_gate, {carry_type->get_pin_by_name("CI")}, {carry_type->get_pin_by_name("CO(3)")});
50  if (chain_res.is_error())
51  {
52  return std::vector<std::unique_ptr<BaseCandidate>>();
53  }
54  std::vector<Gate*> carry_chain = chain_res.get();
55 
56  // remove shift register gates from candidate set
57  for (Gate* g : carry_chain)
58  {
59  carry_gates_set.erase(g);
60  }
61 
62  // only consider carry chains with more than 2 gates for now
63  if (carry_chain.size() >= 2)
64  {
65  log_debug("module_identification", "\tcarry_gate: {}", carry_chain.front()->get_name());
66  carry_chains.push_back(carry_chain);
67  }
68  }
69 
70  // check whether a carry chain is a subset of another one
71  std::vector<std::vector<Gate*>> filtered_carry_chains;
72  for (u32 i = 0; i < carry_chains.size(); i++)
73  {
74  auto& c_test = carry_chains.at(i);
75  std::set<Gate*> test_set = {c_test.begin(), c_test.end()};
76 
77  bool is_subset = false;
78  for (u32 j = 0; j < carry_chains.size(); j++)
79  {
80  if (i == j)
81  {
82  continue;
83  }
84 
85  auto& c_other = carry_chains.at(j);
86  std::set<Gate*> other_set = {c_other.begin(), c_other.end()};
87 
88  if (std::includes(other_set.begin(), other_set.end(), test_set.begin(), test_set.end()))
89  {
90  is_subset = true;
91  break;
92  }
93  }
94 
95  if (!is_subset)
96  {
97  filtered_carry_chains.push_back(c_test);
98  }
99  }
100 
101  std::vector<std::unique_ptr<BaseCandidate>> base_candidates;
102  for (const auto& carry_chain : filtered_carry_chains)
103  {
104  std::unique_ptr<BaseCandidate> base_candidate = std::make_unique<BaseCandidate>(carry_chain);
105  base_candidates.push_back(std::move(base_candidate));
106  }
107 
108  return base_candidates;
109  }
110 
121  std::vector<std::unique_ptr<StructuralCandidate>> build_structural_candidates(BaseCandidate* base_candidate)
122  {
123  std::vector<std::unique_ptr<StructuralCandidate>> candidates;
124 
125  std::vector<Gate*> carry_chain = base_candidate->m_gates;
126 
127  Gate* first_carry = carry_chain.front();
128 
129  // check if first gate is carry
130  if (!first_carry->get_type()->has_property(GateTypeProperty::c_carry))
131  {
132  return std::vector<std::unique_ptr<StructuralCandidate>>();
133  }
134  log_debug("module_identification", "\tcarry_chain: {}", first_carry->get_name());
135 
136  // generate very big candidates and go back until sequential gate or IO
137  {
138  std::unordered_set<Gate*> big_candidate_gates = {carry_chain.begin(), carry_chain.end()};
139  std::unordered_map<const Net*, std::unordered_set<Gate*>> cache;
140 
141  for (const auto& gate : carry_chain)
142  {
143  // TODO make this use the NetlistTraversal decorator
144  auto gates = netlist_utils::get_next_gates(gate, false, 0, [](const Gate* g) {
145  bool add_gate = true;
146  if (g->get_type()->has_property(hal::GateTypeProperty::io))
147  {
148  add_gate = false;
149  }
150  // if (g->get_type()->has_property(hal::GateTypeProperty::c_carry))
151  // {
152  // add_gate = false;
153  // }
154  if (g->get_type()->has_property(hal::GateTypeProperty::dsp))
155  {
156  add_gate = false;
157  }
158  if (g->get_type()->has_property(hal::GateTypeProperty::power))
159  {
160  add_gate = false;
161  }
162  if (g->get_type()->has_property(hal::GateTypeProperty::ground))
163  {
164  add_gate = false;
165  }
166  if (!g->get_type()->has_property(hal::GateTypeProperty::combinational))
167  {
168  add_gate = false;
169  }
170  return add_gate;
171  });
172 
173  for (const auto& gate_to_add : gates)
174  {
175  big_candidate_gates.insert(gate_to_add);
176  }
177  }
178 
179  if (big_candidate_gates.size() < (carry_chain.size() * 128))
180  {
181  // create candidate with many many gates
182  auto gate_vec = utils::to_vector(big_candidate_gates);
183  std::unique_ptr<StructuralCandidate> candidate_big = std::make_unique<StructuralCandidate>(base_candidate, gate_vec);
184  log_debug("module_identification", "big_candidate is {} big", candidate_big->m_gates.size());
185  candidates.push_back(std::move(candidate_big));
186  }
187  else
188  {
189  log_debug("module_identification", "big_candidate is too big with {} gates", big_candidate_gates.size());
190  }
191  }
192 
193  // create candidate with only carry chain, nothing else
194  std::vector<Gate*> candidate_gates(carry_chain);
195 
196  std::unique_ptr<StructuralCandidate> first_candidate = std::make_unique<StructuralCandidate>(base_candidate, candidate_gates);
197  if (first_candidate == nullptr)
198  {
199  log_error("module_identification", "nullptr candidate after creation");
200  }
201  candidates.push_back(std::move(first_candidate));
202 
203  // get gates infront of CARRY
204  for (const auto& gate : carry_chain)
205  {
206  for (const auto& pred_endp : gate->get_predecessors())
207  {
208  auto pred_gate = pred_endp->get_gate();
209 
210  if (pred_gate->is_gnd_gate() || pred_gate->is_vcc_gate())
211  {
212  continue;
213  }
214 
215  if (pred_gate->get_type()->has_property(hal::GateTypeProperty::io))
216  {
217  continue;
218  }
219 
220  if (pred_gate->get_type()->has_property(hal::GateTypeProperty::c_carry))
221  {
222  continue;
223  }
224 
225  if (pred_gate->get_type()->has_property(hal::GateTypeProperty::sequential))
226  {
227  continue;
228  }
229 
230  if (pred_gate->get_type()->has_property(hal::GateTypeProperty::combinational))
231  {
232  candidate_gates.push_back(pred_gate);
233  }
234  }
235  }
236 
237  std::unique_ptr<StructuralCandidate> candidate_all_gates_infront_level_1 = std::make_unique<StructuralCandidate>(base_candidate, candidate_gates);
238  if (candidate_all_gates_infront_level_1 == nullptr)
239  {
240  log_error("module_identification", "nullptr candidate after creation");
241  }
242  candidates.push_back(std::move(candidate_all_gates_infront_level_1));
243 
244  // get gates infront of SI and DI of CARRY
245  std::vector<Gate*> si_di0_candidate_gates(carry_chain);
246  std::vector<std::string> allowed_pins_si_di0 = {"S(0)", "S(1)", "S(2)", "S(3)", "DI(0)"};
247 
248  for (const auto& gate : carry_chain)
249  {
250  for (const auto& pin : allowed_pins_si_di0)
251  {
252  const auto& pred_endp = gate->get_predecessor(pin);
253  if (pred_endp == nullptr)
254  {
255  continue;
256  }
257  auto pred_gate = pred_endp->get_gate();
258  if (pred_gate->is_gnd_gate() || pred_gate->is_vcc_gate())
259  {
260  continue;
261  }
262 
263  if (pred_gate->get_type()->has_property(hal::GateTypeProperty::io))
264  {
265  log_error("module_identification", "\tfound IO gate, but why?");
266  continue;
267  }
268 
269  if (pred_gate->get_type()->has_property(hal::GateTypeProperty::c_carry))
270  {
271  continue;
272  }
273  if (pred_gate->get_type()->has_property(hal::GateTypeProperty::sequential))
274  {
275  continue;
276  }
277 
278  if (pred_gate->get_type()->has_property(hal::GateTypeProperty::combinational))
279  {
280  // log_debug("module_identification", "\t\tadding {}", pred_gate->get_name());
281  si_di0_candidate_gates.push_back(pred_gate);
282  }
283  }
284  }
285  std::unique_ptr<StructuralCandidate> candidate_gates_infront_of_si_di0 = std::make_unique<StructuralCandidate>(base_candidate, si_di0_candidate_gates);
286  if (candidate_gates_infront_of_si_di0 == nullptr)
287  {
288  log_error("module_identification", "nullptr candidate after creation");
289  }
290  candidates.push_back(std::move(candidate_gates_infront_of_si_di0));
291 
292  // get gates infront of SI and DI of CARRY
293  // log_debug("module_identification", "\tsi_di pred:");
294  std::vector<Gate*> si_di_candidate_gates(carry_chain);
295  std::vector<std::string> allowed_pins_si_di = {"S(0)", "S(1)", "S(2)", "S(3)", "DI(0)", "DI(1)", "DI(2)", "DI(3)"};
296 
297  for (const auto& gate : carry_chain)
298  {
299  for (const auto& pin : allowed_pins_si_di)
300  {
301  const auto& pred_endp = gate->get_predecessor(pin);
302  if (pred_endp == nullptr)
303  {
304  continue;
305  }
306  auto pred_gate = pred_endp->get_gate();
307  if (pred_gate->is_gnd_gate() || pred_gate->is_vcc_gate())
308  {
309  continue;
310  }
311 
312  if (pred_gate->get_type()->has_property(hal::GateTypeProperty::io))
313  {
314  log_error("module_identification", "\tfound IO gate, but why?");
315  continue;
316  }
317 
318  if (pred_gate->get_type()->has_property(hal::GateTypeProperty::c_carry))
319  {
320  continue;
321  }
322  if (pred_gate->get_type()->has_property(hal::GateTypeProperty::sequential))
323  {
324  continue;
325  }
326 
327  if (pred_gate->get_type()->has_property(hal::GateTypeProperty::combinational))
328  {
329  si_di_candidate_gates.push_back(pred_gate);
330  }
331  }
332  }
333  std::unique_ptr<StructuralCandidate> candidate_gates_infront_of_si_di = std::make_unique<StructuralCandidate>(base_candidate, si_di_candidate_gates);
334  if (candidate_gates_infront_of_si_di == nullptr)
335  {
336  log_error("module_identification", "nullptr candidate after creation");
337  }
338  candidates.push_back(std::move(candidate_gates_infront_of_si_di));
339 
340  // get gates infront of SI of CARRY
341  std::vector<Gate*> si_candidate_gates(carry_chain);
342 
343  std::vector<std::string> allowed_pins_si = {"S(0)", "S(1)", "S(2)", "S(3)"};
344  for (const auto& gate : carry_chain)
345  {
346  for (const auto& pin : allowed_pins_si)
347  {
348  const auto& pred_endp = gate->get_predecessor(pin);
349  if (pred_endp == nullptr)
350  {
351  continue;
352  }
353  auto pred_gate = pred_endp->get_gate();
354  if (pred_gate->is_gnd_gate() || pred_gate->is_vcc_gate())
355  {
356  continue;
357  }
358 
359  if (pred_gate->get_type()->has_property(hal::GateTypeProperty::io))
360  {
361  log_error("module_identification", "\tfound IO gate, but why?");
362  continue;
363  }
364 
365  if (pred_gate->get_type()->has_property(hal::GateTypeProperty::c_carry))
366  {
367  continue;
368  }
369  if (pred_gate->get_type()->has_property(hal::GateTypeProperty::sequential))
370  {
371  continue;
372  }
373 
374  if (pred_gate->get_type()->has_property(hal::GateTypeProperty::combinational))
375  {
376  // log_debug("module_identification", "\t\tadding {}", pred_gate->get_name());
377  si_candidate_gates.push_back(pred_gate);
378  }
379  }
380  }
381 
382  std::vector<Gate*> candidate_gates_infront_of_si_gates;
383  for (const auto& g : si_candidate_gates)
384  {
385  candidate_gates_infront_of_si_gates.push_back(g);
386  }
387  std::unique_ptr<StructuralCandidate> candidate_gates_infront_of_si = std::make_unique<StructuralCandidate>(base_candidate, candidate_gates_infront_of_si_gates);
388 
389  candidates.push_back(std::move(candidate_gates_infront_of_si));
390 
391  std::vector<std::unique_ptr<StructuralCandidate>> candidates_to_add;
392 
393  // get additional layer
394  for (const auto& cand : candidates)
395  {
396  if (cand == nullptr)
397  {
398  log_error("module_identification", "nullptr candidate");
399  continue;
400  }
401 
402  if (cand->m_gates.empty())
403  {
404  log_error("module_identification", "candidate has no gates");
405  continue;
406  }
407  std::set<Gate*> additional_layer_gates;
408 
409  for (const auto& gate : cand->m_gates)
410  {
411  if (gate->get_type()->has_property(hal::GateTypeProperty::c_carry))
412  {
413  continue;
414  }
415 
416  for (const auto& pred_endp : gate->get_predecessors())
417  {
418  if (pred_endp == nullptr)
419  {
420  continue;
421  }
422 
423  auto pred_gate = pred_endp->get_gate();
424 
425  if (pred_gate == nullptr)
426  {
427  continue;
428  }
429 
430  if (pred_gate->is_gnd_gate() || pred_gate->is_vcc_gate())
431  {
432  continue;
433  }
434 
435  if (pred_gate->get_type()->has_property(hal::GateTypeProperty::io))
436  {
437  continue;
438  }
439 
440  if (pred_gate->get_type()->has_property(hal::GateTypeProperty::c_carry))
441  {
442  continue;
443  }
444 
445  if (pred_gate->get_type()->has_property(hal::GateTypeProperty::sequential))
446  {
447  continue;
448  }
449 
450  if (pred_gate->get_type()->has_property(hal::GateTypeProperty::combinational))
451  {
452  additional_layer_gates.insert(pred_gate);
453  }
454  }
455  }
456  std::vector<Gate*> all_gates(cand->m_gates);
457  for (const auto& g : additional_layer_gates)
458  {
459  all_gates.push_back(g);
460  }
461  std::unique_ptr<StructuralCandidate> additional_gate_candidate = std::make_unique<StructuralCandidate>(base_candidate, all_gates);
462  candidates_to_add.push_back(std::move(additional_gate_candidate));
463  }
464 
465  for (auto& candidate_to_add : candidates_to_add)
466  {
467  candidates.push_back(std::move(candidate_to_add));
468  }
469 
470  std::vector<std::unique_ptr<StructuralCandidate>> inv_candidates_to_add;
471 
472  // get only inverters in front of candidate
473  for (const auto& cand : candidates)
474  {
475  if (cand == nullptr)
476  {
477  log_error("module_identification", "nullptr candidate");
478  continue;
479  }
480 
481  if (cand->m_gates.empty())
482  {
483  log_error("module_identification", "candidate has no gates");
484  continue;
485  }
486  std::set<Gate*> additional_layer_gates;
487 
488  for (const auto& gate : cand->m_gates)
489  {
490  if (gate->get_type()->has_property(hal::GateTypeProperty::c_carry))
491  {
492  continue;
493  }
494 
495  for (const auto& pred_endp : gate->get_predecessors())
496  {
497  if (pred_endp == nullptr)
498  {
499  continue;
500  }
501 
502  auto pred_gate = pred_endp->get_gate();
503 
504  if (pred_gate == nullptr)
505  {
506  continue;
507  }
508 
509  if (pred_gate->get_type()->has_property(hal::GateTypeProperty::c_inverter))
510  {
511  additional_layer_gates.insert(pred_gate);
512  }
513  }
514  }
515  std::vector<Gate*> all_gates(cand->m_gates);
516  for (const auto& g : additional_layer_gates)
517  {
518  all_gates.push_back(g);
519  }
520  std::unique_ptr<StructuralCandidate> additional_gate_candidate = std::make_unique<StructuralCandidate>(base_candidate, all_gates);
521  inv_candidates_to_add.push_back(std::move(additional_gate_candidate));
522  }
523 
524  for (auto& candidate_to_add : inv_candidates_to_add)
525  {
526  candidates.push_back(std::move(candidate_to_add));
527  }
528 
529  // NOTE: i noticed that there are counter candidates that are not built correctly
530  // for each input net of the first carry gate and for each of its successors gates add a new candidate that includes this gate
531  {
532  std::vector<std::unique_ptr<StructuralCandidate>> new_candidates;
533  for (const auto& c : candidates)
534  {
535  for (const auto& in_net : carry_chain.front()->get_fan_in_nets())
536  {
537  if (in_net->is_gnd_net() || in_net->is_vcc_net())
538  {
539  continue;
540  }
541 
542  for (const auto& dst : in_net->get_destinations())
543  {
544  if (dst->get_gate() == carry_chain.front())
545  {
546  continue;
547  }
548 
549  if (dst->get_gate() == nullptr)
550  {
551  continue;
552  }
553 
554  bool is_inverter = dst->get_gate()->get_type()->has_property(GateTypeProperty::c_inverter);
555  bool is_single_input_lut = dst->get_gate()->get_type()->has_property(GateTypeProperty::c_lut) && (dst->get_gate()->get_boolean_functions().size() == 1)
556  && (dst->get_gate()->get_boolean_functions().begin()->second.get_variable_names().size() == 1);
557  // place some constraints on the added gate
558  if (!is_inverter && !is_single_input_lut)
559  {
560  continue;
561  }
562 
563  std::unique_ptr<StructuralCandidate> new_candidate = std::make_unique<StructuralCandidate>(base_candidate, c->m_gates);
564  new_candidate->m_gates.emplace_back(dst->get_gate());
565  new_candidates.emplace_back(std::move(new_candidate));
566  }
567  }
568  }
569  for (auto& nc : new_candidates)
570  {
571  candidates.push_back(std::move(nc));
572  }
573  }
574 
575  // TODO only required for debugging
576  // std::vector<std::unique_ptr<StructuralCandidate>> filtered_candidates;
577  // for (auto& c : candidates)
578  // {
579  // std::set<u32> id_set;
580  // for (const auto& g : c->m_gates)
581  // {
582  // id_set.insert(g->get_id());
583  // }
584 
585  // std::set<u32> filter_set = {};
586  // if (id_set == filter_set)
587  // {
588  // std::cout << "Found filter candidate!" << std::endl;
589  // filtered_candidates.push_back(std::move(c));
590  // break;
591  // }
592  // }
593  // candidates = std::move(filtered_candidates);
594 
595  // iterate over all candidates and add additional candidate variants that include all gates that are only connected to inputs that are already leading to the candidate
596  std::vector<std::unique_ptr<StructuralCandidate>> new_candidates;
597  for (const auto& c : candidates)
598  {
599  std::set<Gate*> additional_gates;
600 
601  const auto c_gates = utils::to_set(c->m_gates);
602  const auto all_inputs = utils::to_set(get_input_nets(c->m_gates));
603  for (const auto& input : all_inputs)
604  {
605  for (const auto& dest : input->get_destinations())
606  {
607  if (dest->get_gate() == nullptr)
608  {
609  continue;
610  }
611 
612  if (c_gates.find(dest->get_gate()) != c_gates.end())
613  {
614  continue;
615  }
616 
617  if (additional_gates.find(dest->get_gate()) != additional_gates.end())
618  {
619  continue;
620  }
621 
622  const auto gate_inputs = dest->get_gate()->get_fan_in_nets();
623 
624  bool is_subset = true;
625  for (auto& gi : gate_inputs)
626  {
627  if (all_inputs.find(gi) == all_inputs.end())
628  {
629  is_subset = false;
630  break;
631  }
632  }
633 
634  if (is_subset)
635  {
636  additional_gates.insert(dest->get_gate());
637  }
638  }
639  }
640 
641  // TODO remove debug print
642  // std::cout << "considering additional gates: " << std::endl;
643  // for (const auto& g : additional_gates)
644  // {
645  // std::cout << g->get_id() << " / " << g->get_name() << std::endl;
646  // }
647 
648  auto total_gates = c->m_gates;
649  total_gates.insert(total_gates.end(), additional_gates.begin(), additional_gates.end());
650  new_candidates.push_back(std::make_unique<StructuralCandidate>(base_candidate, total_gates));
651  }
652  for (auto& nc : new_candidates)
653  {
654  candidates.push_back(std::move(nc));
655  }
656 
657  // remove same candidates
658  std::set<std::set<Gate*>> all_sets;
659  u32 old_size = candidates.size();
660  std::vector<std::unique_ptr<StructuralCandidate>> candidates_to_return;
661 
662  for (auto& cand : candidates)
663  {
664  std::set<Gate*> set_gates = {cand->m_gates.begin(), cand->m_gates.end()};
665  if (all_sets.find(set_gates) == all_sets.end())
666  {
667  all_sets.insert(set_gates);
668  candidates_to_return.push_back(std::move(cand));
669  }
670  }
671 
672  return candidates_to_return;
673  }
674  } // namespace
675 
676  std::vector<std::pair<std::unique_ptr<BaseCandidate>, std::vector<std::unique_ptr<StructuralCandidate>>>> generate_structural_candidates(const Netlist* nl)
677  {
678  std::vector<std::pair<std::unique_ptr<BaseCandidate>, std::vector<std::unique_ptr<StructuralCandidate>>>> base_to_structural_candidates;
679 
680  auto base_candidates = find_carry_chains(nl);
681 
682  log_info("module_identification", "found {} carry chains, building structural variants now...", base_candidates.size());
683 
684  for (auto& base_candidate : base_candidates)
685  {
686  std::vector<std::unique_ptr<StructuralCandidate>> structural_candidates = build_structural_candidates(base_candidate.get());
687  base_to_structural_candidates.push_back({std::move(base_candidate), std::move(structural_candidates)});
688  }
689 
690  return base_to_structural_candidates;
691  }
692  } // namespace xilinx_unisim
693  } // namespace module_identification
694 } // namespace hal
This file contains the definition of the BaseCandidate class, which represents a base candidate in th...
uint32_t u32
Definition: defines.h:41
#define log_error(channel,...)
Definition: log.h:78
#define log_debug(channel,...)
Definition: log.h:74
#define log_info(channel,...)
Definition: log.h:70
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< Net * > get_input_nets(const std::vector< Gate * > &gates)
Get input nets from a list of gates.
Definition: utils.cpp:25
@ xilinx_unisim
Xilinx Unisim FPGA architecture.
std::vector< Gate * > get_next_gates(const Gate *gate, bool get_successors, int depth=0, const std::function< bool(const Gate *)> &filter=nullptr)
std::set< T > to_set(const Container< T, Args... > &container)
Definition: utils.h:571
bool is_subset(const T1 &subset, const T2 &superset)
Definition: utils.h:585
std::vector< T > to_vector(const Container< T, Args... > &container)
Definition: utils.h:559
Definition: defines.h:45
This file contains helper functions for module identification in the HAL framework.
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.