From cca3cb5fbbe5ba127b620be5435697fb0ee66736 Mon Sep 17 00:00:00 2001 From: Andrew Zonenberg Date: Fri, 11 Aug 2017 13:40:37 -0700 Subject: [PATCH 01/11] Added opt_rmports pass (remove unconnected ports from top-level modules) --- passes/opt/Makefile.inc | 1 + passes/opt/opt_rmports.cc | 132 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 passes/opt/opt_rmports.cc diff --git a/passes/opt/Makefile.inc b/passes/opt/Makefile.inc index a8b1537bb..7d54adf0f 100644 --- a/passes/opt/Makefile.inc +++ b/passes/opt/Makefile.inc @@ -6,6 +6,7 @@ OBJS += passes/opt/opt_reduce.o OBJS += passes/opt/opt_rmdff.o OBJS += passes/opt/opt_clean.o OBJS += passes/opt/opt_expr.o +OBJS += passes/opt/opt_rmports.o ifneq ($(SMALL),1) OBJS += passes/opt/share.o diff --git a/passes/opt/opt_rmports.cc b/passes/opt/opt_rmports.cc new file mode 100644 index 000000000..2fd73fff2 --- /dev/null +++ b/passes/opt/opt_rmports.cc @@ -0,0 +1,132 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/register.h" +#include "kernel/sigtools.h" +#include "kernel/log.h" +#include +#include + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct OptRmportsPass : public Pass { + OptRmportsPass() : Pass("opt_rmports", "remove top-level ports with no connections") { } + virtual void help() + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" opt_rmports\n"); + log("\n"); + log("This pass identifies ports in the top-level design which are not used or driven\n"); + log("and removes them\n"); + log("\n"); + } + + virtual void execute(std::vector /*args*/, RTLIL::Design *design) + { + log_header(design, "Executing OPT_RMPORTS pass (remove top level ports with no connections).\n"); + + //vector mods = design->modules(); + //for(auto mod : mods) + // ProcessModule(mod); + ProcessModule(design->top_module()); + } + + virtual void ProcessModule(RTLIL::Module* module) + { + log("Finding unconnected ports in module %s\n", module->name.c_str()); + + std::set used_ports; + + //See what wires are used. + //Start by checking connections between named wires + auto& conns = module->connections(); + for(auto sigsig : conns) + { + auto s1 = sigsig.first.as_wire(); + auto s2 = sigsig.second.as_wire(); + + if( (s1->port_input || s1->port_output) && (used_ports.find(s1->name) == used_ports.end()) ) + used_ports.emplace(s1->name); + + if( (s2->port_input || s2->port_output) && (used_ports.find(s2->name) == used_ports.end()) ) + used_ports.emplace(s2->name); + } + + //Then check connections to cells + auto cells = module->cells(); + for(auto cell : cells) + { + auto& cconns = cell->connections(); + for(auto conn : cconns) + { + if(!conn.second.is_wire()) + continue; + auto sig = conn.second.as_wire(); + + if( (sig->port_input || sig->port_output) && (used_ports.find(sig->name) == used_ports.end()) ) + used_ports.emplace(sig->name); + } + } + + //Now that we know what IS used, get rid of anything that isn't in that list + std::set unused_ports; + for(auto port : module->ports) + { + if(used_ports.find(port) != used_ports.end()) + continue; + unused_ports.emplace(port); + } + + //Print the ports out as we go through them + for(auto port : unused_ports) + { + log(" removing unused top-level port %s\n", port.c_str()); + + //Remove from ports list + for(size_t i=0; iports.size(); i++) + { + if(module->ports[i] == port) + { + module->ports.erase(module->ports.begin() + i); + break; + } + } + + //Mark the wire as no longer a port + auto wire = module->wire(port); + wire->port_input = false; + wire->port_output = false; + wire->port_id = 0; + } + log("Removed %zu unused top-level ports.\n", unused_ports.size()); + + //Re-number all of the wires that DO have ports still on them + for(size_t i=0; iports.size(); i++) + { + auto port = module->ports[i]; + auto wire = module->wire(port); + wire->port_id = i+1; + } + } + +} OptRmportsPass; + +PRIVATE_NAMESPACE_END From 66aac06eeef177318f3a4ade150e20a21be7e7c7 Mon Sep 17 00:00:00 2001 From: Andrew Zonenberg Date: Fri, 11 Aug 2017 13:46:01 -0700 Subject: [PATCH 02/11] Removed commented out debug code --- passes/opt/opt_rmports.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/passes/opt/opt_rmports.cc b/passes/opt/opt_rmports.cc index 2fd73fff2..6c80e2b7c 100644 --- a/passes/opt/opt_rmports.cc +++ b/passes/opt/opt_rmports.cc @@ -42,10 +42,6 @@ struct OptRmportsPass : public Pass { virtual void execute(std::vector /*args*/, RTLIL::Design *design) { log_header(design, "Executing OPT_RMPORTS pass (remove top level ports with no connections).\n"); - - //vector mods = design->modules(); - //for(auto mod : mods) - // ProcessModule(mod); ProcessModule(design->top_module()); } From 3dd7f42e2b07c84178c648a0c3979c61fe25f68f Mon Sep 17 00:00:00 2001 From: Andrew Zonenberg Date: Fri, 11 Aug 2017 15:07:27 -0700 Subject: [PATCH 03/11] opt_rmports: Fixed incorrect handling of multi-bit nets --- passes/opt/opt_rmports.cc | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/passes/opt/opt_rmports.cc b/passes/opt/opt_rmports.cc index 6c80e2b7c..afbbecf84 100644 --- a/passes/opt/opt_rmports.cc +++ b/passes/opt/opt_rmports.cc @@ -56,14 +56,28 @@ struct OptRmportsPass : public Pass { auto& conns = module->connections(); for(auto sigsig : conns) { - auto s1 = sigsig.first.as_wire(); - auto s2 = sigsig.second.as_wire(); + auto s1 = sigsig.first; + auto s2 = sigsig.second; - if( (s1->port_input || s1->port_output) && (used_ports.find(s1->name) == used_ports.end()) ) - used_ports.emplace(s1->name); + int len1 = s1.size(); + int len2 = s2.size(); + int len = len1; + if(len2 < len1) + len = len2; - if( (s2->port_input || s2->port_output) && (used_ports.find(s2->name) == used_ports.end()) ) - used_ports.emplace(s2->name); + for(int i=0; iname.c_str(), w2->name.c_str()); + + if( (w1->port_input || w1->port_output) && (used_ports.find(w1->name) == used_ports.end()) ) + used_ports.emplace(w1->name); + + if( (w2->port_input || w2->port_output) && (used_ports.find(w2->name) == used_ports.end()) ) + used_ports.emplace(w2->name); + } } //Then check connections to cells @@ -73,12 +87,13 @@ struct OptRmportsPass : public Pass { auto& cconns = cell->connections(); for(auto conn : cconns) { - if(!conn.second.is_wire()) - continue; - auto sig = conn.second.as_wire(); - - if( (sig->port_input || sig->port_output) && (used_ports.find(sig->name) == used_ports.end()) ) - used_ports.emplace(sig->name); + for(int i=0; iname.c_str()); + if( (sig->port_input || sig->port_output) && (used_ports.find(sig->name) == used_ports.end()) ) + used_ports.emplace(sig->name); + } } } From 2877d5e50449dd08ebcb183218d015008c9fffcb Mon Sep 17 00:00:00 2001 From: Andrew Zonenberg Date: Fri, 11 Aug 2017 16:16:25 -0700 Subject: [PATCH 04/11] Fixed handling of cell ports that aren't wires --- passes/opt/opt_rmports.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/passes/opt/opt_rmports.cc b/passes/opt/opt_rmports.cc index afbbecf84..5522dfa8e 100644 --- a/passes/opt/opt_rmports.cc +++ b/passes/opt/opt_rmports.cc @@ -90,6 +90,9 @@ struct OptRmportsPass : public Pass { for(int i=0; iname.c_str()); if( (sig->port_input || sig->port_output) && (used_ports.find(sig->name) == used_ports.end()) ) used_ports.emplace(sig->name); From 1bb150c2318a16e8007b4cf76aa2a199f49f0f7e Mon Sep 17 00:00:00 2001 From: Andrew Zonenberg Date: Fri, 11 Aug 2017 16:47:07 -0700 Subject: [PATCH 05/11] Improved handling of constant connections in opt_rmports --- passes/opt/opt_rmports.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/passes/opt/opt_rmports.cc b/passes/opt/opt_rmports.cc index 5522dfa8e..a7a2df866 100644 --- a/passes/opt/opt_rmports.cc +++ b/passes/opt/opt_rmports.cc @@ -69,6 +69,8 @@ struct OptRmportsPass : public Pass { { auto w1 = s1[i].wire; auto w2 = s2[i].wire; + if( (w1 == NULL) || (w2 == NULL) ) + continue; //log(" conn %s, %s\n", w1->name.c_str(), w2->name.c_str()); From 1a6a23f91a93414e0e43f0666d3b2af6295345a8 Mon Sep 17 00:00:00 2001 From: Andrew Zonenberg Date: Mon, 14 Aug 2017 11:00:18 -0700 Subject: [PATCH 06/11] Renamed opt_rmports pass to rmports --- passes/opt/{opt_rmports.cc => rmports.cc} | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) rename passes/opt/{opt_rmports.cc => rmports.cc} (93%) diff --git a/passes/opt/opt_rmports.cc b/passes/opt/rmports.cc similarity index 93% rename from passes/opt/opt_rmports.cc rename to passes/opt/rmports.cc index a7a2df866..30cf149ce 100644 --- a/passes/opt/opt_rmports.cc +++ b/passes/opt/rmports.cc @@ -26,13 +26,13 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -struct OptRmportsPass : public Pass { - OptRmportsPass() : Pass("opt_rmports", "remove top-level ports with no connections") { } +struct RmportsPassPass : public Pass { + RmportsPassPass() : Pass("rmports", "remove top-level ports with no connections") { } virtual void help() { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); - log(" opt_rmports\n"); + log(" rmports\n"); log("\n"); log("This pass identifies ports in the top-level design which are not used or driven\n"); log("and removes them\n"); @@ -41,7 +41,7 @@ struct OptRmportsPass : public Pass { virtual void execute(std::vector /*args*/, RTLIL::Design *design) { - log_header(design, "Executing OPT_RMPORTS pass (remove top level ports with no connections).\n"); + log_header(design, "Executing RMPORTS pass (remove top level ports with no connections).\n"); ProcessModule(design->top_module()); } @@ -143,6 +143,6 @@ struct OptRmportsPass : public Pass { } } -} OptRmportsPass; +} RmportsPassPass; PRIVATE_NAMESPACE_END From d5e5bbad861975761c87a77388ce7add7bd1bdea Mon Sep 17 00:00:00 2001 From: Andrew Zonenberg Date: Mon, 14 Aug 2017 11:04:56 -0700 Subject: [PATCH 07/11] Updated Makefile to reflect opt_rmports being renamed to rmports --- passes/opt/Makefile.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/opt/Makefile.inc b/passes/opt/Makefile.inc index 7d54adf0f..a145cf946 100644 --- a/passes/opt/Makefile.inc +++ b/passes/opt/Makefile.inc @@ -6,7 +6,7 @@ OBJS += passes/opt/opt_reduce.o OBJS += passes/opt/opt_rmdff.o OBJS += passes/opt/opt_clean.o OBJS += passes/opt/opt_expr.o -OBJS += passes/opt/opt_rmports.o +OBJS += passes/opt/rmports.o ifneq ($(SMALL),1) OBJS += passes/opt/share.o From bd2ac68769ebddf8c239eeaf26d43d30453db583 Mon Sep 17 00:00:00 2001 From: Andrew Zonenberg Date: Mon, 14 Aug 2017 11:16:44 -0700 Subject: [PATCH 08/11] rmports now works on all modules in the design, not just the top. --- passes/opt/rmports.cc | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/passes/opt/rmports.cc b/passes/opt/rmports.cc index 30cf149ce..f08d7b126 100644 --- a/passes/opt/rmports.cc +++ b/passes/opt/rmports.cc @@ -27,7 +27,7 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN struct RmportsPassPass : public Pass { - RmportsPassPass() : Pass("rmports", "remove top-level ports with no connections") { } + RmportsPassPass() : Pass("rmports", "remove module ports with no connections") { } virtual void help() { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| @@ -42,7 +42,10 @@ struct RmportsPassPass : public Pass { virtual void execute(std::vector /*args*/, RTLIL::Design *design) { log_header(design, "Executing RMPORTS pass (remove top level ports with no connections).\n"); - ProcessModule(design->top_module()); + + auto modules = design->selected_modules(); + for(auto mod : modules) + ProcessModule(mod); } virtual void ProcessModule(RTLIL::Module* module) @@ -114,7 +117,7 @@ struct RmportsPassPass : public Pass { //Print the ports out as we go through them for(auto port : unused_ports) { - log(" removing unused top-level port %s\n", port.c_str()); + log(" removing unused port %s\n", port.c_str()); //Remove from ports list for(size_t i=0; iports.size(); i++) @@ -132,7 +135,7 @@ struct RmportsPassPass : public Pass { wire->port_output = false; wire->port_id = 0; } - log("Removed %zu unused top-level ports.\n", unused_ports.size()); + log("Removed %zu unused ports.\n", unused_ports.size()); //Re-number all of the wires that DO have ports still on them for(size_t i=0; iports.size(); i++) From 0ee27d0226dcafad798eefdd26480dde1c186e98 Mon Sep 17 00:00:00 2001 From: Andrew Zonenberg Date: Mon, 14 Aug 2017 11:18:09 -0700 Subject: [PATCH 09/11] ProcessModule is no longer virtual (why was it in the first place?) --- passes/opt/rmports.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/opt/rmports.cc b/passes/opt/rmports.cc index f08d7b126..39cef12e6 100644 --- a/passes/opt/rmports.cc +++ b/passes/opt/rmports.cc @@ -48,7 +48,7 @@ struct RmportsPassPass : public Pass { ProcessModule(mod); } - virtual void ProcessModule(RTLIL::Module* module) + void ProcessModule(RTLIL::Module* module) { log("Finding unconnected ports in module %s\n", module->name.c_str()); From 15e41d6363b9f3a71a2fe564c793296f8c1fba6d Mon Sep 17 00:00:00 2001 From: Andrew Zonenberg Date: Mon, 14 Aug 2017 11:44:05 -0700 Subject: [PATCH 10/11] rmports: Now remove ports from cell instances if we optimized them out of that cell --- passes/opt/rmports.cc | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/passes/opt/rmports.cc b/passes/opt/rmports.cc index 39cef12e6..3aaa05c99 100644 --- a/passes/opt/rmports.cc +++ b/passes/opt/rmports.cc @@ -43,12 +43,44 @@ struct RmportsPassPass : public Pass { { log_header(design, "Executing RMPORTS pass (remove top level ports with no connections).\n"); + //The set of ports we removed + std::map< RTLIL::IdString, std::set > removed_ports; + + //Find all of the unused ports, and remove them from that module auto modules = design->selected_modules(); for(auto mod : modules) - ProcessModule(mod); + ScanModule(mod, removed_ports); + + //Remove the unused ports from all instances of those modules + for(auto mod : modules) + CleanupModule(mod, removed_ports); } - void ProcessModule(RTLIL::Module* module) + void CleanupModule(RTLIL::Module* module, std::map< RTLIL::IdString, std::set >& removed_ports) + { + log("Removing now-unused cell ports in module %s\n", module->name.c_str()); + + auto cells = module->cells(); + for(auto cell : cells) + { + if(removed_ports.find(cell->type) == removed_ports.end()) + { + //log(" Not touching instance \"%s\" because we didn't remove any ports from module \"%s\"\n", + // cell->name.c_str(), cell->type.c_str()); + continue; + } + + auto ports_to_remove = removed_ports[cell->type]; + for(auto p : ports_to_remove) + { + log(" Removing port \"%s\" from instance \"%s\"\n", + p.c_str(), cell->type.c_str()); + cell->unsetPort(p); + } + } + } + + void ScanModule(RTLIL::Module* module, std::map< RTLIL::IdString, std::set >& removed_ports) { log("Finding unconnected ports in module %s\n", module->name.c_str()); @@ -118,6 +150,7 @@ struct RmportsPassPass : public Pass { for(auto port : unused_ports) { log(" removing unused port %s\n", port.c_str()); + removed_ports[module->name].emplace(port); //Remove from ports list for(size_t i=0; iports.size(); i++) From 88983f5012ef394b3f3492baef6a6ee40308f05a Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 15 Aug 2017 11:32:35 +0200 Subject: [PATCH 11/11] Mostly coding style related fixes in rmports pass --- passes/opt/rmports.cc | 63 ++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/passes/opt/rmports.cc b/passes/opt/rmports.cc index 3aaa05c99..756be7473 100644 --- a/passes/opt/rmports.cc +++ b/passes/opt/rmports.cc @@ -32,31 +32,34 @@ struct RmportsPassPass : public Pass { { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); - log(" rmports\n"); + log(" rmports [selection]\n"); log("\n"); - log("This pass identifies ports in the top-level design which are not used or driven\n"); - log("and removes them\n"); + log("This pass identifies ports in the selected modules which are not used or\n"); + log("driven and removes them.\n"); log("\n"); } - virtual void execute(std::vector /*args*/, RTLIL::Design *design) + virtual void execute(std::vector args, RTLIL::Design *design) { - log_header(design, "Executing RMPORTS pass (remove top level ports with no connections).\n"); + log_header(design, "Executing RMPORTS pass (remove ports with no connections).\n"); - //The set of ports we removed - std::map< RTLIL::IdString, std::set > removed_ports; + size_t argidx = 1; + extra_args(args, argidx, design); - //Find all of the unused ports, and remove them from that module + // The set of ports we removed + dict> removed_ports; + + // Find all of the unused ports, and remove them from that module auto modules = design->selected_modules(); for(auto mod : modules) ScanModule(mod, removed_ports); - //Remove the unused ports from all instances of those modules + // Remove the unused ports from all instances of those modules for(auto mod : modules) CleanupModule(mod, removed_ports); } - void CleanupModule(RTLIL::Module* module, std::map< RTLIL::IdString, std::set >& removed_ports) + void CleanupModule(Module *module, dict> &removed_ports) { log("Removing now-unused cell ports in module %s\n", module->name.c_str()); @@ -65,7 +68,7 @@ struct RmportsPassPass : public Pass { { if(removed_ports.find(cell->type) == removed_ports.end()) { - //log(" Not touching instance \"%s\" because we didn't remove any ports from module \"%s\"\n", + // log(" Not touching instance \"%s\" because we didn't remove any ports from module \"%s\"\n", // cell->name.c_str(), cell->type.c_str()); continue; } @@ -80,15 +83,15 @@ struct RmportsPassPass : public Pass { } } - void ScanModule(RTLIL::Module* module, std::map< RTLIL::IdString, std::set >& removed_ports) + void ScanModule(Module* module, dict> &removed_ports) { log("Finding unconnected ports in module %s\n", module->name.c_str()); - std::set used_ports; + pool used_ports; - //See what wires are used. - //Start by checking connections between named wires - auto& conns = module->connections(); + // See what wires are used. + // Start by checking connections between named wires + auto &conns = module->connections(); for(auto sigsig : conns) { auto s1 = sigsig.first; @@ -110,18 +113,18 @@ struct RmportsPassPass : public Pass { //log(" conn %s, %s\n", w1->name.c_str(), w2->name.c_str()); if( (w1->port_input || w1->port_output) && (used_ports.find(w1->name) == used_ports.end()) ) - used_ports.emplace(w1->name); + used_ports.insert(w1->name); if( (w2->port_input || w2->port_output) && (used_ports.find(w2->name) == used_ports.end()) ) - used_ports.emplace(w2->name); + used_ports.insert(w2->name); } } - //Then check connections to cells + // Then check connections to cells auto cells = module->cells(); for(auto cell : cells) { - auto& cconns = cell->connections(); + auto &cconns = cell->connections(); for(auto conn : cconns) { for(int i=0; iname.c_str()); + // log(" sig %s\n", sig->name.c_str()); if( (sig->port_input || sig->port_output) && (used_ports.find(sig->name) == used_ports.end()) ) - used_ports.emplace(sig->name); + used_ports.insert(sig->name); } } } - //Now that we know what IS used, get rid of anything that isn't in that list - std::set unused_ports; + // Now that we know what IS used, get rid of anything that isn't in that list + pool unused_ports; for(auto port : module->ports) { if(used_ports.find(port) != used_ports.end()) continue; - unused_ports.emplace(port); + unused_ports.insert(port); } - //Print the ports out as we go through them + // Print the ports out as we go through them for(auto port : unused_ports) { log(" removing unused port %s\n", port.c_str()); - removed_ports[module->name].emplace(port); + removed_ports[module->name].insert(port); - //Remove from ports list + // Remove from ports list for(size_t i=0; iports.size(); i++) { if(module->ports[i] == port) @@ -162,7 +165,7 @@ struct RmportsPassPass : public Pass { } } - //Mark the wire as no longer a port + // Mark the wire as no longer a port auto wire = module->wire(port); wire->port_input = false; wire->port_output = false; @@ -170,7 +173,7 @@ struct RmportsPassPass : public Pass { } log("Removed %zu unused ports.\n", unused_ports.size()); - //Re-number all of the wires that DO have ports still on them + // Re-number all of the wires that DO have ports still on them for(size_t i=0; iports.size(); i++) { auto port = module->ports[i];