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);
41 new_wire_name
+= stringf("%d", wire
->start_offset
+wire
->width
-(offset
+width
)-1);
43 new_wire_name
+= stringf("%d", wire
->start_offset
+offset
+width
-1);
44 if (format
.size() > 2)
45 new_wire_name
+= format
.substr(2, 1);
51 new_wire_name
+= stringf("%d", wire
->start_offset
+wire
->width
-offset
-1);
53 new_wire_name
+= stringf("%d", wire
->start_offset
+offset
);
55 if (format
.size() > 1)
56 new_wire_name
+= format
.substr(1, 1);
58 RTLIL::Wire
*new_wire
= module
->addWire(module
->uniquify(new_wire_name
), width
);
59 new_wire
->port_id
= wire
->port_id
? wire
->port_id
+ offset
: 0;
60 new_wire
->port_input
= wire
->port_input
;
61 new_wire
->port_output
= wire
->port_output
;
63 if (wire
->attributes
.count("\\src"))
64 new_wire
->attributes
["\\src"] = wire
->attributes
.at("\\src");
66 if (wire
->attributes
.count("\\keep"))
67 new_wire
->attributes
["\\keep"] = wire
->attributes
.at("\\keep");
69 if (wire
->attributes
.count("\\init")) {
70 Const old_init
= wire
->attributes
.at("\\init"), new_init
;
71 for (int i
= offset
; i
< offset
+width
; i
++)
72 new_init
.bits
.push_back(i
< GetSize(old_init
) ? old_init
.bits
.at(i
) : State::Sx
);
73 new_wire
->attributes
["\\init"] = new_init
;
76 std::vector
<RTLIL::SigBit
> sigvec
= RTLIL::SigSpec(new_wire
).to_sigbit_vector();
77 splitmap
[wire
].insert(splitmap
[wire
].end(), sigvec
.begin(), sigvec
.end());
80 void operator()(RTLIL::SigSpec
&sig
)
83 if (splitmap
.count(bit
.wire
) > 0)
84 bit
= splitmap
.at(bit
.wire
).at(bit
.offset
);
88 struct SplitnetsPass
: public Pass
{
89 SplitnetsPass() : Pass("splitnets", "split up multi-bit nets") { }
90 void help() YS_OVERRIDE
92 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
94 log(" splitnets [options] [selection]\n");
96 log("This command splits multi-bit nets into single-bit nets.\n");
98 log(" -format char1[char2[char3]]\n");
99 log(" the first char is inserted between the net name and the bit index, the\n");
100 log(" second char is appended to the netname. e.g. -format () creates net\n");
101 log(" names like 'mysignal(42)'. the 3rd character is the range separation\n");
102 log(" character when creating multi-bit wires. the default is '[]:'.\n");
105 log(" also split module ports. per default only internal signals are split.\n");
108 log(" don't blindly split nets in individual bits. instead look at the driver\n");
109 log(" and split nets so that no driver drives only part of a net.\n");
112 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
114 bool flag_ports
= false;
115 bool flag_driver
= false;
116 std::string format
= "[]:";
118 log_header(design
, "Executing SPLITNETS pass (splitting up multi-bit signals).\n");
121 for (argidx
= 1; argidx
< args
.size(); argidx
++)
123 if (args
[argidx
] == "-format" && argidx
+1 < args
.size()) {
124 format
= args
[++argidx
];
127 if (args
[argidx
] == "-ports") {
131 if (args
[argidx
] == "-driver") {
137 extra_args(args
, argidx
, design
);
139 // module_ports_db[module_name][old_port_name] = new_port_name_list
140 dict
<IdString
, dict
<IdString
, vector
<IdString
>>> module_ports_db
;
142 for (auto module
: design
->selected_modules())
144 SplitnetsWorker worker
;
148 int normalized_port_factor
= 0;
150 for (auto wire
: module
->wires())
151 if (wire
->port_id
!= 0) {
152 normalized_port_factor
= max(normalized_port_factor
, wire
->port_id
+1);
153 normalized_port_factor
= max(normalized_port_factor
, GetSize(wire
)+1);
156 for (auto wire
: module
->wires())
157 wire
->port_id
*= normalized_port_factor
;
162 CellTypes
ct(design
);
164 std::map
<RTLIL::Wire
*, std::set
<int>> split_wires_at
;
166 for (auto &c
: module
->cells_
)
167 for (auto &p
: c
.second
->connections())
169 if (!ct
.cell_known(c
.second
->type
))
171 if (!ct
.cell_output(c
.second
->type
, p
.first
))
174 RTLIL::SigSpec sig
= p
.second
;
175 for (auto &chunk
: sig
.chunks()) {
176 if (chunk
.wire
== NULL
)
178 if (chunk
.wire
->port_id
== 0 || flag_ports
) {
179 if (chunk
.offset
!= 0)
180 split_wires_at
[chunk
.wire
].insert(chunk
.offset
);
181 if (chunk
.offset
+ chunk
.width
< chunk
.wire
->width
)
182 split_wires_at
[chunk
.wire
].insert(chunk
.offset
+ chunk
.width
);
187 for (auto &it
: split_wires_at
) {
189 for (int next_cursor
: it
.second
) {
190 worker
.append_wire(module
, it
.first
, cursor
, next_cursor
- cursor
, format
);
191 cursor
= next_cursor
;
193 worker
.append_wire(module
, it
.first
, cursor
, it
.first
->width
- cursor
, format
);
198 for (auto &w
: module
->wires_
) {
199 RTLIL::Wire
*wire
= w
.second
;
200 if (wire
->width
> 1 && (wire
->port_id
== 0 || flag_ports
) && design
->selected(module
, w
.second
))
201 worker
.splitmap
[wire
] = std::vector
<RTLIL::SigBit
>();
204 for (auto &it
: worker
.splitmap
)
205 for (int i
= 0; i
< it
.first
->width
; i
++)
206 worker
.append_wire(module
, it
.first
, i
, 1, format
);
209 module
->rewrite_sigspecs(worker
);
213 for (auto wire
: module
->wires())
215 if (wire
->port_id
== 0)
224 vector
<IdString
> &new_ports
= module_ports_db
[module
->name
][wire
->name
];
226 for (SigSpec c
: sig
.chunks())
227 new_ports
.push_back(c
.as_wire()->name
);
231 pool
<RTLIL::Wire
*> delete_wires
;
232 for (auto &it
: worker
.splitmap
)
233 delete_wires
.insert(it
.first
);
234 module
->remove(delete_wires
);
237 module
->fixup_ports();
240 if (!module_ports_db
.empty())
242 for (auto module
: design
->modules())
243 for (auto cell
: module
->cells())
245 if (module_ports_db
.count(cell
->type
) == 0)
248 for (auto &it
: module_ports_db
.at(cell
->type
))
250 IdString port_id
= it
.first
;
251 const auto &new_port_ids
= it
.second
;
253 if (!cell
->hasPort(port_id
))
257 SigSpec sig
= cell
->getPort(port_id
);
259 for (auto nid
: new_port_ids
)
261 int nlen
= GetSize(design
->module(cell
->type
)->wire(nid
));
262 if (offset
+ nlen
> GetSize(sig
))
263 nlen
= GetSize(sig
) - offset
;
265 cell
->setPort(nid
, sig
.extract(offset
, nlen
));
269 cell
->unsetPort(port_id
);
276 PRIVATE_NAMESPACE_END