HAL  v4.5.0-83-g30c8f0afc
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
bitorder_propagation.cpp
Go to the documentation of this file.
8 #include "nlohmann/json.hpp"
9 
10 #include <deque>
11 #include <fstream>
12 
13 // #define PRINT_CONFLICT
14 // #define PRINT_CONNECTIVITY
15 // #define PRINT_CONNECTIVITY_BUILDING
16 // #define PRINT_GENERAL
17 
18 namespace hal
19 {
20  namespace bitorder_propagation
21  {
22  namespace
23  {
24  typedef std::pair<Module*, PinGroup<ModulePin>*> MPG;
25  typedef std::map<MPG, std::set<u32>> POSSIBLE_BITINDICES;
26 
35  Result<std::map<MPG, std::map<MPG, i32>>> build_offset_matrix(const std::map<Net*, POSSIBLE_BITINDICES>& reduced_indices)
36  {
37  // offset at matrix[org_0][org_1] means index_0 + offset = index_1
38  std::map<MPG, std::map<MPG, i32>> origin_offset_matrix;
39 
40  for (const auto& [net, possible_bitindices] : reduced_indices)
41  {
42  std::map<MPG, u32> all_possible_indices;
43 
44  // fill all possible indices
45  for (const auto& [org_mpg, indices] : possible_bitindices)
46  {
47  all_possible_indices[org_mpg] = *(indices.begin());
48  }
49 
50  // check whether all possible indices are just shifted version of each other with a stable offset
51  for (const auto& [org_mpg, indices] : possible_bitindices)
52  {
53  for (const auto& [already_set_org, already_set_index] : all_possible_indices)
54  {
55  // there does not yet exist an offset between the already set index and the one to be added next
56  if (origin_offset_matrix[org_mpg].find(already_set_org) == origin_offset_matrix[org_mpg].end())
57  {
58  i32 new_index = *indices.begin();
59  i32 offset = already_set_index - new_index;
60 
61  origin_offset_matrix[org_mpg][already_set_org] = offset;
62  origin_offset_matrix[already_set_org][org_mpg] = -offset;
63  }
64  // check wether the already existing offset leads to the same index
65  else
66  {
67  i32 new_index = *indices.begin();
68  i32 offset = origin_offset_matrix.at(org_mpg).at(already_set_org);
69 
70  if (new_index + offset != i32(already_set_index))
71  {
72  return ERR("unable to build offset matrix: failed to find valid offset between " + std::to_string(org_mpg.first->get_id()) + "-" + org_mpg.second->get_name()
73  + " and " + std::to_string(already_set_org.first->get_id()) + "-" + already_set_org.second->get_name());
74  }
75  }
76  }
77  }
78  }
79 
80  return OK(origin_offset_matrix);
81  }
82 
95  Result<i32> get_offset(const MPG& org1, const MPG& org2, std::map<MPG, std::map<MPG, i32>>& m, std::set<std::set<MPG>>& v)
96  {
97  if (v.find({org1, org2}) != v.end())
98  {
99  return ERR("already tried to follow that offset.");
100  }
101 
102  v.insert({org1, org2});
103 
104  if (org1 == org2)
105  {
106  m[org1][org2] = 0;
107  return OK(0);
108  }
109 
110  if (m.find(org1) == m.end())
111  {
112  return ERR("no valid offset to other origins.");
113  }
114 
115  if (m.at(org1).find(org2) != m.at(org1).end())
116  {
117  return OK(m.at(org1).at(org2));
118  }
119 
120  for (auto& [dst_c, first_proxy_offset] : m.at(org1))
121  {
122  auto second_proxy_offset_res = get_offset(dst_c, org2, m, v);
123  if (second_proxy_offset_res.is_error())
124  {
125  continue;
126  }
127  i32 second_proxy_offset = second_proxy_offset_res.get();
128 
129  m[org1][org2] = first_proxy_offset + second_proxy_offset;
130 
131  return OK(first_proxy_offset + second_proxy_offset);
132  }
133 
134  return ERR("could not find an valid offset");
135  }
136 
149  Result<std::map<MPG, std::set<Net*>>> gather_connected_neighbors(Net* n,
150  bool successors,
151  const std::set<MPG>& relevant_pin_groups,
152  const bool guarantee_propagation,
153  const Module* inwards_module,
154  std::set<std::tuple<Endpoint*, const bool, const Module*>>& visited,
155  std::map<std::tuple<Endpoint*, const bool, const Module*>, std::map<MPG, std::set<Net*>>>& cache)
156  {
157  std::map<MPG, std::set<Net*>> connected_neighbors;
158 
159 #ifdef PRINT_CONNECTIVITY_BUILDING
160  std::cout << "Gathering bit index for net " << n->get_id() << " with" << (guarantee_propagation ? "" : "out") << " guaranteed propagation "
161  << "in direction: " << (successors ? "forwards" : "backwards") << std::endl;
162 #endif
163 
164  // check whether the net is a global input or global output net (has no sources or destinations, but might have a bitorder annotated at the top module)
165  if ((successors && n->is_global_output_net()) || (!successors && n->is_global_input_net()))
166  {
167  auto m = n->get_netlist()->get_top_module();
168  bool is_border_pin = successors ? m->is_input_net(n) : m->is_output_net(n);
169  if (is_border_pin)
170  {
171  auto border_pin = m->get_pin_by_net(n);
172  if (border_pin == nullptr)
173  {
174  return ERR("cannot get bit index information for net with ID " + std::to_string(n->get_id()) + " from module with ID " + std::to_string(m->get_id())
175  + ": net is border net but does not have a pin.");
176  }
177  auto pg = border_pin->get_group().first;
178 
179 #ifdef PRINT_CONNECTIVITY_BUILDING
180  std::cout << "Added global IO net as origin " << m->get_name() << " - " << pg->get_name() << " - " << n->get_id() << std::endl;
181 #endif
182 
183  connected_neighbors[{m, pg}].insert(n);
184  }
185  }
186 
187  const auto neighbors = successors ? n->get_destinations() : n->get_sources();
188  for (const auto& ep : neighbors)
189  {
190  std::tuple<Endpoint*, const bool, const Module*> t_ep = {ep, guarantee_propagation, inwards_module};
191  if (visited.find(t_ep) != visited.end())
192  {
193  continue;
194  }
195  visited.insert(t_ep);
196 
197  Gate* g = ep->get_gate();
198 
199  if (g == nullptr)
200  {
201  continue;
202  }
203 
204 #ifdef PRINT_CONNECTIVITY_BUILDING
205  std::cout << "Checking gate " << g->get_id() << std::endl;
206 #endif
207 
208  if ((inwards_module != nullptr) && !inwards_module->contains_gate(g, true))
209  {
210 #ifdef PRINT_CONNECTIVITY_BUILDING
211  std::cout << "Ended propagation at gate " << g->get_id() << " as it is not contained in the currently entered module " << inwards_module->get_name() << std::endl;
212 #endif
213 
214  continue;
215  }
216 
217  const auto modules = g->get_modules();
218 
219  if (!guarantee_propagation)
220  {
221  // check whether the net that leads to the gate is part of a relevant pin_group
222  bool found_relevant_pin_group = false;
223  for (const auto& m : modules)
224  {
225  bool is_border_pin = successors ? m->is_input_net(n) : m->is_output_net(n);
226  if (is_border_pin)
227  {
228  auto border_pin = m->get_pin_by_net(n);
229  if (border_pin == nullptr)
230  {
231  return ERR("cannot get bit index information for net with ID " + std::to_string(n->get_id()) + " from module with ID " + std::to_string(m->get_id())
232  + ": net is border net but does not have a pin.");
233  }
234  auto border_pg = border_pin->get_group().first;
235 
236  // only consider relevant pin groups that already have a known bitorder or that are currently unknown but might get one
237  if (relevant_pin_groups.find({m, border_pg}) == relevant_pin_groups.end())
238  {
239 #ifdef PRINT_CONNECTIVITY_BUILDING
240  std::cout << "Skipping border pin " << border_pin->get_name() << " of module " << m->get_name() << " as it is not relevant." << std::endl;
241 #endif
242  continue;
243  }
244 
245  connected_neighbors[{m, border_pg}].insert(n);
246  found_relevant_pin_group = true;
247  }
248  }
249 
250  // stop the propagation at the gate when we reached it via at least one relevant pin group
251  if (found_relevant_pin_group)
252  {
253 #ifdef PRINT_CONNECTIVITY_BUILDING
254  std::cout << "Ended propagation at gate " << g->get_id() << " as we reached it via a relevant pin group." << std::endl;
255 #endif
256  continue;
257  }
258  }
259 
260  // propagate
261  std::vector<Endpoint*> next_eps;
262 
263  for (const auto& next_ep : successors ? g->get_fan_out_endpoints() : g->get_fan_in_endpoints())
264  {
265  const GatePin* pin = next_ep->get_pin();
266  if (g->get_type()->has_property(GateTypeProperty::sequential) && (g->get_type()->has_property(GateTypeProperty::ff) || g->get_type()->has_property(GateTypeProperty::latch)))
267  {
268  if (PinType t = pin->get_type(); (t == PinType::data) || (t == PinType::state) || (t == PinType::neg_state))
269  {
270  next_eps.push_back(next_ep);
271  }
272  }
273  else
274  {
275  next_eps.push_back(next_ep);
276  }
277  }
278 
279  for (Endpoint* next_ep : next_eps)
280  {
281  // Check whether we leave the gate via a relevant pin group, if that is the case stop
282  bool found_relevant_pin_group = false;
283  for (const auto& m : modules)
284  {
285  bool is_border_pin = successors ? m->is_output_net(next_ep->get_net()) : m->is_input_net(next_ep->get_net());
286  if (is_border_pin)
287  {
288  auto border_pin = m->get_pin_by_net(next_ep->get_net());
289  if (border_pin == nullptr)
290  {
291  return ERR("cannot get bit index information for net with ID " + std::to_string(next_ep->get_net()->get_id()) + " from module with ID "
292  + std::to_string(m->get_id()) + ": net is border net but does not have a pin.");
293  }
294  auto border_pg = border_pin->get_group().first;
295 
296  // only consider relevant pin groups that already have a known bitorder or that are currently unknown but might get one
297  if (relevant_pin_groups.find({m, border_pg}) == relevant_pin_groups.end())
298  {
299  continue;
300  }
301 
302  connected_neighbors[{m, border_pg}].insert(next_ep->get_net());
303  found_relevant_pin_group = true;
304  }
305  }
306 
307  // stop the propagation at the gate when we would leave it via at least one relevant pin group
308  if (found_relevant_pin_group)
309  {
310  continue;
311  }
312 
313  std::map<MPG, std::set<hal::Net*>> connected;
314  std::tuple<Endpoint*, const bool, const Module*> t = {next_ep, false, nullptr};
315  if (auto it = cache.find(t); it != cache.end())
316  {
317  connected = it->second;
318  }
319  else
320  {
321  auto res = gather_connected_neighbors(next_ep->get_net(), successors, relevant_pin_groups, false, nullptr, visited, cache);
322  if (res.is_error())
323  {
324  return res;
325  }
326  connected = res.get();
327  }
328 
329  cache[t] = connected;
330 
331  for (auto& [org_mpg, nets] : connected)
332  {
333  connected_neighbors[org_mpg].insert(nets.begin(), nets.end());
334  }
335  }
336  }
337 
338  return OK(connected_neighbors);
339  }
340 
350  const std::map<Net*, POSSIBLE_BITINDICES> reduce_indices(const std::map<Net*, POSSIBLE_BITINDICES>& collected_bitindices)
351  {
352 #ifdef PRINT_CONFLICT
353  std::cout << "\tVanilla indices: " << std::endl;
354  for (const auto& [net, possible_bitindices] : collected_bitindices)
355  {
356  std::cout << "\t\tNet " << net->get_id() << " - " << net->get_name() << ": " << std::endl;
357  u32 origins = 0;
358  for (const auto& [org_mpg, indices] : possible_bitindices)
359  {
360  auto org_m = org_mpg.first;
361  auto org_pg = org_mpg.second;
362 
363  std::cout << "\t\t\t" << org_m->get_id() << "-" << org_pg->get_name() << ": [";
364  for (const auto& index : indices)
365  {
366  std::cout << index << ", ";
367  }
368  std::cout << "]" << std::endl;
369  origins += 1;
370  }
371 
372  std::cout << "\t\tORIGINS: [" << origins << "]" << std::endl;
373  }
374 #endif
375 
376  auto reduced_collected_indices = collected_bitindices;
377 
378  // 1) Checks whether the mpg has annotated the same index to different nets
379  std::set<std::pair<MPG, u32>> origin_indices;
380  std::set<std::pair<MPG, u32>> origin_indices_to_remove;
381 
382  for (const auto& [net, possible_bitindices] : reduced_collected_indices)
383  {
384  for (const auto& [org_mpg, indices] : possible_bitindices)
385  {
386  for (const auto& index : indices)
387  {
388  if (origin_indices.find({org_mpg, index}) != origin_indices.end())
389  {
390  origin_indices_to_remove.insert({org_mpg, index});
391  }
392  else
393  {
394  origin_indices.insert({org_mpg, index});
395  }
396  }
397  }
398  }
399 
400 #ifdef PRINT_CONFLICT
401  for (const auto& [org_mpg, index] : origin_indices_to_remove)
402  {
403  std::cout << "Found org " << org_mpg.first->get_id() << "-" << org_mpg.second->get_name() << " index " << index << " pair to remove!" << std::endl;
404  }
405 #endif
406 
407  for (auto& [net, possible_bitindices] : collected_bitindices)
408  {
409  for (auto& [org_mpg, indices] : possible_bitindices)
410  {
411  for (const auto& index : indices)
412  {
413  if (origin_indices_to_remove.find({org_mpg, index}) != origin_indices_to_remove.end())
414  {
415  reduced_collected_indices.at(net).at(org_mpg).erase(index);
416  }
417  }
418 
419  if (reduced_collected_indices.at(net).at(org_mpg).empty())
420  {
421  reduced_collected_indices.at(net).erase(org_mpg);
422  }
423  }
424 
425  if (reduced_collected_indices.at(net).empty())
426  {
427  reduced_collected_indices.erase(net);
428  }
429  }
430 
431  if (reduced_collected_indices.empty())
432  {
433  return {};
434  }
435 
436  // 2) Checks whether a net has multiple indices annotated from the same origin mpg
437  auto further_reduced_collected_indices = reduced_collected_indices;
438  for (auto& [net, possible_bitindices] : reduced_collected_indices)
439  {
440  for (auto& [org_mpg, indices] : possible_bitindices)
441  {
442  if (indices.size() != 1)
443  {
444  further_reduced_collected_indices.at(net).erase(org_mpg);
445  }
446  }
447 
448  if (further_reduced_collected_indices.at(net).empty())
449  {
450  further_reduced_collected_indices.erase(net);
451  }
452  }
453 
454  if (further_reduced_collected_indices.empty())
455  {
456  return {};
457  }
458 
459 #ifdef PRINT_CONFLICT
460  std::cout << "\tReduced Possible Indices: " << std::endl;
461  for (const auto& [net, possible_bitindices] : further_reduced_collected_indices)
462  {
463  std::cout << "\t\tNet " << net->get_id() << ": " << std::endl;
464  u32 origins = 0;
465  for (const auto& [org_mpg, indices] : possible_bitindices)
466  {
467  auto org_m = org_mpg.first;
468  auto org_pg = org_mpg.second;
469 
470  std::cout << "\t\t\t" << org_m->get_id() << "-" << org_pg->get_name() << ": [";
471  for (const auto& index : indices)
472  {
473  std::cout << index << ", ";
474  }
475  std::cout << "]" << std::endl;
476  }
477  }
478 #endif
479 
480  return further_reduced_collected_indices;
481  }
482 
490  const bool check_completeness(const MPG& mpg, const std::map<Net*, i32>& consensus_bitindices)
491  {
492  bool is_complete_pin_group_bitorder = true;
493 
494  for (auto& pin : mpg.second->get_pins())
495  {
496  Net* net = pin->get_net();
497  if (consensus_bitindices.find(net) == consensus_bitindices.end())
498  {
499  is_complete_pin_group_bitorder = false;
500 
501 #ifdef PRINT_CONFLICT
502  std::cout << "Missing net " << net->get_id() << " - " << net->get_name() << " for complete bitorder." << std::endl;
503 #endif
504  break;
505  }
506  }
507 
508 #ifdef PRINT_CONFLICT
509  if (is_complete_pin_group_bitorder)
510  {
511  std::cout << "Found complete bitorder for pingroup " << mpg.second->get_name() << std::endl;
512  for (const auto& [net, index] : consensus_bitindices)
513  {
514  std::cout << net->get_id() << ": " << index << std::endl;
515  }
516  }
517 #endif
518 
519  return is_complete_pin_group_bitorder;
520  }
521 
531  const std::map<Net*, u32> align_indices(const std::map<Net*, i32>& consensus_bitindices, const bool enforce_continuous_bitorders)
532  {
533  std::map<Net*, u32> aligned_consensus;
534 
535  std::set<i32> unique_indices;
536  for (const auto& [_n, index] : consensus_bitindices)
537  {
538  unique_indices.insert(index);
539  }
540 
541  if (unique_indices.empty())
542  {
543  return {};
544  }
545 
546  const i32 min_index = *(unique_indices.begin());
547  const i32 max_index = *(unique_indices.rbegin());
548 
549  // when the range is larger than pin group size there are holes in the bitorder
550  if (enforce_continuous_bitorders && ((max_index - min_index) > (i32(consensus_bitindices.size()) - 1)))
551  {
552  return {};
553  }
554 
555  // when there are less unique indices in the range than nets, there are duplicates
556  if (unique_indices.size() < consensus_bitindices.size())
557  {
558  return {};
559  }
560 
561  std::map<i32, Net*> index_to_net;
562  for (const auto& [net, index] : consensus_bitindices)
563  {
564  index_to_net[index] = net;
565  }
566 
567  u32 index_counter = 0;
568  for (const auto& [_unaligned_index, net] : index_to_net)
569  {
570  aligned_consensus[net] = index_counter++;
571  }
572 
573  return aligned_consensus;
574  }
575 
586  std::map<Net*, u32> find_consensus_via_offset(const MPG& mpg, const std::map<hal::Net*, POSSIBLE_BITINDICES>& indices, const bool enforce_continuous_bitorders)
587  {
588  std::map<Net*, i32> consensus_bitindices;
589 
590  auto offset_matrix_res = build_offset_matrix(indices);
591  if (offset_matrix_res.is_error())
592  {
593 #ifdef PRINT_CONFLICT
594  std::cout << "Failed to build offset matrix : " << offset_matrix_res.get_error().get() << std::endl;
595 #endif
596  return {};
597  }
598  auto offset_matrix = offset_matrix_res.get();
599 
600  // select a pseudo random base line and gather the offsets between the base line and all other possible module/pin group origins
601  auto base_line = offset_matrix.begin()->first;
602 
603 #ifdef PRINT_CONFLICT
604  std::cout << "Found valid offsets pingroup " << mpg.second->get_name() << ": " << std::endl;
605  std::cout << "Baseline: " << base_line.first->get_id() << "-" << base_line.second->get_name() << std::endl;
606  for (const auto& [org1, col] : offset_matrix)
607  {
608  std::cout << org1.first->get_id() << "-" << org1.second->get_name() << ": ";
609  for (const auto& [org2, offset] : col)
610  {
611  std::cout << org2.first->get_id() << "-" << org2.second->get_name() << "[" << offset << "] ";
612  }
613  std::cout << std::endl;
614  }
615 #endif
616 
617  for (const auto& [net, possible_bitindices] : indices)
618  {
619  // pair of first possible org_mod and org_pin_group
620  MPG org = possible_bitindices.begin()->first;
621  // index at first possible origin
622  i32 org_index = *(possible_bitindices.begin()->second.begin());
623  std::set<std::set<MPG>> v;
624  auto offset_res = get_offset(org, base_line, offset_matrix, v);
625  if (offset_res.is_error())
626  {
627  if (possible_bitindices.size() == 1)
628  {
629  // if there cannot be found any valid offset to the baseline, but there is just one possible index annotated, we still allow it
630  // -> this wont break anything, since this only allows for bitorders that we otherwise would have discarded because of a missing net
631  consensus_bitindices[net] = org_index;
632  }
633  else
634  {
635  break;
636  }
637  }
638  else
639  {
640  i32 offset = offset_res.get();
641  consensus_bitindices[net] = org_index + offset;
642  }
643  }
644 
645 #ifdef PRINT_CONFLICT
646  std::cout << "Found offset bitorder: " << std::endl;
647  for (const auto& [net, index] : consensus_bitindices)
648  {
649  std::cout << net->get_id() << ": " << index << std::endl;
650  }
651 #endif
652 
653  // check completeness, i.e., whether each pin of the pin group was annotated an index
654  const auto is_complete_pin_group_bitorder = check_completeness(mpg, consensus_bitindices);
655 
656  if (!is_complete_pin_group_bitorder)
657  {
658  return {};
659  }
660 
661  // check if consecutive and shift so that indices start at 0
662  const auto aligned_indices = align_indices(consensus_bitindices, enforce_continuous_bitorders);
663 
664  return aligned_indices;
665  }
666 
673  const std::map<Net*, i32> conduct_majority_vote(const std::map<hal::Net*, POSSIBLE_BITINDICES>& indices)
674  {
675  std::map<Net*, i32> majority_indices;
676 
677  for (const auto& [net, possible_indices] : indices)
678  {
679  std::map<u32, u32> index_to_count;
680  for (const auto& [_org, org_indices] : possible_indices)
681  {
682  for (const auto& index : org_indices)
683  {
684  index_to_count[index]++;
685  }
686  }
687 
688  // if there is only one index use this one
689  if (index_to_count.size() == 1)
690  {
691  majority_indices.insert({net, index_to_count.begin()->first});
692  continue;
693  }
694 
695  // sort possible indices by how often they occur and afterwards check whether there is a clear majority
696  std::vector<std::pair<u32, u32>> index_counts = {index_to_count.begin(), index_to_count.end()};
697  std::sort(index_counts.begin(), index_counts.end(), [](const auto& p1, const auto& p2) { return p1.second > p2.second; });
698 
699  // check if unambiguous majority exists
700  if (index_counts.at(0).second > index_counts.at(1).second)
701  {
702  majority_indices.insert({net, index_counts.at(0).first});
703  }
704  }
705 
706  return majority_indices;
707  }
708 
717  std::map<Net*, u32> find_consensus_via_majority(const MPG& mpg, const std::map<hal::Net*, POSSIBLE_BITINDICES>& indices, const bool enforce_continuous_bitorders)
718  {
719  const auto majority_indices = conduct_majority_vote(indices);
720 
721 #ifdef PRINT_CONFLICT
722  std::cout << "Found majority bitorder: " << std::endl;
723  for (const auto& [net, index] : majority_indices)
724  {
725  std::cout << net->get_id() << ": " << index << std::endl;
726  }
727 #endif
728 
729  // check completeness, i.e., whether each pin of the pin group was annotated an index
730  const auto is_complete_pin_group_bitorder = check_completeness(mpg, majority_indices);
731  if (!is_complete_pin_group_bitorder)
732  {
733  return {};
734  }
735 
736  // check if consecutive and shift so that indices start at 0
737  const auto aligned_indices = align_indices(majority_indices, enforce_continuous_bitorders);
738 
739  return aligned_indices;
740  }
741 
755  std::map<Net*, u32> find_consensus_via_majority_relaxed(const MPG& mpg,
756  const std::map<hal::Net*, POSSIBLE_BITINDICES>& all_indices,
757  const std::map<hal::Net*, POSSIBLE_BITINDICES>& reduced_indices,
758  const bool enforce_continuous_bitorders)
759  {
760  // 1st iteration
761  const auto first_majority_indices = conduct_majority_vote(reduced_indices);
762 
763  // take ALL collected net indices and delete the ones already annotated in the first iteration
764  auto unfound_indices = all_indices;
765  for (const auto& [net, _] : first_majority_indices)
766  {
767  unfound_indices.erase(net);
768  }
769 
770  // reduce indices again, but this time only consider nets that do not yet have an index found via majority
771  auto relaxed_reduced_indices = reduce_indices(unfound_indices);
772 
773  // 2nd iteration
774  const auto second_majority_indices = conduct_majority_vote(relaxed_reduced_indices);
775 
776 #ifdef PRINT_CONFLICT
777  std::cout << "Found majority bitorder: " << std::endl;
778  for (const auto& [net, index] : second_majority_indices)
779  {
780  std::cout << net->get_id() << ": " << index << std::endl;
781  }
782 #endif
783 
784  std::map<Net*, i32> combined_indices = first_majority_indices;
785  for (const auto& p : second_majority_indices)
786  {
787  combined_indices.insert(p);
788  }
789 
790  // check completeness, i.e., whether each pin of the pin group was annotated an index
791  const auto is_complete_pin_group_bitorder = check_completeness(mpg, combined_indices);
792  if (!is_complete_pin_group_bitorder)
793  {
794  return {};
795  }
796 
797  // check if consecutive and shift so that indices start at 0
798  const auto aligned_indices = align_indices(combined_indices, enforce_continuous_bitorders);
799 
800  return aligned_indices;
801  }
802 
816  std::map<Net*, u32> extract_well_formed_bitorder(const MPG& mpg, const std::map<Net*, POSSIBLE_BITINDICES>& collected_bitindices, bool enforce_continuous_bitorders = true)
817  {
818  auto reduced_collected_indices = reduce_indices(collected_bitindices);
819 
820  if (reduced_collected_indices.empty())
821  {
822  return {};
823  }
824 
825  auto aligned_consensus = find_consensus_via_offset(mpg, reduced_collected_indices, enforce_continuous_bitorders);
826 
827  if (aligned_consensus.empty())
828  {
829  aligned_consensus = find_consensus_via_majority(mpg, reduced_collected_indices, enforce_continuous_bitorders);
830  }
831 
832  if (aligned_consensus.empty())
833  {
834  aligned_consensus = find_consensus_via_majority_relaxed(mpg, collected_bitindices, reduced_collected_indices, enforce_continuous_bitorders);
835  }
836 
837  if (aligned_consensus.empty())
838  {
839  return {};
840  }
841 
842 #ifdef PRINT_CONFLICT
843  std::cout << "Found valid input bitorder for pingroup " << mpg.second->get_name() << std::endl;
844  for (const auto& [net, index] : aligned_consensus)
845  {
846  std::cout << net->get_id() << ": " << index << std::endl;
847  }
848 #endif
849 
850  return aligned_consensus;
851  }
852 
853  } // namespace
854 
855  Result<std::map<MPG, std::map<Net*, u32>>>
856  propagate_module_pingroup_bitorder(const std::map<MPG, std::map<Net*, u32>>& known_bitorders, const std::set<MPG>& unknown_bitorders, const bool enforce_continuous_bitorders)
857  {
858  // std::unordered_map<std::pair<MPG, Net*>, std::vector<std::pair<MPG, std::set<Net*>>>, boost::hash<std::pair<MPG, std::set<Net*>>>> connectivity_inwards;
859  // std::unordered_map<std::pair<MPG, Net*>, std::vector<std::pair<MPG, std::set<Net*>>>, boost::hash<std::pair<MPG, std::set<Net*>>>> connectivity_outwards;
860 
861  std::map<std::pair<MPG, Net*>, std::vector<std::pair<MPG, std::set<Net*>>>> connectivity_inwards;
862  std::map<std::pair<MPG, Net*>, std::vector<std::pair<MPG, std::set<Net*>>>> connectivity_outwards;
863 
864 #ifdef PRINT_GENERAL
865  std::cout << "Known bitorders [" << known_bitorders.size() << "]:" << std::endl;
866  for (const auto& [mpg, net_indices] : known_bitorders)
867  {
868  std::cout << "\t" << mpg.first->get_name() << " - " << mpg.second->get_name() << std::endl;
869  for (const auto& [net, index] : net_indices)
870  {
871  std::cout << "\t\t" << net->get_id() << " / " << net->get_name() << " - " << index << std::endl;
872  }
873  }
874 
875  std::cout << "Unknown bitorders [" << unknown_bitorders.size() << "]:" << std::endl;
876  for (const auto& [m, pg] : unknown_bitorders)
877  {
878  std::cout << "\t" << m->get_name() << " - " << pg->get_name() << std::endl;
879  }
880 
881 #endif
882 
883  std::set<MPG> relevant_pin_groups = unknown_bitorders;
884  for (const auto& [kb, _] : known_bitorders)
885  {
886  relevant_pin_groups.insert(kb);
887  }
888 
889  std::map<std::tuple<Endpoint*, const bool, const Module*>, std::map<MPG, std::set<Net*>>> cache_outwards;
890  std::map<std::tuple<Endpoint*, const bool, const Module*>, std::map<MPG, std::set<Net*>>> cache_inwards;
891 
892  // Build connectivity
893  for (const auto& [m, pg] : unknown_bitorders)
894  {
895  // determine the pin groups direction
896  PinDirection pg_direction = pg->get_direction();
897 
898  if (pg_direction != PinDirection::input && pg_direction != PinDirection::output && pg_direction != PinDirection::none)
899  {
900  return ERR("cannot propagate bitorder: pin group " + pg->get_name() + " of module " + m->get_name() + " has direction other than input, output or none.");
901  }
902 
903  if (pg_direction == PinDirection::none)
904  {
905  // Check whether all pins in the pin group have the same direction and assume it to be the pin groups direction but print a warning
906  std::set<PinDirection> pin_directions;
907  for (const auto& p : pg->get_pins())
908  {
909  pin_directions.insert(p->get_direction());
910  if (pin_directions.size() > 1)
911  {
912  break;
913  }
914  }
915 
916  pg_direction = *(pin_directions.begin());
917  log_warning("bitorder_propagation",
918  "Pin group {} of module {} has no set direction, but all pins have the same direction {}. Assuming this to be the pin groups direction.",
919  pg->get_name(),
920  m->get_name(),
921  enum_to_string(pg_direction));
922  }
923 
924  if (pg_direction != PinDirection::input && pg_direction != PinDirection::output)
925  {
926  return ERR("cannot propagate bitorder: pin group " + pg->get_name() + " of module " + m->get_name()
927  + " has direction other than input or output and contains pins of different or other directions, such that we cannot deduce a pin group order.");
928  }
929 
930  bool successors = (pg_direction == PinDirection::output);
931 
932  for (const auto& p : pg->get_pins())
933  {
934  const auto starting_net = p->get_net();
935 
936  std::set<std::tuple<Endpoint*, const bool, const Module*>> visited_outwards;
937  const auto res_outwards = gather_connected_neighbors(starting_net, successors, relevant_pin_groups, false, nullptr, visited_outwards, cache_outwards);
938  if (res_outwards.is_error())
939  {
940  return ERR_APPEND(res_outwards.get_error(),
941  "cannot porpagate bitorder: failed to gather bit indices outwards starting from the module with ID " + std::to_string(m->get_id()) + " and pin group "
942  + pg->get_name());
943  }
944  const auto connected_outwards = res_outwards.get();
945 
946  std::set<std::tuple<Endpoint*, const bool, const Module*>> visited_inwards;
947  // NOTE when propagating inwards we guarantee the first propagation since otherwise we would stop at our starting pingroup
948  const auto res_inwards = gather_connected_neighbors(starting_net, !successors, relevant_pin_groups, true, m, visited_inwards, cache_inwards);
949  if (res_inwards.is_error())
950  {
951  return ERR_APPEND(res_inwards.get_error(),
952  "cannot porpagate bitorder: failed to gather bit indices inwards starting from the module with ID " + std::to_string(m->get_id()) + " and pin group "
953  + pg->get_name());
954  }
955  const auto connected_inwards = res_inwards.get();
956 
957  for (const auto& [org_mpg, nets] : connected_outwards)
958  {
959  connectivity_outwards[{{m, pg}, starting_net}].push_back({org_mpg, nets});
960  }
961 
962  for (const auto& [org_mpg, nets] : connected_inwards)
963  {
964  connectivity_inwards[{{m, pg}, starting_net}].push_back({org_mpg, nets});
965  }
966  }
967  }
968 
969 #ifdef PRINT_CONNECTIVITY
970  for (const auto& [start, connected] : connectivity_outwards)
971  {
972  std::cout << start.first.first->get_id() << " / " << start.first.first->get_name() << " - " << start.first.second->get_name() << " (OUTWARDS)@ " << start.second->get_id() << " / "
973  << start.second->get_name() << std::endl;
974  for (const auto& [mpg, nets] : connected)
975  {
976  for (const auto& net : nets)
977  {
978  std::cout << "\t" << mpg.first->get_id() << " / " << mpg.first->get_name() << " - " << mpg.second->get_name() << ": " << net->get_id() << " / " << net->get_name() << std::endl;
979  }
980  }
981  }
982  for (const auto& [start, connected] : connectivity_inwards)
983  {
984  std::cout << start.first.first->get_id() << " / " << start.first.first->get_name() << " - " << start.first.second->get_name() << " (INWARDS)@ " << start.second->get_id() << " / "
985  << start.second->get_name() << std::endl;
986  for (const auto& [mpg, nets] : connected)
987  {
988  for (const auto& net : nets)
989  {
990  std::cout << "\t" << mpg.first->get_id() << " / " << mpg.first->get_name() << " - " << mpg.second->get_name() << ": " << net->get_id() << " / " << net->get_name() << std::endl;
991  }
992  }
993  }
994 #endif
995 
996  log_info("bitorder_propagation", "Finished conncetivity analysis for bitorder propagation");
997 
998  std::map<MPG, std::map<Net*, u32>> wellformed_module_pin_groups = known_bitorders;
999 
1000  u32 iteration_ctr = 0;
1001 
1002  while (true)
1003  {
1004  // find modules that are neither blocked nor are they already wellformed
1005  std::vector<MPG> modules_and_pingroup;
1006  for (const auto& mpg : unknown_bitorders)
1007  {
1008  if (mpg.first->is_top_module())
1009  {
1010  log_error("bitorder_propagation", "Top module is part of the unknown bitorders!");
1011  continue;
1012  }
1013 
1014  // NOTE We can skip module/pin group pairs that are already wellformed
1015  if (wellformed_module_pin_groups.find(mpg) == wellformed_module_pin_groups.end())
1016  {
1017  modules_and_pingroup.push_back(mpg);
1018  }
1019  };
1020 
1021  std::deque<MPG> q = {modules_and_pingroup.begin(), modules_and_pingroup.end()};
1022 
1023  if (q.empty())
1024  {
1025  break;
1026  }
1027 
1028  log_info("bitorder_propagation", "Starting {}bitorder propagation iteration {}.", (enforce_continuous_bitorders ? "strict " : ""), iteration_ctr);
1029 
1030  std::map<MPG, std::map<Net*, u32>> new_wellformed_module_pin_groups = {};
1031 
1032  while (!q.empty())
1033  {
1034  auto [m, pg] = q.front();
1035  q.pop_front();
1036 
1037  // check wether m has submodules that are in the q
1038  bool no_submodules_in_q = true;
1039  for (const auto& sub_m : m->get_submodules(nullptr, true))
1040  {
1041  for (const auto& [sm, sp] : q)
1042  {
1043  if (sm == sub_m)
1044  {
1045  no_submodules_in_q = false;
1046  break;
1047  }
1048  }
1049  }
1050 
1051  if (!no_submodules_in_q)
1052  {
1053  q.push_back({m, pg});
1054  continue;
1055  }
1056 
1057  bool successors = pg->get_direction() == PinDirection::output;
1058 
1059  std::map<Net*, POSSIBLE_BITINDICES> collected_inwards;
1060  std::map<Net*, POSSIBLE_BITINDICES> collected_outwards;
1061  std::map<Net*, POSSIBLE_BITINDICES> collected_combined;
1062 
1063  for (const auto& pin : pg->get_pins())
1064  {
1065  Net* starting_net = pin->get_net();
1066 
1067  // ############################################### //
1068  // ################### INWARDS ################### //
1069  // ############################################### //
1070 
1071  if (auto con_it = connectivity_inwards.find({{m, pg}, starting_net}); con_it == connectivity_inwards.end())
1072  {
1073 #ifdef PRINT_CONNECTIVITY
1074  std::cout << "There are no valid origins connected inwards to modue " << m->get_id() << " / " << m->get_name() << " with pin group " << pg->get_name() << " and net "
1075  << starting_net->get_id() << " / " << starting_net->get_name() << "." << std::endl;
1076 #endif
1077  }
1078  else
1079  {
1080  const auto& connected_inwards = con_it->second;
1081 
1082  for (const auto& [org_mpg, org_nets] : connected_inwards)
1083  {
1084  if (auto mpg_it = wellformed_module_pin_groups.find(org_mpg); mpg_it != wellformed_module_pin_groups.end())
1085  {
1086  const auto& nets = mpg_it->second;
1087  for (const auto& org_net : org_nets)
1088  {
1089  if (auto net_it = nets.find(org_net); net_it != nets.end())
1090  {
1091  collected_inwards[starting_net][org_mpg].insert(net_it->second);
1092  collected_combined[starting_net][org_mpg].insert(net_it->second);
1093  }
1094  else
1095  {
1096  log_warning("bitorder_propagation",
1097  "Module {} / {} and pin group {} are wellformed but are missing an index for net {} / {}!",
1098  org_mpg.first->get_id(),
1099  org_mpg.first->get_name(),
1100  org_mpg.second->get_name(),
1101  org_net->get_id(),
1102  org_net->get_name());
1103  }
1104  }
1105  }
1106  }
1107  }
1108 
1109  // ############################################### //
1110  // ################### OUTWARDS ################## //
1111  // ############################################### //
1112 
1113  if (const auto con_it = connectivity_outwards.find({{m, pg}, starting_net}); con_it == connectivity_outwards.end())
1114  {
1115 #ifdef PRINT_CONNECTIVITY
1116  std::cout << "There are no valid origins connected outwards to modue " << m->get_id() << " / " << m->get_name() << " with pin group " << pg->get_name() << " and net "
1117  << starting_net->get_id() << " / " << starting_net->get_name() << "." << std::endl;
1118 #endif
1119  continue;
1120  }
1121  else
1122  {
1123  const auto& connected_outwards = con_it->second;
1124 
1125  for (const auto& [org_mpg, org_nets] : connected_outwards)
1126  {
1127  if (auto mpg_it = wellformed_module_pin_groups.find(org_mpg); mpg_it != wellformed_module_pin_groups.end())
1128  {
1129  const auto& nets = mpg_it->second;
1130  for (const auto& org_net : org_nets)
1131  {
1132  if (auto net_it = nets.find(org_net); net_it != nets.end())
1133  {
1134  collected_outwards[starting_net][org_mpg].insert(net_it->second);
1135  collected_combined[starting_net][org_mpg].insert(net_it->second);
1136  }
1137  else
1138  {
1139  log_warning("bitorder_propagation",
1140  "Module {} / {} and pin group {} are wellformed but are missing an index for net {} / {}!",
1141  org_mpg.first->get_id(),
1142  org_mpg.first->get_name(),
1143  org_mpg.second->get_name(),
1144  org_net->get_id(),
1145  org_net->get_name());
1146  }
1147  }
1148  }
1149  }
1150  }
1151  }
1152 
1153 #ifdef PRINT_CONFLICT
1154  std::cout << "Extract for " << m->get_id() << " / " << m->get_name() << " - " << pg->get_name() << ": (INWARDS) " << std::endl;
1155  for (const auto& [net, collected] : collected_inwards)
1156  {
1157  std::cout << net->get_id() << " / " << net->get_name() << std::endl;
1158  for (const auto& [mpg, indices] : collected)
1159  {
1160  std::cout << "\t" << mpg.first->get_id() << " / " << mpg.first->get_name() << " - " << mpg.second->get_name() << std::endl;
1161  std::cout << "\t\t";
1162  for (const auto& index : indices)
1163  {
1164  std::cout << index << ", ";
1165  }
1166  std::cout << std::endl;
1167  }
1168  }
1169 #endif
1170 
1171  const auto newly_wellformed_inwards = extract_well_formed_bitorder({m, pg}, collected_inwards, enforce_continuous_bitorders);
1172  if (!newly_wellformed_inwards.empty())
1173  {
1174  new_wellformed_module_pin_groups[{m, pg}] = newly_wellformed_inwards;
1175  continue;
1176  }
1177 
1178 #ifdef PRINT_CONFLICT
1179  std::cout << "Extract for " << m->get_id() << " / " << m->get_name() << " - " << pg->get_name() << ": (OUTWARDS) " << std::endl;
1180  for (const auto& [net, collected] : collected_outwards)
1181  {
1182  std::cout << net->get_id() << " / " << net->get_name() << std::endl;
1183  for (const auto& [mpg, indices] : collected)
1184  {
1185  std::cout << "\t" << mpg.first->get_id() << " / " << mpg.first->get_name() << " - " << mpg.second->get_name() << std::endl;
1186  std::cout << "\t\t";
1187  for (const auto& index : indices)
1188  {
1189  std::cout << index << ", ";
1190  }
1191  std::cout << std::endl;
1192  }
1193  }
1194 #endif
1195  const auto newly_wellformed_outwards = extract_well_formed_bitorder({m, pg}, collected_outwards, enforce_continuous_bitorders);
1196  if (!newly_wellformed_outwards.empty())
1197  {
1198  new_wellformed_module_pin_groups[{m, pg}] = newly_wellformed_outwards;
1199  continue;
1200  }
1201 
1202 #ifdef PRINT_CONFLICT
1203  std::cout << "Extract for " << m->get_id() << " / " << m->get_name() << " - " << pg->get_name() << ": (COMBINED) " << std::endl;
1204 #endif
1205  const auto newly_wellformed_combined = extract_well_formed_bitorder({m, pg}, collected_combined, enforce_continuous_bitorders);
1206  if (!newly_wellformed_combined.empty())
1207  {
1208  new_wellformed_module_pin_groups[{m, pg}] = newly_wellformed_combined;
1209  }
1210  }
1211 
1212  if (new_wellformed_module_pin_groups.empty())
1213  {
1214  break;
1215  }
1216 
1217  log_info("bitorder_propagation", "Found {} new bitorders in iteration: {}", new_wellformed_module_pin_groups.size(), iteration_ctr);
1218 
1219  // NOTE could think about merging if we find that information is lost between iterations
1220  wellformed_module_pin_groups.insert(new_wellformed_module_pin_groups.begin(), new_wellformed_module_pin_groups.end());
1221 
1222  iteration_ctr++;
1223 
1224  if (iteration_ctr > 100)
1225  {
1226  log_error("bitorder_propagation", "Endless loop protection, something went wrong!");
1227  break;
1228  }
1229  }
1230 
1231  log_info("bitorder_propagation", "Found a valid bitorder for {} pingroups.", wellformed_module_pin_groups.size());
1232 
1233  return OK(wellformed_module_pin_groups);
1234  }
1235 
1236  Result<std::monostate> reorder_module_pin_groups(const std::map<MPG, std::map<Net*, u32>>& ordered_module_pin_groups)
1237  {
1238  // reorder pin groups to match found bit orders
1239  for (const auto& [mpg, bitorder] : ordered_module_pin_groups)
1240  {
1241  auto m = mpg.first;
1242  auto pg = mpg.second;
1243 
1244  std::map<u32, ModulePin*> index_to_pin;
1245 
1246  // collect pins by the nets that run through them and store new index of each pin
1247  for (const auto& [net, index] : bitorder)
1248  {
1249  ModulePin* pin = m->get_pin_by_net(net);
1250  if (pin != nullptr)
1251  {
1252  auto [current_pin_group, _old_index] = pin->get_group();
1253  if (pg == current_pin_group)
1254  {
1255  index_to_pin[index] = pin;
1256  }
1257  else
1258  {
1259  return ERR("cannot reorder module pin groups: pin '" + pin->get_name() + "' appears in bit order of pin group '" + pg->get_name() + "' for module with ID "
1260  + std::to_string(m->get_id()) + " but belongs to pin group '" + current_pin_group->get_name() + "'");
1261  }
1262  }
1263  }
1264 
1265  // apply new indices to pins
1266  for (const auto& [index, pin] : index_to_pin)
1267  {
1268  if (!m->move_pin_within_group(pg, pin, index))
1269  {
1270  return ERR("cannot reorder module pin groups: failed to move pin '" + pin->get_name() + "' in pin group '" + pg->get_name() + "' of module with ID "
1271  + std::to_string(m->get_id()) + " to new index " + std::to_string(index));
1272  }
1273 
1274  const auto pin_name = pg->get_name() + "(" + std::to_string(index) + ")";
1275  if (auto collision_pins = m->get_pins([pin_name](const ModulePin* pin) { return pin->get_name() == pin_name; }); !collision_pins.empty())
1276  {
1277  m->set_pin_name(collision_pins.front(), pin_name + "_OLD");
1278  }
1279 
1280  m->set_pin_name(pin, pin_name);
1281  }
1282  }
1283 
1284  return OK({});
1285  }
1286 
1287  Result<std::map<std::pair<Module*, PinGroup<ModulePin>*>, std::map<Net*, u32>>> propagate_bitorder(Netlist* nl, const std::pair<u32, std::string>& src, const std::pair<u32, std::string>& dst)
1288  {
1289  const std::vector<std::pair<u32, std::string>> src_vec = {src};
1290  const std::vector<std::pair<u32, std::string>> dst_vec = {dst};
1291  return propagate_bitorder(nl, src_vec, dst_vec);
1292  }
1293 
1295  const std::pair<Module*, PinGroup<ModulePin>*>& dst)
1296  {
1297  if (!src.second)
1298  {
1299  return ERR("cannot propagate bitorder: no source given");
1300  }
1301  if (!dst.second)
1302  {
1303  return ERR("cannot propagate bitorder: no destination given");
1304  }
1305  const std::vector<std::pair<Module*, PinGroup<ModulePin>*>> src_vec = {src};
1306  const std::vector<std::pair<Module*, PinGroup<ModulePin>*>> dst_vec = {dst};
1307  return propagate_bitorder(src_vec, dst_vec);
1308  }
1309 
1311  propagate_bitorder(Netlist* nl, const std::vector<std::pair<u32, std::string>>& src, const std::vector<std::pair<u32, std::string>>& dst)
1312  {
1313  std::vector<std::pair<Module*, PinGroup<ModulePin>*>> internal_src;
1314  std::vector<std::pair<Module*, PinGroup<ModulePin>*>> internal_dst;
1315 
1316  // collect known bit orders
1317  for (const auto& [mod_id, pg_name] : src)
1318  {
1319  auto src_mod = nl->get_module_by_id(mod_id);
1320  if (src_mod == nullptr)
1321  {
1322  return ERR("Cannot propagate bit order: failed to find a module with ID " + std::to_string(mod_id));
1323  }
1324 
1325  PinGroup<ModulePin>* src_pin_group = nullptr;
1326  for (const auto& pin_group : src_mod->get_pin_groups())
1327  {
1328  if (pin_group->get_name() == pg_name)
1329  {
1330  // check whether there are multiple pin groups with the same name
1331  if (src_pin_group != nullptr)
1332  {
1333  return ERR("Cannot propagate bit order: found multiple pin groups with name " + pg_name + " at module with ID " + std::to_string(mod_id));
1334  }
1335 
1336  src_pin_group = pin_group;
1337  }
1338  }
1339 
1340  if (src_pin_group == nullptr)
1341  {
1342  return ERR("Cannot propagate bit order: failed to find a pin group with the name '" + pg_name + "' at module with ID " + std::to_string(mod_id));
1343  }
1344 
1345  internal_src.push_back({src_mod, src_pin_group});
1346  }
1347 
1348  // collect unknown bit orders
1349  for (const auto& [mod_id, pg_name] : dst)
1350  {
1351  auto src_mod = nl->get_module_by_id(mod_id);
1352  if (src_mod == nullptr)
1353  {
1354  return ERR("Cannot propagate bit order: failed to find a module with ID " + std::to_string(mod_id));
1355  }
1356 
1357  PinGroup<ModulePin>* src_pin_group = nullptr;
1358  for (const auto& pin_group : src_mod->get_pin_groups())
1359  {
1360  if (pin_group->get_name() == pg_name)
1361  {
1362  // check whether there are multiple pin groups with the same name
1363  if (src_pin_group != nullptr)
1364  {
1365  return ERR("Cannot propagate bitorder: found multiple pin groups with name '" + pg_name + "' at module with ID " + std::to_string(mod_id));
1366  }
1367 
1368  src_pin_group = pin_group;
1369  }
1370  }
1371 
1372  if (src_pin_group == nullptr)
1373  {
1374  return ERR("Cannot propagate bitorder: failed to find a pin group with the name '" + pg_name + "' at module with ID " + std::to_string(mod_id));
1375  }
1376 
1377  internal_dst.push_back({src_mod, src_pin_group});
1378  }
1379 
1380  // actually propagate the bit order
1381  return propagate_bitorder(internal_src, internal_dst);
1382  }
1383 
1384  Result<std::map<std::pair<Module*, PinGroup<ModulePin>*>, std::map<Net*, u32>>> propagate_bitorder(const std::vector<std::pair<Module*, PinGroup<ModulePin>*>>& src,
1385  const std::vector<std::pair<Module*, PinGroup<ModulePin>*>>& dst)
1386  {
1387  std::map<MPG, std::map<Net*, u32>> known_bitorders;
1388  std::set<MPG> unknown_bitorders = {dst.begin(), dst.end()};
1389 
1390  // collect known bit orders
1391  for (auto& [m, pg] : src)
1392  {
1393  std::map<Net*, u32> src_bitorder;
1394 
1395  // TODO this is gonna crash if pin does not start at index 0
1396  for (u32 index = 0; index < pg->get_pins().size(); index++)
1397  {
1398  auto pin_res = pg->get_pin_at_index(index);
1399  if (pin_res.is_error())
1400  {
1401  return ERR_APPEND(pin_res.get_error(), "cannot propagate bit order: failed to get pin at index " + std::to_string(index) + " inside of pin group '" + pg->get_name() + "'");
1402  }
1403  const ModulePin* pin = pin_res.get();
1404 
1405  src_bitorder.insert({pin->get_net(), index});
1406  }
1407 
1408  known_bitorders.insert({{m, pg}, src_bitorder});
1409  }
1410 
1411  // actually propagate the bit order
1412  const auto res = propagate_module_pingroup_bitorder(known_bitorders, unknown_bitorders);
1413  if (res.is_error())
1414  {
1415  return ERR_APPEND(res.get_error(), "cannot propagate bit order: failed propagation");
1416  }
1417 
1418  const auto all_wellformed_module_pin_groups = res.get();
1419 
1420  // apply bit orders to module pin groups (rename and reorder pins)
1421  reorder_module_pin_groups(all_wellformed_module_pin_groups);
1422 
1423 #ifdef PRINT_GENERAL
1424  for (const auto& [mpg, bitorder] : all_wellformed_module_pin_groups)
1425  {
1426  auto m = mpg.first;
1427  auto pg = mpg.second;
1428 
1429  std::cout << "Module: " << m->get_id() << " / " << m->get_name() << ": " << std::endl;
1430  std::cout << "Pingroup: " << pg->get_name() << ": " << std::endl;
1431 
1432  for (const auto& [net, index] : bitorder)
1433  {
1434  std::cout << net->get_id() << ": " << index << std::endl;
1435  }
1436  }
1437 #endif
1438 
1439  // print stats
1440  const u32 all_wellformed_bitorders_count = all_wellformed_module_pin_groups.size();
1441  const u32 new_bit_order_count = all_wellformed_bitorders_count - src.size();
1442 
1443  log_info("bitorder_propagation", "reconstructed {} unknown bit orders from {} known bit orders", new_bit_order_count, src.size());
1444  log_info("bitorder_propagation", "{} / {} = {} of all unknown bit orders", new_bit_order_count, dst.size(), double(new_bit_order_count) / double(dst.size()));
1445  log_info("bitorder_propagation",
1446  "{} / {} = {} of all pin group bit orders",
1447  all_wellformed_bitorders_count,
1448  dst.size() + src.size(),
1449  double(all_wellformed_bitorders_count) / double(dst.size() + src.size()));
1450 
1451  return OK(all_wellformed_module_pin_groups);
1452  }
1453 
1455  const std::vector<std::pair<Module*, PinGroup<ModulePin>*>>& dst,
1456  const std::string& export_filepath)
1457  {
1458  std::map<MPG, std::map<Net*, u32>> known_bitorders;
1459  std::set<MPG> unknown_bitorders = {dst.begin(), dst.end()};
1460 
1461  // collect known bit orders
1462  for (auto& [m, pg] : src)
1463  {
1464  std::map<Net*, u32> src_bitorder;
1465 
1466  // TODO this is gonna crash if pin does not start at index 0
1467  for (u32 index = 0; index < pg->get_pins().size(); index++)
1468  {
1469  auto pin_res = pg->get_pin_at_index(index);
1470  if (pin_res.is_error())
1471  {
1472  return ERR_APPEND(pin_res.get_error(), "cannot propagate bit order: failed to get pin at index " + std::to_string(index) + " inside of pin group '" + pg->get_name() + "'");
1473  }
1474  const ModulePin* pin = pin_res.get();
1475 
1476  src_bitorder.insert({pin->get_net(), index});
1477  }
1478 
1479  known_bitorders.insert({{m, pg}, src_bitorder});
1480  }
1481 
1482  return export_bitorder_propagation_information(known_bitorders, unknown_bitorders, export_filepath);
1483  }
1484 
1485  Result<std::map<MPG, u32>> export_bitorder_propagation_information(const std::map<std::pair<Module*, PinGroup<ModulePin>*>, std::map<Net*, u32>>& known_bitorders,
1486  const std::set<std::pair<Module*, PinGroup<ModulePin>*>>& unknown_bitorders,
1487  const std::string& export_filepath)
1488  {
1489  std::map<std::pair<MPG, Net*>, std::vector<std::pair<MPG, std::set<Net*>>>> connectivity_inwards;
1490  std::map<std::pair<MPG, Net*>, std::vector<std::pair<MPG, std::set<Net*>>>> connectivity_outwards;
1491 
1492  std::set<MPG> relevant_pin_groups = unknown_bitorders;
1493  for (const auto& [kb, _] : known_bitorders)
1494  {
1495  relevant_pin_groups.insert(kb);
1496  }
1497 
1498  std::map<std::tuple<Endpoint*, const bool, const Module*>, std::map<MPG, std::set<Net*>>> cache_outwards;
1499  std::map<std::tuple<Endpoint*, const bool, const Module*>, std::map<MPG, std::set<Net*>>> cache_inwards;
1500 
1501  // Build connectivity
1502  for (const auto& [m, pg] : relevant_pin_groups)
1503  {
1504  bool successors = pg->get_direction() == PinDirection::output;
1505 
1506  for (const auto& p : pg->get_pins())
1507  {
1508  const auto starting_net = p->get_net();
1509 
1510  std::set<std::tuple<Endpoint*, const bool, const Module*>> visited_outwards;
1511  const auto res_outwards = gather_connected_neighbors(starting_net, successors, relevant_pin_groups, false, nullptr, visited_outwards, cache_outwards);
1512  if (res_outwards.is_error())
1513  {
1514  return ERR_APPEND(res_outwards.get_error(),
1515  "cannot porpagate bitorder: failed to gather bit indices outwards starting from the module with ID " + std::to_string(m->get_id()) + " and pin group "
1516  + pg->get_name());
1517  }
1518  const auto connected_outwards = res_outwards.get();
1519 
1520  std::set<std::tuple<Endpoint*, const bool, const Module*>> visited_inwards;
1521  // NOTE when propagating inwards we guarantee the first propagation since otherwise we would stop at our starting pingroup
1522  const auto res_inwards = gather_connected_neighbors(starting_net, !successors, relevant_pin_groups, true, m, visited_inwards, cache_inwards);
1523  if (res_inwards.is_error())
1524  {
1525  return ERR_APPEND(res_inwards.get_error(),
1526  "cannot porpagate bitorder: failed to gather bit indices inwwards starting from the module with ID " + std::to_string(m->get_id()) + " and pin group "
1527  + pg->get_name());
1528  }
1529  const auto connected_inwards = res_inwards.get();
1530 
1531  for (const auto& [org_mpg, nets] : connected_outwards)
1532  {
1533  connectivity_outwards[{{m, pg}, starting_net}].push_back({org_mpg, nets});
1534  }
1535 
1536  for (const auto& [org_mpg, nets] : connected_inwards)
1537  {
1538  connectivity_inwards[{{m, pg}, starting_net}].push_back({org_mpg, nets});
1539  }
1540  }
1541  }
1542 
1543  nlohmann::json info;
1544 
1545  // export word definitions
1546  std::vector<MPG> mpgs;
1547  std::map<MPG, u32> mpg_to_idx;
1548  std::vector<std::vector<Net*>> words;
1549  std::map<std::string, std::vector<std::string>> word_definitions;
1550 
1551  for (const auto& [m, pg] : relevant_pin_groups)
1552  {
1553  std::vector<Net*> nets;
1554  std::vector<std::string> nets_str;
1555 
1556  for (const auto& p : pg->get_pins())
1557  {
1558  const auto& n = p->get_net();
1559  nets.push_back(n);
1560  nets_str.push_back(BooleanFunctionNetDecorator(*n).get_boolean_variable_name());
1561  }
1562 
1563  word_definitions.insert({std::to_string(words.size()), nets_str});
1564  mpg_to_idx.insert({{m, pg}, (unsigned int)mpg_to_idx.size()});
1565  mpgs.push_back({m, pg});
1566  words.push_back(nets);
1567  }
1568 
1569  info["word_definitions"] = word_definitions;
1570 
1571  // export known bitorders
1572  std::map<std::string, std::vector<std::string>> known_word_orders;
1573 
1574  for (u32 i = 0; i < mpgs.size(); i++)
1575  {
1576  const auto& mpg = mpgs.at(i);
1577 
1578  if (const auto it = known_bitorders.find(mpg); it != known_bitorders.end())
1579  {
1580  std::vector<std::string> ordered_nets_str;
1581 
1582  std::vector<std::pair<Net*, u32>> net_index_vec = {it->second.begin(), it->second.end()};
1583  std::sort(net_index_vec.begin(), net_index_vec.end(), [](const auto& p1, const auto& p2) { return p1.second < p2.second; });
1584  for (const auto& [n, _idx] : net_index_vec)
1585  {
1586  ordered_nets_str.push_back(BooleanFunctionNetDecorator(*n).get_boolean_variable_name());
1587  }
1588 
1589  known_word_orders.insert({std::to_string(i), ordered_nets_str});
1590  }
1591  }
1592 
1593  info["known_bit_order"] = known_word_orders;
1594 
1595  // export connectivity
1596  std::map<std::string, std::vector<std::pair<u32, std::string>>> connected_words;
1597  std::map<std::string, std::vector<std::pair<u32, std::string>>> connected_words_forward;
1598  std::map<std::string, std::vector<std::pair<u32, std::string>>> connected_words_backward;
1599 
1600  for (u32 i = 0; i < mpgs.size(); i++)
1601  {
1602  const auto& mpg = mpgs.at(i);
1603  const auto& nets = words.at(i);
1604 
1605  for (const auto& src_net : nets)
1606  {
1607  std::vector<std::pair<u32, std::string>> connections;
1608  std::vector<std::pair<u32, std::string>> connections_forward;
1609  std::vector<std::pair<u32, std::string>> connections_backward;
1610 
1611  const auto it_in = connectivity_inwards.find({mpg, src_net});
1612  if (it_in != connectivity_inwards.end())
1613  {
1614  for (const auto& [dst_mpg, dst_nets] : it_in->second)
1615  {
1616  for (const auto& dst_net : dst_nets)
1617  {
1618  connections.push_back({mpg_to_idx.at(dst_mpg), BooleanFunctionNetDecorator(*dst_net).get_boolean_variable_name()});
1619  connections_backward.push_back({mpg_to_idx.at(dst_mpg), BooleanFunctionNetDecorator(*dst_net).get_boolean_variable_name()});
1620  }
1621  }
1622  }
1623 
1624  const auto it_out = connectivity_outwards.find({mpg, src_net});
1625  if (it_out != connectivity_outwards.end())
1626  {
1627  for (const auto& [dst_mpg, dst_nets] : it_out->second)
1628  {
1629  for (const auto& dst_net : dst_nets)
1630  {
1631  connections.push_back({mpg_to_idx.at(dst_mpg), BooleanFunctionNetDecorator(*dst_net).get_boolean_variable_name()});
1632  connections_forward.push_back({mpg_to_idx.at(dst_mpg), BooleanFunctionNetDecorator(*dst_net).get_boolean_variable_name()});
1633  }
1634  }
1635  }
1636 
1637  if (!connections.empty())
1638  {
1639  const std::string identifier = "(" + std::to_string(i) + ", " + BooleanFunctionNetDecorator(*src_net).get_boolean_variable_name() + ")";
1640 
1641  connected_words.insert({identifier, connections});
1642 
1643  if (!connections_backward.empty())
1644  {
1645  connected_words_backward.insert({identifier, connections_backward});
1646  }
1647 
1648  if (!connections_forward.empty())
1649  {
1650  connected_words_forward.insert({identifier, connections_forward});
1651  }
1652  }
1653  }
1654  }
1655 
1656  info["connected_words"] = connected_words;
1657  info["connected_words_backward"] = connected_words_backward;
1658  info["connected_words_forward"] = connected_words_forward;
1659 
1660  // Open a file in write mode
1661  std::ofstream json_file(export_filepath);
1662 
1663  // Serialize the JSON object to the json_file
1664  if (json_file.is_open())
1665  {
1666  json_file << info.dump(4); // Pretty print with an indentation of 4 spaces
1667  }
1668  else
1669  {
1670  return ERR("cannot export bitorder information: failed to open file at path " + export_filepath + " for writing");
1671  }
1672 
1673  return OK(mpg_to_idx);
1674  }
1675 
1676  } // namespace bitorder_propagation
1677 } // namespace hal
This file contains functions for bit-order propagation from pin groups of known bit order to pin grou...
u32 size
const std::string & get_name() const
Definition: base_pin.h:110
const std::pair< PinGroup< T > *, i32 > & get_group() const
Definition: base_pin.h:160
Net * get_net() const
Definition: module_pin.cpp:19
Definition: net.h:58
u32 get_id() const
Definition: net.cpp:88
Module * get_module_by_id(u32 module_id) const
Definition: netlist.cpp:613
uint32_t u32
Definition: defines.h:41
int32_t i32
Definition: defines.h:36
#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
#define ERR_APPEND(prev_error, message)
Definition: result.h:64
Result< std::map< std::pair< Module *, PinGroup< ModulePin > * >, std::map< Net *, u32 > > > propagate_bitorder(Netlist *nl, const std::pair< u32, std::string > &src, const std::pair< u32, std::string > &dst)
Propagate known bit-order information from one module pin group to another module pin group of unknow...
Result< std::map< std::pair< Module *, PinGroup< ModulePin > * >, u32 > > export_bitorder_propagation_information(const std::vector< std::pair< Module *, PinGroup< ModulePin > * >> &src, const std::vector< std::pair< Module *, PinGroup< ModulePin > * >> &dst, const std::string &export_filepath)
Export word composition, known bitorder and connectivity in .json format to solve with external tools...
Result< std::map< MPG, std::map< Net *, u32 > > > propagate_module_pingroup_bitorder(const std::map< MPG, std::map< Net *, u32 >> &known_bitorders, const std::set< MPG > &unknown_bitorders, const bool enforce_continuous_bitorders)
Result< std::map< std::pair< Module *, PinGroup< ModulePin > * >, std::map< Net *, u32 > > > propagate_module_pingroup_bitorder(const std::map< std::pair< Module *, PinGroup< ModulePin > * >, std::map< Net *, u32 >> &src, const std::set< std::pair< Module *, PinGroup< ModulePin > * >> &dst, const bool enforce_continuous_bitorders=true)
Propagate known bit-order information from the given module pin groups to module pin groups of unknow...
Result< std::monostate > reorder_module_pin_groups(const std::map< MPG, std::map< Net *, u32 >> &ordered_module_pin_groups)
Definition: defines.h:45
PinDirection
Definition: pin_direction.h:36
PinType
Definition: pin_type.h:36
std::string enum_to_string(T e)
Definition: enums.h:53
Net * net
std::string identifier