diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index 469bbb180..c0ec287d9 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -26,6 +26,7 @@ #include "passes/hierarchy/util/positionals.h" #include "passes/hierarchy/util/verilog.h" #include "passes/hierarchy/util/generate.h" +#include "passes/hierarchy/util/ports.h" #include #include #include @@ -241,6 +242,10 @@ struct HierarchyPass : public Pass { expand_all_interfaces(design, top_mod, flag_check, flag_simcheck, flag_smtcheck, libdirs); + log_header(design, "Resolving $connect directionality..\n"); + for (auto module : design->modules()) + resolve_connect_directionality(module); + if (top_mod != NULL) { log_header(design, "Analyzing design hierarchy..\n"); clean(design, top_mod, purge_lib); diff --git a/passes/hierarchy/util/ports.cc b/passes/hierarchy/util/ports.cc index f0d6ab9c2..e866fc47f 100644 --- a/passes/hierarchy/util/ports.cc +++ b/passes/hierarchy/util/ports.cc @@ -100,5 +100,60 @@ namespace Hierarchy { } } + bool resolve_connect_directionality(Module* module) { + pool cells_to_remove; + vector new_connections; + + for (auto cell : module->cells()) + { + if (cell->type != ID($connect)) + continue; + + if (cell->has_keep_attr()) + continue; + + SigSpec sig_a = cell->getPort(ID::A); + SigSpec sig_b = cell->getPort(ID::B); + + // TODO + if (!sig_a.is_wire() || !sig_b.is_wire()) + continue; + + Wire *wire_a = sig_a.as_wire(); + Wire *wire_b = sig_b.as_wire(); + + bool a_is_input = wire_a->port_input && !wire_a->port_output; + bool a_is_output = wire_a->port_output && !wire_a->port_input; + bool b_is_input = wire_b->port_input && !wire_b->port_output; + bool b_is_output = wire_b->port_output && !wire_b->port_input; + + SigSpec driver, driven; + + if (a_is_output && b_is_input) { + driver = sig_a; + driven = sig_b; + } else if (a_is_input && b_is_output) { + driver = sig_b; + driven = sig_a; + } else { + continue; + } + + 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); + } + + // Apply the changes + for (auto &conn : new_connections) + module->connect(conn); + + for (auto cell : cells_to_remove) + module->remove(cell); + + return !cells_to_remove.empty(); + } + }; YOSYS_NAMESPACE_END diff --git a/passes/hierarchy/util/ports.h b/passes/hierarchy/util/ports.h index 925393bdc..cd1664bdb 100644 --- a/passes/hierarchy/util/ports.h +++ b/passes/hierarchy/util/ports.h @@ -27,6 +27,7 @@ YOSYS_NAMESPACE_BEGIN namespace Hierarchy { 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); }; YOSYS_NAMESPACE_END