Merge pull request #1085 from YosysHQ/eddie/shregmap_improve
[yosys.git] / passes / cmds / splice.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5 *
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.
9 *
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.
17 *
18 */
19
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"
25 #include <tuple>
26
27 USING_YOSYS_NAMESPACE
28 PRIVATE_NAMESPACE_BEGIN
29
30 struct SpliceWorker
31 {
32 RTLIL::Design *design;
33 RTLIL::Module *module;
34
35 bool sel_by_cell;
36 bool sel_by_wire;
37 bool sel_any_bit;
38 bool no_outputs;
39 bool do_wires;
40
41 std::set<RTLIL::IdString> ports;
42 std::set<RTLIL::IdString> no_ports;
43
44 CellTypes ct;
45 SigMap sigmap;
46
47 std::vector<RTLIL::SigBit> driven_bits;
48 std::map<RTLIL::SigBit, int> driven_bits_map;
49
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;
53
54 SpliceWorker(RTLIL::Design *design, RTLIL::Module *module) : design(design), module(module), ct(design), sigmap(module)
55 {
56 }
57
58 RTLIL::SigSpec get_sliced_signal(RTLIL::SigSpec sig)
59 {
60 if (sig.size() == 0 || sig.is_fully_const())
61 return sig;
62
63 if (sliced_signals_cache.count(sig))
64 return sliced_signals_cache.at(sig);
65
66 int offset = 0;
67 int p = driven_bits_map.at(sig.extract(0, 1).as_bit()) - 1;
68 while (driven_bits.at(p) != RTLIL::State::Sm)
69 p--, offset++;
70
71 RTLIL::SigSpec sig_a;
72 for (p++; driven_bits.at(p) != RTLIL::State::Sm; p++)
73 sig_a.append(driven_bits.at(p));
74
75 RTLIL::SigSpec new_sig = sig;
76
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");
85 }
86
87 sliced_signals_cache[sig] = new_sig;
88
89 return new_sig;
90 }
91
92 RTLIL::SigSpec get_spliced_signal(RTLIL::SigSpec sig)
93 {
94 if (sig.size() == 0 || sig.is_fully_const())
95 return sig;
96
97 if (spliced_signals_cache.count(sig))
98 return spliced_signals_cache.at(sig);
99
100 int last_bit = -1;
101 std::vector<RTLIL::SigSpec> chunks;
102
103 for (auto &bit : sig.to_sigbit_vector())
104 {
105 if (bit.wire == NULL)
106 {
107 if (last_bit == 0)
108 chunks.back().append(bit);
109 else
110 chunks.push_back(bit);
111 last_bit = 0;
112 continue;
113 }
114
115 if (driven_bits_map.count(bit))
116 {
117 int this_bit = driven_bits_map.at(bit);
118 if (last_bit+1 == this_bit)
119 chunks.back().append(bit);
120 else
121 chunks.push_back(bit);
122 last_bit = this_bit;
123 continue;
124 }
125
126 log(" Failed to generate spliced signal %s.\n", log_signal(sig));
127 spliced_signals_cache[sig] = sig;
128 return sig;
129 }
130
131
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");
142 }
143
144 spliced_signals_cache[sig] = new_sig;
145
146 log(" Created spliced signal: %s -> %s\n", log_signal(sig), log_signal(new_sig));
147 return new_sig;
148 }
149
150 void run()
151 {
152 log("Splicing signals in module %s:\n", RTLIL::id2cstr(module->name));
153
154 driven_bits.push_back(RTLIL::State::Sm);
155 driven_bits.push_back(RTLIL::State::Sm);
156
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);
164 }
165
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);
174 }
175
176 driven_bits.push_back(RTLIL::State::Sm);
177
178 for (size_t i = 0; i < driven_bits.size(); i++)
179 driven_bits_map[driven_bits[i]] = i;
180
181 SigPool selected_bits;
182 if (!sel_by_cell)
183 for (auto &it : module->wires_)
184 if (design->selected(module, it.second))
185 selected_bits.add(sigmap(it.second));
186
187 std::vector<Cell*> mod_cells = module->cells();
188
189 for (auto cell : mod_cells) {
190 if (!sel_by_wire && !design->selected(module, cell))
191 continue;
192 for (auto &conn : cell->connections_)
193 if (ct.cell_input(cell->type, conn.first)) {
194 if (ports.size() > 0 && !ports.count(conn.first))
195 continue;
196 if (no_ports.size() > 0 && no_ports.count(conn.first))
197 continue;
198 RTLIL::SigSpec sig = sigmap(conn.second);
199 if (!sel_by_cell) {
200 if (!sel_any_bit && !selected_bits.check_all(sig))
201 continue;
202 if (sel_any_bit && !selected_bits.check_any(sig))
203 continue;
204 }
205 if (driven_chunks.count(sig) > 0)
206 continue;
207 conn.second = get_spliced_signal(sig);
208 }
209 }
210
211 std::vector<std::pair<RTLIL::Wire*, RTLIL::SigSpec>> rework_wires;
212 std::vector<Wire*> mod_wires = module->wires();
213
214 for (auto wire : mod_wires)
215 if ((!no_outputs && wire->port_output) || (do_wires && wire->name[0] == '\\')) {
216 if (!design->selected(module, wire))
217 continue;
218 RTLIL::SigSpec sig = sigmap(wire);
219 if (driven_chunks.count(sig) > 0)
220 continue;
221 RTLIL::SigSpec new_sig = get_spliced_signal(sig);
222 if (new_sig != sig)
223 rework_wires.push_back(std::pair<RTLIL::Wire*, RTLIL::SigSpec>(wire, new_sig));
224 } else
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)));
231 }
232
233 for (auto &it : rework_wires)
234 {
235 RTLIL::IdString orig_name = it.first->name;
236 module->rename(it.first, NEW_ID);
237
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;
242
243 module->connect(RTLIL::SigSig(new_port, it.second));
244 }
245 }
246 };
247
248 struct SplicePass : public Pass {
249 SplicePass() : Pass("splice", "create explicit splicing cells") { }
250 void help() YS_OVERRIDE
251 {
252 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
253 log("\n");
254 log(" splice [options] [selection]\n");
255 log("\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");
259 log("\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");
263 log("\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");
268 log("\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");
272 log("\n");
273 log(" -wires\n");
274 log(" also add $slice and $concat cells to drive otherwise unused wires.\n");
275 log("\n");
276 log(" -no_outputs\n");
277 log(" do not rewire selected module outputs.\n");
278 log("\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");
282 log("\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");
286 log("\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");
289 log("\n");
290 }
291 void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
292 {
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;
299
300 size_t argidx;
301 for (argidx = 1; argidx < args.size(); argidx++) {
302 if (args[argidx] == "-sel_by_cell") {
303 sel_by_cell = true;
304 continue;
305 }
306 if (args[argidx] == "-sel_by_wire") {
307 sel_by_wire = true;
308 continue;
309 }
310 if (args[argidx] == "-sel_any_bit") {
311 sel_any_bit = true;
312 continue;
313 }
314 if (args[argidx] == "-wires") {
315 do_wires = true;
316 continue;
317 }
318 if (args[argidx] == "-no_outputs") {
319 no_outputs = true;
320 continue;
321 }
322 if (args[argidx] == "-port" && argidx+1 < args.size()) {
323 ports.insert(RTLIL::escape_id(args[++argidx]));
324 no_outputs = true;
325 continue;
326 }
327 if (args[argidx] == "-no_port" && argidx+1 < args.size()) {
328 no_ports.insert(RTLIL::escape_id(args[++argidx]));
329 continue;
330 }
331 break;
332 }
333 extra_args(args, argidx, design);
334
335 if (sel_by_cell && sel_by_wire)
336 log_cmd_error("The options -sel_by_cell and -sel_by_wire are exclusive!\n");
337
338 if (sel_by_cell && sel_any_bit)
339 log_cmd_error("The options -sel_by_cell and -sel_any_bit are exclusive!\n");
340
341 if (!ports.empty() && !no_ports.empty())
342 log_cmd_error("The options -port and -no_port are exclusive!\n");
343
344 log_header(design, "Executing SPLICE pass (creating cells for signal splicing).\n");
345
346 for (auto &mod_it : design->modules_)
347 {
348 if (!design->selected(mod_it.second))
349 continue;
350
351 if (mod_it.second->processes.size()) {
352 log("Skipping module %s as it contains processes.\n", mod_it.second->name.c_str());
353 continue;
354 }
355
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;
364 worker.run();
365 }
366 }
367 } SplicePass;
368
369 PRIVATE_NAMESPACE_END