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/celltypes.h"
22 #include "kernel/sigtools.h"
23 #include "kernel/rtlil.h"
24 #include "kernel/log.h"
28 PRIVATE_NAMESPACE_BEGIN
32 RTLIL::Design
*design
;
33 RTLIL::Module
*module
;
41 std::set
<RTLIL::IdString
> ports
;
42 std::set
<RTLIL::IdString
> no_ports
;
47 std::vector
<RTLIL::SigBit
> driven_bits
;
48 std::map
<RTLIL::SigBit
, int> driven_bits_map
;
50 std::set
<RTLIL::SigSpec
> driven_chunks
;
51 std::map
<RTLIL::SigSpec
, RTLIL::SigSpec
> spliced_signals_cache
;
52 std::map
<RTLIL::SigSpec
, RTLIL::SigSpec
> sliced_signals_cache
;
54 SpliceWorker(RTLIL::Design
*design
, RTLIL::Module
*module
) : design(design
), module(module
), ct(design
), sigmap(module
)
58 RTLIL::SigSpec
get_sliced_signal(RTLIL::SigSpec sig
)
60 if (sig
.size() == 0 || sig
.is_fully_const())
63 if (sliced_signals_cache
.count(sig
))
64 return sliced_signals_cache
.at(sig
);
67 int p
= driven_bits_map
.at(sig
.extract(0, 1).as_bit()) - 1;
68 while (driven_bits
.at(p
) != RTLIL::State::Sm
)
72 for (p
++; driven_bits
.at(p
) != RTLIL::State::Sm
; p
++)
73 sig_a
.append(driven_bits
.at(p
));
75 RTLIL::SigSpec new_sig
= sig
;
77 if (sig_a
.size() != sig
.size()) {
78 RTLIL::Cell
*cell
= module
->addCell(NEW_ID
, "$slice");
79 cell
->parameters
["\\OFFSET"] = offset
;
80 cell
->parameters
["\\A_WIDTH"] = sig_a
.size();
81 cell
->parameters
["\\Y_WIDTH"] = sig
.size();
82 cell
->setPort("\\A", sig_a
);
83 cell
->setPort("\\Y", module
->addWire(NEW_ID
, sig
.size()));
84 new_sig
= cell
->getPort("\\Y");
87 sliced_signals_cache
[sig
] = new_sig
;
92 RTLIL::SigSpec
get_spliced_signal(RTLIL::SigSpec sig
)
94 if (sig
.size() == 0 || sig
.is_fully_const())
97 if (spliced_signals_cache
.count(sig
))
98 return spliced_signals_cache
.at(sig
);
101 std::vector
<RTLIL::SigSpec
> chunks
;
103 for (auto &bit
: sig
.to_sigbit_vector())
105 if (bit
.wire
== NULL
)
108 chunks
.back().append(bit
);
110 chunks
.push_back(bit
);
115 if (driven_bits_map
.count(bit
))
117 int this_bit
= driven_bits_map
.at(bit
);
118 if (last_bit
+1 == this_bit
)
119 chunks
.back().append(bit
);
121 chunks
.push_back(bit
);
126 log(" Failed to generate spliced signal %s.\n", log_signal(sig
));
127 spliced_signals_cache
[sig
] = sig
;
132 RTLIL::SigSpec new_sig
= get_sliced_signal(chunks
.front());
133 for (size_t i
= 1; i
< chunks
.size(); i
++) {
134 RTLIL::SigSpec sig2
= get_sliced_signal(chunks
[i
]);
135 RTLIL::Cell
*cell
= module
->addCell(NEW_ID
, "$concat");
136 cell
->parameters
["\\A_WIDTH"] = new_sig
.size();
137 cell
->parameters
["\\B_WIDTH"] = sig2
.size();
138 cell
->setPort("\\A", new_sig
);
139 cell
->setPort("\\B", sig2
);
140 cell
->setPort("\\Y", module
->addWire(NEW_ID
, new_sig
.size() + sig2
.size()));
141 new_sig
= cell
->getPort("\\Y");
144 spliced_signals_cache
[sig
] = new_sig
;
146 log(" Created spliced signal: %s -> %s\n", log_signal(sig
), log_signal(new_sig
));
152 log("Splicing signals in module %s:\n", RTLIL::id2cstr(module
->name
));
154 driven_bits
.push_back(RTLIL::State::Sm
);
155 driven_bits
.push_back(RTLIL::State::Sm
);
157 for (auto &it
: module
->wires_
)
158 if (it
.second
->port_input
) {
159 RTLIL::SigSpec sig
= sigmap(it
.second
);
160 driven_chunks
.insert(sig
);
161 for (auto &bit
: sig
.to_sigbit_vector())
162 driven_bits
.push_back(bit
);
163 driven_bits
.push_back(RTLIL::State::Sm
);
166 for (auto &it
: module
->cells_
)
167 for (auto &conn
: it
.second
->connections())
168 if (!ct
.cell_known(it
.second
->type
) || ct
.cell_output(it
.second
->type
, conn
.first
)) {
169 RTLIL::SigSpec sig
= sigmap(conn
.second
);
170 driven_chunks
.insert(sig
);
171 for (auto &bit
: sig
.to_sigbit_vector())
172 driven_bits
.push_back(bit
);
173 driven_bits
.push_back(RTLIL::State::Sm
);
176 driven_bits
.push_back(RTLIL::State::Sm
);
178 for (size_t i
= 0; i
< driven_bits
.size(); i
++)
179 driven_bits_map
[driven_bits
[i
]] = i
;
181 SigPool selected_bits
;
183 for (auto &it
: module
->wires_
)
184 if (design
->selected(module
, it
.second
))
185 selected_bits
.add(sigmap(it
.second
));
187 std::vector
<Cell
*> mod_cells
= module
->cells();
189 for (auto cell
: mod_cells
) {
190 if (!sel_by_wire
&& !design
->selected(module
, cell
))
192 for (auto &conn
: cell
->connections_
)
193 if (ct
.cell_input(cell
->type
, conn
.first
)) {
194 if (ports
.size() > 0 && !ports
.count(conn
.first
))
196 if (no_ports
.size() > 0 && no_ports
.count(conn
.first
))
198 RTLIL::SigSpec sig
= sigmap(conn
.second
);
200 if (!sel_any_bit
&& !selected_bits
.check_all(sig
))
202 if (sel_any_bit
&& !selected_bits
.check_any(sig
))
205 if (driven_chunks
.count(sig
) > 0)
207 conn
.second
= get_spliced_signal(sig
);
211 std::vector
<std::pair
<RTLIL::Wire
*, RTLIL::SigSpec
>> rework_wires
;
212 std::vector
<Wire
*> mod_wires
= module
->wires();
214 for (auto wire
: mod_wires
)
215 if ((!no_outputs
&& wire
->port_output
) || (do_wires
&& wire
->name
[0] == '\\')) {
216 if (!design
->selected(module
, wire
))
218 RTLIL::SigSpec sig
= sigmap(wire
);
219 if (driven_chunks
.count(sig
) > 0)
221 RTLIL::SigSpec new_sig
= get_spliced_signal(sig
);
223 rework_wires
.push_back(std::pair
<RTLIL::Wire
*, RTLIL::SigSpec
>(wire
, new_sig
));
225 if (!wire
->port_input
) {
226 RTLIL::SigSpec sig
= sigmap(wire
);
227 if (spliced_signals_cache
.count(sig
) && spliced_signals_cache
.at(sig
) != sig
)
228 rework_wires
.push_back(std::pair
<RTLIL::Wire
*, RTLIL::SigSpec
>(wire
, spliced_signals_cache
.at(sig
)));
229 else if (sliced_signals_cache
.count(sig
) && sliced_signals_cache
.at(sig
) != sig
)
230 rework_wires
.push_back(std::pair
<RTLIL::Wire
*, RTLIL::SigSpec
>(wire
, sliced_signals_cache
.at(sig
)));
233 for (auto &it
: rework_wires
)
235 RTLIL::IdString orig_name
= it
.first
->name
;
236 module
->rename(it
.first
, NEW_ID
);
238 RTLIL::Wire
*new_port
= module
->addWire(orig_name
, it
.first
);
239 it
.first
->port_id
= 0;
240 it
.first
->port_input
= false;
241 it
.first
->port_output
= false;
243 module
->connect(RTLIL::SigSig(new_port
, it
.second
));
248 struct SplicePass
: public Pass
{
249 SplicePass() : Pass("splice", "create explicit splicing cells") { }
250 void help() YS_OVERRIDE
252 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
254 log(" splice [options] [selection]\n");
256 log("This command adds $slice and $concat cells to the design to make the splicing\n");
257 log("of multi-bit signals explicit. This for example is useful for coarse grain\n");
258 log("synthesis, where dedicated hardware is needed to splice signals.\n");
260 log(" -sel_by_cell\n");
261 log(" only select the cell ports to rewire by the cell. if the selection\n");
262 log(" contains a cell, than all cell inputs are rewired, if necessary.\n");
264 log(" -sel_by_wire\n");
265 log(" only select the cell ports to rewire by the wire. if the selection\n");
266 log(" contains a wire, than all cell ports driven by this wire are wired,\n");
267 log(" if necessary.\n");
269 log(" -sel_any_bit\n");
270 log(" it is sufficient if the driver of any bit of a cell port is selected.\n");
271 log(" by default all bits must be selected.\n");
274 log(" also add $slice and $concat cells to drive otherwise unused wires.\n");
276 log(" -no_outputs\n");
277 log(" do not rewire selected module outputs.\n");
279 log(" -port <name>\n");
280 log(" only rewire cell ports with the specified name. can be used multiple\n");
281 log(" times. implies -no_output.\n");
283 log(" -no_port <name>\n");
284 log(" do not rewire cell ports with the specified name. can be used multiple\n");
285 log(" times. can not be combined with -port <name>.\n");
287 log("By default selected output wires and all cell ports of selected cells driven\n");
288 log("by selected wires are rewired.\n");
291 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
293 bool sel_by_cell
= false;
294 bool sel_by_wire
= false;
295 bool sel_any_bit
= false;
296 bool no_outputs
= false;
297 bool do_wires
= false;
298 std::set
<RTLIL::IdString
> ports
, no_ports
;
301 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
302 if (args
[argidx
] == "-sel_by_cell") {
306 if (args
[argidx
] == "-sel_by_wire") {
310 if (args
[argidx
] == "-sel_any_bit") {
314 if (args
[argidx
] == "-wires") {
318 if (args
[argidx
] == "-no_outputs") {
322 if (args
[argidx
] == "-port" && argidx
+1 < args
.size()) {
323 ports
.insert(RTLIL::escape_id(args
[++argidx
]));
327 if (args
[argidx
] == "-no_port" && argidx
+1 < args
.size()) {
328 no_ports
.insert(RTLIL::escape_id(args
[++argidx
]));
333 extra_args(args
, argidx
, design
);
335 if (sel_by_cell
&& sel_by_wire
)
336 log_cmd_error("The options -sel_by_cell and -sel_by_wire are exclusive!\n");
338 if (sel_by_cell
&& sel_any_bit
)
339 log_cmd_error("The options -sel_by_cell and -sel_any_bit are exclusive!\n");
341 if (!ports
.empty() && !no_ports
.empty())
342 log_cmd_error("The options -port and -no_port are exclusive!\n");
344 log_header(design
, "Executing SPLICE pass (creating cells for signal splicing).\n");
346 for (auto &mod_it
: design
->modules_
)
348 if (!design
->selected(mod_it
.second
))
351 if (mod_it
.second
->processes
.size()) {
352 log("Skipping module %s as it contains processes.\n", mod_it
.second
->name
.c_str());
356 SpliceWorker
worker(design
, mod_it
.second
);
357 worker
.sel_by_cell
= sel_by_cell
;
358 worker
.sel_by_wire
= sel_by_wire
;
359 worker
.sel_any_bit
= sel_any_bit
;
360 worker
.no_outputs
= no_outputs
;
361 worker
.do_wires
= do_wires
;
362 worker
.ports
= ports
;
363 worker
.no_ports
= no_ports
;
369 PRIVATE_NAMESPACE_END