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
;
62 new_wire
->start_offset
= wire
->start_offset
+ offset
;
64 auto it
= wire
->attributes
.find(ID::src
);
65 if (it
!= wire
->attributes
.end())
66 new_wire
->attributes
.emplace(ID::src
, it
->second
);
68 it
= wire
->attributes
.find(ID::hdlname
);
69 if (it
!= wire
->attributes
.end())
70 new_wire
->attributes
.emplace(ID::hdlname
, it
->second
);
72 it
= wire
->attributes
.find(ID::keep
);
73 if (it
!= wire
->attributes
.end())
74 new_wire
->attributes
.emplace(ID::keep
, it
->second
);
76 it
= wire
->attributes
.find(ID::init
);
77 if (it
!= wire
->attributes
.end()) {
78 Const old_init
= it
->second
, new_init
;
79 for (int i
= offset
; i
< offset
+width
; i
++)
80 new_init
.bits
.push_back(i
< GetSize(old_init
) ? old_init
.bits
.at(i
) : State::Sx
);
81 new_wire
->attributes
.emplace(ID::init
, new_init
);
84 std::vector
<RTLIL::SigBit
> sigvec
= RTLIL::SigSpec(new_wire
).to_sigbit_vector();
85 splitmap
[wire
].insert(splitmap
[wire
].end(), sigvec
.begin(), sigvec
.end());
88 void operator()(RTLIL::SigSpec
&sig
)
91 if (splitmap
.count(bit
.wire
) > 0)
92 bit
= splitmap
.at(bit
.wire
).at(bit
.offset
);
96 struct SplitnetsPass
: public Pass
{
97 SplitnetsPass() : Pass("splitnets", "split up multi-bit nets") { }
98 void help() YS_OVERRIDE
100 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
102 log(" splitnets [options] [selection]\n");
104 log("This command splits multi-bit nets into single-bit nets.\n");
106 log(" -format char1[char2[char3]]\n");
107 log(" the first char is inserted between the net name and the bit index, the\n");
108 log(" second char is appended to the netname. e.g. -format () creates net\n");
109 log(" names like 'mysignal(42)'. the 3rd character is the range separation\n");
110 log(" character when creating multi-bit wires. the default is '[]:'.\n");
113 log(" also split module ports. per default only internal signals are split.\n");
116 log(" don't blindly split nets in individual bits. instead look at the driver\n");
117 log(" and split nets so that no driver drives only part of a net.\n");
120 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
122 bool flag_ports
= false;
123 bool flag_driver
= false;
124 std::string format
= "[]:";
126 log_header(design
, "Executing SPLITNETS pass (splitting up multi-bit signals).\n");
129 for (argidx
= 1; argidx
< args
.size(); argidx
++)
131 if (args
[argidx
] == "-format" && argidx
+1 < args
.size()) {
132 format
= args
[++argidx
];
135 if (args
[argidx
] == "-ports") {
139 if (args
[argidx
] == "-driver") {
145 extra_args(args
, argidx
, design
);
147 // module_ports_db[module_name][old_port_name] = new_port_name_list
148 dict
<IdString
, dict
<IdString
, vector
<IdString
>>> module_ports_db
;
150 for (auto module
: design
->selected_modules())
152 if (module
->has_processes_warn())
155 SplitnetsWorker worker
;
159 int normalized_port_factor
= 0;
161 for (auto wire
: module
->wires())
162 if (wire
->port_id
!= 0) {
163 normalized_port_factor
= max(normalized_port_factor
, wire
->port_id
+1);
164 normalized_port_factor
= max(normalized_port_factor
, GetSize(wire
)+1);
167 for (auto wire
: module
->wires())
168 wire
->port_id
*= normalized_port_factor
;
173 CellTypes
ct(design
);
175 std::map
<RTLIL::Wire
*, std::set
<int>> split_wires_at
;
177 for (auto c
: module
->cells())
178 for (auto &p
: c
->connections())
180 if (!ct
.cell_known(c
->type
))
182 if (!ct
.cell_output(c
->type
, p
.first
))
185 RTLIL::SigSpec sig
= p
.second
;
186 for (auto &chunk
: sig
.chunks()) {
187 if (chunk
.wire
== NULL
)
189 if (chunk
.wire
->port_id
== 0 || flag_ports
) {
190 if (chunk
.offset
!= 0)
191 split_wires_at
[chunk
.wire
].insert(chunk
.offset
);
192 if (chunk
.offset
+ chunk
.width
< chunk
.wire
->width
)
193 split_wires_at
[chunk
.wire
].insert(chunk
.offset
+ chunk
.width
);
198 for (auto &it
: split_wires_at
) {
200 for (int next_cursor
: it
.second
) {
201 worker
.append_wire(module
, it
.first
, cursor
, next_cursor
- cursor
, format
);
202 cursor
= next_cursor
;
204 worker
.append_wire(module
, it
.first
, cursor
, it
.first
->width
- cursor
, format
);
209 for (auto wire
: module
->wires()) {
210 if (wire
->width
> 1 && (wire
->port_id
== 0 || flag_ports
) && design
->selected(module
, wire
))
211 worker
.splitmap
[wire
] = std::vector
<RTLIL::SigBit
>();
214 for (auto &it
: worker
.splitmap
)
215 for (int i
= 0; i
< it
.first
->width
; i
++)
216 worker
.append_wire(module
, it
.first
, i
, 1, format
);
219 module
->rewrite_sigspecs(worker
);
223 for (auto wire
: module
->wires())
225 if (wire
->port_id
== 0)
234 vector
<IdString
> &new_ports
= module_ports_db
[module
->name
][wire
->name
];
236 for (SigSpec c
: sig
.chunks())
237 new_ports
.push_back(c
.as_wire()->name
);
241 pool
<RTLIL::Wire
*> delete_wires
;
242 for (auto &it
: worker
.splitmap
)
243 delete_wires
.insert(it
.first
);
244 module
->remove(delete_wires
);
247 module
->fixup_ports();
250 if (!module_ports_db
.empty())
252 for (auto module
: design
->modules())
253 for (auto cell
: module
->cells())
255 if (module_ports_db
.count(cell
->type
) == 0)
258 for (auto &it
: module_ports_db
.at(cell
->type
))
260 IdString port_id
= it
.first
;
261 const auto &new_port_ids
= it
.second
;
263 if (!cell
->hasPort(port_id
))
267 SigSpec sig
= cell
->getPort(port_id
);
269 for (auto nid
: new_port_ids
)
271 int nlen
= GetSize(design
->module(cell
->type
)->wire(nid
));
272 if (offset
+ nlen
> GetSize(sig
))
273 nlen
= GetSize(sig
) - offset
;
275 cell
->setPort(nid
, sig
.extract(offset
, nlen
));
279 cell
->unsetPort(port_id
);
286 PRIVATE_NAMESPACE_END