1 /* 2 * yosys -- Yosys Open SYnthesis Suite 3 * 4 * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com> 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 * 18 */ 19 20 #include "kernel/register.h" 21 #include "kernel/sigtools.h" 22 #include "kernel/log.h" 23 #include <stdlib.h> 24 #include <stdio.h> 25 26 USING_YOSYS_NAMESPACE 27 PRIVATE_NAMESPACE_BEGIN 28 29 struct RmportsPassPass : public Pass { RmportsPassPassRmportsPassPass30 RmportsPassPass() : Pass("rmports", "remove module ports with no connections") { } helpRmportsPassPass31 void help() override 32 { 33 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| 34 log("\n"); 35 log(" rmports [selection]\n"); 36 log("\n"); 37 log("This pass identifies ports in the selected modules which are not used or\n"); 38 log("driven and removes them.\n"); 39 log("\n"); 40 } 41 executeRmportsPassPass42 void execute(std::vector<std::string> args, RTLIL::Design *design) override 43 { 44 log_header(design, "Executing RMPORTS pass (remove ports with no connections).\n"); 45 46 size_t argidx = 1; 47 extra_args(args, argidx, design); 48 49 // The set of ports we removed 50 dict<IdString, pool<IdString>> removed_ports; 51 52 // Find all of the unused ports, and remove them from that module 53 auto modules = design->selected_modules(); 54 for(auto mod : modules) 55 ScanModule(mod, removed_ports); 56 57 // Remove the unused ports from all instances of those modules 58 for(auto mod : modules) 59 CleanupModule(mod, removed_ports); 60 } 61 CleanupModuleRmportsPassPass62 void CleanupModule(Module *module, dict<IdString, pool<IdString>> &removed_ports) 63 { 64 log("Removing now-unused cell ports in module %s\n", module->name.c_str()); 65 66 auto cells = module->cells(); 67 for(auto cell : cells) 68 { 69 if(removed_ports.find(cell->type) == removed_ports.end()) 70 { 71 // log(" Not touching instance \"%s\" because we didn't remove any ports from module \"%s\"\n", 72 // cell->name.c_str(), cell->type.c_str()); 73 continue; 74 } 75 76 auto ports_to_remove = removed_ports[cell->type]; 77 for(auto p : ports_to_remove) 78 { 79 log(" Removing port \"%s\" from instance \"%s\"\n", 80 p.c_str(), cell->type.c_str()); 81 cell->unsetPort(p); 82 } 83 } 84 } 85 ScanModuleRmportsPassPass86 void ScanModule(Module* module, dict<IdString, pool<IdString>> &removed_ports) 87 { 88 log("Finding unconnected ports in module %s\n", module->name.c_str()); 89 90 pool<IdString> used_ports; 91 92 // See what wires are used. 93 // Start by checking connections between named wires 94 auto &conns = module->connections(); 95 for(auto sigsig : conns) 96 { 97 auto s1 = sigsig.first; 98 auto s2 = sigsig.second; 99 100 int len1 = s1.size(); 101 int len2 = s2.size(); 102 int len = len1; 103 if(len2 < len1) 104 len = len2; 105 106 for(int i=0; i<len; i++) 107 { 108 auto w1 = s1[i].wire; 109 auto w2 = s2[i].wire; 110 if( (w1 == NULL) || (w2 == NULL) ) 111 continue; 112 113 //log(" conn %s, %s\n", w1->name.c_str(), w2->name.c_str()); 114 115 if( (w1->port_input || w1->port_output) && (used_ports.find(w1->name) == used_ports.end()) ) 116 used_ports.insert(w1->name); 117 118 if( (w2->port_input || w2->port_output) && (used_ports.find(w2->name) == used_ports.end()) ) 119 used_ports.insert(w2->name); 120 } 121 } 122 123 // Then check connections to cells 124 auto cells = module->cells(); 125 for(auto cell : cells) 126 { 127 auto &cconns = cell->connections(); 128 for(auto conn : cconns) 129 { 130 for(int i=0; i<conn.second.size(); i++) 131 { 132 auto sig = conn.second[i].wire; 133 if(sig == NULL) 134 continue; 135 136 // log(" sig %s\n", sig->name.c_str()); 137 if( (sig->port_input || sig->port_output) && (used_ports.find(sig->name) == used_ports.end()) ) 138 used_ports.insert(sig->name); 139 } 140 } 141 } 142 143 // Now that we know what IS used, get rid of anything that isn't in that list 144 pool<IdString> unused_ports; 145 for(auto port : module->ports) 146 { 147 if(used_ports.find(port) != used_ports.end()) 148 continue; 149 unused_ports.insert(port); 150 } 151 152 // Print the ports out as we go through them 153 for(auto port : unused_ports) 154 { 155 log(" removing unused port %s\n", port.c_str()); 156 removed_ports[module->name].insert(port); 157 158 // Remove from ports list 159 for(size_t i=0; i<module->ports.size(); i++) 160 { 161 if(module->ports[i] == port) 162 { 163 module->ports.erase(module->ports.begin() + i); 164 break; 165 } 166 } 167 168 // Mark the wire as no longer a port 169 auto wire = module->wire(port); 170 wire->port_input = false; 171 wire->port_output = false; 172 wire->port_id = 0; 173 } 174 log("Removed %d unused ports.\n", GetSize(unused_ports)); 175 176 // Re-number all of the wires that DO have ports still on them 177 for(size_t i=0; i<module->ports.size(); i++) 178 { 179 auto port = module->ports[i]; 180 auto wire = module->wire(port); 181 wire->port_id = i+1; 182 } 183 } 184 185 } RmportsPassPass; 186 187 PRIVATE_NAMESPACE_END 188