HAL  v4.5.0-254-g8f9f6a423
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
netlist_comparison.cpp
Go to the documentation of this file.
2 
8 #include "hal_core/netlist/net.h"
10 #include "hal_core/utilities/log.h"
11 #include "nlohmann/json.hpp"
12 #include "z3_utils/z3_utils.h"
13 
14 namespace hal
15 {
16  namespace z3_utils
17  {
18  // NOTE this is almost an exact copy of the subgraph function generator with the small addition to pass a variable name prefix.
19  // This allows us to generate distinct net variables for two different netlists by passing differend prefixes to the function (netlist_a_net_1 vs. netlist_b_net_1)
20  namespace
21  {
22  // the Boolean function of each gate output pin, keyed by gate ID and pin
23  using GateFunctionCache = std::map<std::pair<u32, const GatePin*>, BooleanFunction>;
24 
25  Result<z3::expr> get_prefixed_function_of_net(const std::vector<Gate*>& subgraph_gates,
26  const Net* net,
27  const std::string& variable_prefix,
28  z3::context& ctx,
29  std::map<u32, z3::expr>& net_cache,
30  GateFunctionCache& gate_cache)
31  {
32  if (const auto it = net_cache.find(net->get_id()); it != net_cache.end())
33  {
34  return OK(it->second);
35  }
36 
37  const std::vector<Endpoint*> sources = net->get_sources();
38 
39  // net is multi driven
40  if (sources.size() > 1)
41  {
42  return ERR("cannot get Boolean z3 function of net " + net->get_name() + " with ID " + std::to_string(net->get_id()) + ": net is multi driven.");
43  }
44 
45  // net has no source
46  if (sources.empty())
47  {
48  const std::string var_name = variable_prefix + BooleanFunctionNetDecorator(*net).get_boolean_variable_name();
49  z3::expr ret = ctx.bv_const(var_name.c_str(), 1);
50  net_cache.insert({net->get_id(), ret});
51  return OK(ret);
52  }
53 
54  const Endpoint* src_ep = sources.front();
55 
56  if (src_ep->get_gate() == nullptr)
57  {
58  return ERR("cannot get Boolean z3 function of net " + net->get_name() + " with ID " + std::to_string(net->get_id()) + ": net source is null.");
59  }
60 
61  const Gate* src = src_ep->get_gate();
62 
63  // source is not in subgraph gates
64  if (std::find(subgraph_gates.begin(), subgraph_gates.end(), src) == subgraph_gates.end())
65  {
66  const std::string var_name = variable_prefix + BooleanFunctionNetDecorator(*net).get_boolean_variable_name();
67  z3::expr ret = ctx.bv_const(var_name.c_str(), 1);
68  net_cache.insert({net->get_id(), ret});
69  return OK(ret);
70  }
71 
72  BooleanFunction bf;
73  if (const auto it = gate_cache.find({src->get_id(), src_ep->get_pin()}); it == gate_cache.end())
74  {
75  const auto bf_res = src->get_boolean_function(src_ep->get_pin(), true, true);
76  if (bf_res.is_error())
77  {
78  return ERR_APPEND(bf_res.get_error(),
79  "cannot get Boolean z3 function of net " + net->get_name() + " with ID " + std::to_string(net->get_id()) + ": failed to get function of gate.");
80  }
81  bf = bf_res.get();
82 
83  gate_cache.insert({{src->get_id(), src_ep->get_pin()}, bf});
84  }
85  else
86  {
87  bf = it->second;
88  }
89 
90  std::map<std::string, z3::expr> input_to_expr;
91 
92  for (const std::string& in_net_str : bf.get_variable_names())
93  {
94  const auto in_net_res = BooleanFunctionNetDecorator::get_net_from(src->get_netlist(), in_net_str);
95  if (in_net_res.is_error())
96  {
97  return ERR_APPEND(in_net_res.get_error(),
98  "cannot get Boolean z3 function of net " + net->get_name() + " with ID " + std::to_string(net->get_id()) + ": failed to reconstruct input net from variable "
99  + in_net_str + ".");
100  }
101  const auto in_net = in_net_res.get();
102 
103  const auto in_bf_res = get_prefixed_function_of_net(subgraph_gates, in_net, variable_prefix, ctx, net_cache, gate_cache);
104  if (in_bf_res.is_error())
105  {
106  // NOTE since this can lead to a deep recursion we do not append the error and instead only propagate it.
107  return in_bf_res;
108  }
109  const auto in_bf = in_bf_res.get();
110 
111  input_to_expr.insert({in_net_str, in_bf});
112  }
113 
114  z3::expr ret = z3_utils::from_bf(bf, ctx, input_to_expr).simplify();
115  net_cache.insert({net->get_id(), ret});
116 
117  return OK(ret);
118  }
119 
120  Result<z3::expr> get_prefixed_subgraph_z3_function_internal(const std::vector<Gate*>& subgraph_gates,
121  const Net* net,
122  const std::string& variable_prefix,
123  z3::context& ctx,
124  std::map<u32, z3::expr>& net_cache,
125  GateFunctionCache& gate_cache)
126  {
127  // check validity of subgraph_gates
128  if (subgraph_gates.empty())
129  {
130  return ERR("could not get subgraph z3 function of net '" + net->get_name() + "' with ID " + std::to_string(net->get_id()) + ": subgraph contains no gates");
131  }
132  else if (std::any_of(subgraph_gates.begin(), subgraph_gates.end(), [](const Gate* g) { return g == nullptr; }))
133  {
134  return ERR("could not get subgraph z3 function of net '" + net->get_name() + "' with ID " + std::to_string(net->get_id()) + ": subgraph contains a gate that is a 'nullptr'");
135  }
136  else if (net == nullptr)
137  {
138  return ERR("could not get subgraph z3 function: net is a 'nullptr'");
139  }
140  else if (net->get_num_of_sources() > 1)
141  {
142  return ERR("could not get subgraph z3 function of net '" + net->get_name() + "' with ID " + std::to_string(net->get_id()) + ": net has more than one source");
143  }
144 
145  return get_prefixed_function_of_net(subgraph_gates, net, variable_prefix, ctx, net_cache, gate_cache);
146  }
147 
148  Result<z3::expr> get_prefixed_subgraph_z3_function(const std::vector<Gate*>& subgraph_gates, const Net* subgraph_output, const std::string& variable_prefix, z3::context& ctx)
149  {
150  std::map<u32, z3::expr> net_cache;
151  GateFunctionCache gate_cache;
152 
153  return get_prefixed_subgraph_z3_function_internal(subgraph_gates, subgraph_output, variable_prefix, ctx, net_cache, gate_cache);
154  }
155  } // namespace
156 
157  namespace
158  {
159  std::unordered_map<Gate*, std::vector<std::string>> restore_ff_replacements(const Netlist* nl)
160  {
161  std::unordered_map<Gate*, std::vector<std::string>> replacements;
162 
163  for (auto& g : nl->get_gates())
164  {
165  if (g->has_data("preprocessing_information", "replaced_gates"))
166  {
167  const auto& [_, s] = g->get_data("preprocessing_information", "replaced_gates");
168  std::vector<std::string> replaced_gate_names = nlohmann::json::parse(s);
169  replacements.insert({g, replaced_gate_names});
170  }
171  }
172 
173  return replacements;
174  }
175  } // namespace
176 
177  namespace
178  {
179  Result<std::monostate> substitute_net_ids(z3::context& ctx, z3::solver& s, const std::vector<Net*>& nets, const std::string& variable_prefix, const Netlist* nl)
180  {
181  // replace nets
182  for (const auto& net : nets)
183  {
184  if (net->get_sources().size() > 1)
185  {
186  return ERR("cannot replace net id for net " + net->get_name() + " with ID " + std::to_string(net->get_id()) + " because it is multi driven!");
187  }
188 
189  const std::string var_name = variable_prefix + BooleanFunctionNetDecorator(*net).get_boolean_variable_name();
190  const auto sources = net->get_sources([](const Endpoint* ep) { return (ep->get_gate() != nullptr) && (ep->get_gate()->get_type()->has_property(GateTypeProperty::sequential)); });
191  if (net->is_global_input_net())
192  {
193  const auto pin = nl->get_top_module()->get_pin_by_net(net);
194 
195  if (pin == nullptr)
196  {
197  return ERR("cannot replace net id for net " + net->get_name() + " with ID " + std::to_string(net->get_id())
198  + ": net is global input but unable to find pin at top module!");
199  }
200 
201  const z3::expr new_expr = ctx.bv_const(("GLOBAL_IN_" + pin->get_name()).c_str(), 1);
202  const z3::expr net_expr = ctx.bv_const(var_name.c_str(), 1);
203 
204  s.add(net_expr == new_expr);
205  continue;
206  }
207 
208  if (sources.empty())
209  {
210  // TODO this is not an ideal solution, but i dont know a better one
211  log_debug("z3_utils", "No source found for net {}. Cannot replace net and will rename with net name {}!", net->get_id(), net->get_name());
212 
213  const z3::expr new_expr = ctx.bv_const(net->get_name().c_str(), 1);
214  const z3::expr net_expr = ctx.bv_const(var_name.c_str(), 1);
215 
216  s.add(net_expr == new_expr);
217  continue;
218  }
219 
220  const Endpoint* src = sources.front();
221 
222  if (src->get_gate() == nullptr)
223  {
224  log_warning("z3_utils", "No source gate found for net {}. Cannot replace net and will rename with net name {}!", net->get_id(), net->get_name());
225 
226  const z3::expr new_expr = ctx.bv_const(net->get_name().c_str(), 1);
227  const z3::expr net_expr = ctx.bv_const(var_name.c_str(), 1);
228 
229  s.add(net_expr == new_expr);
230  continue;
231  }
232 
233  const std::string src_gate_name = src->get_gate()->get_name();
234  const std::string src_pin = src->get_pin()->get_name();
235  const std::string name = src_gate_name + "_" + src_pin;
236  const z3::expr new_expr = ctx.bv_const(name.c_str(), 1);
237  const z3::expr net_expr = ctx.bv_const(var_name.c_str(), 1);
238 
239  s.add(net_expr == new_expr);
240  }
241 
242  return OK({});
243  }
244 
245  void add_replacements_equal_constraints(z3::context& ctx, z3::solver& s, const std::unordered_map<Gate*, std::vector<std::string>>& replacements)
246  {
247  for (const auto& [g, replaced_names] : replacements)
248  {
249  for (const auto& ep : g->get_fan_out_endpoints())
250  {
251  const std::string g_name = g->get_name() + "_" + ep->get_pin()->get_name();
252  const z3::expr g_expr = ctx.bv_const(g_name.c_str(), 1);
253 
254  for (const auto& name : replaced_names)
255  {
256  const std::string replaced_name = name + "_" + ep->get_pin()->get_name();
257  const z3::expr replaced_expr = ctx.bv_const(replaced_name.c_str(), 1);
258 
259  s.add(g_expr == replaced_expr);
260  }
261  }
262  }
263 
264  return;
265  }
266 
267  Result<std::monostate> setup_solver(z3::context& ctx,
268  z3::solver& s,
269  const Netlist* netlist_a,
270  const Netlist* netlist_b,
271  const std::unordered_map<hal::Gate*, std::vector<std::string>>& ff_replacements_a,
272  const std::unordered_map<hal::Gate*, std::vector<std::string>>& ff_replacements_b)
273  {
274  std::vector<Net*> sub_nets_a;
275  for (const auto& n : netlist_a->get_nets())
276  {
277  const auto comb_sources =
278  n->get_sources([](const Endpoint* ep) { return (ep->get_gate() != nullptr) && (ep->get_gate()->get_type()->has_property(GateTypeProperty::combinational)); });
279  if (comb_sources.empty())
280  {
281  sub_nets_a.push_back(n);
282  }
283  }
284  std::vector<Net*> sub_nets_b;
285  for (const auto& n : netlist_b->get_nets())
286  {
287  const auto comb_sources =
288  n->get_sources([](const Endpoint* ep) { return (ep->get_gate() != nullptr) && (ep->get_gate()->get_type()->has_property(GateTypeProperty::combinational)); });
289  if (comb_sources.empty())
290  {
291  sub_nets_b.push_back(n);
292  }
293  }
294 
295  auto sub_a_res = substitute_net_ids(ctx, s, sub_nets_a, "netlist_a_", netlist_a);
296  if (sub_a_res.is_error())
297  {
298  return ERR_APPEND(sub_a_res.get_error(), "cannot compare netA" + std::to_string(netlist_a->get_id()));
299  }
300  auto sub_b_res = substitute_net_ids(ctx, s, sub_nets_b, "netlist_b_", netlist_b);
301  if (sub_b_res.is_error())
302  {
303  return ERR_APPEND(sub_b_res.get_error(), "cannot compare net A " + std::to_string(netlist_b->get_id()));
304  }
305 
306  add_replacements_equal_constraints(ctx, s, ff_replacements_a);
307  add_replacements_equal_constraints(ctx, s, ff_replacements_b);
308 
309  return OK({});
310  }
311 
312  Result<bool> compare_nets_internal(z3::context& ctx,
313  z3::solver& s,
314  const Net* net_a,
315  const Net* net_b,
316  const std::vector<Gate*>& gates_a,
317  const std::vector<Gate*>& gates_b,
318  const bool fail_on_unknown,
319  const u32 solver_timeout)
320  {
321  const auto bf_res_a = z3_utils::get_prefixed_subgraph_z3_function(gates_a, net_a, "netlist_a_", ctx);
322  if (bf_res_a.is_error())
323  {
324  return ERR_APPEND(bf_res_a.get_error(),
325  "cannot compare net A " + net_a->get_name() + " with ID " + std::to_string(net_a->get_id()) + " with net B " + net_b->get_name() + " with ID "
326  + std::to_string(net_b->get_id()) + ": failed to build subgraph function for net a");
327  }
328  const auto bf_a = bf_res_a.get();
329 
330  const auto bf_res_b = z3_utils::get_prefixed_subgraph_z3_function(gates_b, net_b, "netlist_b_", ctx);
331  if (bf_res_b.is_error())
332  {
333  return ERR_APPEND(bf_res_b.get_error(),
334  "cannot compare net A " + net_a->get_name() + " with ID " + std::to_string(net_a->get_id()) + " with net B " + net_b->get_name() + " with ID "
335  + std::to_string(net_b->get_id()) + ": failed to build subgraph function for net b");
336  }
337  const auto bf_b = bf_res_b.get();
338 
339  auto config = hal::SMT::QueryConfig().with_timeout(solver_timeout).without_model_generation();
340 
341  s.add(bf_a != bf_b);
342  auto smt2_str = s.to_smt2();
343  auto query_res = SMT::Solver::query_local_with_smt2(config, smt2_str);
344  if (query_res.is_error())
345  {
346  return ERR_APPEND(query_res.get_error(),
347  "cannot compare net A " + net_a->get_name() + " with ID " + std::to_string(net_a->get_id()) + " with net B " + net_b->get_name() + " with ID "
348  + std::to_string(net_b->get_id()) + ": failed solver_check");
349  }
350  const auto check_result = query_res.get();
351 
352  if (check_result.is_unsat())
353  {
354  return OK(true);
355  }
356 
357  if (check_result.is_unknown())
358  {
359  return OK(!fail_on_unknown);
360  }
361 
362  return OK(false);
363  }
364  } // namespace
365 
366  Result<bool> compare_nets(const Netlist* netlist_a, const Netlist* netlist_b, const Net* net_a, const Net* net_b, const bool fail_on_unknown, const u32 solver_timeout)
367  {
368  if (netlist_a == nullptr)
369  {
370  return ERR("cannot compare nets: netlist_a is a nullptr!");
371  }
372 
373  if (netlist_b == nullptr)
374  {
375  return ERR("cannot compare nets: netlist_b is a nullptr!");
376  }
377 
378  if (net_a == nullptr)
379  {
380  return ERR("cannot compare nets: net_a is a nullptr!");
381  }
382 
383  if (net_b == nullptr)
384  {
385  return ERR("cannot compare nets: net_b is a nullptr!");
386  }
387 
388  z3::context ctx;
389  z3::solver s(ctx);
390 
391  const auto ff_replacements_a = restore_ff_replacements(netlist_a);
392  const auto ff_replacements_b = restore_ff_replacements(netlist_b);
393 
394  const std::vector<Gate*> comb_gates_a = netlist_a->get_gates([](const Gate* g) { return g->get_type()->has_property(GateTypeProperty::combinational); });
395  const std::vector<Gate*> comb_gates_b = netlist_b->get_gates([](const Gate* g) { return g->get_type()->has_property(GateTypeProperty::combinational); });
396 
397  auto setup_res = setup_solver(ctx, s, netlist_a, netlist_b, ff_replacements_a, ff_replacements_b);
398  if (setup_res.is_error())
399  {
400  return ERR_APPEND(setup_res.get_error(),
401  "cannot compare netlist a with ID " + std::to_string(netlist_a->get_id()) + " netlist b with ID " + std::to_string(netlist_b->get_id()) + ": failed to setup solver");
402  }
403 
404  return compare_nets_internal(ctx, s, net_a, net_b, comb_gates_a, comb_gates_b, fail_on_unknown, solver_timeout);
405  }
406 
407  Result<bool> compare_nets(const Netlist* netlist_a, const Netlist* netlist_b, const std::vector<std::pair<Net*, Net*>>& nets, const bool fail_on_unknown, const u32 solver_timeout)
408  {
409  if (netlist_a == nullptr)
410  {
411  return ERR("cannot compare nets: netlist_a is a nullptr!");
412  }
413 
414  if (netlist_b == nullptr)
415  {
416  return ERR("cannot compare nets: netlist_b is a nullptr!");
417  }
418 
419  z3::context ctx;
420  z3::solver s(ctx);
421 
422  const auto ff_replacements_a = restore_ff_replacements(netlist_a);
423  const auto ff_replacements_b = restore_ff_replacements(netlist_b);
424 
425  const std::vector<Gate*> comb_gates_a = netlist_a->get_gates([](const Gate* g) { return g->get_type()->has_property(GateTypeProperty::combinational); });
426  const std::vector<Gate*> comb_gates_b = netlist_b->get_gates([](const Gate* g) { return g->get_type()->has_property(GateTypeProperty::combinational); });
427 
428  auto setup_res = setup_solver(ctx, s, netlist_a, netlist_b, ff_replacements_a, ff_replacements_b);
429  if (setup_res.is_error())
430  {
431  return ERR_APPEND(setup_res.get_error(),
432  "cannot compare netlist a with ID " + std::to_string(netlist_a->get_id()) + " netlist b with ID " + std::to_string(netlist_b->get_id()) + ": failed to setup solver");
433  }
434 
435  for (const auto& [net_a, net_b] : nets)
436  {
437  if ((net_a == nullptr) && (net_b == nullptr))
438  {
439  continue;
440  }
441 
442  if ((net_a == nullptr) || (net_b == nullptr))
443  {
444  return OK(false);
445  }
446 
447  s.push();
448  auto comp_res = compare_nets_internal(ctx, s, net_a, net_b, comb_gates_a, comb_gates_b, fail_on_unknown, solver_timeout);
449  s.pop();
450 
451  if (comp_res.is_error())
452  {
453  return ERR_APPEND(comp_res.get_error(),
454  "cannot compare netlist a with ID " + std::to_string(netlist_a->get_id()) + " netlist b with ID " + std::to_string(netlist_b->get_id())
455  + ": failed net comparison");
456  }
457  const auto eq = comp_res.get();
458 
459  if (!eq)
460  {
461  log_warning("z3_utils", "Failed net comparison for net A {} / {} and net B {} / {}", net_a->get_id(), net_a->get_name(), net_b->get_id(), net_b->get_name());
462  return OK(false);
463  }
464  }
465 
466  return OK(true);
467  }
468 
469  Result<bool> compare_netlists(const Netlist* netlist_a, const Netlist* netlist_b, const bool fail_on_unknown, const u32 solver_timeout)
470  {
471  const std::vector<Gate*> seq_gates_a = netlist_a->get_gates([](const Gate* g) { return g->get_type()->has_property(GateTypeProperty::sequential); });
472  const std::vector<Gate*> seq_gates_b = netlist_b->get_gates([](const Gate* g) { return g->get_type()->has_property(GateTypeProperty::sequential); });
473 
474  const std::vector<Gate*> comb_gates_a = netlist_a->get_gates([](const Gate* g) { return g->get_type()->has_property(GateTypeProperty::combinational); });
475  const std::vector<Gate*> comb_gates_b = netlist_b->get_gates([](const Gate* g) { return g->get_type()->has_property(GateTypeProperty::combinational); });
476 
477  const auto ff_replacements_a = restore_ff_replacements(netlist_a);
478  const auto ff_replacements_b = restore_ff_replacements(netlist_b);
479 
480  // TODO let the user provide a name mapping from gate a to net b incase there was a renaming of the sequential gates
481  std::unordered_map<std::string, Gate*> gate_name_to_gate_a;
482  std::unordered_map<std::string, Gate*> gate_name_to_gate_b;
483 
484  for (const auto& gate_a : seq_gates_a)
485  {
486  gate_name_to_gate_a[gate_a->get_name()] = gate_a;
487 
488  if (const auto& it = ff_replacements_a.find(gate_a); it != ff_replacements_a.end())
489  {
490  for (const auto& s : it->second)
491  {
492  gate_name_to_gate_a[s] = gate_a;
493  }
494  }
495  }
496  for (const auto& gate_b : seq_gates_b)
497  {
498  gate_name_to_gate_b[gate_b->get_name()] = gate_b;
499 
500  if (const auto& it = ff_replacements_b.find(gate_b); it != ff_replacements_b.end())
501  {
502  for (const auto& s : it->second)
503  {
504  gate_name_to_gate_b[s] = gate_b;
505  }
506  }
507  }
508 
509  for (const auto& [gate_a_name, gate_a] : gate_name_to_gate_a)
510  {
511  if (const auto gate_b_it = gate_name_to_gate_b.find(gate_a_name); gate_b_it == gate_name_to_gate_b.end())
512  {
513  log_debug("z3_utils",
514  "netlist a with ID {} and netlist b with ID {} are not equal: gate a {} with ID {} is included in netlist a but does not have a counter part in netlist b!",
515  netlist_a->get_id(),
516  netlist_b->get_id(),
517  gate_a->get_name(),
518  gate_a->get_id());
519  return OK(false);
520  }
521  }
522  for (const auto& [gate_b_name, gate_b] : gate_name_to_gate_b)
523  {
524  if (const auto gate_a_it = gate_name_to_gate_a.find(gate_b_name); gate_a_it == gate_name_to_gate_a.end())
525  {
526  log_debug("z3_utils",
527  "netlist a with ID {} and netlist b with ID {} are not equal: gate b {} with ID {} is included in netlist b but does not have a counter part in netlist a!",
528  netlist_a->get_id(),
529  netlist_b->get_id(),
530  gate_b->get_name(),
531  gate_b->get_id());
532  return OK(false);
533  }
534  }
535 
536  log_info("z3_utils", "Checking {} sequential gates for equality.", seq_gates_a.size());
537 
538  z3::context ctx;
539  z3::solver s(ctx);
540 
541  auto setup_res = setup_solver(ctx, s, netlist_a, netlist_b, ff_replacements_a, ff_replacements_b);
542  if (setup_res.is_error())
543  {
544  return ERR_APPEND(setup_res.get_error(),
545  "cannot compare netlist a with ID " + std::to_string(netlist_a->get_id()) + " netlist b with ID " + std::to_string(netlist_b->get_id()) + ": failed to setup solver");
546  }
547 
548  std::set<std::pair<Net*, Net*>> to_compare;
549 
550  // find matching global output and add the to the comparison set
551  const auto out_pins_a = netlist_a->get_top_module()->get_output_pin_names();
552  const auto out_pins_b = netlist_b->get_top_module()->get_output_pin_names();
553 
554  auto all_out_pins = out_pins_a;
555  all_out_pins.insert(all_out_pins.end(), out_pins_b.begin(), out_pins_b.end());
556 
557  for (const auto& pin : all_out_pins)
558  {
559  auto it_a = std::find(out_pins_a.begin(), out_pins_a.end(), pin);
560  if (it_a == out_pins_a.end())
561  {
562  log_warning("z3_utils",
563  "netlist a with ID {} and netlist b with ID {} might not be equal: netlist a has output pin {} that does not exist in netlist b!",
564  netlist_a->get_id(),
565  netlist_b->get_id(),
566  pin);
567  continue;
568  }
569 
570  auto it_b = std::find(out_pins_b.begin(), out_pins_b.end(), pin);
571  if (it_b == out_pins_b.end())
572  {
573  log_warning("z3_utils",
574  "netlist a with ID {} and netlist b with ID {} might not be equal: netlist a has output pin {} that does not exist in netlist b!",
575  netlist_a->get_id(),
576  netlist_b->get_id(),
577  pin);
578  continue;
579  }
580 
581  Net* net_a = netlist_a->get_top_module()->get_pin_by_name(pin)->get_net();
582  Net* net_b = netlist_b->get_top_module()->get_pin_by_name(pin)->get_net();
583 
584  to_compare.insert({net_a, net_b});
585  }
586 
587  // add inputs of sequential gates to the comparison list
588  for (const Gate* gate_a : seq_gates_a)
589  {
590  const Gate* gate_b = gate_name_to_gate_b.at(gate_a->get_name());
591 
592  if (gate_a->get_type() != gate_b->get_type())
593  {
594  log_warning("z3_utils",
595  "netlist a with ID {} and netlist b with ID {} are not equal: gate a {} with ID {} and gate b {} with ID {} do not have the same type! {} vs. {}",
596  netlist_a->get_id(),
597  netlist_b->get_id(),
598  gate_a->get_name(),
599  gate_a->get_id(),
600  gate_b->get_name(),
601  gate_b->get_id(),
602  gate_a->get_type()->get_name(),
603  gate_b->get_type()->get_name());
604  return OK(false);
605  }
606 
607  for (const GatePin* pin : gate_a->get_type()->get_input_pins())
608  {
609  Net* net_a = gate_a->get_fan_in_net(pin);
610  Net* net_b = gate_b->get_fan_in_net(pin);
611 
612  to_compare.insert({net_a, net_b});
613  }
614  }
615 
616  return compare_nets(netlist_a, netlist_b, utils::to_vector(to_compare), fail_on_unknown, solver_timeout);
617  }
618  } // namespace z3_utils
619 } // namespace hal
PinType get_type() const
Definition: base_pin.h:150
static Result< Net * > get_net_from(const Netlist *netlist, const BooleanFunction &var)
Definition: gate.h:59
Net * get_fan_in_net(const std::string &pin_name) const
Definition: gate.cpp:852
GateType * get_type() const
Definition: gate.cpp:162
const std::string & get_name() const
Definition: gate.cpp:142
u32 get_id() const
Definition: gate.cpp:132
const std::string & get_name() const
Definition: gate_type.cpp:64
ModulePin * get_pin_by_name(const std::string &name) const
Definition: module.cpp:1009
std::vector< std::string > get_output_pin_names() const
Definition: module.cpp:963
Net * get_net() const
Definition: module_pin.cpp:19
Definition: net.h:58
Module * get_top_module() const
Definition: netlist.cpp:610
const std::vector< Gate * > & get_gates() const
Definition: netlist.cpp:206
u32 get_id() const
Definition: netlist.cpp:77
static Result< SolverResult > query_local_with_smt2(const QueryConfig &config, const std::string &smt2)
Definition: solver.cpp:429
uint32_t u32
Definition: defines.h:41
#define log_debug(channel,...)
Definition: log.h:74
#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
std::unique_ptr< GateLibrary > parse(std::filesystem::path file_path)
std::vector< T > to_vector(const Container< T, Args... > &container)
Definition: utils.h:559
Result< bool > compare_netlists(const Netlist *netlist_a, const Netlist *netlist_b, const bool fail_on_unknown=true, const u32 solver_timeout=10)
Compares two netlists on a functional level.
z3::expr from_bf(const BooleanFunction &bf, z3::context &ctx, const std::map< std::string, z3::expr > &var2expr={})
Definition: z3_utils.cpp:15
Result< bool > compare_nets(const Netlist *netlist_a, const Netlist *netlist_b, const Net *net_a, const Net *net_b, const bool fail_on_unknown=true, const u32 solver_timeout=10)
Compare two nets from two different netlists.
Definition: defines.h:45
Net * net
std::string name
QueryConfig & without_model_generation()
Definition: types.cpp:119
QueryConfig & with_timeout(u64 seconds)
Definition: types.cpp:125