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