17 namespace module_identification
31 std::vector<std::unique_ptr<BaseCandidate>> find_carry_chains(
const Netlist* nl)
33 std::vector<std::vector<Gate*>> carry_chains;
36 std::vector<Gate*> carry_gates = nl->get_gates([](
const Gate* g) {
return g->get_type()->has_property(
GateTypeProperty::c_carry); });
37 std::set<Gate*> carry_gates_set = std::set<Gate*>(carry_gates.begin(), carry_gates.end());
40 while (!carry_gates_set.empty())
42 Gate* current_gate = *carry_gates_set.begin();
43 const GateType* carry_type = current_gate->get_type();
47 if (chain_res.is_error())
49 return std::vector<std::unique_ptr<BaseCandidate>>();
51 std::vector<Gate*> carry_chain = chain_res.get();
54 for (Gate* g : carry_chain)
56 carry_gates_set.erase(g);
60 if (carry_chain.size() >= 2)
62 carry_chains.push_back(carry_chain);
67 std::vector<std::vector<Gate*>> filtered_carry_chains;
68 for (
u32 i = 0; i < carry_chains.size(); i++)
70 auto& c_test = carry_chains.at(i);
71 std::set<Gate*> test_set = {c_test.begin(), c_test.end()};
74 for (
u32 j = 0; j < carry_chains.size(); j++)
81 auto& c_other = carry_chains.at(j);
82 std::set<Gate*> other_set = {c_other.begin(), c_other.end()};
84 if (std::includes(other_set.begin(), other_set.end(), test_set.begin(), test_set.end()))
93 filtered_carry_chains.push_back(c_test);
97 std::vector<std::unique_ptr<BaseCandidate>> base_candidates;
98 for (
const auto& carry_chain : filtered_carry_chains)
100 std::unique_ptr<BaseCandidate> base_candidate = std::make_unique<BaseCandidate>(carry_chain);
101 base_candidates.emplace_back(std::move(base_candidate));
104 return base_candidates;
116 std::vector<std::vector<Gate*>> generate_carry_chain_variants(
const BaseCandidate* base_candidate,
const std::vector<std::vector<Gate*>>& all_base_candidates_gates)
118 std::set<u32> possible_starting_points = {0};
119 for (
u32 idx = 1; idx < base_candidate->m_gates.size(); idx++)
122 if (idx < (base_candidate->m_gates.size() - 1))
124 const auto& g = base_candidate->m_gates.at(idx);
125 const auto& constant_inputs = g->get_fan_in_nets([](
const auto& n) {
return n->is_gnd_net() || n->is_vcc_net(); });
127 const auto& g_next = base_candidate->m_gates.at(idx + 1);
128 const auto& constant_inputs_next = g_next->get_fan_in_nets([](
const auto& n) {
return n->is_gnd_net() || n->is_vcc_net(); });
130 if (!constant_inputs.empty() && constant_inputs_next.empty())
132 possible_starting_points.insert(idx);
133 possible_starting_points.insert(idx + 1);
138 if (idx < (base_candidate->m_gates.size() - 1))
140 const auto& g_curr = base_candidate->m_gates.at(idx);
142 bool is_part_of_multiple_base_candidates =
false;
143 for (
const auto& bc_gates : all_base_candidates_gates)
145 if (bc_gates == base_candidate->m_gates)
150 if (std::find(bc_gates.begin(), bc_gates.end(), g_curr) != bc_gates.end())
152 is_part_of_multiple_base_candidates =
true;
157 if (is_part_of_multiple_base_candidates)
159 possible_starting_points.insert(idx + 1);
164 const auto& g_prev = base_candidate->m_gates.at(idx - 1);
165 const auto& g_curr = base_candidate->m_gates.at(idx);
167 bool prev_has_outside_succ = !g_prev
168 ->get_successors([&](
const auto _gp,
auto ep) {
170 return std::find(base_candidate->m_gates.begin(), base_candidate->m_gates.end(), ep->get_gate()) == base_candidate->m_gates.end();
173 bool curr_has_outside_succ = !g_curr
174 ->get_successors([&](
const auto _gp,
auto ep) {
176 return std::find(base_candidate->m_gates.begin(), base_candidate->m_gates.end(), ep->get_gate()) == base_candidate->m_gates.end();
180 if (curr_has_outside_succ && !prev_has_outside_succ)
182 possible_starting_points.insert(idx);
187 if (possible_starting_points.size() > 4)
189 return {base_candidate->m_gates};
192 std::vector<std::vector<Gate*>> carry_chain_variants;
193 for (
const auto& idx : possible_starting_points)
195 carry_chain_variants.push_back({base_candidate->m_gates.begin() + idx, base_candidate->m_gates.end()});
198 return carry_chain_variants;
212 std::vector<std::unique_ptr<StructuralCandidate>> build_structural_candidates(BaseCandidate* base_candidate,
const std::vector<Gate*>& carry_chain)
214 std::vector<std::unique_ptr<StructuralCandidate>> candidates;
218 std::set<Gate*> all_comb_gates = {};
219 for (
const auto& g : carry_chain)
225 all_comb_gates.insert(g);
226 all_comb_gates.insert(next_gates.begin(), next_gates.end());
229 std::unique_ptr<StructuralCandidate> all_comb_candidate = std::make_unique<StructuralCandidate>(base_candidate,
utils::to_vector(all_comb_gates));
230 if (all_comb_gates.size() <= (base_candidate->m_gates.size() * 16))
232 candidates.emplace_back(std::move(all_comb_candidate));
239 std::vector<Gate*> starting_gates = carry_chain;
240 std::set<Gate*> successor_gates;
241 for (
const auto& sg : starting_gates)
243 for (
const auto& ep : sg->get_successors())
247 successor_gates.insert(ep->get_gate());
252 starting_gates.insert(starting_gates.end(), successor_gates.begin(), successor_gates.end());
253 std::set<Gate*> all_comb_gates = {};
254 for (
const auto& g : starting_gates)
260 all_comb_gates.insert(g);
261 all_comb_gates.insert(next_gates.begin(), next_gates.end());
265 std::unique_ptr<StructuralCandidate> all_comb_candidate_ext = std::make_unique<StructuralCandidate>(base_candidate,
utils::to_vector(all_comb_gates));
266 if (all_comb_gates.size() <= (base_candidate->m_gates.size() * 8))
268 candidates.emplace_back(std::move(all_comb_candidate_ext));
272 Gate* first_carry = carry_chain.front();
273 Gate* last_carry = carry_chain.back();
275 std::vector<std::vector<Gate*>> candidate_gate_variants = {carry_chain};
276 std::vector<std::vector<Gate*>> candidate_gate_variants_without_last_gate = {carry_chain};
283 log_info(
"module_identification",
"\tcarry_chain: {}", first_carry->get_name());
287 for (
const auto& gate : carry_chain)
289 std::vector<std::vector<Gate*>> new_candidate_gate_variants;
290 std::vector<std::vector<Gate*>> new_candidate_gate_variants_without_last_gate;
292 if ((gate != last_carry) && (gate->get_successors().size() > 4))
297 for (
const auto& suc_endp : gate->get_successors())
299 auto suc_gate = suc_endp->get_gate();
303 log_error(
"module_identification",
"\tfound IO gate, but why?");
312 for (
const auto& cgv : candidate_gate_variants)
314 if (std::find(cgv.begin(), cgv.end(), suc_gate) != cgv.end())
320 new_cgv.push_back(suc_gate);
322 new_candidate_gate_variants.push_back(new_cgv);
325 if (new_candidate_gate_variants.size() > 4)
330 if (gate != last_carry)
332 new_candidate_gate_variants_without_last_gate = new_candidate_gate_variants;
336 new_candidate_gate_variants_without_last_gate = candidate_gate_variants_without_last_gate;
341 if (!new_candidate_gate_variants.empty())
343 candidate_gate_variants = new_candidate_gate_variants;
344 candidate_gate_variants_without_last_gate = new_candidate_gate_variants_without_last_gate;
348 for (
const auto& cgv : candidate_gate_variants)
350 std::set<Gate*> unique_gates = {cgv.begin(), cgv.end()};
351 std::vector<Gate*> cgv_filtered = {unique_gates.begin(), unique_gates.end()};
353 candidates.push_back(std::make_unique<StructuralCandidate>(base_candidate, cgv_filtered));
356 for (
const auto& cgv : candidate_gate_variants_without_last_gate)
358 std::set<Gate*> unique_gates = {cgv.begin(), cgv.end()};
359 std::vector<Gate*> cgv_filtered = {unique_gates.begin(), unique_gates.end()};
361 candidates.push_back(std::make_unique<StructuralCandidate>(base_candidate, cgv_filtered));
365 auto input_nets_first_gate = first_carry->get_fan_in_nets([](Net*
net) {
return !(
net->is_gnd_net() ||
net->is_vcc_net()); });
367 std::vector<Gate*> total_successor_gates;
368 std::vector<Gate*> total_reduced_successor_gates;
369 std::vector<Gate*> total_more_reduced_successor_gates;
371 for (
const auto input_net : input_nets_first_gate)
373 auto successor_enpoints = input_net->get_destinations();
374 for (
const auto& ep : successor_enpoints)
376 auto gate = ep->get_gate();
402 total_successor_gates.push_back(gate);
404 const auto gt = gate->get_type();
408 bool is_not_four_input = gate->get_fan_in_nets([](Net*
net) {
return !(
net->is_gnd_net() ||
net->is_vcc_net()); }).
size() < 4;
410 bool to_be_considered = is_not_four_input;
412 if (!to_be_considered)
417 total_reduced_successor_gates.push_back(gate);
420 bool is_not_three_input = gate->get_fan_in_nets([](Net*
net) {
return !(
net->is_gnd_net() ||
net->is_vcc_net()); }).
size() < 3;
422 bool to_be_more_considered = is_not_three_input && is_not_ao;
424 if (!to_be_more_considered)
429 total_more_reduced_successor_gates.push_back(gate);
433 std::set<std::vector<Gate*>> possible_first_gates;
435 const auto considered_gates =
436 ((total_successor_gates.size() > 16) ? ((total_reduced_successor_gates.size() > 16) ? total_more_reduced_successor_gates : total_reduced_successor_gates) : total_successor_gates);
438 for (
const auto& gate : considered_gates)
440 auto nets = gate->get_fan_in_nets([](Net*
net) {
return !(
net->is_gnd_net() ||
net->is_vcc_net()); });
441 bool consider_gate =
true;
442 for (
auto const& mandatory_input_net : input_nets_first_gate)
444 if (std::find(nets.begin(), nets.end(), mandatory_input_net) == nets.end())
446 consider_gate =
false;
455 possible_first_gates.insert({gate});
458 auto pres_first_gate = gate->get_predecessors();
459 std::vector<Gate*> new_inv_first_gates;
460 for (
const auto& pre_first_gate : pres_first_gate)
464 new_inv_first_gates.emplace_back(pre_first_gate->get_gate());
468 for (
const auto& inv_gate : new_inv_first_gates)
470 possible_first_gates.insert({gate, inv_gate});
474 for (
const auto& gate2 : total_reduced_successor_gates)
481 possible_first_gates.insert({gate, gate2});
488 std::vector<Gate*> first_carry_inverters;
489 for (
const auto& pre_first_carry : first_carry->get_predecessors())
493 first_carry_inverters.emplace_back(pre_first_carry->get_gate());
497 if (possible_first_gates.empty())
499 for (
const auto& gate : considered_gates)
501 possible_first_gates.insert({gate});
503 for (
const auto& inv_gate : first_carry_inverters)
505 possible_first_gates.insert({gate, inv_gate});
509 auto successors = gate->get_successors();
510 if (successors.size() != 1)
514 auto suc_gate = successors.front()->get_gate();
521 possible_first_gates.insert({gate, suc_gate});
526 std::vector<std::vector<Gate*>> new_candidate_gate_variants;
527 for (
const auto& c : candidates)
529 for (
const auto& add_gates : possible_first_gates)
531 auto new_gates = c->m_gates;
532 new_gates.insert(new_gates.end(), add_gates.begin(), add_gates.end());
533 new_candidate_gate_variants.push_back(new_gates);
537 for (
auto& new_cgv : new_candidate_gate_variants)
539 candidates.push_back(std::make_unique<StructuralCandidate>(base_candidate, new_cgv));
542 std::vector<std::unique_ptr<StructuralCandidate>> new_inverter_candidates;
545 for (
const auto& candidate : candidates)
547 u32 inverter_counter = 0;
548 u32 carry_counter = 0;
549 std::unique_ptr<StructuralCandidate> new_candidate = std::make_unique<StructuralCandidate>(base_candidate, candidate->m_gates);
550 for (
const auto& gate : candidate->m_gates)
554 auto suc_endpoints = gate->get_successors();
555 std::vector<Gate*> inverter_successors;
556 for (
const auto& suc_endpoint : suc_endpoints)
558 auto suc_gate = suc_endpoint->get_gate();
561 inverter_successors.push_back(suc_gate);
565 if (inverter_successors.size() > 2)
570 for (
const auto& is : inverter_successors)
573 new_candidate->m_gates.push_back(is);
581 if (inverter_counter >= carry_counter - 1)
583 new_inverter_candidates.emplace_back(std::move(new_candidate));
587 for (
auto& ic : new_inverter_candidates)
589 candidates.push_back(std::move(ic));
593 std::vector<std::unique_ptr<StructuralCandidate>> new_candidates;
597 for (
const auto& candidate : candidates)
599 Gate* last_gate = candidate->m_gates.back();
601 for (
const auto& pred_endp : last_gate->get_predecessors())
603 Gate* pred_gate = pred_endp->get_gate();
609 std::unique_ptr<StructuralCandidate> new_candidate = std::make_unique<StructuralCandidate>(base_candidate, candidate->m_gates);
610 new_candidate->m_gates.emplace_back(pred_gate);
611 new_candidates.emplace_back(std::move(new_candidate));
614 for (
auto& nc : new_candidates)
616 candidates.push_back(std::move(nc));
622 for (
auto& cand : candidates)
624 if (!std::any_of(cand->m_gates.begin(), cand->m_gates.end(), [](
const auto& g) { return g->is_gnd_gate() || g->is_vcc_gate(); }))
630 cand->m_gates.erase(std::remove_if(cand->m_gates.begin(),
633 return g->is_gnd_gate() || g->is_vcc_gate();
635 cand->m_gates.end());
640 std::set<std::set<Gate*>> all_sets;
641 u32 old_size = candidates.size();
642 std::vector<std::unique_ptr<StructuralCandidate>> candidates_to_return;
644 for (
auto& cand : candidates)
646 std::set<Gate*> set_gates = {cand->m_gates.begin(), cand->m_gates.end()};
647 if (all_sets.find(set_gates) == all_sets.end())
649 all_sets.insert(set_gates);
650 candidates_to_return.push_back(std::make_unique<StructuralCandidate>(base_candidate, std::vector<Gate*>{set_gates.begin(), set_gates.end()}));
654 log_info(
"module_identification",
"\tremaining {}/{} after double candidate removal", candidates_to_return.size(), old_size);
655 return candidates_to_return;
661 std::vector<std::pair<std::unique_ptr<BaseCandidate>, std::vector<std::unique_ptr<StructuralCandidate>>>> base_to_structural_candidates;
663 auto base_candidates = find_carry_chains(nl);
665 std::vector<std::vector<Gate*>> all_base_candidates_gates;
666 for (
const auto& bc : base_candidates)
668 all_base_candidates_gates.push_back(bc->m_gates);
671 log_info(
"module_identification",
"found {} carry chains, building structural variants now...", base_candidates.size());
673 for (
auto& base_candidate : base_candidates)
675 const auto& carry_chain_variants = generate_carry_chain_variants(base_candidate.get(), all_base_candidates_gates);
677 std::vector<std::unique_ptr<StructuralCandidate>> structural_candidates;
678 for (
const auto& ccv : carry_chain_variants)
680 auto new_candidates = build_structural_candidates(base_candidate.get(), ccv);
681 for (
auto& nc : new_candidates)
683 structural_candidates.push_back(std::move(nc));
687 base_to_structural_candidates.push_back({std::move(base_candidate), std::move(structural_candidates)});
690 return base_to_structural_candidates;
This file contains the definition of the BaseCandidate class, which represents a base candidate in th...
#define log_error(channel,...)
#define log_info(channel,...)
This file contains the function to generate structural candidates for Lattice iCE40 FPGAs.
std::vector< std::pair< std::unique_ptr< BaseCandidate >, std::vector< std::unique_ptr< StructuralCandidate > > > > generate_structural_candidates(const Netlist *nl)
Generate structural candidates for a given netlist.
@ lattice_ice40
Lattice iCE40 FPGA architecture.
Result< std::vector< Gate * > > get_gate_chain(Gate *start_gate, const std::vector< const GatePin * > &input_pins={}, const std::vector< const GatePin * > &output_pins={}, const std::function< bool(const Gate *)> &filter=nullptr)
std::vector< Gate * > get_next_gates(const Gate *gate, bool get_successors, int depth=0, const std::function< bool(const Gate *)> &filter=nullptr)
bool is_subset(const T1 &subset, const T2 &superset)
std::vector< T > to_vector(const Container< T, Args... > &container)
This file contains the class for defining and managing structural candidates within the module identi...