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(ID::src
))
64 new_wire
->attributes
[ID::src
] = wire
->attributes
.at(ID::src
);
66 if (wire
->attributes
.count(ID::keep
))
67 new_wire
->attributes
[ID::keep
] = wire
->attributes
.at(ID::keep
);
69 if (wire
->attributes
.count(ID::init
)) {
70 Const old_init
= wire
->attributes
.at(ID::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
[ID::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 if (module
->has_processes_warn())
147 SplitnetsWorker worker
;
151 int normalized_port_factor
= 0;
153 for (auto wire
: module
->wires())
154 if (wire
->port_id
!= 0) {
155 normalized_port_factor
= max(normalized_port_factor
, wire
->port_id
+1);
156 normalized_port_factor
= max(normalized_port_factor
, GetSize(wire
)+1);
159 for (auto wire
: module
->wires())
160 wire
->port_id
*= normalized_port_factor
;
165 CellTypes
ct(design
);
167 std::map
<RTLIL::Wire
*, std::set
<int>> split_wires_at
;
169 for (auto &c
: module
->cells_
)
170 for (auto &p
: c
.second
->connections())
172 if (!ct
.cell_known(c
.second
->type
))
174 if (!ct
.cell_output(c
.second
->type
, p
.first
))
177 RTLIL::SigSpec sig
= p
.second
;
178 for (auto &chunk
: sig
.chunks()) {
179 if (chunk
.wire
== NULL
)
181 if (chunk
.wire
->port_id
== 0 || flag_ports
) {
182 if (chunk
.offset
!= 0)
183 split_wires_at
[chunk
.wire
].insert(chunk
.offset
);
184 if (chunk
.offset
+ chunk
.width
< chunk
.wire
->width
)
185 split_wires_at
[chunk
.wire
].insert(chunk
.offset
+ chunk
.width
);
190 for (auto &it
: split_wires_at
) {
192 for (int next_cursor
: it
.second
) {
193 worker
.append_wire(module
, it
.first
, cursor
, next_cursor
- cursor
, format
);
194 cursor
= next_cursor
;
196 worker
.append_wire(module
, it
.first
, cursor
, it
.first
->width
- cursor
, format
);
201 for (auto &w
: module
->wires_
) {
202 RTLIL::Wire
*wire
= w
.second
;
203 if (wire
->width
> 1 && (wire
->port_id
== 0 || flag_ports
) && design
->selected(module
, w
.second
))
204 worker
.splitmap
[wire
] = std::vector
<RTLIL::SigBit
>();
207 for (auto &it
: worker
.splitmap
)
208 for (int i
= 0; i
< it
.first
->width
; i
++)
209 worker
.append_wire(module
, it
.first
, i
, 1, format
);
212 module
->rewrite_sigspecs(worker
);
216 for (auto wire
: module
->wires())
218 if (wire
->port_id
== 0)
227 vector
<IdString
> &new_ports
= module_ports_db
[module
->name
][wire
->name
];
229 for (SigSpec c
: sig
.chunks())
230 new_ports
.push_back(c
.as_wire()->name
);
234 pool
<RTLIL::Wire
*> delete_wires
;
235 for (auto &it
: worker
.splitmap
)
236 delete_wires
.insert(it
.first
);
237 module
->remove(delete_wires
);
240 module
->fixup_ports();
243 if (!module_ports_db
.empty())
245 for (auto module
: design
->modules())
246 for (auto cell
: module
->cells())
248 if (module_ports_db
.count(cell
->type
) == 0)
251 for (auto &it
: module_ports_db
.at(cell
->type
))
253 IdString port_id
= it
.first
;
254 const auto &new_port_ids
= it
.second
;
256 if (!cell
->hasPort(port_id
))
260 SigSpec sig
= cell
->getPort(port_id
);
262 for (auto nid
: new_port_ids
)
264 int nlen
= GetSize(design
->module(cell
->type
)->wire(nid
));
265 if (offset
+ nlen
> GetSize(sig
))
266 nlen
= GetSize(sig
) - offset
;
268 cell
->setPort(nid
, sig
.extract(offset
, nlen
));
272 cell
->unsetPort(port_id
);
279 PRIVATE_NAMESPACE_END