de275874f6fb11c3287e974f36404db49f362340
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 if (wire
->attributes
.count(ID::src
))
65 new_wire
->attributes
[ID::src
] = wire
->attributes
.at(ID::src
);
67 if (wire
->attributes
.count(ID::hdlname
))
68 new_wire
->attributes
[ID::hdlname
] = wire
->attributes
.at(ID::hdlname
);
70 if (wire
->attributes
.count(ID::keep
))
71 new_wire
->attributes
[ID::keep
] = wire
->attributes
.at(ID::keep
);
73 if (wire
->attributes
.count(ID::init
)) {
74 Const old_init
= wire
->attributes
.at(ID::init
), new_init
;
75 for (int i
= offset
; i
< offset
+width
; i
++)
76 new_init
.bits
.push_back(i
< GetSize(old_init
) ? old_init
.bits
.at(i
) : State::Sx
);
77 new_wire
->attributes
[ID::init
] = new_init
;
80 std::vector
<RTLIL::SigBit
> sigvec
= RTLIL::SigSpec(new_wire
).to_sigbit_vector();
81 splitmap
[wire
].insert(splitmap
[wire
].end(), sigvec
.begin(), sigvec
.end());
84 void operator()(RTLIL::SigSpec
&sig
)
87 if (splitmap
.count(bit
.wire
) > 0)
88 bit
= splitmap
.at(bit
.wire
).at(bit
.offset
);
92 struct SplitnetsPass
: public Pass
{
93 SplitnetsPass() : Pass("splitnets", "split up multi-bit nets") { }
94 void help() YS_OVERRIDE
96 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
98 log(" splitnets [options] [selection]\n");
100 log("This command splits multi-bit nets into single-bit nets.\n");
102 log(" -format char1[char2[char3]]\n");
103 log(" the first char is inserted between the net name and the bit index, the\n");
104 log(" second char is appended to the netname. e.g. -format () creates net\n");
105 log(" names like 'mysignal(42)'. the 3rd character is the range separation\n");
106 log(" character when creating multi-bit wires. the default is '[]:'.\n");
109 log(" also split module ports. per default only internal signals are split.\n");
112 log(" don't blindly split nets in individual bits. instead look at the driver\n");
113 log(" and split nets so that no driver drives only part of a net.\n");
116 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
118 bool flag_ports
= false;
119 bool flag_driver
= false;
120 std::string format
= "[]:";
122 log_header(design
, "Executing SPLITNETS pass (splitting up multi-bit signals).\n");
125 for (argidx
= 1; argidx
< args
.size(); argidx
++)
127 if (args
[argidx
] == "-format" && argidx
+1 < args
.size()) {
128 format
= args
[++argidx
];
131 if (args
[argidx
] == "-ports") {
135 if (args
[argidx
] == "-driver") {
141 extra_args(args
, argidx
, design
);
143 // module_ports_db[module_name][old_port_name] = new_port_name_list
144 dict
<IdString
, dict
<IdString
, vector
<IdString
>>> module_ports_db
;
146 for (auto module
: design
->selected_modules())
148 if (module
->has_processes_warn())
151 SplitnetsWorker worker
;
155 int normalized_port_factor
= 0;
157 for (auto wire
: module
->wires())
158 if (wire
->port_id
!= 0) {
159 normalized_port_factor
= max(normalized_port_factor
, wire
->port_id
+1);
160 normalized_port_factor
= max(normalized_port_factor
, GetSize(wire
)+1);
163 for (auto wire
: module
->wires())
164 wire
->port_id
*= normalized_port_factor
;
169 CellTypes
ct(design
);
171 std::map
<RTLIL::Wire
*, std::set
<int>> split_wires_at
;
173 for (auto &c
: module
->cells_
)
174 for (auto &p
: c
.second
->connections())
176 if (!ct
.cell_known(c
.second
->type
))
178 if (!ct
.cell_output(c
.second
->type
, p
.first
))
181 RTLIL::SigSpec sig
= p
.second
;
182 for (auto &chunk
: sig
.chunks()) {
183 if (chunk
.wire
== NULL
)
185 if (chunk
.wire
->port_id
== 0 || flag_ports
) {
186 if (chunk
.offset
!= 0)
187 split_wires_at
[chunk
.wire
].insert(chunk
.offset
);
188 if (chunk
.offset
+ chunk
.width
< chunk
.wire
->width
)
189 split_wires_at
[chunk
.wire
].insert(chunk
.offset
+ chunk
.width
);
194 for (auto &it
: split_wires_at
) {
196 for (int next_cursor
: it
.second
) {
197 worker
.append_wire(module
, it
.first
, cursor
, next_cursor
- cursor
, format
);
198 cursor
= next_cursor
;
200 worker
.append_wire(module
, it
.first
, cursor
, it
.first
->width
- cursor
, format
);
205 for (auto &w
: module
->wires_
) {
206 RTLIL::Wire
*wire
= w
.second
;
207 if (wire
->width
> 1 && (wire
->port_id
== 0 || flag_ports
) && design
->selected(module
, w
.second
))
208 worker
.splitmap
[wire
] = std::vector
<RTLIL::SigBit
>();
211 for (auto &it
: worker
.splitmap
)
212 for (int i
= 0; i
< it
.first
->width
; i
++)
213 worker
.append_wire(module
, it
.first
, i
, 1, format
);
216 module
->rewrite_sigspecs(worker
);
220 for (auto wire
: module
->wires())
222 if (wire
->port_id
== 0)
231 vector
<IdString
> &new_ports
= module_ports_db
[module
->name
][wire
->name
];
233 for (SigSpec c
: sig
.chunks())
234 new_ports
.push_back(c
.as_wire()->name
);
238 pool
<RTLIL::Wire
*> delete_wires
;
239 for (auto &it
: worker
.splitmap
)
240 delete_wires
.insert(it
.first
);
241 module
->remove(delete_wires
);
244 module
->fixup_ports();
247 if (!module_ports_db
.empty())
249 for (auto module
: design
->modules())
250 for (auto cell
: module
->cells())
252 if (module_ports_db
.count(cell
->type
) == 0)
255 for (auto &it
: module_ports_db
.at(cell
->type
))
257 IdString port_id
= it
.first
;
258 const auto &new_port_ids
= it
.second
;
260 if (!cell
->hasPort(port_id
))
264 SigSpec sig
= cell
->getPort(port_id
);
266 for (auto nid
: new_port_ids
)
268 int nlen
= GetSize(design
->module(cell
->type
)->wire(nid
));
269 if (offset
+ nlen
> GetSize(sig
))
270 nlen
= GetSize(sig
) - offset
;
272 cell
->setPort(nid
, sig
.extract(offset
, nlen
));
276 cell
->unsetPort(port_id
);
283 PRIVATE_NAMESPACE_END