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"
30 RTLIL::Design
*design
;
31 RTLIL::Module
*module
;
36 std::string name
, full_name
;
37 std::set
<RTLIL::Cell
*> cells
;
40 std::map
<std::string
, SubModule
> submodules
;
43 RTLIL::Wire
*new_wire
;
44 bool is_int_driven
, is_int_used
, is_ext_driven
, is_ext_used
;
45 wire_flags_t() : new_wire(NULL
), is_int_driven(false), is_int_used(false), is_ext_driven(false), is_ext_used(false) { }
47 std::map
<RTLIL::Wire
*, wire_flags_t
> wire_flags
;
48 bool flag_found_something
;
50 void flag_wire(RTLIL::Wire
*wire
, bool create
, bool set_int_driven
, bool set_int_used
, bool set_ext_driven
, bool set_ext_used
)
52 if (wire_flags
.count(wire
) == 0) {
55 wire_flags
[wire
] = wire_flags_t();
58 wire_flags
[wire
].is_int_driven
= true;
60 wire_flags
[wire
].is_int_used
= true;
62 wire_flags
[wire
].is_ext_driven
= true;
64 wire_flags
[wire
].is_ext_used
= true;
65 flag_found_something
= true;
68 void flag_signal(RTLIL::SigSpec
&sig
, bool create
, bool set_int_driven
, bool set_int_used
, bool set_ext_driven
, bool set_ext_used
)
70 for (auto &c
: sig
.chunks())
72 flag_wire(c
.wire
, create
, set_int_driven
, set_int_used
, set_ext_driven
, set_ext_used
);
75 void handle_submodule(SubModule
&submod
)
77 log("Creating submodule %s (%s) of module %s.\n", submod
.name
.c_str(), submod
.full_name
.c_str(), module
->name
.c_str());
80 for (RTLIL::Cell
*cell
: submod
.cells
) {
81 if (ct
.cell_known(cell
->type
)) {
82 for (auto &conn
: cell
->connections
)
83 flag_signal(conn
.second
, true, ct
.cell_output(cell
->type
, conn
.first
), ct
.cell_input(cell
->type
, conn
.first
), false, false);
85 log("WARNING: Port directions for cell %s (%s) are unknown. Assuming inout for all ports.\n", cell
->name
.c_str(), cell
->type
.c_str());
86 for (auto &conn
: cell
->connections
)
87 flag_signal(conn
.second
, true, true, true, false, false);
90 for (auto &it
: module
->cells
) {
91 RTLIL::Cell
*cell
= it
.second
;
92 if (submod
.cells
.count(cell
) > 0)
94 if (ct
.cell_known(cell
->type
)) {
95 for (auto &conn
: cell
->connections
)
96 flag_signal(conn
.second
, false, false, false, ct
.cell_output(cell
->type
, conn
.first
), ct
.cell_input(cell
->type
, conn
.first
));
98 flag_found_something
= false;
99 for (auto &conn
: cell
->connections
)
100 flag_signal(conn
.second
, false, false, false, true, true);
101 if (flag_found_something
)
102 log("WARNING: Port directions for cell %s (%s) are unknown. Assuming inout for all ports.\n", cell
->name
.c_str(), cell
->type
.c_str());
106 RTLIL::Module
*new_mod
= new RTLIL::Module
;
107 new_mod
->name
= submod
.full_name
;
108 design
->modules
[new_mod
->name
] = new_mod
;
109 int port_counter
= 1, auto_name_counter
= 1;
111 std::set
<std::string
> all_wire_names
;
112 for (auto &it
: wire_flags
) {
113 all_wire_names
.insert(it
.first
->name
);
116 for (auto &it
: wire_flags
)
118 RTLIL::Wire
*wire
= it
.first
;
119 wire_flags_t
&flags
= it
.second
;
121 if (wire
->port_input
)
122 flags
.is_ext_driven
= true;
123 if (wire
->port_output
)
124 flags
.is_ext_used
= true;
126 RTLIL::Wire
*new_wire
= new RTLIL::Wire
;
127 new_wire
->name
= wire
->name
;
128 new_wire
->width
= wire
->width
;
129 new_wire
->start_offset
= wire
->start_offset
;
130 new_wire
->attributes
= wire
->attributes
;
132 if (flags
.is_int_driven
&& flags
.is_ext_used
)
133 new_wire
->port_output
= true;
134 if (flags
.is_ext_driven
&& flags
.is_int_used
)
135 new_wire
->port_input
= true;
137 if (flags
.is_int_driven
&& flags
.is_ext_driven
)
138 new_wire
->port_input
= true, new_wire
->port_output
= true;
140 if (new_wire
->port_input
|| new_wire
->port_output
) {
141 new_wire
->port_id
= port_counter
++;
142 while (new_wire
->name
[0] == '$') {
143 std::string new_wire_name
= stringf("\\n%d", auto_name_counter
++);
144 if (all_wire_names
.count(new_wire_name
) == 0) {
145 all_wire_names
.insert(new_wire_name
);
146 new_wire
->name
= new_wire_name
;
151 if (new_wire
->port_input
&& new_wire
->port_output
)
152 log(" signal %s: inout %s\n", wire
->name
.c_str(), new_wire
->name
.c_str());
153 else if (new_wire
->port_input
)
154 log(" signal %s: input %s\n", wire
->name
.c_str(), new_wire
->name
.c_str());
155 else if (new_wire
->port_output
)
156 log(" signal %s: output %s\n", wire
->name
.c_str(), new_wire
->name
.c_str());
158 log(" signal %s: internal\n", wire
->name
.c_str());
160 new_mod
->wires
[new_wire
->name
] = new_wire
;
161 flags
.new_wire
= new_wire
;
164 for (RTLIL::Cell
*cell
: submod
.cells
) {
165 RTLIL::Cell
*new_cell
= new RTLIL::Cell(*cell
);
166 for (auto &conn
: new_cell
->connections
)
167 for (auto &c
: conn
.second
.chunks_rw())
168 if (c
.wire
!= NULL
) {
169 assert(wire_flags
.count(c
.wire
) > 0);
170 c
.wire
= wire_flags
[c
.wire
].new_wire
;
172 log(" cell %s (%s)\n", new_cell
->name
.c_str(), new_cell
->type
.c_str());
173 new_mod
->cells
[new_cell
->name
] = new_cell
;
174 module
->cells
.erase(cell
->name
);
177 submod
.cells
.clear();
179 RTLIL::Cell
*new_cell
= new RTLIL::Cell
;
180 new_cell
->name
= submod
.full_name
;
181 new_cell
->type
= submod
.full_name
;
182 for (auto &it
: wire_flags
)
184 RTLIL::Wire
*old_wire
= it
.first
;
185 RTLIL::Wire
*new_wire
= it
.second
.new_wire
;
186 if (new_wire
->port_id
> 0)
187 new_cell
->connections
[new_wire
->name
] = RTLIL::SigSpec(old_wire
);
189 module
->cells
[new_cell
->name
] = new_cell
;
192 SubmodWorker(RTLIL::Design
*design
, RTLIL::Module
*module
, std::string opt_name
= std::string()) : design(design
), module(module
), opt_name(opt_name
)
194 if (!design
->selected_whole_module(module
->name
) && opt_name
.empty())
197 if (module
->processes
.size() > 0) {
198 log("Skipping module %s as it contains processes (run 'proc' pass first).\n", module
->name
.c_str());
202 if (module
->memories
.size() > 0) {
203 log("Skipping module %s as it contains memories (run 'memory' pass first).\n", module
->name
.c_str());
207 ct
.setup_internals();
208 ct
.setup_internals_mem();
210 ct
.setup_stdcells_mem();
211 ct
.setup_design(design
);
213 if (opt_name
.empty())
215 for (auto &it
: module
->wires
)
216 it
.second
->attributes
.erase("\\submod");
218 for (auto &it
: module
->cells
)
220 RTLIL::Cell
*cell
= it
.second
;
221 if (cell
->attributes
.count("\\submod") == 0 || cell
->attributes
["\\submod"].bits
.size() == 0) {
222 cell
->attributes
.erase("\\submod");
226 std::string submod_str
= cell
->attributes
["\\submod"].decode_string();
227 cell
->attributes
.erase("\\submod");
229 if (submodules
.count(submod_str
) == 0) {
230 submodules
[submod_str
].name
= submod_str
;
231 submodules
[submod_str
].full_name
= module
->name
+ "_" + submod_str
;
232 while (design
->modules
.count(submodules
[submod_str
].full_name
) != 0 ||
233 module
->count_id(submodules
[submod_str
].full_name
) != 0)
234 submodules
[submod_str
].full_name
+= "_";
237 submodules
[submod_str
].cells
.insert(cell
);
242 for (auto &it
: module
->cells
)
244 RTLIL::Cell
*cell
= it
.second
;
245 if (!design
->selected(module
, cell
))
247 submodules
[opt_name
].name
= opt_name
;
248 submodules
[opt_name
].full_name
= RTLIL::escape_id(opt_name
);
249 submodules
[opt_name
].cells
.insert(cell
);
252 if (submodules
.size() == 0)
253 log("Nothing selected -> do nothing.\n");
256 for (auto &it
: submodules
)
257 handle_submodule(it
.second
);
261 struct SubmodPass
: public Pass
{
262 SubmodPass() : Pass("submod", "moving part of a module to a new submodule") { }
265 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
267 log(" submod [selection]\n");
269 log("This pass identifies all cells with the 'submod' attribute and moves them to\n");
270 log("a newly created module. The value of the attribute is used as name for the\n");
271 log("cell that replaces the group of cells with the same attribute value.\n");
273 log("This pass can be used to create a design hierarchy in flat design. This can\n");
274 log("be useful for analyzing or reverse-engineering a design.\n");
276 log("This pass only operates on completely selected modules with no processes\n");
277 log("or memories.\n");
280 log(" submod -name <name> [selection]\n");
282 log("As above, but don't use the 'submod' attribute but instead use the selection.\n");
283 log("Only objects from one module might be selected. The value of the -name option\n");
284 log("is used as the value of the 'submod' attribute above.\n");
287 virtual void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
)
289 log_header("Executing SUBMOD pass (moving cells to submodules as requested).\n");
292 std::string opt_name
;
295 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
296 if (args
[argidx
] == "-name" && argidx
+1 < args
.size()) {
297 opt_name
= args
[++argidx
];
302 extra_args(args
, argidx
, design
);
304 if (opt_name
.empty())
306 Pass::call(design
, "opt_clean");
307 log_header("Continuing SUBMOD pass.\n");
309 std::set
<std::string
> handled_modules
;
311 bool did_something
= true;
312 while (did_something
) {
313 did_something
= false;
314 std::vector
<std::string
> queued_modules
;
315 for (auto &mod_it
: design
->modules
)
316 if (handled_modules
.count(mod_it
.first
) == 0 && design
->selected_whole_module(mod_it
.first
))
317 queued_modules
.push_back(mod_it
.first
);
318 for (auto &modname
: queued_modules
)
319 if (design
->modules
.count(modname
) != 0) {
320 SubmodWorker
worker(design
, design
->modules
[modname
]);
321 handled_modules
.insert(modname
);
322 did_something
= true;
326 Pass::call(design
, "opt_clean");
330 RTLIL::Module
*module
= NULL
;
331 for (auto &mod_it
: design
->modules
) {
332 if (!design
->selected_module(mod_it
.first
))
335 log_cmd_error("More than one module selected: %s %s\n", module
->name
.c_str(), mod_it
.first
.c_str());
336 module
= mod_it
.second
;
339 log("Nothing selected -> do nothing.\n");
341 Pass::call_on_module(design
, module
, "opt_clean");
342 log_header("Continuing SUBMOD pass.\n");
343 SubmodWorker
worker(design
, module
, opt_name
);