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/log.h"
28 PRIVATE_NAMESPACE_BEGIN
33 RTLIL::Design
*design
;
34 RTLIL::Module
*module
;
41 std::string name
, full_name
;
42 std::set
<RTLIL::Cell
*> cells
;
45 std::map
<std::string
, SubModule
> submodules
;
48 RTLIL::Wire
*new_wire
;
49 bool is_int_driven
, is_int_used
, is_ext_driven
, is_ext_used
;
50 wire_flags_t() : new_wire(NULL
), is_int_driven(false), is_int_used(false), is_ext_driven(false), is_ext_used(false) { }
52 std::map
<RTLIL::Wire
*, wire_flags_t
> wire_flags
;
53 bool flag_found_something
;
55 void flag_wire(RTLIL::Wire
*wire
, bool create
, bool set_int_driven
, bool set_int_used
, bool set_ext_driven
, bool set_ext_used
)
57 if (wire_flags
.count(wire
) == 0) {
60 wire_flags
[wire
] = wire_flags_t();
63 wire_flags
[wire
].is_int_driven
= true;
65 wire_flags
[wire
].is_int_used
= true;
67 wire_flags
[wire
].is_ext_driven
= true;
69 wire_flags
[wire
].is_ext_used
= true;
70 flag_found_something
= true;
73 void flag_signal(const RTLIL::SigSpec
&sig
, bool create
, bool set_int_driven
, bool set_int_used
, bool set_ext_driven
, bool set_ext_used
)
75 for (auto &c
: sig
.chunks())
77 flag_wire(c
.wire
, create
, set_int_driven
, set_int_used
, set_ext_driven
, set_ext_used
);
80 void handle_submodule(SubModule
&submod
)
82 log("Creating submodule %s (%s) of module %s.\n", submod
.name
.c_str(), submod
.full_name
.c_str(), module
->name
.c_str());
85 for (RTLIL::Cell
*cell
: submod
.cells
) {
86 if (ct
.cell_known(cell
->type
)) {
87 for (auto &conn
: cell
->connections())
88 flag_signal(conn
.second
, true, ct
.cell_output(cell
->type
, conn
.first
), ct
.cell_input(cell
->type
, conn
.first
), false, false);
90 log_warning("Port directions for cell %s (%s) are unknown. Assuming inout for all ports.\n", cell
->name
.c_str(), cell
->type
.c_str());
91 for (auto &conn
: cell
->connections())
92 flag_signal(conn
.second
, true, true, true, false, false);
95 for (auto &it
: module
->cells_
) {
96 RTLIL::Cell
*cell
= it
.second
;
97 if (submod
.cells
.count(cell
) > 0)
99 if (ct
.cell_known(cell
->type
)) {
100 for (auto &conn
: cell
->connections())
101 flag_signal(conn
.second
, false, false, false, ct
.cell_output(cell
->type
, conn
.first
), ct
.cell_input(cell
->type
, conn
.first
));
103 flag_found_something
= false;
104 for (auto &conn
: cell
->connections())
105 flag_signal(conn
.second
, false, false, false, true, true);
106 if (flag_found_something
)
107 log_warning("Port directions for cell %s (%s) are unknown. Assuming inout for all ports.\n", cell
->name
.c_str(), cell
->type
.c_str());
111 RTLIL::Module
*new_mod
= new RTLIL::Module
;
112 new_mod
->name
= submod
.full_name
;
113 design
->add(new_mod
);
114 int auto_name_counter
= 1;
116 std::set
<RTLIL::IdString
> all_wire_names
;
117 for (auto &it
: wire_flags
) {
118 all_wire_names
.insert(it
.first
->name
);
121 for (auto &it
: wire_flags
)
123 RTLIL::Wire
*wire
= it
.first
;
124 wire_flags_t
&flags
= it
.second
;
126 if (wire
->port_input
)
127 flags
.is_ext_driven
= true;
128 if (wire
->port_output
)
129 flags
.is_ext_used
= true;
131 bool new_wire_port_input
= false;
132 bool new_wire_port_output
= false;
134 if (flags
.is_int_driven
&& flags
.is_ext_used
)
135 new_wire_port_output
= true;
136 if (flags
.is_ext_driven
&& flags
.is_int_used
)
137 new_wire_port_input
= true;
139 if (flags
.is_int_driven
&& flags
.is_ext_driven
)
140 new_wire_port_input
= true, new_wire_port_output
= true;
142 std::string new_wire_name
= wire
->name
.str();
143 if (new_wire_port_input
|| new_wire_port_output
) {
144 while (new_wire_name
[0] == '$') {
145 std::string next_wire_name
= stringf("\\n%d", auto_name_counter
++);
146 if (all_wire_names
.count(next_wire_name
) == 0) {
147 all_wire_names
.insert(next_wire_name
);
148 new_wire_name
= next_wire_name
;
153 RTLIL::Wire
*new_wire
= new_mod
->addWire(new_wire_name
, wire
->width
);
154 new_wire
->port_input
= new_wire_port_input
;
155 new_wire
->port_output
= new_wire_port_output
;
156 new_wire
->start_offset
= wire
->start_offset
;
157 new_wire
->attributes
= wire
->attributes
;
159 if (new_wire
->port_input
&& new_wire
->port_output
)
160 log(" signal %s: inout %s\n", wire
->name
.c_str(), new_wire
->name
.c_str());
161 else if (new_wire
->port_input
)
162 log(" signal %s: input %s\n", wire
->name
.c_str(), new_wire
->name
.c_str());
163 else if (new_wire
->port_output
)
164 log(" signal %s: output %s\n", wire
->name
.c_str(), new_wire
->name
.c_str());
166 log(" signal %s: internal\n", wire
->name
.c_str());
168 flags
.new_wire
= new_wire
;
171 new_mod
->fixup_ports();
172 ct
.setup_module(new_mod
);
174 for (RTLIL::Cell
*cell
: submod
.cells
) {
175 RTLIL::Cell
*new_cell
= new_mod
->addCell(cell
->name
, cell
);
176 for (auto &conn
: new_cell
->connections_
)
177 for (auto &bit
: conn
.second
)
178 if (bit
.wire
!= NULL
) {
179 log_assert(wire_flags
.count(bit
.wire
) > 0);
180 bit
.wire
= wire_flags
[bit
.wire
].new_wire
;
182 log(" cell %s (%s)\n", new_cell
->name
.c_str(), new_cell
->type
.c_str());
184 module
->remove(cell
);
186 submod
.cells
.clear();
189 RTLIL::Cell
*new_cell
= module
->addCell(submod
.full_name
, submod
.full_name
);
190 for (auto &it
: wire_flags
)
192 RTLIL::Wire
*old_wire
= it
.first
;
193 RTLIL::Wire
*new_wire
= it
.second
.new_wire
;
194 if (new_wire
->port_id
> 0)
195 new_cell
->setPort(new_wire
->name
, RTLIL::SigSpec(old_wire
));
200 SubmodWorker(RTLIL::Design
*design
, RTLIL::Module
*module
, bool copy_mode
= false, std::string opt_name
= std::string()) :
201 design(design
), module(module
), copy_mode(copy_mode
), opt_name(opt_name
)
203 if (!design
->selected_whole_module(module
->name
) && opt_name
.empty())
206 if (module
->processes
.size() > 0) {
207 log("Skipping module %s as it contains processes (run 'proc' pass first).\n", module
->name
.c_str());
211 if (module
->memories
.size() > 0) {
212 log("Skipping module %s as it contains memories (run 'memory' pass first).\n", module
->name
.c_str());
216 ct
.setup_internals();
217 ct
.setup_internals_mem();
219 ct
.setup_stdcells_mem();
220 ct
.setup_design(design
);
222 if (opt_name
.empty())
224 for (auto &it
: module
->wires_
)
225 it
.second
->attributes
.erase("\\submod");
227 for (auto &it
: module
->cells_
)
229 RTLIL::Cell
*cell
= it
.second
;
230 if (cell
->attributes
.count("\\submod") == 0 || cell
->attributes
["\\submod"].bits
.size() == 0) {
231 cell
->attributes
.erase("\\submod");
235 std::string submod_str
= cell
->attributes
["\\submod"].decode_string();
236 cell
->attributes
.erase("\\submod");
238 if (submodules
.count(submod_str
) == 0) {
239 submodules
[submod_str
].name
= submod_str
;
240 submodules
[submod_str
].full_name
= module
->name
.str() + "_" + submod_str
;
241 while (design
->modules_
.count(submodules
[submod_str
].full_name
) != 0 ||
242 module
->count_id(submodules
[submod_str
].full_name
) != 0)
243 submodules
[submod_str
].full_name
+= "_";
246 submodules
[submod_str
].cells
.insert(cell
);
251 for (auto &it
: module
->cells_
)
253 RTLIL::Cell
*cell
= it
.second
;
254 if (!design
->selected(module
, cell
))
256 submodules
[opt_name
].name
= opt_name
;
257 submodules
[opt_name
].full_name
= RTLIL::escape_id(opt_name
);
258 submodules
[opt_name
].cells
.insert(cell
);
261 if (submodules
.size() == 0)
262 log("Nothing selected -> do nothing.\n");
265 for (auto &it
: submodules
)
266 handle_submodule(it
.second
);
270 struct SubmodPass
: public Pass
{
271 SubmodPass() : Pass("submod", "moving part of a module to a new submodule") { }
272 void help() YS_OVERRIDE
274 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
276 log(" submod [-copy] [selection]\n");
278 log("This pass identifies all cells with the 'submod' attribute and moves them to\n");
279 log("a newly created module. The value of the attribute is used as name for the\n");
280 log("cell that replaces the group of cells with the same attribute value.\n");
282 log("This pass can be used to create a design hierarchy in flat design. This can\n");
283 log("be useful for analyzing or reverse-engineering a design.\n");
285 log("This pass only operates on completely selected modules with no processes\n");
286 log("or memories.\n");
289 log(" submod -name <name> [-copy] [selection]\n");
291 log("As above, but don't use the 'submod' attribute but instead use the selection.\n");
292 log("Only objects from one module might be selected. The value of the -name option\n");
293 log("is used as the value of the 'submod' attribute above.\n");
295 log("By default the cells are 'moved' from the source module and the source module\n");
296 log("will use an instance of the new module after this command is finished. Call\n");
297 log("with -copy to not modify the source module.\n");
300 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
302 log_header(design
, "Executing SUBMOD pass (moving cells to submodules as requested).\n");
305 std::string opt_name
;
306 bool copy_mode
= false;
309 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
310 if (args
[argidx
] == "-name" && argidx
+1 < args
.size()) {
311 opt_name
= args
[++argidx
];
314 if (args
[argidx
] == "-copy") {
320 extra_args(args
, argidx
, design
);
322 if (opt_name
.empty())
324 Pass::call(design
, "opt_clean");
325 log_header(design
, "Continuing SUBMOD pass.\n");
327 std::set
<RTLIL::IdString
> handled_modules
;
329 bool did_something
= true;
330 while (did_something
) {
331 did_something
= false;
332 std::vector
<RTLIL::IdString
> queued_modules
;
333 for (auto &mod_it
: design
->modules_
)
334 if (handled_modules
.count(mod_it
.first
) == 0 && design
->selected_whole_module(mod_it
.first
))
335 queued_modules
.push_back(mod_it
.first
);
336 for (auto &modname
: queued_modules
)
337 if (design
->modules_
.count(modname
) != 0) {
338 SubmodWorker
worker(design
, design
->modules_
[modname
], copy_mode
);
339 handled_modules
.insert(modname
);
340 did_something
= true;
344 Pass::call(design
, "opt_clean");
348 RTLIL::Module
*module
= NULL
;
349 for (auto &mod_it
: design
->modules_
) {
350 if (!design
->selected_module(mod_it
.first
))
353 log_cmd_error("More than one module selected: %s %s\n", module
->name
.c_str(), mod_it
.first
.c_str());
354 module
= mod_it
.second
;
357 log("Nothing selected -> do nothing.\n");
359 Pass::call_on_module(design
, module
, "opt_clean");
360 log_header(design
, "Continuing SUBMOD pass.\n");
361 SubmodWorker
worker(design
, module
, copy_mode
, opt_name
);
369 PRIVATE_NAMESPACE_END