Accumulate connect cells.

This commit is contained in:
nella 2026-05-12 14:47:49 +02:00
parent 4e4fd1a26e
commit d9faee0153
5 changed files with 99 additions and 75 deletions

View File

@ -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");

View File

@ -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<std::string> &libdirs) {
void expand_all_interfaces(Design* design, Module*& top_mod, bool flag_check, bool flag_simcheck, bool flag_smtcheck, const std::vector<std::string> &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<std::string> &libdirs)
bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check, bool flag_simcheck, bool flag_smtcheck, const std::vector<std::string> &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;

View File

@ -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<std::string> &libdirs);
bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check, bool flag_simcheck, bool flag_smtcheck, const std::vector<std::string> &libdirs);
struct ConnectAccumulator {
dict<IdString, pool<IdString>> 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<std::string> &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<std::string> &libdirs, ConnectAccumulator* connect_acc);
// For expanding a module's interface connections
struct IFModExpander

View File

@ -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<IdString> 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<Cell*> cells_to_remove;
vector<SigSig> 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<IdString>& cell_names = connect_acc.module_connect_cells.at(mod_name);
pool<IdString> remaining_cell_names = cell_names;
int iteration = 0;
for (auto cell : module->cells())
{
if (cell->type != ID($connect))
continue;
while (true) {
iteration++;
pool<Cell*> cells_to_remove;
vector<SigSig> 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;
}
};

View File

@ -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<Module*, bool> derive_blackbox_dynports(Module* module, Cell* cell, Design* design, std::set<Module*>& blackbox_derivatives);
void check_and_adjust_ports(Module* module, std::set<Module*>& 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