HAL  v4.5.0-83-g30c8f0afc
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
python_bindings.cpp
Go to the documentation of this file.
2 
3 #include "pybind11/operators.h"
4 #include "pybind11/pybind11.h"
5 #include "pybind11/stl.h"
6 #include "pybind11/stl_bind.h"
11 #include "z3_utils/z3_utils.h"
12 
13 namespace py = pybind11;
14 
15 namespace hal
16 {
17 
18  // the name in PYBIND11_MODULE/PYBIND11_PLUGIN *MUST* match the filename of the output library (without extension),
19  // otherwise you will get "ImportError: dynamic module does not define module export function" when importing the module
20 
21 #ifdef PYBIND11_MODULE
22  PYBIND11_MODULE(z3_utils, m)
23  {
24  m.doc() = "hal Z3UtilsPlugin python bindings";
25 #else
26  PYBIND11_PLUGIN(z3_utils)
27  {
28  py::module m("z3_utils", "hal Z3UtilsPlugin python bindings");
29 #endif // ifdef PYBIND11_MODULE
30 
31  py::class_<Z3UtilsPlugin, RawPtrWrapper<Z3UtilsPlugin>, BasePluginInterface> py_z3_utils(m, "Z3UtilsPlugin", R"(
32  The plugin that provides utilities to translate between HAL Boolean functions and z3 expressions.
33  )");
34 
35  py_z3_utils.def_property_readonly("name", &Z3UtilsPlugin::get_name, R"(
36  The name of the plugin.
37 
38  :type: str
39  )");
40 
41  py_z3_utils.def("get_name", &Z3UtilsPlugin::get_name, R"(
42  Get the name of the plugin.
43 
44  :returns: The name of the plugin.
45  :rtype: str
46  )");
47 
48  py_z3_utils.def_property_readonly("version", &Z3UtilsPlugin::get_version, R"(
49  The version of the plugin.
50 
51  :type: str
52  )");
53 
54  py_z3_utils.def("get_version", &Z3UtilsPlugin::get_version, R"(
55  Get the version of the plugin.
56 
57  :returns: The version of the plugin.
58  :rtype: str
59  )");
60 
61  m.def(
62  "get_subgraph_function",
63  [](const std::vector<Gate*>& subgraph_gates, const Net* subgraph_output) -> std::optional<hal::BooleanFunction> {
64  z3::context ctx;
65 
66  const auto res = z3_utils::get_subgraph_z3_function(subgraph_gates, subgraph_output, ctx);
67  if (res.is_error())
68  {
69  log_error("z3_utils", "{}", res.get_error().get());
70  return std::nullopt;
71  }
72 
73  BooleanFunction bf = z3_utils::to_bf(res.get()).get();
74 
75  return bf;
76  },
77  py::arg("subgraph_gates"),
78  py::arg("subgraph_output"),
79  R"(
80  Get the combined Boolean function of a subgraph of combinational gates starting at the source of the provided subgraph output net.
81 
82  :param list[hal_py.Gate] subgraph_gates: The gates making up the subgraph to consider.
83  :param hal_py.Net subgraph_output: The output net of the subgraph whose function shall be generated.
84  :returns: The Boolean function implemented by the subgraph on success, ``None`` otherwise.
85  :rtype: hal_py.BooleanFunction or None
86  )");
87 
88  m.def(
89  "compare_nets",
90  [](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) -> std::optional<bool> {
91  auto res = z3_utils::compare_nets(netlist_a, netlist_b, net_a, net_b, fail_on_unknown, solver_timeout);
92  if (res.is_ok())
93  {
94  return res.get();
95  }
96  else
97  {
98  log_error("python_context", "{}", res.get_error().get());
99  return std::nullopt;
100  }
101  },
102  py::arg("netlist_a"),
103  py::arg("netlist_b"),
104  py::arg("net_a"),
105  py::arg("net_b"),
106  py::arg("fail_on_unknown") = true,
107  py::arg("solver_timeout") = 10,
108  R"(
109  Compare two nets from two different netlists.
110  This is done on a functional level by building the subgraph function of each net considering all combinational gates of the netlist.
111  In order for this to work the sequential gates of both netlists must have identical names and only the combinational gates may differ.
112 
113  :param hal_py.Netlist netlist_a: First netlist.
114  :param hal_py.Netlist netlist_b: Second netlist.
115  :param hal_py.Net net_a: First net.
116  :param hal_py.Net net_b: Second net.
117  :param bool fail_on_unknown: Determines whether the function returns ``False`` or ``True`` in case the SAT solver returns unknown.
118  :param int solver_timeout: The timeout for each SAT solver query in seconds.
119  :returns: A Boolean indicating whether the two nets are functionally equivalent on success, ``None`` otherwise.
120  :rtype: bool or None
121  )");
122 
123  m.def(
124  "compare_nets",
125  [](const Netlist* netlist_a, const Netlist* netlist_b, const std::vector<std::pair<Net*, Net*>>& nets, const bool fail_on_unknown = true, const u32 solver_timeout = 10)
126  -> std::optional<bool> {
127  auto res = z3_utils::compare_nets(netlist_a, netlist_b, nets, fail_on_unknown, solver_timeout);
128  if (res.is_ok())
129  {
130  return res.get();
131  }
132  else
133  {
134  log_error("python_context", "{}", res.get_error().get());
135  return std::nullopt;
136  }
137  },
138  py::arg("netlist_a"),
139  py::arg("netlist_b"),
140  py::arg("nets"),
141  py::arg("fail_on_unknown") = true,
142  py::arg("solver_timeout") = 10,
143  R"(
144  Compare two nets from two different netlists.
145  This is done on a functional level by building the subgraph function of each net considering all combinational gates of the netlist.
146  In order for this to work the sequential gates of both netlists must have identical names and only the combinational gates may differ.
147 
148  :param hal_py.Netlist netlist_a: First netlist.
149  :param hal_py.Netlist netlist_b: Second netlist.
150  :param list[tuple(hal_py.Net,hal_py.Net)] nets: The pairs of nets to compare against each other.
151  :param bool fail_on_unknown: Determines whether the function returns ``False`` or ``True`` in case the SAT solver returns unknown.
152  :param int solver_timeout: The timeout for each SAT solver query in seconds.
153  :returns: A Boolean indicating whether the two nets are functionally equivalent on success, ``None`` otherwise.
154  :rtype: bool or None
155  )");
156 
157  m.def(
158  "compare_netlists",
159  [](const Netlist* netlist_a, const Netlist* netlist_b, const bool fail_on_unknown = true, const u32 solver_timeout = 10) -> std::optional<bool> {
160  auto res = z3_utils::compare_netlists(netlist_a, netlist_b, fail_on_unknown, solver_timeout);
161  if (res.is_ok())
162  {
163  return res.get();
164  }
165  else
166  {
167  log_error("python_context", "{}", res.get_error().get());
168  return std::nullopt;
169  }
170  },
171  py::arg("netlist_a"),
172  py::arg("netlist_b"),
173  py::arg("fail_on_unknown") = true,
174  py::arg("solver_timeout") = 10,
175  R"(
176  Compares two netlists by finding a corresponding partner for each sequential gate in the netlist and checking whether they are identical.
177  This is done on a functional level by building the subgraph function of all their input nets considering all combinational gates of the netlist.
178  In order for this to work the sequential gates of both netlists must have identical names and only the combinational gates may differ.
179 
180  :param hal_py.Netlist netlist_a: First netlist to compare.
181  :param hal_py.Netlist netlist_b: Second netlist to compare.
182  :param bool fail_on_unknown: Determines whether the function returns ``False`` or ``True`` in case the SAT solver returns unknown.
183  :param int solver_timeout: The timeout for each SAT solver query in seconds.
184  :returns: A Boolean indicating whether the two netlists are functionally equivalent on success, ``None`` otherwise.
185  :rtype: bool or None
186  )");
187 
188  m.def(
189  "simplify",
190  [](const BooleanFunction& bf) -> std::optional<BooleanFunction> {
191  auto ctx = z3::context();
192  auto expr = z3_utils::from_bf(bf, ctx);
193 
194  auto res = z3_utils::simplify_local(expr);
195  if (res.is_error())
196  {
197  log_error("python_context", "{}", res.get_error().get());
198  return std::nullopt;
199  }
200 
201  auto bf_s = z3_utils::to_bf(res.get());
202  if (bf_s.is_ok())
203  {
204  return bf_s.get();
205  }
206  else
207  {
208  log_error("python_context", "{}", res.get_error().get());
209  return std::nullopt;
210  }
211  },
212  py::arg("bf"),
213  R"(
214  Simplifies a Boolean function using the Z3 solver.
215  This is done by using the Z3 solver to simplify the function and then converting it back to a Boolean function.
216  :param hal_py.BooleanFunction bf: The Boolean function to simplify.
217  :returns: The simplified Boolean function on success, ``None`` otherwise.
218  :rtype: hal_py.BooleanFunction or None
219  )");
220 
221 #ifndef PYBIND11_MODULE
222  return m.ptr();
223 #endif // PYBIND11_MODULE
224  }
225 } // namespace hal
Definition: net.h:58
std::string get_version() const override
std::string get_name() const override
uint32_t u32
Definition: defines.h:41
#define log_error(channel,...)
Definition: log.h:78
const Module * module(const Gate *g, const NodeBoxes &boxes)
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.
Result< z3::expr > simplify_local(const z3::expr &e, std::unordered_map< u32, z3::expr > &cache, const bool check_correctness=false)
Applies hand-crafted simplification rules iteratively until no further simplifications can be made.
z3::expr from_bf(const BooleanFunction &bf, z3::context &ctx, const std::map< std::string, z3::expr > &var2expr={})
Definition: z3_utils.cpp:15
Result< z3::expr > get_subgraph_z3_function(const std::vector< Gate * > &subgraph_gates, const Net *subgraph_output, z3::context &ctx)
Get the z3 expression representation of a combined Boolean function of a subgraph of combinational ga...
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.
Result< BooleanFunction > to_bf(const z3::expr &e)
Definition: z3_utils.cpp:443
Definition: defines.h:45
PYBIND11_PLUGIN(hal_py)