40 struct bitDef_t :
public std::pair<RTLIL::Wire*, int> {
75 log(
"Running muxtree optimizier on module %s..\n", module->
name.
c_str());
77 log(
" Creating internal representation of mux trees.\n");
87 for (
auto cell : module->
cells())
89 if (cell->type ==
"$mux" || cell->type ==
"$pmux")
99 for (
int i = 0; i < sig_s.
size(); i++) {
110 portinfo.enabled =
false;
111 muxinfo.
ports.push_back(portinfo);
121 muxinfo.
ports.push_back(portinfo);
133 for (
auto &it : cell->connections()) {
139 for (
auto wire : module->
wires()) {
140 if (wire->port_output)
146 log(
" No muxes found in this module.\n");
152 for (
size_t i = 0; i <
bit2info.size(); i++)
160 log(
" Evaluating internal representation of mux trees.\n");
162 std::set<int> root_muxes;
164 if (!bi.seen_non_mux)
166 for (
int mux_idx : bi.mux_drivers)
167 root_muxes.insert(mux_idx);
169 for (
int mux_idx : root_muxes)
172 log(
" Analyzing evaluation results.\n");
176 std::vector<int> live_ports;
177 for (
int port_idx = 0; port_idx <
GetSize(mi.ports); port_idx++) {
180 live_ports.push_back(port_idx);
182 log(
" dead port %d/%d on %s %s.\n", port_idx+1,
GetSize(mi.ports),
183 mi.cell->type.c_str(), mi.cell->name.c_str());
188 if (live_ports.size() == mi.ports.size())
191 if (live_ports.size() == 0) {
204 if (live_ports.size() == 1)
214 for (
size_t i = 0; i < live_ports.size(); i++) {
216 if (i == live_ports.size()-1) {
224 mi.cell->setPort(
"\\A", new_sig_a);
225 mi.cell->setPort(
"\\B", new_sig_b);
226 mi.cell->setPort(
"\\S", new_sig_s);
227 if (new_sig_s.
size() == 1) {
228 mi.cell->type =
"$mux";
229 mi.cell->parameters.erase(
"\\S_WIDTH");
256 list.push_back(value);
261 std::vector<int> results;
263 for (
auto &bit : sig)
264 if (bit.wire !=
NULL) {
273 results.push_back(
bit2num[bit]);
299 muxinfo.
ports[port_idx].enabled =
true;
301 for (
size_t i = 0; i < muxinfo.
ports.size(); i++) {
302 if (
int(i) == port_idx)
304 for (
int b : muxinfo.
ports[i].ctrl_sigs)
308 if (port_idx <
int(muxinfo.
ports.size())-1 && !muxinfo.
ports[port_idx].const_activated)
311 std::vector<int> parent_muxes;
312 for (
int m : muxinfo.
ports[port_idx].input_muxes) {
316 parent_muxes.push_back(m);
318 for (
int m : parent_muxes)
320 for (
int m : parent_muxes)
323 if (port_idx <
int(muxinfo.
ports.size())-1 && !muxinfo.
ports[port_idx].const_activated)
326 for (
size_t i = 0; i < muxinfo.
ports.size(); i++) {
327 if (
int(i) == port_idx)
329 for (
int b : muxinfo.
ports[i].ctrl_sigs)
339 for (
size_t port_idx = 0; port_idx < muxinfo.
ports.size()-1; port_idx++)
351 for (
size_t port_idx = 0; port_idx < muxinfo.
ports.size()-1; port_idx++)
354 for (
size_t i = 0; i < knowledge.
known_active.size(); i++) {
366 for (
size_t port_idx = 0; port_idx < muxinfo.
ports.size(); port_idx++)
370 if (port_idx < muxinfo.
ports.size()-1) {
371 bool found_non_known_inactive =
false;
374 found_non_known_inactive =
true;
375 if (!found_non_known_inactive)
379 bool port_active =
true;
380 std::vector<int> other_ctrl_sig;
381 for (
size_t i = 0; i < muxinfo.
ports.size()-1; i++) {
384 other_ctrl_sig.insert(other_ctrl_sig.end(),
385 muxinfo.
ports[i].ctrl_sigs.begin(), muxinfo.
ports[i].ctrl_sigs.end());
387 for (
size_t i = 0; i < knowledge.
known_active.size(); i++) {
410 log(
" opt_muxtree [selection]\n");
412 log(
"This pass analyzes the control signals for the multiplexer trees in the design\n");
413 log(
"and identifies inputs that can never be active. It then removes this dead\n");
414 log(
"branches from the multiplexer trees.\n");
416 log(
"This pass only operates on completely selected modules without processes.\n");
421 log_header(
"Executing OPT_MUXTREE pass (detect dead branches in mux trees).\n");
425 for (
auto mod : design->
modules()) {
428 log(
"Skipping module %s as it is only partially selected.\n",
log_id(mod));
431 if (mod->processes.size() > 0) {
432 log(
"Skipping module %s as it contains processes.\n",
log_id(mod));
440 log(
"Removed %d multiplexer ports.\n", total_count);
const char * c_str() const
bool selected(T1 *module) const
std::vector< int > input_sigs
std::vector< int > input_muxes
std::set< int > visited_muxes
void log_header(const char *format,...)
std::vector< bitinfo_t > bit2info
static std::string idx(std::string str)
RTLIL::ObjRange< RTLIL::Wire * > wires()
bitDef_t(const RTLIL::SigBit &bit)
virtual void execute(std::vector< std::string > args, RTLIL::Design *design)
bool list_is_subset(const std::vector< int > &sub, const std::vector< int > &super)
std::vector< muxinfo_t > mux2info
std::vector< int > sig2bits(RTLIL::SigSpec sig)
void add_to_list(std::vector< int > &list, int value)
void apply(RTLIL::SigBit &bit) const
OptMuxtreeWorker(RTLIL::Design *design, RTLIL::Module *module)
void connect(const RTLIL::SigSig &conn)
std::vector< std::vector< int > > known_active
#define PRIVATE_NAMESPACE_BEGIN
int GetSize(RTLIL::Wire *wire)
bool is_fully_const() const
void eval_mux_port(knowledge_t &knowledge, int mux_idx, int port_idx)
bool selected_whole_module(RTLIL::IdString mod_name) const
#define PRIVATE_NAMESPACE_END
static const char * id2cstr(const RTLIL::IdString &str)
std::map< bitDef_t, int > bit2num
#define USING_YOSYS_NAMESPACE
void eval_root_mux(int mux_idx)
RTLIL::ObjRange< RTLIL::Cell * > cells()
RTLIL::ObjRange< RTLIL::Module * > modules()
std::vector< int > ctrl_sigs
void remove(const std::set< RTLIL::Wire * > &wires)
SigSet< RTLIL::Cell * > mux_drivers
OptMuxtreePass OptMuxtreePass
std::vector< int > mux_users
void log(const char *format,...)
std::vector< portinfo_t > ports
RTLIL::SigSpec extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other=NULL) const
std::vector< int > mux_drivers
void eval_mux(knowledge_t &knowledge, int mux_idx)
void scratchpad_set_bool(std::string varname, bool value)
void append(const RTLIL::SigSpec &signal)
bool is_in_list(const std::vector< int > &list, int value)
void extra_args(std::vector< std::string > args, size_t argidx, RTLIL::Design *design, bool select=true)
std::map< int, int > known_inactive
std::pair< SigSpec, SigSpec > SigSig
const char * log_id(RTLIL::IdString str)