5 #include "pybind11/operators.h"
6 #include "pybind11/pybind11.h"
7 #include "pybind11/stl.h"
8 #include "pybind11/stl_bind.h"
20 #ifdef PYBIND11_MODULE
23 m.doc() =
"Plugin to automatically generate FSM state transition graphs for given FSMs.";
27 py::module m(
"solve_fsm",
"Plugin to automatically generate FSM state transition graphs for given FSMs.");
30 py::class_<SolveFsmPlugin, RawPtrWrapper<SolveFsmPlugin>,
BasePluginInterface> py_solve_fsm(
31 m,
"SolveFsmPlugin", R
"(This class provides an interface to integrate FSM solving as a plugin within the HAL framework.)");
33 The name of the plugin.
39 Get the name of the plugin.
41 :returns: Plugin name.
46 The version of the plugin.
52 Get the version of the plugin.
54 :returns: Plugin version.
59 The description of the plugin.
65 Get the description of the plugin.
67 :returns: The description of the plugin.
71 py::class_<solve_fsm::Configuration> py_solve_fsm_configuration(m, "Configuration", R
"(
72 The configuration of a run of the FSM solver.
74 Holds everything the solver needs to know about the FSM, including the netlist that implements it.
75 The state register and the transition logic are mandatory, everything else is optional.
77 States are encoded as integers, with the first flip-flop of the state register providing the least significant bit.
80 py_solve_fsm_configuration.def(py::init<Netlist*>(), py::arg("nl"), R
"(
81 Construct a new FSM solver configuration for the given netlist.
83 :param hal_py.Netlist nl: The netlist that implements the FSM.
87 The netlist that implements the FSM.
93 The flip-flops that make up the state register of the FSM.
95 The first flip-flop provides the least significant bit of the state.
96 Defaults to an empty list, but a state register is required for the solver to run.
98 :type: list[hal_py.Gate]
102 The combinational gates that compute the next state of the FSM.
104 Defaults to an empty list, but transition logic is required for the solver to run.
106 :type: list[hal_py.Gate]
110 The outputs of the FSM, each given as a name and the nets that make up that output.
112 The first net of an output provides its least significant bit, so a single-bit output is a list holding one net.
113 Defaults to an empty list, in which case no outputs are computed.
115 :type: list[tuple(str,list[hal_py.Net])]
119 The initial value of each flip-flop of the state register.
121 Only states reachable from the resulting initial state are explored.
122 Defaults to an empty dict, in which case the FSM starts in state 0.
124 :type: dict[hal_py.Gate,bool]
128 The timeout for the underlying SMT solver in milliseconds. Defaults to 600000 ms.
130 Has no effect when ``brute_force`` is set, as no SMT solver is used then.
136 Enumerate all states instead of using an SMT solver. Defaults to ``False``.
138 Brute forcing needs no external solver and is faster for small state registers, but its runtime doubles with every additional flip-flop.
139 Both approaches produce the same state transition graph.
145 Set the flip-flops that make up the state register of the FSM.
147 :param list[hal_py.Gate] state_register: The flip-flops of the state register, least significant bit first.
148 :returns: The updated FSM solver configuration.
149 :rtype: solve_fsm.Configuration
153 Set the combinational gates that compute the next state of the FSM.
155 :param list[hal_py.Gate] transition_logic: The gates of the transition logic.
156 :returns: The updated FSM solver configuration.
157 :rtype: solve_fsm.Configuration
161 Set the outputs of the FSM that the solver should evaluate in each state.
163 :param list[tuple(str,list[hal_py.Net])] outputs: The outputs, each given as a name and the nets that make up that output, least significant bit first.
164 :returns: The updated FSM solver configuration.
165 :rtype: solve_fsm.Configuration
169 Set the initial value of each flip-flop of the state register.
171 :param dict[hal_py.Gate,bool] initial_state: The initial value of each flip-flop of the state register.
172 :returns: The updated FSM solver configuration.
173 :rtype: solve_fsm.Configuration
177 Set the timeout for the underlying SMT solver.
179 :param int timeout: The timeout in milliseconds.
180 :returns: The updated FSM solver configuration.
181 :rtype: solve_fsm.Configuration
185 Set whether to enumerate all states instead of using an SMT solver.
187 :param bool brute_force: Set ``True`` to enumerate all states, ``False`` to use an SMT solver. Defaults to ``True``.
188 :returns: The updated FSM solver configuration.
189 :rtype: solve_fsm.Configuration
192 py::class_<solve_fsm::StateTransitionGraph> py_state_transition_graph(m, "StateTransitionGraph", R
"(
193 The state transition graph of an FSM, i.e., the behavior that its netlist implements.
195 States are encoded as integers, with the first flip-flop of the state register providing the least significant bit.
199 A dict from each state to its successor states, together with the condition under which the respective transition is taken.
201 :type: dict[int,dict[int,hal_py.BooleanFunction]]
205 A dict from each state to the value of every output of the FSM in that state.
207 The outputs of a state are given in the order in which they were configured.
208 An output of a Moore FSM only depends on the state, so its Boolean function is constant.
209 An output of a Mealy FSM may also depend on the inputs of the FSM, in which case its Boolean function still contains the input variables.
211 Empty unless outputs were configured.
213 :type: dict[int,list[tuple(str,hal_py.BooleanFunction)]]
217 The netlist that implements the FSM.
219 :type: hal_py.Netlist
223 The flip-flops that make up the state register, in the order that determines the encoding of a state.
225 The first flip-flop provides the least significant bit, so this is what maps a state back to the netlist.
227 :type: list[hal_py.Gate]
231 The outputs of the FSM, each given as a name and the nets that make up that output.
233 The first net of an output provides its least significant bit. Empty unless outputs were configured.
235 :type: list[tuple(str,list[hal_py.Net])]
239 Get the number of flip-flops that make up the state register, i.e., the bit-size of a state.
241 :returns: The bit-size of a state.
245 py_state_transition_graph.def(
246 "generate_dot_graph",
248 auto res =
self.generate_dot_graph(graph_path, max_condition_length, base);
255 log_error(
"python_context",
"{}", res.get_error().get());
259 py::arg(
"graph_path") =
"",
260 py::arg(
"max_condition_length") = 128,
261 py::arg(
"base") = 10,
263 Render the state transition graph in the DOT format.
265 Each state becomes a node labeled with its value and, if outputs were computed, with the value of every output in that state.
266 Each transition becomes an edge labeled with its condition.
268 :param pathlib.Path graph_path: The file path at which to store the graph. No file is written if the path is left empty. Defaults to an empty path.
269 :param int max_condition_length: The maximum number of characters printed for a Boolean function. Defaults to 128.
270 :param int base: The base in which state and output values are printed, either 2 or 10. Defaults to 10.
271 :returns: The graph in the DOT format on success, ``None`` otherwise.
275 py_state_transition_graph.def(
278 auto res =
self.to_string(base);
285 log_error(
"python_context",
"{}", res.get_error().get());
289 py::arg(
"base") = 10,
291 Render the state transition graph as human-readable text, without truncating anything.
293 Starts with a legend that maps each bit of the state to the flip-flop holding it, each output to the nets that make it up, and every net variable appearing in a Boolean function to the net it stands for.
294 The legend is followed by one block per state holding its outputs and all of its outgoing transitions together with the full condition of each.
296 :param int base: The base in which state and output values are printed, either 2 or 10. Defaults to 10.
297 :returns: The state transition graph as text on success, ``None`` otherwise.
301 py_state_transition_graph.def(
304 auto res =
self.write_txt(file_path, base);
309 log_error(
"python_context",
"{}", res.get_error().get());
312 py::arg(
"file_path"),
313 py::arg(
"base") = 10,
315 Write the state transition graph to a text file, without truncating anything.
317 :param pathlib.Path file_path: The file path at which to store the text representation.
318 :param int base: The base in which state and output values are printed, either 2 or 10. Defaults to 10.
319 :returns: ``True`` on success, ``False`` otherwise.
333 log_error(
"python_context",
"{}", res.get_error().get());
339 Recover the state transition graph of an FSM from the netlist that implements it.
341 Explores the states that are reachable from the initial state and determines, for each of them, which successor states it can reach and under which condition.
342 If outputs are configured, the value of each output in each state is computed as well.
344 No file is written. Use ``StateTransitionGraph.generate_dot_graph`` on the result to render the graph.
346 :param solve_fsm.Configuration config: The configuration of the FSM solver run.
347 :returns: The state transition graph of the FSM on success, ``None`` otherwise.
348 :rtype: solve_fsm.StateTransitionGraph or None
352 #ifndef PYBIND11_MODULE
std::string get_name() const override
Get the name of the plugin.
std::string get_description() const override
Get a short description of the plugin.
std::string get_version() const override
Get the version of the plugin.
#define log_error(channel,...)
const Module * module(const Gate *g, const NodeBoxes &boxes)
Result< StateTransitionGraph > solve_fsm(const Configuration &config)
Recover the state transition graph of an FSM from the netlist that implements it.
This file contains the function to recover the state transition graph of a finite state machine.
The configuration of a run of the FSM solver.
Configuration & with_brute_force(const bool brute_force=true)
Set whether to enumerate all states instead of using an SMT solver.
Configuration & with_transition_logic(const std::vector< Gate * > &transition_logic)
Set the combinational gates that compute the next state of the FSM.
Configuration & with_timeout(const u32 timeout)
Set the timeout for the underlying SMT solver.
u32 timeout
The timeout for the underlying SMT solver in milliseconds. Defaults to 600000 ms.
std::vector< Gate * > state_register
The flip-flops that make up the state register of the FSM.
Configuration & with_outputs(const std::vector< std::pair< std::string, std::vector< Net * >>> &outputs)
Set the outputs of the FSM that the solver should evaluate in each state.
Configuration & with_state_register(const std::vector< Gate * > &state_register)
Set the flip-flops that make up the state register of the FSM.
Netlist * netlist
The netlist that implements the FSM.
std::vector< std::pair< std::string, std::vector< Net * > > > outputs
The outputs of the FSM, each given as a name and the nets that make up that output.
Configuration & with_initial_state(const std::map< Gate *, bool > &initial_state)
Set the initial value of each flip-flop of the state register.
bool brute_force
Enumerate all states instead of using an SMT solver. Defaults to false.
std::map< Gate *, bool > initial_state
The initial value of each flip-flop of the state register.
std::vector< Gate * > transition_logic
The combinational gates that compute the next state of the FSM.
The state transition graph of an FSM, i.e., the behavior that its netlist implements.
std::vector< std::pair< std::string, std::vector< Net * > > > output_nets
The outputs of the FSM, each given as a name and the nets that make up that output.
std::map< u64, std::map< u64, BooleanFunction > > transitions
A map from each state to its successor states, together with the condition under which the respective...
u32 get_state_size() const
Get the number of flip-flops that make up the state register, i.e., the bit-size of a state.
std::vector< Gate * > state_register
The flip-flops that make up the state register, in the order that determines the encoding of a state.
Netlist * netlist
The netlist that implements the FSM.
std::map< u64, std::vector< std::pair< std::string, BooleanFunction > > > outputs
A map from each state to the value of every output of the FSM in that state.