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