2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5 * 2019 Eddie Hung <eddie@fpgeh.com>
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 #include "kernel/yosys.h"
22 #include "kernel/sigtools.h"
25 PRIVATE_NAMESPACE_BEGIN
32 int mux_count
, pmux_count
;
34 pool
<Cell
*> remove_cells
;
36 dict
<SigSpec
, Cell
*> sig_chain_next
;
37 dict
<SigSpec
, Cell
*> sig_chain_prev
;
38 pool
<SigBit
> sigbit_with_non_chain_users
;
39 pool
<Cell
*> chain_start_cells
;
40 pool
<Cell
*> candidate_cells
;
42 void make_sig_chain_next_prev()
44 for (auto wire
: module
->wires())
46 if (wire
->port_output
|| wire
->get_bool_attribute("\\keep")) {
47 for (auto bit
: sigmap(wire
))
48 sigbit_with_non_chain_users
.insert(bit
);
52 for (auto cell
: module
->cells())
54 if (cell
->type
.in("$mux", "$pmux") && !cell
->get_bool_attribute("\\keep"))
56 SigSpec a_sig
= sigmap(cell
->getPort("\\A"));
58 if (cell
->type
== "$mux")
59 b_sig
= sigmap(cell
->getPort("\\B"));
60 SigSpec y_sig
= sigmap(cell
->getPort("\\Y"));
62 if (sig_chain_next
.count(a_sig
))
63 for (auto a_bit
: a_sig
.bits())
64 sigbit_with_non_chain_users
.insert(a_bit
);
66 sig_chain_next
[a_sig
] = cell
;
67 candidate_cells
.insert(cell
);
71 if (sig_chain_next
.count(b_sig
))
72 for (auto b_bit
: b_sig
.bits())
73 sigbit_with_non_chain_users
.insert(b_bit
);
75 sig_chain_next
[b_sig
] = cell
;
76 candidate_cells
.insert(cell
);
80 sig_chain_prev
[y_sig
] = cell
;
84 for (auto conn
: cell
->connections())
85 if (cell
->input(conn
.first
))
86 for (auto bit
: sigmap(conn
.second
))
87 sigbit_with_non_chain_users
.insert(bit
);
91 void find_chain_start_cells()
93 for (auto cell
: candidate_cells
)
95 log_debug("Considering %s (%s)\n", log_id(cell
), log_id(cell
->type
));
97 SigSpec a_sig
= cell
->getPort("\\A");
98 if (cell
->type
== "$mux") {
99 SigSpec b_sig
= cell
->getPort("\\B");
100 if (sig_chain_prev
.count(a_sig
) + sig_chain_prev
.count(b_sig
) != 1)
103 if (!sig_chain_prev
.count(a_sig
))
106 else if (cell
->type
== "$pmux") {
107 if (!sig_chain_prev
.count(a_sig
))
113 for (auto bit
: a_sig
.bits())
114 if (sigbit_with_non_chain_users
.count(bit
))
117 Cell
*c1
= sig_chain_prev
.at(a_sig
);
120 if (c1
->getParam("\\WIDTH") != c2
->getParam("\\WIDTH"))
127 chain_start_cells
.insert(cell
);
131 vector
<Cell
*> create_chain(Cell
*start_cell
)
135 Cell
*c
= start_cell
;
140 SigSpec y_sig
= sigmap(c
->getPort("\\Y"));
142 if (sig_chain_next
.count(y_sig
) == 0)
145 c
= sig_chain_next
.at(y_sig
);
146 if (chain_start_cells
.count(c
) != 0)
153 void process_chain(vector
<Cell
*> &chain
)
155 if (GetSize(chain
) < 2)
159 while (cursor
< GetSize(chain
))
161 int cases
= GetSize(chain
) - cursor
;
163 Cell
*first_cell
= chain
[cursor
];
164 dict
<int, SigBit
> taps_dict
;
171 Cell
*last_cell
= chain
[cursor
+cases
-1];
173 log("Converting %s.%s ... %s.%s to a pmux with %d cases.\n",
174 log_id(module
), log_id(first_cell
), log_id(module
), log_id(last_cell
), cases
);
179 first_cell
->type
= "$pmux";
180 SigSpec b_sig
= first_cell
->getPort("\\B");
181 SigSpec s_sig
= first_cell
->getPort("\\S");
183 for (int i
= 1; i
< cases
; i
++) {
184 Cell
* prev_cell
= chain
[cursor
+i
-1];
185 Cell
* cursor_cell
= chain
[cursor
+i
];
186 if (sigmap(prev_cell
->getPort("\\Y")) == sigmap(cursor_cell
->getPort("\\A"))) {
187 b_sig
.append(cursor_cell
->getPort("\\B"));
188 s_sig
.append(cursor_cell
->getPort("\\S"));
191 b_sig
.append(cursor_cell
->getPort("\\A"));
192 s_sig
.append(module
->LogicNot(NEW_ID
, cursor_cell
->getPort("\\S")));
194 remove_cells
.insert(cursor_cell
);
197 first_cell
->setPort("\\B", b_sig
);
198 first_cell
->setPort("\\S", s_sig
);
199 first_cell
->setParam("\\S_WIDTH", GetSize(s_sig
));
200 first_cell
->setPort("\\Y", last_cell
->getPort("\\Y"));
208 for (auto cell
: remove_cells
)
209 module
->remove(cell
);
211 remove_cells
.clear();
212 sig_chain_next
.clear();
213 sig_chain_prev
.clear();
214 chain_start_cells
.clear();
215 candidate_cells
.clear();
218 MuxpackWorker(Module
*module
) :
219 module(module
), sigmap(module
), mux_count(0), pmux_count(0)
221 make_sig_chain_next_prev();
222 find_chain_start_cells();
224 for (auto c
: chain_start_cells
) {
225 vector
<Cell
*> chain
= create_chain(c
);
226 process_chain(chain
);
233 struct MuxpackPass
: public Pass
{
234 MuxpackPass() : Pass("muxpack", "$mux/$pmux cascades to $pmux") { }
235 void help() YS_OVERRIDE
237 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
239 log(" muxpack [selection]\n");
241 log("This pass converts cascaded chains of $pmux cells (e.g. those create from case\n");
242 log("constructs) and $mux cells (e.g. those created by if-else constructs) into \n");
243 log("into $pmux cells.\n");
246 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
248 log_header(design
, "Executing MUXPACK pass ($mux cell cascades to $pmux).\n");
251 for (argidx
= 1; argidx
< args
.size(); argidx
++)
255 extra_args(args
, argidx
, design
);
260 for (auto module
: design
->selected_modules()) {
261 MuxpackWorker
worker(module
);
262 mux_count
+= worker
.mux_count
;
263 pmux_count
+= worker
.pmux_count
;
266 log("Converted %d (p)mux cells into %d pmux cells.\n", mux_count
, pmux_count
);
270 PRIVATE_NAMESPACE_END