51 Result<std::vector<std::pair<Net*, BooleanFunction>>>
52 generate_state_bfs(Netlist* nl,
const std::vector<Gate*>& state_reg,
const std::vector<Gate*>& transition_logic,
const bool consider_control_inputs)
54 std::map<Net*, Net*> output_net_to_input_net;
56 for (
const auto& ff : state_reg)
58 const std::vector<GatePin*> d_pins =
ff->get_type()->get_pins([](
const GatePin* pin) {
return pin->get_type() ==
PinType::data; });
59 if (d_pins.size() != 1)
61 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())
62 +
" for gate type " +
ff->get_type()->get_name() +
".");
66 if (
auto res =
ff->get_fan_in_net(d_pins.front()); res ==
nullptr)
68 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()) +
".");
75 for (
const auto& out_net :
ff->get_fan_out_nets())
77 output_net_to_input_net.insert({out_net, input_net});
81 std::vector<std::pair<Net*, BooleanFunction>> state_bfs;
83 const std::vector<const Gate*> subgraph_gates = {transition_logic.begin(), transition_logic.end()};
84 const auto nl_dec = SubgraphNetlistDecorator(*nl);
86 for (
const auto& ff : state_reg)
88 const std::vector<GatePin*> d_pins =
ff->get_type()->get_pins([](
const GatePin* pin) {
return pin->get_type() ==
PinType::data; });
89 const GatePin* d_pin = d_pins.front();
91 const std::vector<GatePin*> state_pins =
ff->get_type()->get_pins([](
const GatePin* pin) {
return pin->get_type() ==
PinType::state; });
92 const std::vector<GatePin*> neg_state_pins =
ff->get_type()->get_pins([](
const GatePin* pin) {
return pin->get_type() ==
PinType::neg_state; });
94 Net* data_net =
ff->get_fan_in_net(d_pin);
97 if (consider_control_inputs)
99 BooleanFunction complete_bf;
100 std::string internal_state_identifier;
101 std::string internal_negated_state_identifier;
105 const FFComponent* ff_component =
ff->get_type()->get_component_as<FFComponent>([](
const GateTypeComponent* c) {
return FFComponent::is_class_of(c); });
106 const StateComponent* state_componenet =
ff->get_type()->get_component_as<StateComponent>([](
const GateTypeComponent* c) {
return StateComponent::is_class_of(c); });
108 complete_bf = ff_component->get_next_state_function();
109 internal_state_identifier = state_componenet->get_state_identifier();
110 internal_negated_state_identifier = state_componenet->get_neg_state_identifier();
114 return ERR(
"failed to generate boolean functions of state: gate " +
ff->get_name() +
" with ID " + std::to_string(
ff->get_id())
115 +
" of state register has an unhandeled type " +
ff->get_type()->get_name());
118 for (
const auto& pin_var : complete_bf.get_variable_names())
122 if (pin_var == internal_state_identifier)
124 if (state_pins.size() != 1)
126 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 "
127 + std::to_string(
ff->get_id()) +
", but we expect exactly 1.");
130 complete_bf = complete_bf.substitute(internal_state_identifier, BooleanFunctionNetDecorator(*(
ff->get_fan_out_net(state_pins.front()))).get_boolean_variable_name());
135 if (pin_var == internal_negated_state_identifier)
137 if (neg_state_pins.size() != 1)
139 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()
140 +
" with ID " + std::to_string(
ff->get_id()) +
", but we expect exactly 1.");
144 complete_bf.substitute(internal_state_identifier, BooleanFunctionNetDecorator(*(
ff->get_fan_out_net(neg_state_pins.front()))).get_boolean_variable_name());
149 const auto pin_net =
ff->get_fan_in_net(pin_var);
150 BooleanFunction pin_bf;
151 if (
auto res = nl_dec.get_subgraph_function(subgraph_gates, pin_net); res.is_error())
154 "failed to generate boolean functions of state: could not generate subgraph function for state net " + std::to_string(pin_net->get_id()) +
".");
161 if (
auto res = BooleanFunctionDecorator(pin_bf).substitute_power_ground_nets(nl); res.is_error())
164 "failed to generate boolean functions of state: could not substitute power and ground nets in boolean funtion of net "
165 + std::to_string(pin_net->get_id()));
172 if (
auto res = complete_bf.substitute(pin_var, pin_bf); res.is_error())
175 "failed to generate boolean functions of state: could not substitute variable " + pin_var +
" in boolean funtion of net "
176 + std::to_string(pin_net->get_id()));
180 complete_bf = res.get();
188 if (
auto res = nl_dec.get_subgraph_function(subgraph_gates, data_net); res.is_error())
191 "failed to generate boolean functions of state: could not generate subgraph function for state net " + std::to_string(data_net->get_id()) +
".");
198 if (
auto res = BooleanFunctionDecorator(bf).substitute_power_ground_nets(nl); res.is_error())
201 "failed to generate boolean functions of state: could not substitute power and ground nets in boolean funtion of net "
202 + std::to_string(data_net->get_id()));
212 const auto var_names = bf.get_variable_names();
215 for (
const auto& [out, in] : output_net_to_input_net)
218 if (var_names.find(BooleanFunctionNetDecorator(*out).get_boolean_variable_name()) == var_names.end())
223 auto in_bf = BooleanFunctionNetDecorator(*in).get_boolean_variable();
226 if (out->get_sources().size() != 1)
228 return ERR(
"failed to generate boolean functions of state: found multi driven net " + std::to_string(out->get_id()) +
".");
232 const GatePin* src_pin = out->get_sources().front()->get_pin();
238 auto res = bf.substitute(BooleanFunctionNetDecorator(*out).get_boolean_variable_name(), in_bf);
242 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())
249 state_bfs.push_back({data_net, bf});
252 return OK(state_bfs);
260 Result<std::vector<std::pair<std::string, BooleanFunction>>> generate_output_bfs(Netlist* nl,
const std::vector<std::pair<std::string, std::vector<Net*>>>& outputs)
265 const SubgraphNetlistDecorator
dec(*nl);
267 std::vector<std::pair<std::string, BooleanFunction>> res;
268 for (
const auto& [
name, nets] : outputs)
272 return ERR(
"failed to generate output functions: output '" +
name +
"' does not contain any nets.");
276 for (
u32 i = 0; i < nets.size(); i++)
278 if (nets.at(i) ==
nullptr)
280 return ERR(
"failed to generate output functions: output '" +
name +
"' contains a nullptr net at index " + std::to_string(i) +
".");
283 auto bit_res =
dec.get_subgraph_function(comb_gates, nets.at(i));
284 if (bit_res.is_error())
286 return ERR_APPEND(bit_res.get_error(),
"failed to generate output functions: could not generate function for net " + std::to_string(nets.at(i)->get_id()) +
".");
296 if (concat_res.is_error())
298 return ERR_APPEND(concat_res.get_error(),
"failed to generate output functions: could not concatenate the nets of output '" +
name +
"'.");
300 bf = concat_res.get();
303 res.push_back({
name, std::move(bf)});
313 std::map<std::string, BooleanFunction> generate_state_substitution(
const std::vector<Gate*>& state_reg,
const u64 state)
315 std::map<std::string, BooleanFunction> res;
317 for (
u32 i = 0; i < state_reg.size(); i++)
319 const bool bit = (
state >> i) & 0x1;
320 const Gate*
ff = state_reg.at(i);
321 const auto pins =
ff->get_type()->get_pins([](
const GatePin* p) {
325 for (
const auto* pin :
pins)
327 if (
const Net* n =
ff->get_fan_out_net(pin); n !=
nullptr)
330 res.insert({BooleanFunctionNetDecorator(*n).get_boolean_variable_name(),
BooleanFunction::Const(val ? 1 : 0, 1)});
342 Result<std::vector<std::pair<std::string, BooleanFunction>>>
343 evaluate_outputs_in_state(
const std::vector<std::pair<std::string, BooleanFunction>>& output_bfs,
const std::vector<Gate*>& state_reg,
const u64 state)
345 const auto substitution = generate_state_substitution(state_reg, state);
347 std::vector<std::pair<std::string, BooleanFunction>> res;
348 for (
const auto& [
name, bf] : output_bfs)
350 auto sub_res = bf.substitute(substitution);
351 if (sub_res.is_error())
353 return ERR_APPEND(sub_res.get_error(),
"failed to evaluate outputs: could not substitute the state register in output '" +
name +
"'.");
356 res.push_back({
name, sub_res.get().simplify()});
362 Result<std::map<u64, std::map<u64, BooleanFunction>>> generate_conditional_transitions(
const std::vector<std::pair<Net*, BooleanFunction>>& state_bfs,
363 const std::map<
u64, std::set<u64>>& transitions)
366 std::map<u64, std::map<u64, BooleanFunction>> conditional_transitions;
369 for (
const auto& [prev, successors] : transitions)
372 std::map<std::string, BooleanFunction> prev_mapping;
373 for (
u32 i = 0; i < state_bfs.size(); i++)
376 {BooleanFunctionNetDecorator(*(state_bfs.at(i).first)).get_boolean_variable_name(), ((prev >> i) & 1) ?
BooleanFunction::Const(1, 1) : BooleanFunction::Const(0, 1)});
379 for (
const auto& suc : successors)
382 BooleanFunction condition;
384 for (
u32 i = 0; i < state_bfs.size(); i++)
386 auto next_state_bit_bf = ((suc >> i) & 1) ? state_bfs.at(i).second :
BooleanFunction::Not(state_bfs.at(i).second.clone(), 1).get();
388 if (condition.is_empty())
390 condition = next_state_bit_bf;
399 condition = condition.substitute(prev_mapping).get();
402 condition = condition.simplify();
404 conditional_transitions[prev].insert({suc, condition});
408 return OK(conditional_transitions);
416 Result<std::map<u64, std::set<u64>>> generate_transitions_brute_force(
const std::vector<std::pair<Net*, BooleanFunction>>& state_bfs,
const u32 state_size)
419 BooleanFunction next_state_vec = state_bfs.front().second;
420 for (
u32 i = 1; i < state_size; i++)
422 next_state_vec =
BooleanFunction::Concat(state_bfs.at(i).second.clone(), std::move(next_state_vec), next_state_vec.size() + 1).get();
425 std::map<u64, std::set<u64>> all_transitions;
430 std::map<std::string, BooleanFunction> var_to_val;
431 for (
u32 state_index = 0; state_index < state_size; state_index++)
433 std::string var = BooleanFunctionNetDecorator(*(state_bfs.at(state_index).first)).get_boolean_variable_name();
435 var_to_val.insert({var, val});
438 const auto sub_res = next_state_vec.substitute(var_to_val);
439 if (sub_res.is_error())
441 return ERR_APPEND(sub_res.get_error(),
"failed to solve fsm: unable to substitute variables in next state vec.");
444 const auto state_bf = sub_res.get().simplify();
448 for (
u64 input_val = 0; input_val < (
u64(1) << inputs.size()); input_val++)
451 std::unordered_map<std::string, std::vector<BooleanFunction::Value>> input_mapping;
452 for (
u32 input_index = 0; input_index < inputs.size(); input_index++)
454 std::string input_var = inputs.at(input_index);
455 BooleanFunction::Value val = ((input_val >> input_index) & 0x1) ? BooleanFunction::Value::ONE : BooleanFunction::Value::ZERO;
456 input_mapping.insert({input_var, {val}});
459 const auto& eval_res = state_bf.evaluate(input_mapping);
460 if (sub_res.is_error())
462 return ERR_APPEND(sub_res.get_error(),
"failed to solve fsm: unable to evaluate next state function.");
465 const auto eval = eval_res.get();
467 if (eval.front() == BooleanFunction::Value::X)
469 return ERR(
"failed to solve fsm: evaluating state function resulted in X state.");
473 all_transitions[
state].insert(suc_state);
477 return OK(all_transitions);
484 Result<std::map<u64, std::set<u64>>>
485 generate_transitions_smt(
const std::vector<std::pair<Net*, BooleanFunction>>& state_bfs,
const u32 state_size,
const u64 initial_state_num,
const u32 timeout)
487 BooleanFunction prev_state_vec = BooleanFunctionNetDecorator(*(state_bfs.front().first)).get_boolean_variable();
488 BooleanFunction next_state_vec = state_bfs.front().second;
489 for (
u32 i = 1; i < state_size; i++)
492 prev_state_vec =
BooleanFunction::Concat(BooleanFunctionNetDecorator(*(state_bfs.at(i).first)).get_boolean_variable(), std::move(prev_state_vec), i + 1).get();
495 next_state_vec =
BooleanFunction::Concat(state_bfs.at(i).second.clone(), std::move(next_state_vec), i + 1).get();
498 std::map<u64, std::set<u64>> all_transitions;
501 std::unordered_set<u64> visited;
503 q.push_back(initial_state_num);
507 std::vector<u64> successor_states;
512 if (visited.find(n) != visited.end())
526 if (
auto res = s.query(SMT::QueryConfig().with_model_generation().with_timeout(timeout)); res.is_error())
528 return ERR_APPEND(res.get_error(),
"failed to solve fsm: failed to querry SMT solver for state " + std::to_string(n) +
".");
532 auto s_res = res.get();
534 if (s_res.is_unsat())
539 if (s_res.is_unknown())
541 return ERR(
"failed to solve fsm: received an unknown solver result for state " + std::to_string(n) +
".");
544 auto m = s_res.model.value();
545 auto suc = m.evaluate(next_state_vec).get();
549 if (suc.is_constant())
551 suc_num = suc.get_constant_value_u64().get();
557 std::unordered_map<std::string, std::vector<BooleanFunction::Value>> zero_mapping;
558 for (
const auto& var : suc.get_variable_names())
560 zero_mapping.insert({var, {BooleanFunction::Value::ZERO}});
563 if (
auto eval_res = suc.evaluate(zero_mapping); eval_res.is_error())
565 return ERR_APPEND(eval_res.get_error(),
"failed to solve fsm: could not evaluate successor state to constant.");
573 q.push_back(suc_num);
574 all_transitions[n].insert(suc_num);
580 return OK(all_transitions);
587 std::map<u64, std::set<u64>> restrict_to_reachable(
const std::map<
u64, std::set<u64>>& all_transitions,
const u64 initial_state_num)
589 std::map<u64, std::set<u64>> res;
591 std::deque<u64> q = {initial_state_num};
592 std::unordered_set<u64> visited;
599 if (!visited.insert(state).second)
604 const auto it = all_transitions.find(state);
605 if (it == all_transitions.end())
610 res[
state] = it->second;
611 for (
const u64 successor : it->second)
613 q.push_back(successor);
626 return ERR(
"failed to solve FSM: netlist is a nullptr.");
631 return ERR(
"failed to solve FSM: no state register configured.");
636 return ERR(
"failed to solve FSM: no transition logic configured.");
642 return ERR(
"failed to solve FSM: only up to 64 state flip-flops are supported, but got " + std::to_string(state_size) +
".");
647 if (state_bfs_res.is_error())
649 return ERR_APPEND(state_bfs_res.get_error(),
"failed to solve FSM: unable to generate the Boolean functions of the state.");
651 const std::vector<std::pair<Net*, BooleanFunction>> state_bfs = state_bfs_res.get();
654 u64 initial_state_num = 0;
655 for (
u32 i = 0; i < state_size; i++)
665 return ERR(
"failed to solve FSM: unable to find an initial value for gate '" + gate->
get_name() +
"' with ID " + std::to_string(gate->
get_id())
666 +
" in the provided initial state.");
672 std::map<u64, std::set<u64>> all_transitions;
675 auto transitions_res = generate_transitions_brute_force(state_bfs, state_size);
676 if (transitions_res.is_error())
678 return ERR_APPEND(transitions_res.get_error(),
"failed to solve FSM: unable to determine the transitions by brute force.");
683 all_transitions = restrict_to_reachable(transitions_res.get(), initial_state_num);
687 auto transitions_res = generate_transitions_smt(state_bfs, state_size, initial_state_num, config.
timeout);
688 if (transitions_res.is_error())
690 return ERR_APPEND(transitions_res.get_error(),
"failed to solve FSM: unable to determine the transitions using the SMT solver.");
693 all_transitions = transitions_res.get();
701 auto conditional_res = generate_conditional_transitions(state_bfs, all_transitions);
702 if (conditional_res.is_error())
704 return ERR_APPEND(conditional_res.get_error(),
"failed to solve FSM: unable to determine the conditions of the transitions.");
710 const auto output_bfs_res = generate_output_bfs(config.
netlist, config.
outputs);
711 if (output_bfs_res.is_error())
713 return ERR_APPEND(output_bfs_res.get_error(),
"failed to solve FSM: unable to generate the Boolean functions of the outputs.");
715 const auto output_bfs = output_bfs_res.get();
717 for (
const auto& [
state, _] : all_transitions)
719 auto state_outputs_res = evaluate_outputs_in_state(output_bfs, config.
state_register,
state);
720 if (state_outputs_res.is_error())
722 return ERR_APPEND(state_outputs_res.get_error(),
"failed to solve FSM: unable to evaluate the outputs in state " + std::to_string(
state) +
".");
static Result< BooleanFunction > Eq(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Concat(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
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)
static bool is_class_of(const GateTypeComponent *component)
const std::string & get_name() const
static bool is_class_of(const GateTypeComponent *component)
#define ERR_APPEND(prev_error, message)
Result< StateTransitionGraph > solve_fsm(const Configuration &config)
Recover the state transition graph of an FSM from the netlist that implements it.
std::vector< T > to_vector(const Container< T, Args... > &container)
std::vector< PinInformation > pins
QTextStream & dec(QTextStream &stream)
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.
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.
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.
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...
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.