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/rtlil.h"
23 #include "kernel/log.h"
26 PRIVATE_NAMESPACE_BEGIN
28 struct SplitnetsWorker
30 std::map
<RTLIL::Wire
*, std::vector
<RTLIL::SigBit
>> splitmap
;
32 void append_wire(RTLIL::Module
*module
, RTLIL::Wire
*wire
, int offset
, int width
, std::string format
)
34 std::string new_wire_name
= wire
->name
.str();
36 if (format
.size() > 0)
37 new_wire_name
+= format
.substr(0, 1);
40 new_wire_name
+= stringf("%d", offset
+width
-1);
41 if (format
.size() > 2)
42 new_wire_name
+= format
.substr(2, 1);
47 new_wire_name
+= stringf("%d", offset
);
49 if (format
.size() > 1)
50 new_wire_name
+= format
.substr(1, 1);
52 RTLIL::Wire
*new_wire
= module
->addWire(module
->uniquify(new_wire_name
), width
);
53 new_wire
->port_id
= wire
->port_id
;
54 new_wire
->port_input
= wire
->port_input
;
55 new_wire
->port_output
= wire
->port_output
;
57 std::vector
<RTLIL::SigBit
> sigvec
= RTLIL::SigSpec(new_wire
).to_sigbit_vector();
58 splitmap
[wire
].insert(splitmap
[wire
].end(), sigvec
.begin(), sigvec
.end());
61 void operator()(RTLIL::SigSpec
&sig
)
64 if (splitmap
.count(bit
.wire
) > 0)
65 bit
= splitmap
.at(bit
.wire
).at(bit
.offset
);
69 struct SplitnetsPass
: public Pass
{
70 SplitnetsPass() : Pass("splitnets", "split up multi-bit nets") { }
73 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
75 log(" splitnets [options] [selection]\n");
77 log("This command splits multi-bit nets into single-bit nets.\n");
79 log(" -format char1[char2[char3]]\n");
80 log(" the first char is inserted between the net name and the bit index, the\n");
81 log(" second char is appended to the netname. e.g. -format () creates net\n");
82 log(" names like 'mysignal(42)'. the 3rd character is the range separation\n");
83 log(" character when creating multi-bit wires. the default is '[]:'.\n");
86 log(" also split module ports. per default only internal signals are split.\n");
89 log(" don't blindly split nets in individual bits. instead look at the driver\n");
90 log(" and split nets so that no driver drives only part of a net.\n");
93 virtual void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
)
95 bool flag_ports
= false;
96 bool flag_driver
= false;
97 std::string format
= "[]:";
99 log_header("Executing SPLITNETS pass (splitting up multi-bit signals).\n");
102 for (argidx
= 1; argidx
< args
.size(); argidx
++)
104 if (args
[argidx
] == "-format" && argidx
+1 < args
.size()) {
105 format
= args
[++argidx
];
108 if (args
[argidx
] == "-ports") {
112 if (args
[argidx
] == "-driver") {
118 extra_args(args
, argidx
, design
);
120 for (auto &mod_it
: design
->modules_
)
122 RTLIL::Module
*module
= mod_it
.second
;
123 if (!design
->selected(module
))
126 SplitnetsWorker worker
;
130 CellTypes
ct(design
);
132 std::map
<RTLIL::Wire
*, std::set
<int>> split_wires_at
;
134 for (auto &c
: module
->cells_
)
135 for (auto &p
: c
.second
->connections())
137 if (!ct
.cell_known(c
.second
->type
))
139 if (!ct
.cell_output(c
.second
->type
, p
.first
))
142 RTLIL::SigSpec sig
= p
.second
;
143 for (auto &chunk
: sig
.chunks()) {
144 if (chunk
.wire
== NULL
)
146 if (chunk
.wire
->port_id
== 0 || flag_ports
) {
147 if (chunk
.offset
!= 0)
148 split_wires_at
[chunk
.wire
].insert(chunk
.offset
);
149 if (chunk
.offset
+ chunk
.width
< chunk
.wire
->width
)
150 split_wires_at
[chunk
.wire
].insert(chunk
.offset
+ chunk
.width
);
155 for (auto &it
: split_wires_at
) {
157 for (int next_cursor
: it
.second
) {
158 worker
.append_wire(module
, it
.first
, cursor
, next_cursor
- cursor
, format
);
159 cursor
= next_cursor
;
161 worker
.append_wire(module
, it
.first
, cursor
, it
.first
->width
- cursor
, format
);
166 for (auto &w
: module
->wires_
) {
167 RTLIL::Wire
*wire
= w
.second
;
168 if (wire
->width
> 1 && (wire
->port_id
== 0 || flag_ports
) && design
->selected(module
, w
.second
))
169 worker
.splitmap
[wire
] = std::vector
<RTLIL::SigBit
>();
172 for (auto &it
: worker
.splitmap
)
173 for (int i
= 0; i
< it
.first
->width
; i
++)
174 worker
.append_wire(module
, it
.first
, i
, 1, format
);
177 module
->rewrite_sigspecs(worker
);
179 nodict
<RTLIL::Wire
*> delete_wires
;
180 for (auto &it
: worker
.splitmap
)
181 delete_wires
.insert(it
.first
);
182 module
->remove(delete_wires
);
184 module
->fixup_ports();
189 PRIVATE_NAMESPACE_END