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"
25 PRIVATE_NAMESPACE_BEGIN
29 RTLIL::Module
*module
;
33 typedef std::pair
<RTLIL::Cell
*, int> cell_int_t
;
34 std::map
<RTLIL::SigBit
, cell_int_t
> bit2mux
;
35 std::vector
<RTLIL::Cell
*> dff_cells
;
36 std::map
<RTLIL::SigBit
, int> bitusers
;
38 typedef std::map
<RTLIL::SigBit
, bool> pattern_t
;
39 typedef std::set
<pattern_t
> patterns_t
;
41 Dff2dffeWorker(RTLIL::Module
*module
) : module(module
), sigmap(module
), ct(module
->design
)
43 for (auto wire
: module
->wires()) {
44 if (wire
->port_output
)
45 for (auto bit
: sigmap(wire
))
49 for (auto cell
: module
->cells()) {
50 if (cell
->type
== "$mux" || cell
->type
== "$pmux") {
51 RTLIL::SigSpec sig_y
= sigmap(cell
->getPort("\\Y"));
52 for (int i
= 0; i
< GetSize(sig_y
); i
++)
53 bit2mux
[sig_y
[i
]] = cell_int_t(cell
, i
);
55 if (cell
->type
== "$dff")
56 dff_cells
.push_back(cell
);
57 for (auto conn
: cell
->connections()) {
58 if (ct
.cell_output(cell
->type
, conn
.first
))
60 for (auto bit
: sigmap(conn
.second
))
66 patterns_t
find_muxtree_feedback_patterns(RTLIL::SigBit d
, RTLIL::SigBit q
, pattern_t path
)
75 if (bit2mux
.count(d
) == 0 || bitusers
[d
] > 1)
78 cell_int_t mux_cell_int
= bit2mux
.at(d
);
79 RTLIL::SigSpec sig_a
= sigmap(mux_cell_int
.first
->getPort("\\A"));
80 RTLIL::SigSpec sig_b
= sigmap(mux_cell_int
.first
->getPort("\\B"));
81 RTLIL::SigSpec sig_s
= sigmap(mux_cell_int
.first
->getPort("\\S"));
82 int width
= GetSize(sig_a
), index
= mux_cell_int
.second
;
84 for (int i
= 0; i
< GetSize(sig_s
); i
++)
85 if (path
.count(sig_s
[i
]) && path
.at(sig_s
[i
]))
87 ret
= find_muxtree_feedback_patterns(sig_b
[i
*width
+ index
], q
, path
);
89 if (sig_b
[i
*width
+ index
] == q
) {
90 RTLIL::SigSpec s
= mux_cell_int
.first
->getPort("\\B");
91 s
[i
*width
+ index
] = RTLIL::Sx
;
92 mux_cell_int
.first
->setPort("\\B", s
);
98 pattern_t path_else
= path
;
100 for (int i
= 0; i
< GetSize(sig_s
); i
++)
102 if (path
.count(sig_s
[i
]))
105 pattern_t path_this
= path
;
106 path_else
[sig_s
[i
]] = false;
107 path_this
[sig_s
[i
]] = true;
109 for (auto &pat
: find_muxtree_feedback_patterns(sig_b
[i
*width
+ index
], q
, path_this
))
112 if (sig_b
[i
*width
+ index
] == q
) {
113 RTLIL::SigSpec s
= mux_cell_int
.first
->getPort("\\B");
114 s
[i
*width
+ index
] = RTLIL::Sx
;
115 mux_cell_int
.first
->setPort("\\B", s
);
119 for (auto &pat
: find_muxtree_feedback_patterns(sig_a
[index
], q
, path_else
))
122 if (sig_a
[index
] == q
) {
123 RTLIL::SigSpec s
= mux_cell_int
.first
->getPort("\\A");
124 s
[index
] = RTLIL::Sx
;
125 mux_cell_int
.first
->setPort("\\A", s
);
131 void simplify_patterns(patterns_t
&)
136 RTLIL::SigSpec
make_patterns_logic(patterns_t patterns
)
138 RTLIL::SigSpec or_input
;
139 for (auto pat
: patterns
) {
140 RTLIL::SigSpec s1
, s2
;
141 for (auto it
: pat
) {
143 s2
.append(it
.second
);
145 or_input
.append(module
->Ne(NEW_ID
, s1
, s2
));
147 if (GetSize(or_input
) == 0)
149 if (GetSize(or_input
) == 1)
151 return module
->ReduceOr(NEW_ID
, or_input
);
154 void handle_dff_cell(RTLIL::Cell
*dff_cell
)
156 RTLIL::SigSpec sig_d
= sigmap(dff_cell
->getPort("\\D"));
157 RTLIL::SigSpec sig_q
= sigmap(dff_cell
->getPort("\\Q"));
159 std::map
<patterns_t
, std::set
<int>> grouped_patterns
;
160 std::set
<int> remaining_indices
;
162 for (int i
= 0 ; i
< GetSize(sig_d
); i
++) {
163 patterns_t patterns
= find_muxtree_feedback_patterns(sig_d
[i
], sig_q
[i
], pattern_t());
164 if (!patterns
.empty()) {
165 simplify_patterns(patterns
);
166 grouped_patterns
[patterns
].insert(i
);
168 remaining_indices
.insert(i
);
171 for (auto &it
: grouped_patterns
) {
172 RTLIL::SigSpec new_sig_d
, new_sig_q
;
173 for (int i
: it
.second
) {
174 new_sig_d
.append(sig_d
[i
]);
175 new_sig_q
.append(sig_q
[i
]);
177 RTLIL::Cell
*new_cell
= module
->addDffe(NEW_ID
, dff_cell
->getPort("\\CLK"), make_patterns_logic(it
.first
),
178 new_sig_d
, new_sig_q
, dff_cell
->getParam("\\CLK_POLARITY").as_bool(), true);
179 log(" created $dffe cell %s for %s -> %s.\n", log_id(new_cell
), log_signal(new_sig_d
), log_signal(new_sig_q
));
182 if (remaining_indices
.empty()) {
183 log(" removing now obsolete cell %s.\n", log_id(dff_cell
));
184 module
->remove(dff_cell
);
185 } else if (GetSize(remaining_indices
) != GetSize(sig_d
)) {
186 log(" removing %d now obsolete bits from cell %s.\n", GetSize(sig_d
) - GetSize(remaining_indices
), log_id(dff_cell
));
187 RTLIL::SigSpec new_sig_d
, new_sig_q
;
188 for (int i
: remaining_indices
) {
189 new_sig_d
.append(sig_d
[i
]);
190 new_sig_q
.append(sig_q
[i
]);
192 dff_cell
->setPort("\\D", new_sig_d
);
193 dff_cell
->setPort("\\Q", new_sig_q
);
194 dff_cell
->setParam("\\WIDTH", GetSize(remaining_indices
));
200 log("Transforming $dff to $dffe cells in module %s:\n", log_id(module
));
201 for (auto dff_cell
: dff_cells
)
202 handle_dff_cell(dff_cell
);
206 struct Dff2dffePass
: public Pass
{
207 Dff2dffePass() : Pass("dff2dffe", "transform $dff cells to $dffe cells") { }
210 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
212 log(" dff2dffe [selection]\n");
214 log("This pass transforms $dff cells driven by a tree of multiplexers with one or\n");
215 log("more feedback paths to $dffe cells.\n");
218 virtual void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
)
220 log_header("Executing DFF2DFFE pass (transform $dff to $dffe where applicable).\n");
223 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
224 // if (args[argidx] == "-foobar") {
225 // foobar_mode = true;
230 extra_args(args
, argidx
, design
);
232 for (auto mod
: design
->selected_modules())
233 if (!mod
->has_processes_warn()) {
234 Dff2dffeWorker
worker(mod
);
240 PRIVATE_NAMESPACE_END