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/yosys.h"
21 #include "kernel/sigtools.h"
22 #include "kernel/celltypes.h"
23 #include "passes/techmap/simplemap.h"
26 PRIVATE_NAMESPACE_BEGIN
30 RTLIL::Module
*module
;
34 typedef std::pair
<RTLIL::Cell
*, int> cell_int_t
;
35 std::map
<RTLIL::SigBit
, cell_int_t
> bit2mux
;
36 std::vector
<RTLIL::Cell
*> dff_cells
;
37 std::map
<RTLIL::SigBit
, int> bitusers
;
39 typedef std::map
<RTLIL::SigBit
, bool> pattern_t
;
40 typedef std::set
<pattern_t
> patterns_t
;
42 Dff2dffeWorker(RTLIL::Module
*module
) : module(module
), sigmap(module
), ct(module
->design
)
44 for (auto wire
: module
->wires()) {
45 if (wire
->port_output
)
46 for (auto bit
: sigmap(wire
))
50 for (auto cell
: module
->cells()) {
51 if (cell
->type
== "$mux" || cell
->type
== "$pmux" || cell
->type
== "$_MUX_") {
52 RTLIL::SigSpec sig_y
= sigmap(cell
->getPort("\\Y"));
53 for (int i
= 0; i
< GetSize(sig_y
); i
++)
54 bit2mux
[sig_y
[i
]] = cell_int_t(cell
, i
);
56 if (cell
->type
== "$dff" || cell
->type
== "$_DFF_N_" || cell
->type
== "$_DFF_P_")
57 dff_cells
.push_back(cell
);
58 for (auto conn
: cell
->connections()) {
59 if (ct
.cell_output(cell
->type
, conn
.first
))
61 for (auto bit
: sigmap(conn
.second
))
67 patterns_t
find_muxtree_feedback_patterns(RTLIL::SigBit d
, RTLIL::SigBit q
, pattern_t path
)
76 if (bit2mux
.count(d
) == 0 || bitusers
[d
] > 1)
79 cell_int_t mux_cell_int
= bit2mux
.at(d
);
80 RTLIL::SigSpec sig_a
= sigmap(mux_cell_int
.first
->getPort("\\A"));
81 RTLIL::SigSpec sig_b
= sigmap(mux_cell_int
.first
->getPort("\\B"));
82 RTLIL::SigSpec sig_s
= sigmap(mux_cell_int
.first
->getPort("\\S"));
83 int width
= GetSize(sig_a
), index
= mux_cell_int
.second
;
85 for (int i
= 0; i
< GetSize(sig_s
); i
++)
86 if (path
.count(sig_s
[i
]) && path
.at(sig_s
[i
]))
88 ret
= find_muxtree_feedback_patterns(sig_b
[i
*width
+ index
], q
, path
);
90 if (sig_b
[i
*width
+ index
] == q
) {
91 RTLIL::SigSpec s
= mux_cell_int
.first
->getPort("\\B");
92 s
[i
*width
+ index
] = RTLIL::Sx
;
93 mux_cell_int
.first
->setPort("\\B", s
);
99 pattern_t path_else
= path
;
101 for (int i
= 0; i
< GetSize(sig_s
); i
++)
103 if (path
.count(sig_s
[i
]))
106 pattern_t path_this
= path
;
107 path_else
[sig_s
[i
]] = false;
108 path_this
[sig_s
[i
]] = true;
110 for (auto &pat
: find_muxtree_feedback_patterns(sig_b
[i
*width
+ index
], q
, path_this
))
113 if (sig_b
[i
*width
+ index
] == q
) {
114 RTLIL::SigSpec s
= mux_cell_int
.first
->getPort("\\B");
115 s
[i
*width
+ index
] = RTLIL::Sx
;
116 mux_cell_int
.first
->setPort("\\B", s
);
120 for (auto &pat
: find_muxtree_feedback_patterns(sig_a
[index
], q
, path_else
))
123 if (sig_a
[index
] == q
) {
124 RTLIL::SigSpec s
= mux_cell_int
.first
->getPort("\\A");
125 s
[index
] = RTLIL::Sx
;
126 mux_cell_int
.first
->setPort("\\A", s
);
132 void simplify_patterns(patterns_t
&)
137 RTLIL::SigSpec
make_patterns_logic(patterns_t patterns
, bool make_gates
)
139 RTLIL::SigSpec or_input
;
141 for (auto pat
: patterns
)
143 RTLIL::SigSpec s1
, s2
;
144 for (auto it
: pat
) {
146 s2
.append(it
.second
);
149 RTLIL::SigSpec y
= module
->addWire(NEW_ID
);
150 RTLIL::Cell
*c
= module
->addNe(NEW_ID
, s1
, s2
, y
);
153 simplemap(module
, c
);
160 if (GetSize(or_input
) == 0)
163 if (GetSize(or_input
) == 1)
166 RTLIL::SigSpec y
= module
->addWire(NEW_ID
);
167 RTLIL::Cell
*c
= module
->addReduceOr(NEW_ID
, or_input
, y
);
170 simplemap(module
, c
);
177 void handle_dff_cell(RTLIL::Cell
*dff_cell
)
179 RTLIL::SigSpec sig_d
= sigmap(dff_cell
->getPort("\\D"));
180 RTLIL::SigSpec sig_q
= sigmap(dff_cell
->getPort("\\Q"));
182 std::map
<patterns_t
, std::set
<int>> grouped_patterns
;
183 std::set
<int> remaining_indices
;
185 for (int i
= 0 ; i
< GetSize(sig_d
); i
++) {
186 patterns_t patterns
= find_muxtree_feedback_patterns(sig_d
[i
], sig_q
[i
], pattern_t());
187 if (!patterns
.empty()) {
188 simplify_patterns(patterns
);
189 grouped_patterns
[patterns
].insert(i
);
191 remaining_indices
.insert(i
);
194 for (auto &it
: grouped_patterns
) {
195 RTLIL::SigSpec new_sig_d
, new_sig_q
;
196 for (int i
: it
.second
) {
197 new_sig_d
.append(sig_d
[i
]);
198 new_sig_q
.append(sig_q
[i
]);
200 if (dff_cell
->type
== "$dff") {
201 RTLIL::Cell
*new_cell
= module
->addDffe(NEW_ID
, dff_cell
->getPort("\\CLK"), make_patterns_logic(it
.first
, false),
202 new_sig_d
, new_sig_q
, dff_cell
->getParam("\\CLK_POLARITY").as_bool(), true);
203 log(" created $dffe cell %s for %s -> %s.\n", log_id(new_cell
), log_signal(new_sig_d
), log_signal(new_sig_q
));
205 RTLIL::Cell
*new_cell
= module
->addDffeGate(NEW_ID
, dff_cell
->getPort("\\C"), make_patterns_logic(it
.first
, true),
206 new_sig_d
, new_sig_q
, dff_cell
->type
== "$_DFF_P_", true);
207 log(" created %s cell %s for %s -> %s.\n", log_id(new_cell
->type
), log_id(new_cell
), log_signal(new_sig_d
), log_signal(new_sig_q
));
211 if (remaining_indices
.empty()) {
212 log(" removing now obsolete cell %s.\n", log_id(dff_cell
));
213 module
->remove(dff_cell
);
214 } else if (GetSize(remaining_indices
) != GetSize(sig_d
)) {
215 log(" removing %d now obsolete bits from cell %s.\n", GetSize(sig_d
) - GetSize(remaining_indices
), log_id(dff_cell
));
216 RTLIL::SigSpec new_sig_d
, new_sig_q
;
217 for (int i
: remaining_indices
) {
218 new_sig_d
.append(sig_d
[i
]);
219 new_sig_q
.append(sig_q
[i
]);
221 dff_cell
->setPort("\\D", new_sig_d
);
222 dff_cell
->setPort("\\Q", new_sig_q
);
223 dff_cell
->setParam("\\WIDTH", GetSize(remaining_indices
));
229 log("Transforming $dff to $dffe cells in module %s:\n", log_id(module
));
230 for (auto dff_cell
: dff_cells
)
231 handle_dff_cell(dff_cell
);
235 struct Dff2dffePass
: public Pass
{
236 Dff2dffePass() : Pass("dff2dffe", "transform $dff cells to $dffe cells") { }
239 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
241 log(" dff2dffe [selection]\n");
243 log("This pass transforms $dff cells driven by a tree of multiplexers with one or\n");
244 log("more feedback paths to $dffe cells.\n");
247 virtual void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
)
249 log_header("Executing DFF2DFFE pass (transform $dff to $dffe where applicable).\n");
252 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
253 // if (args[argidx] == "-foobar") {
254 // foobar_mode = true;
259 extra_args(args
, argidx
, design
);
261 for (auto mod
: design
->selected_modules())
262 if (!mod
->has_processes_warn()) {
263 Dff2dffeWorker
worker(mod
);
269 PRIVATE_NAMESPACE_END