20627d601e7818be892e26095b27e21093ba5a15
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
, ID($slice
));
79 cell
->parameters
[ID::OFFSET
] = offset
;
80 cell
->parameters
[ID::A_WIDTH
] = sig_a
.size();
81 cell
->parameters
[ID::Y_WIDTH
] = sig
.size();
82 cell
->setPort(ID::A
, sig_a
);
83 cell
->setPort(ID::Y
, module
->addWire(NEW_ID
, sig
.size()));
84 new_sig
= cell
->getPort(ID::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
== nullptr)
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
, ID($concat
));
136 cell
->parameters
[ID::A_WIDTH
] = new_sig
.size();
137 cell
->parameters
[ID::B_WIDTH
] = sig2
.size();
138 cell
->setPort(ID::A
, new_sig
);
139 cell
->setPort(ID::B
, sig2
);
140 cell
->setPort(ID::Y
, module
->addWire(NEW_ID
, new_sig
.size() + sig2
.size()));
141 new_sig
= cell
->getPort(ID::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", log_id(module
->name
));
154 driven_bits
.push_back(RTLIL::State::Sm
);
155 driven_bits
.push_back(RTLIL::State::Sm
);
157 for (auto wire
: module
->wires())
158 if (wire
->port_input
) {
159 RTLIL::SigSpec sig
= sigmap(wire
);
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 cell
: module
->cells())
167 for (auto &conn
: cell
->connections())
168 if (!ct
.cell_known(cell
->type
) || ct
.cell_output(cell
->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 wire
: module
->selected_wires())
184 selected_bits
.add(sigmap(wire
));
186 std::vector
<Cell
*> mod_cells
= module
->cells();
188 for (auto cell
: mod_cells
) {
189 if (!sel_by_wire
&& !design
->selected(module
, cell
))
191 for (auto &conn
: cell
->connections_
)
192 if (ct
.cell_input(cell
->type
, conn
.first
)) {
193 if (ports
.size() > 0 && !ports
.count(conn
.first
))
195 if (no_ports
.size() > 0 && no_ports
.count(conn
.first
))
197 RTLIL::SigSpec sig
= sigmap(conn
.second
);
199 if (!sel_any_bit
&& !selected_bits
.check_all(sig
))
201 if (sel_any_bit
&& !selected_bits
.check_any(sig
))
204 if (driven_chunks
.count(sig
) > 0)
206 conn
.second
= get_spliced_signal(sig
);
210 std::vector
<std::pair
<RTLIL::Wire
*, RTLIL::SigSpec
>> rework_wires
;
211 std::vector
<Wire
*> mod_wires
= module
->wires();
213 for (auto wire
: mod_wires
)
214 if ((!no_outputs
&& wire
->port_output
) || (do_wires
&& wire
->name
[0] == '\\')) {
215 if (!design
->selected(module
, wire
))
217 RTLIL::SigSpec sig
= sigmap(wire
);
218 if (driven_chunks
.count(sig
) > 0)
220 RTLIL::SigSpec new_sig
= get_spliced_signal(sig
);
222 rework_wires
.push_back(std::pair
<RTLIL::Wire
*, RTLIL::SigSpec
>(wire
, new_sig
));
224 if (!wire
->port_input
) {
225 RTLIL::SigSpec sig
= sigmap(wire
);
226 if (spliced_signals_cache
.count(sig
) && spliced_signals_cache
.at(sig
) != sig
)
227 rework_wires
.push_back(std::pair
<RTLIL::Wire
*, RTLIL::SigSpec
>(wire
, spliced_signals_cache
.at(sig
)));
228 else if (sliced_signals_cache
.count(sig
) && sliced_signals_cache
.at(sig
) != sig
)
229 rework_wires
.push_back(std::pair
<RTLIL::Wire
*, RTLIL::SigSpec
>(wire
, sliced_signals_cache
.at(sig
)));
232 for (auto &it
: rework_wires
)
234 RTLIL::IdString orig_name
= it
.first
->name
;
235 module
->rename(it
.first
, NEW_ID
);
237 RTLIL::Wire
*new_port
= module
->addWire(orig_name
, it
.first
);
238 it
.first
->port_id
= 0;
239 it
.first
->port_input
= false;
240 it
.first
->port_output
= false;
242 module
->connect(RTLIL::SigSig(new_port
, it
.second
));
247 struct SplicePass
: public Pass
{
248 SplicePass() : Pass("splice", "create explicit splicing cells") { }
251 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
253 log(" splice [options] [selection]\n");
255 log("This command adds $slice and $concat cells to the design to make the splicing\n");
256 log("of multi-bit signals explicit. This for example is useful for coarse grain\n");
257 log("synthesis, where dedicated hardware is needed to splice signals.\n");
259 log(" -sel_by_cell\n");
260 log(" only select the cell ports to rewire by the cell. if the selection\n");
261 log(" contains a cell, than all cell inputs are rewired, if necessary.\n");
263 log(" -sel_by_wire\n");
264 log(" only select the cell ports to rewire by the wire. if the selection\n");
265 log(" contains a wire, than all cell ports driven by this wire are wired,\n");
266 log(" if necessary.\n");
268 log(" -sel_any_bit\n");
269 log(" it is sufficient if the driver of any bit of a cell port is selected.\n");
270 log(" by default all bits must be selected.\n");
273 log(" also add $slice and $concat cells to drive otherwise unused wires.\n");
275 log(" -no_outputs\n");
276 log(" do not rewire selected module outputs.\n");
278 log(" -port <name>\n");
279 log(" only rewire cell ports with the specified name. can be used multiple\n");
280 log(" times. implies -no_output.\n");
282 log(" -no_port <name>\n");
283 log(" do not rewire cell ports with the specified name. can be used multiple\n");
284 log(" times. can not be combined with -port <name>.\n");
286 log("By default selected output wires and all cell ports of selected cells driven\n");
287 log("by selected wires are rewired.\n");
290 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) override
292 bool sel_by_cell
= false;
293 bool sel_by_wire
= false;
294 bool sel_any_bit
= false;
295 bool no_outputs
= false;
296 bool do_wires
= false;
297 std::set
<RTLIL::IdString
> ports
, no_ports
;
300 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
301 if (args
[argidx
] == "-sel_by_cell") {
305 if (args
[argidx
] == "-sel_by_wire") {
309 if (args
[argidx
] == "-sel_any_bit") {
313 if (args
[argidx
] == "-wires") {
317 if (args
[argidx
] == "-no_outputs") {
321 if (args
[argidx
] == "-port" && argidx
+1 < args
.size()) {
322 ports
.insert(RTLIL::escape_id(args
[++argidx
]));
326 if (args
[argidx
] == "-no_port" && argidx
+1 < args
.size()) {
327 no_ports
.insert(RTLIL::escape_id(args
[++argidx
]));
332 extra_args(args
, argidx
, design
);
334 if (sel_by_cell
&& sel_by_wire
)
335 log_cmd_error("The options -sel_by_cell and -sel_by_wire are exclusive!\n");
337 if (sel_by_cell
&& sel_any_bit
)
338 log_cmd_error("The options -sel_by_cell and -sel_any_bit are exclusive!\n");
340 if (!ports
.empty() && !no_ports
.empty())
341 log_cmd_error("The options -port and -no_port are exclusive!\n");
343 log_header(design
, "Executing SPLICE pass (creating cells for signal splicing).\n");
345 for (auto module
: design
->selected_modules())
347 if (module
->processes
.size()) {
348 log("Skipping module %s as it contains processes.\n", module
->name
.c_str());
352 SpliceWorker
worker(design
, module
);
353 worker
.sel_by_cell
= sel_by_cell
;
354 worker
.sel_by_wire
= sel_by_wire
;
355 worker
.sel_any_bit
= sel_any_bit
;
356 worker
.no_outputs
= no_outputs
;
357 worker
.do_wires
= do_wires
;
358 worker
.ports
= ports
;
359 worker
.no_ports
= no_ports
;
365 PRIVATE_NAMESPACE_END