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