26 Result<std::vector<std::pair<Net*, BooleanFunction>>>
27 generate_state_bfs(Netlist* nl,
const std::vector<Gate*>& state_reg,
const std::vector<Gate*>& transition_logic,
const bool consider_control_inputs)
29 std::map<Net*, Net*> output_net_to_input_net;
31 for (
const auto& ff : state_reg)
33 const std::vector<GatePin*> d_pins =
ff->get_type()->get_pins([](
const GatePin* pin) {
return pin->get_type() ==
PinType::data; });
34 if (d_pins.size() != 1)
36 return ERR(
"failed to create input - output mapping: currently not supporting flip-flops with multiple or no data inputs, but found " + std::to_string(d_pins.size())
37 +
" for gate type " +
ff->get_type()->get_name() +
".");
41 if (
auto res =
ff->get_fan_in_net(d_pins.front()); res ==
nullptr)
43 return ERR(
"failed to create input - output mapping: could not get fan-in net at pin " + d_pins.front()->get_name() +
" of gate " + std::to_string(
ff->get_id()) +
".");
50 for (
const auto& out_net :
ff->get_fan_out_nets())
52 output_net_to_input_net.insert({out_net, input_net});
56 std::vector<std::pair<Net*, BooleanFunction>> state_bfs;
58 const std::vector<const Gate*> subgraph_gates = {transition_logic.begin(), transition_logic.end()};
59 const auto nl_dec = SubgraphNetlistDecorator(*nl);
61 for (
const auto& ff : state_reg)
63 const std::vector<GatePin*> d_pins =
ff->get_type()->get_pins([](
const GatePin* pin) {
return pin->get_type() ==
PinType::data; });
64 const GatePin* d_pin = d_pins.front();
66 const std::vector<GatePin*> state_pins =
ff->get_type()->get_pins([](
const GatePin* pin) {
return pin->get_type() ==
PinType::state; });
67 const std::vector<GatePin*> neg_state_pins =
ff->get_type()->get_pins([](
const GatePin* pin) {
return pin->get_type() ==
PinType::neg_state; });
69 Net* data_net =
ff->get_fan_in_net(d_pin);
72 if (consider_control_inputs)
74 BooleanFunction complete_bf;
75 std::string internal_state_identifier;
76 std::string internal_negated_state_identifier;
80 const FFComponent* ff_component =
ff->get_type()->get_component_as<FFComponent>([](
const GateTypeComponent* c) {
return FFComponent::is_class_of(c); });
81 const StateComponent* state_componenet =
ff->get_type()->get_component_as<StateComponent>([](
const GateTypeComponent* c) {
return StateComponent::is_class_of(c); });
83 complete_bf = ff_component->get_next_state_function();
84 internal_state_identifier = state_componenet->get_state_identifier();
85 internal_negated_state_identifier = state_componenet->get_neg_state_identifier();
89 return ERR(
"failed to generate boolean functions of state: gate " +
ff->get_name() +
" with ID " + std::to_string(
ff->get_id())
90 +
" of state register has an unhandeled type " +
ff->get_type()->get_name());
93 std::cout << complete_bf << std::endl;
95 for (
const auto& pin_var : complete_bf.get_variable_names())
99 if (pin_var == internal_state_identifier)
101 if (state_pins.size() != 1)
103 return ERR(
"failed to generate boolean functions of state: found " + std::to_string(state_pins.size()) +
" state pins at gate " +
ff->get_name() +
" with ID "
104 + std::to_string(
ff->get_id()) +
", but we expect exactly 1.");
107 complete_bf = complete_bf.substitute(internal_state_identifier, BooleanFunctionNetDecorator(*(
ff->get_fan_out_net(state_pins.front()))).get_boolean_variable_name());
112 if (pin_var == internal_negated_state_identifier)
114 if (neg_state_pins.size() != 1)
116 return ERR(
"failed to generate boolean functions of state: found " + std::to_string(neg_state_pins.size()) +
" neg state pins at gate " +
ff->get_name()
117 +
" with ID " + std::to_string(
ff->get_id()) +
", but we expect exactly 1.");
121 complete_bf.substitute(internal_state_identifier, BooleanFunctionNetDecorator(*(
ff->get_fan_out_net(neg_state_pins.front()))).get_boolean_variable_name());
126 const auto pin_net =
ff->get_fan_in_net(pin_var);
127 BooleanFunction pin_bf;
128 if (
auto res = nl_dec.get_subgraph_function(subgraph_gates, pin_net); res.is_error())
131 "failed to generate boolean functions of state: could not generate subgraph function for state net " + std::to_string(pin_net->get_id()) +
".");
138 if (
auto res = BooleanFunctionDecorator(pin_bf).substitute_power_ground_nets(nl); res.is_error())
141 "failed to generate boolean functions of state: could not substitute power and ground nets in boolean funtion of net "
142 + std::to_string(pin_net->get_id()));
149 if (
auto res = complete_bf.substitute(pin_var, pin_bf); res.is_error())
152 "failed to generate boolean functions of state: could not substitute variable " + pin_var +
" in boolean funtion of net "
153 + std::to_string(pin_net->get_id()));
157 complete_bf = res.get();
161 std::cout << complete_bf << std::endl;
167 if (
auto res = nl_dec.get_subgraph_function(subgraph_gates, data_net); res.is_error())
170 "failed to generate boolean functions of state: could not generate subgraph function for state net " + std::to_string(data_net->get_id()) +
".");
177 if (
auto res = BooleanFunctionDecorator(bf).substitute_power_ground_nets(nl); res.is_error())
180 "failed to generate boolean functions of state: could not substitute power and ground nets in boolean funtion of net "
181 + std::to_string(data_net->get_id()));
191 const auto var_names = bf.get_variable_names();
194 for (
const auto& [out, in] : output_net_to_input_net)
197 if (var_names.find(BooleanFunctionNetDecorator(*out).get_boolean_variable_name()) == var_names.end())
202 auto in_bf = BooleanFunctionNetDecorator(*in).get_boolean_variable();
205 if (out->get_sources().size() != 1)
207 return ERR(
"failed to generate boolean functions of state: found multi driven net " + std::to_string(out->get_id()) +
".");
211 const GatePin* src_pin = out->get_sources().front()->get_pin();
217 auto res = bf.substitute(BooleanFunctionNetDecorator(*out).get_boolean_variable_name(), in_bf);
221 return ERR(
"failed to generate boolean functions of state: unable to replace out net " + std::to_string(out->get_id()) +
" with in net " + std::to_string(in->get_id())
228 state_bfs.push_back({data_net, bf});
231 return OK(state_bfs);
235 Result<std::map<u64, std::map<u64, BooleanFunction>>> generate_conditional_transitions(
const std::vector<std::pair<Net*, BooleanFunction>>& state_bfs,
236 const std::map<
u64, std::set<u64>>& transitions)
239 std::map<u64, std::map<u64, BooleanFunction>> conditional_transitions;
242 for (
const auto& [prev, successors] : transitions)
245 std::map<std::string, BooleanFunction> prev_mapping;
246 for (
u32 i = 0; i < state_bfs.size(); i++)
249 {BooleanFunctionNetDecorator(*(state_bfs.at(i).first)).get_boolean_variable_name(), ((prev >> i) & 1) ?
BooleanFunction::Const(1, 1) : BooleanFunction::Const(0, 1)});
252 for (
const auto& suc : successors)
255 BooleanFunction condition;
257 for (
u32 i = 0; i < state_bfs.size(); i++)
259 auto next_state_bit_bf = ((suc >> i) & 1) ? state_bfs.at(i).second :
BooleanFunction::Not(state_bfs.at(i).second.clone(), 1).get();
261 if (condition.is_empty())
263 condition = next_state_bit_bf;
272 condition = condition.substitute(prev_mapping).get();
275 condition = condition.simplify();
277 conditional_transitions[prev].insert({suc, condition});
281 return OK(conditional_transitions);
285 void open_dot_in_viewer(
const std::filesystem::path& out_path)
290 log_info(
"solve_fsm",
"Cannot find 'dot_viewer' plugin, dot graph not displayed.");
293 GuiExtensionInterface* geif = bpif->get_first_extension<GuiExtensionInterface>();
296 log_info(
"solve_fsm",
"Cannot find dot_viewer GUI interface, dot graph not displayed.");
299 std::vector<PluginParameter> params;
303 geif->set_parameter(params);
304 log_info(
"solve_fsm",
"Request to display graph '{}' send to dot viewer.", out_path.string());
309 Result<std::map<u64, std::map<u64, BooleanFunction>>>
312 const u32 state_size = state_reg.size();
315 return ERR(
"failed to solve fsm: Currently only supports fsm with up to 64 state flip-flops but got " + std::to_string(state_size) +
".");
319 const auto state_bfs_res = generate_state_bfs(nl, state_reg, transition_logic,
true);
320 if (state_bfs_res.is_error())
322 return ERR_APPEND(state_bfs_res.get_error(),
"failed to solve fsm: unable to generate Boolean functions for state.");
324 const std::vector<std::pair<Net*, BooleanFunction>> state_bfs = state_bfs_res.get();
328 for (
u32 i = 1; i < state_reg.size(); i++)
330 next_state_vec =
BooleanFunction::Concat(state_bfs.at(i).second.clone(), std::move(next_state_vec), next_state_vec.
size() + 1).get();
333 std::map<u64, std::set<u64>> all_transitions;
338 std::map<std::string, BooleanFunction> var_to_val;
339 for (
u32 state_index = 0; state_index < state_size; state_index++)
343 var_to_val.insert({var, val});
346 const auto sub_res = next_state_vec.
substitute(var_to_val);
347 if (sub_res.is_error())
349 return ERR_APPEND(sub_res.get_error(),
"failed to solve fsm: unable to substitute variables in next state vec.");
352 const auto state_bf = sub_res.get().simplify();
356 for (
u64 input_val = 0; input_val < (
u64(1) << inputs.size()); input_val++)
359 std::unordered_map<std::string, std::vector<BooleanFunction::Value>> input_mapping;
360 for (
u32 input_index = 0; input_index < inputs.size(); input_index++)
362 std::string input_var = inputs.at(input_index);
363 BooleanFunction::Value val = ((input_val >> input_index) & 0x1) ? BooleanFunction::Value::ONE : BooleanFunction::Value::ZERO;
364 input_mapping.insert({input_var, {val}});
367 const auto& eval_res = state_bf.evaluate(input_mapping);
368 if (sub_res.is_error())
370 return ERR_APPEND(sub_res.get_error(),
"failed to solve fsm: unable to evaluate next state function.");
373 const auto eval = eval_res.get();
375 if (eval.front() == BooleanFunction::Value::X)
377 return ERR(
"failed to solve fsm: evaluating state function resulted in X state.");
381 all_transitions[
state].insert(suc_state);
385 const auto conditional_transitions = generate_conditional_transitions(state_bfs, all_transitions).get();
388 for (
const auto& [org, successors] : conditional_transitions)
390 std::cout << org <<
": " << std::endl;
391 for (
const auto& [suc, condition] : successors)
393 std::cout <<
"\t" << suc <<
": " << condition.to_string() << std::endl;
400 return ERR_APPEND(graph_res.get_error(),
"failed to solve fsm: unable to generate dot graph.");
403 return OK(conditional_transitions);
407 const std::vector<Gate*>& state_reg,
408 const std::vector<Gate*>& transition_logic,
413 const u32 state_size = state_reg.size();
416 return ERR(
"failed to solve fsm: Currently only supports fsm with up to 64 state flip-flops but got " + std::to_string(state_size) +
".");
420 const auto state_bfs_res = generate_state_bfs(nl, state_reg, transition_logic,
true);
421 if (state_bfs_res.is_error())
423 return ERR_APPEND(state_bfs_res.get_error(),
"failed to solve fsm: unable to generate Boolean functions for state.");
425 const std::vector<std::pair<Net*, BooleanFunction>> state_bfs = state_bfs_res.get();
429 for (
u32 i = 1; i < state_reg.size(); i++)
435 next_state_vec =
BooleanFunction::Concat(state_bfs.at(i).second.clone(), std::move(next_state_vec), i + 1).get();
439 u64 initial_state_num = 0;
442 for (
const auto& gate : state_reg)
446 return ERR(
"failed to solve fsm: Unable to find intial value for gate " + std::to_string(gate->get_id()) +
" in the provided initial state map.");
449 initial_state_num = initial_state_num << 1;
455 std::map<u64, std::set<u64>> all_transitions;
458 std::unordered_set<u64> visited;
460 q.push_back(initial_state_num);
464 std::vector<u64> successor_states;
469 if (visited.find(
n) != visited.end())
485 return ERR_APPEND(res.get_error(),
"failed to solve fsm: failed to querry SMT solver for state " + std::to_string(
n) +
".");
489 auto s_res = res.get();
491 if (s_res.is_unsat())
496 if (s_res.is_unknown())
498 return ERR(
"failed to solve fsm: received an unknown solver result for state " + std::to_string(
n) +
".");
501 auto m = s_res.model.value();
502 auto suc = m.evaluate(next_state_vec).get();
506 if (suc.is_constant())
508 suc_num = suc.get_constant_value_u64().get();
514 std::unordered_map<std::string, std::vector<BooleanFunction::Value>> zero_mapping;
515 for (
const auto& var : suc.get_variable_names())
517 zero_mapping.insert({var, {BooleanFunction::Value::ZERO}});
520 if (
auto eval_res = suc.evaluate(zero_mapping); eval_res.is_error())
522 return ERR_APPEND(eval_res.get_error(),
"failed to solve fsm: could not evaluate successor state to constant.");
530 q.push_back(suc_num);
531 all_transitions[
n].insert(suc_num);
537 const auto conditional_transitions = generate_conditional_transitions(state_bfs, all_transitions).get();
540 for (
const auto& [org, successors] : conditional_transitions)
542 std::cout << org <<
": " << std::endl;
543 for (
const auto& [suc, condition] : successors)
545 std::cout <<
"\t" << suc <<
": " << condition.to_string() << std::endl;
552 return ERR_APPEND(graph_res.get_error(),
"failed to solve fsm: unable to generate dot graph.");
555 return OK(conditional_transitions);
560 const std::map<
u64, std::map<u64, BooleanFunction>>& transitions,
562 const u32 max_condition_length,
565 std::string graph_str =
"digraph {\ncomment=\"created by HAL plugin solve_fsm\"\n";
567 for (
const auto& [org, successors] : transitions)
569 for (
const auto& [suc, cond] : successors)
571 std::string start_name;
572 std::string end_name;
577 start_name = std::bitset<64>(org).to_string().substr(64 - state_reg.size(), 64);
578 end_name = std::bitset<64>(suc).to_string().substr(64 - state_reg.size(), 64);
581 start_name = std::to_string(org);
582 end_name = std::to_string(suc);
585 return ERR(
"failed to generate DOT graph: base " + std::to_string(base) +
"not implemented.");
589 start_name +
" -> " + end_name +
"[label=\"" + cond.to_string().substr(0, max_condition_length) +
"\", weight=\"" + cond.to_string().substr(0, max_condition_length) +
"\"];\n";
602 return ERR(
"failed to generate DOT graph: could not open file '" +
graph_path.string() +
"' for writing.");
610 return OK(graph_str);
static Result< BooleanFunction > Eq(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Concat(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
BooleanFunction clone() const
Value
represents the type of the node
static BooleanFunction Const(const BooleanFunction::Value &value)
static Result< u64 > to_u64(const std::vector< BooleanFunction::Value > &value)
static Result< BooleanFunction > Not(BooleanFunction &&p0, u16 size)
static Result< BooleanFunction > And(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
BooleanFunction substitute(const std::string &old_variable_name, const std::string &new_variable_name) const
std::string get_boolean_variable_name() const
BooleanFunction get_boolean_variable() const
static bool is_class_of(const GateTypeComponent *component)
Result< SolverResult > query(const QueryConfig &config=QueryConfig()) const
Solver & with_constraint(const Constraint &constraint)
static bool is_class_of(const GateTypeComponent *component)
#define log_info(channel,...)
#define ERR_APPEND(prev_error, message)
BasePluginInterface * get_plugin_instance(const std::string &plugin_name, bool initialize, bool silent)
Result< std::string > generate_dot_graph(const std::vector< Gate * > &state_reg, const std::map< u64, std::map< u64, BooleanFunction >> &transitions, const std::filesystem::path &graph_path="", const u32 max_condition_length=128, const u32 base=10)
Result< std::map< u64, std::map< u64, BooleanFunction > > > solve_fsm(Netlist *nl, const std::vector< Gate * > &state_reg, const std::vector< Gate * > &transition_logic, const std::map< Gate *, bool > &initial_state={}, const std::filesystem::path &graph_path="", const u32 timeout=600000)
Result< std::map< u64, std::map< u64, BooleanFunction > > > solve_fsm_brute_force(Netlist *nl, const std::vector< Gate * > &state_reg, const std::vector< Gate * > &transition_logic, const std::filesystem::path &graph_path="")
CORE_API std::vector< T > to_vector(const Container< T, Args... > &container)
This file contains functions to generate the state transition graph of a given FSM.
QueryConfig & with_model_generation()
QueryConfig & with_timeout(u64 seconds)