From d9faee015393ff4f9b0bbda0d5cfaf6c0ee997c5 Mon Sep 17 00:00:00 2001 From: nella Date: Tue, 12 May 2026 14:47:49 +0200 Subject: [PATCH] Accumulate connect cells. --- passes/hierarchy/hierarchy.cc | 6 +- passes/hierarchy/util/interfaces.cc | 8 +- passes/hierarchy/util/interfaces.h | 19 +++- passes/hierarchy/util/ports.cc | 138 +++++++++++++++------------- passes/hierarchy/util/ports.h | 3 +- 5 files changed, 99 insertions(+), 75 deletions(-) diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index c0ec287d9..5109c1d62 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -240,11 +240,11 @@ struct HierarchyPass : public Pass { if ((flag_simcheck || flag_smtcheck) && top_mod == nullptr) log_error("Design has no top module.\n"); - expand_all_interfaces(design, top_mod, flag_check, flag_simcheck, flag_smtcheck, libdirs); + Hierarchy::ConnectAccumulator connect_acc; + expand_all_interfaces(design, top_mod, flag_check, flag_simcheck, flag_smtcheck, libdirs, &connect_acc); log_header(design, "Resolving $connect directionality..\n"); - for (auto module : design->modules()) - resolve_connect_directionality(module); + Hierarchy::resolve_acc_connects(design, connect_acc); if (top_mod != NULL) { log_header(design, "Analyzing design hierarchy..\n"); diff --git a/passes/hierarchy/util/interfaces.cc b/passes/hierarchy/util/interfaces.cc index ae73a2f94..2b65f898e 100644 --- a/passes/hierarchy/util/interfaces.cc +++ b/passes/hierarchy/util/interfaces.cc @@ -172,14 +172,14 @@ void delete_marked_modules(Design* design) { } } -void expand_all_interfaces(Design* design, Module*& top_mod, bool flag_check, bool flag_simcheck, bool flag_smtcheck, const std::vector &libdirs) { +void expand_all_interfaces(Design* design, Module*& top_mod, bool flag_check, bool flag_simcheck, bool flag_smtcheck, const std::vector &libdirs, ConnectAccumulator* connect_acc) { bool did_something = true; while (did_something) { did_something = false; for (auto module : used_modules(design, top_mod)) { - if (expand_module(design, module, flag_check, flag_simcheck, flag_smtcheck, libdirs)) + if (expand_module(design, module, flag_check, flag_simcheck, flag_smtcheck, libdirs, connect_acc)) did_something = true; } @@ -246,7 +246,7 @@ struct CellArrays { } }; -bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check, bool flag_simcheck, bool flag_smtcheck, const std::vector &libdirs) +bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check, bool flag_simcheck, bool flag_smtcheck, const std::vector &libdirs, ConnectAccumulator* connect_acc) { bool did_something = false; CellArrays cell_arrays; @@ -264,6 +264,8 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check } IFModExpander if_mod_expander(*design, *module); for (auto cell : module->cells()) { + if (connect_acc) + connect_acc->collect(module, cell); if (auto unarrayed_type = cell_arrays.trim_and_register(cell)) cell->type = *unarrayed_type; diff --git a/passes/hierarchy/util/interfaces.h b/passes/hierarchy/util/interfaces.h index 138d25daf..558d4a68d 100644 --- a/passes/hierarchy/util/interfaces.h +++ b/passes/hierarchy/util/interfaces.h @@ -26,8 +26,23 @@ YOSYS_NAMESPACE_BEGIN namespace Hierarchy { -void expand_all_interfaces(Design* design, Module*& top_mod, bool flag_check, bool flag_simcheck, bool flag_smtcheck, const std::vector &libdirs); -bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check, bool flag_simcheck, bool flag_smtcheck, const std::vector &libdirs); +struct ConnectAccumulator { + dict> module_connect_cells; + + // Collect a $connect cell during hierarchy traversal + void collect(Module* module, Cell* cell) { + if (cell->type == ID($connect) && !cell->has_keep_attr()) { + SigSpec sig_a = cell->getPort(ID::A); + SigSpec sig_b = cell->getPort(ID::B); + if (sig_a.size() > 0 && sig_b.size() > 0) { + module_connect_cells[module->name].insert(cell->name); + } + } + } +}; + +void expand_all_interfaces(Design* design, Module*& top_mod, bool flag_check, bool flag_simcheck, bool flag_smtcheck, const std::vector &libdirs, ConnectAccumulator* connect_acc); +bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check, bool flag_simcheck, bool flag_smtcheck, const std::vector &libdirs, ConnectAccumulator* connect_acc); // For expanding a module's interface connections struct IFModExpander diff --git a/passes/hierarchy/util/ports.cc b/passes/hierarchy/util/ports.cc index 69d8bf309..40c49cd75 100644 --- a/passes/hierarchy/util/ports.cc +++ b/passes/hierarchy/util/ports.cc @@ -20,6 +20,7 @@ #include "kernel/yosys_common.h" #include "passes/hierarchy/util/ports.h" +#include "passes/hierarchy/util/interfaces.h" #include "kernel/sigtools.h" YOSYS_NAMESPACE_BEGIN @@ -190,87 +191,92 @@ namespace Hierarchy { } } - bool resolve_connect_directionality(Module* module) { - bool did_something = false; - int iteration = 0; + void resolve_acc_connects(Design* design, const ConnectAccumulator& connect_acc) { + std::vector sorted_module_names; + for (const auto& [mod_name, cell_names] : connect_acc.module_connect_cells) + sorted_module_names.push_back(mod_name); + std::sort(sorted_module_names.begin(), sorted_module_names.end()); - while (true) { - iteration++; - pool cells_to_remove; - vector new_connections; - SigMap sigmap(module); - SigPool driven_signals; + for (auto mod_name : sorted_module_names) { + Module* module = design->module(mod_name); + if (!module) + continue; - build_driven_signals_index(module, sigmap, driven_signals); + const pool& cell_names = connect_acc.module_connect_cells.at(mod_name); + pool remaining_cell_names = cell_names; + int iteration = 0; - for (auto cell : module->cells()) - { - if (cell->type != ID($connect)) - continue; + while (true) { + iteration++; + pool cells_to_remove; + vector new_connections; + SigMap sigmap(module); + SigPool driven_signals; - if (cell->has_keep_attr()) - continue; + build_driven_signals_index(module, sigmap, driven_signals); - SigSpec sig_a = cell->getPort(ID::A); - SigSpec sig_b = cell->getPort(ID::B); + for (auto cell_name : remaining_cell_names) { + Cell* cell = module->cell(cell_name); + if (!cell || cell->type != ID($connect) || cell->has_keep_attr()) + continue; - if (sig_a.size() == 0 || sig_b.size() == 0) - continue; + SigSpec sig_a = cell->getPort(ID::A); + SigSpec sig_b = cell->getPort(ID::B); - SigDirection dir_a = get_signal_direction(sig_a, sigmap, driven_signals); - SigDirection dir_b = get_signal_direction(sig_b, sigmap, driven_signals); + if (sig_a.size() == 0 || sig_b.size() == 0) + continue; - if (dir_a == SigDirection::CONFLICT || dir_b == SigDirection::CONFLICT) - continue; + SigDirection dir_a = get_signal_direction(sig_a, sigmap, driven_signals); + SigDirection dir_b = get_signal_direction(sig_b, sigmap, driven_signals); - SigSpec driver, driven; - bool can_resolve = false; + if (dir_a == SigDirection::CONFLICT || dir_b == SigDirection::CONFLICT) + continue; - if ((dir_a == SigDirection::OUTPUT || dir_a == SigDirection::DRIVEN) && dir_b == SigDirection::INPUT) { - driver = sig_a; - driven = sig_b; - can_resolve = true; - } - else if (dir_a == SigDirection::INPUT && (dir_b == SigDirection::OUTPUT || dir_b == SigDirection::DRIVEN)) { - driver = sig_b; - driven = sig_a; - can_resolve = true; - } - else if (dir_a == SigDirection::DRIVEN && dir_b == SigDirection::UNKNOWN) { - driver = sig_a; - driven = sig_b; - can_resolve = true; - } - else if (dir_a == SigDirection::UNKNOWN && dir_b == SigDirection::DRIVEN) { - driver = sig_b; - driven = sig_a; - can_resolve = true; - } - else { - continue; + SigSpec driver, driven; + bool can_resolve = false; + + if ((dir_a == SigDirection::OUTPUT || dir_a == SigDirection::DRIVEN) && dir_b == SigDirection::INPUT) { + driver = sig_a; + driven = sig_b; + can_resolve = true; + } + else if (dir_a == SigDirection::INPUT && (dir_b == SigDirection::OUTPUT || dir_b == SigDirection::DRIVEN)) { + driver = sig_b; + driven = sig_a; + can_resolve = true; + } + else if (dir_a == SigDirection::DRIVEN && dir_b == SigDirection::UNKNOWN) { + driver = sig_a; + driven = sig_b; + can_resolve = true; + } + else if (dir_a == SigDirection::UNKNOWN && dir_b == SigDirection::DRIVEN) { + driver = sig_b; + driven = sig_a; + can_resolve = true; + } + + if (can_resolve) { + log_debug("Resolving $connect %s: %s <- %s\n", log_id(cell), log_signal(driven), log_signal(driver)); + new_connections.push_back({driven, driver}); + cells_to_remove.insert(cell); + } } - if (can_resolve) { - log_debug("Resolving $connect %s: %s <- %s\n", log_id(cell), log_signal(driven), log_signal(driver)); - new_connections.push_back({driven, driver}); - cells_to_remove.insert(cell); + for (auto &conn : new_connections) + module->connect(conn); + + for (auto cell : cells_to_remove) { + remaining_cell_names.erase(cell->name); + module->remove(cell); } + + if (cells_to_remove.empty()) + break; + + log_debug("$connect res iteration %d: resolved %d cells\n", iteration, GetSize(cells_to_remove)); } - - for (auto &conn : new_connections) - module->connect(conn); - - for (auto cell : cells_to_remove) - module->remove(cell); - - if (cells_to_remove.empty()) - break; - - did_something = true; - log_debug("$connect res iteration %d: resolved %d cells\n", iteration, GetSize(cells_to_remove)); } - - return did_something; } }; diff --git a/passes/hierarchy/util/ports.h b/passes/hierarchy/util/ports.h index 37e59807f..2918249e0 100644 --- a/passes/hierarchy/util/ports.h +++ b/passes/hierarchy/util/ports.h @@ -22,13 +22,14 @@ #define HIERARCHY_PORTS_H #include "kernel/yosys.h" +#include "passes/hierarchy/util/interfaces.h" YOSYS_NAMESPACE_BEGIN namespace Hierarchy { std::pair derive_blackbox_dynports(Module* module, Cell* cell, Design* design, std::set& blackbox_derivatives); void check_and_adjust_ports(Module* module, std::set& blackbox_derivatives, bool keep_portwidths, bool top_is_from_verific); - bool resolve_connect_directionality(Module* module); + void resolve_acc_connects(Design* design, const ConnectAccumulator& connect_acc); }; YOSYS_NAMESPACE_END