2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
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.
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.
20 #include "kernel/register.h"
21 #include "kernel/sigtools.h"
22 #include "kernel/log.h"
27 PRIVATE_NAMESPACE_BEGIN
29 struct RmportsPassPass
: public Pass
{
30 RmportsPassPass() : Pass("rmports", "remove module ports with no connections") { }
31 void help() YS_OVERRIDE
33 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
35 log(" rmports [selection]\n");
37 log("This pass identifies ports in the selected modules which are not used or\n");
38 log("driven and removes them.\n");
42 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
44 log_header(design
, "Executing RMPORTS pass (remove ports with no connections).\n");
47 extra_args(args
, argidx
, design
);
49 // The set of ports we removed
50 dict
<IdString
, pool
<IdString
>> removed_ports
;
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
);
57 // Remove the unused ports from all instances of those modules
58 for(auto mod
: modules
)
59 CleanupModule(mod
, removed_ports
);
62 void CleanupModule(Module
*module
, dict
<IdString
, pool
<IdString
>> &removed_ports
)
64 log("Removing now-unused cell ports in module %s\n", module
->name
.c_str());
66 auto cells
= module
->cells();
67 for(auto cell
: cells
)
69 if(removed_ports
.find(cell
->type
) == removed_ports
.end())
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());
76 auto ports_to_remove
= removed_ports
[cell
->type
];
77 for(auto p
: ports_to_remove
)
79 log(" Removing port \"%s\" from instance \"%s\"\n",
80 p
.c_str(), cell
->type
.c_str());
86 void ScanModule(Module
* module
, dict
<IdString
, pool
<IdString
>> &removed_ports
)
88 log("Finding unconnected ports in module %s\n", module
->name
.c_str());
90 pool
<IdString
> used_ports
;
92 // See what wires are used.
93 // Start by checking connections between named wires
94 auto &conns
= module
->connections();
95 for(auto sigsig
: conns
)
97 auto s1
= sigsig
.first
;
98 auto s2
= sigsig
.second
;
100 int len1
= s1
.size();
101 int len2
= s2
.size();
106 for(int i
=0; i
<len
; i
++)
108 auto w1
= s1
[i
].wire
;
109 auto w2
= s2
[i
].wire
;
110 if( (w1
== NULL
) || (w2
== NULL
) )
113 //log(" conn %s, %s\n", w1->name.c_str(), w2->name.c_str());
115 if( (w1
->port_input
|| w1
->port_output
) && (used_ports
.find(w1
->name
) == used_ports
.end()) )
116 used_ports
.insert(w1
->name
);
118 if( (w2
->port_input
|| w2
->port_output
) && (used_ports
.find(w2
->name
) == used_ports
.end()) )
119 used_ports
.insert(w2
->name
);
123 // Then check connections to cells
124 auto cells
= module
->cells();
125 for(auto cell
: cells
)
127 auto &cconns
= cell
->connections();
128 for(auto conn
: cconns
)
130 for(int i
=0; i
<conn
.second
.size(); i
++)
132 auto sig
= conn
.second
[i
].wire
;
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
);
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
)
147 if(used_ports
.find(port
) != used_ports
.end())
149 unused_ports
.insert(port
);
152 // Print the ports out as we go through them
153 for(auto port
: unused_ports
)
155 log(" removing unused port %s\n", port
.c_str());
156 removed_ports
[module
->name
].insert(port
);
158 // Remove from ports list
159 for(size_t i
=0; i
<module
->ports
.size(); i
++)
161 if(module
->ports
[i
] == port
)
163 module
->ports
.erase(module
->ports
.begin() + i
);
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;
174 log("Removed %zu unused ports.\n", unused_ports
.size());
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
++)
179 auto port
= module
->ports
[i
];
180 auto wire
= module
->wire(port
);
187 PRIVATE_NAMESPACE_END