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"
23 #include "kernel/sigtools.h"
29 PRIVATE_NAMESPACE_BEGIN
34 RTLIL::Design
*design
;
35 RTLIL::Module
*module
;
37 std::map
<RTLIL::SigBit
, RTLIL::SigBit
> replace_const
;
45 std::string name
, full_name
;
46 std::set
<RTLIL::Cell
*> cells
;
49 std::map
<std::string
, SubModule
> submodules
;
52 RTLIL::Wire
*new_wire
;
53 RTLIL::Const is_int_driven
;
54 bool is_int_used
, is_ext_driven
, is_ext_used
;
55 wire_flags_t(RTLIL::Wire
* wire
) : new_wire(NULL
), is_int_driven(State::S0
, GetSize(wire
)), is_int_used(false), is_ext_driven(false), is_ext_used(false) { }
57 std::map
<RTLIL::Wire
*, wire_flags_t
> wire_flags
;
58 bool flag_found_something
;
60 void flag_wire(RTLIL::Wire
*wire
, bool create
, bool /*set_int_driven*/, bool set_int_used
, bool set_ext_driven
, bool set_ext_used
)
62 if (wire_flags
.count(wire
) == 0) {
65 wire_flags
.emplace(wire
, wire_flags_t(wire
));
68 // wire_flags[wire].is_int_driven = true;
70 wire_flags
.at(wire
).is_int_used
= true;
72 wire_flags
.at(wire
).is_ext_driven
= true;
74 wire_flags
.at(wire
).is_ext_used
= true;
75 flag_found_something
= true;
78 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
)
80 for (auto &c
: sig
.chunks())
82 flag_wire(c
.wire
, create
, set_int_driven
, set_int_used
, set_ext_driven
, set_ext_used
);
84 for (int i
= c
.offset
; i
< c
.offset
+c
.width
; i
++) {
85 wire_flags
.at(c
.wire
).is_int_driven
[i
] = State::S1
;
86 flag_found_something
= true;
91 void handle_submodule(SubModule
&submod
)
93 log("Creating submodule %s (%s) of module %s.\n", submod
.name
.c_str(), submod
.full_name
.c_str(), module
->name
.c_str());
96 for (RTLIL::Cell
*cell
: submod
.cells
) {
97 if (ct
.cell_known(cell
->type
)) {
98 for (auto &conn
: cell
->connections())
99 flag_signal(conn
.second
, true, ct
.cell_output(cell
->type
, conn
.first
), ct
.cell_input(cell
->type
, conn
.first
), false, false);
101 log_warning("Port directions for cell %s (%s) are unknown. Assuming inout for all ports.\n", cell
->name
.c_str(), cell
->type
.c_str());
102 for (auto &conn
: cell
->connections())
103 flag_signal(conn
.second
, true, true, true, false, false);
106 for (auto &it
: module
->cells_
) {
107 RTLIL::Cell
*cell
= it
.second
;
108 if (submod
.cells
.count(cell
) > 0)
110 if (ct
.cell_known(cell
->type
)) {
111 for (auto &conn
: cell
->connections())
112 flag_signal(conn
.second
, false, false, false, ct
.cell_output(cell
->type
, conn
.first
), ct
.cell_input(cell
->type
, conn
.first
));
114 flag_found_something
= false;
115 for (auto &conn
: cell
->connections())
116 flag_signal(conn
.second
, false, false, false, true, true);
117 if (flag_found_something
)
118 log_warning("Port directions for cell %s (%s) are unknown. Assuming inout for all ports.\n", cell
->name
.c_str(), cell
->type
.c_str());
122 RTLIL::Module
*new_mod
= new RTLIL::Module
;
123 new_mod
->name
= submod
.full_name
;
124 design
->add(new_mod
);
125 int auto_name_counter
= 1;
127 std::set
<RTLIL::IdString
> all_wire_names
;
128 for (auto &it
: wire_flags
) {
129 all_wire_names
.insert(it
.first
->name
);
132 for (auto &it
: wire_flags
)
134 RTLIL::Wire
*wire
= it
.first
;
135 wire_flags_t
&flags
= it
.second
;
137 if (wire
->port_input
)
138 flags
.is_ext_driven
= true;
139 if (wire
->port_output
)
140 flags
.is_ext_used
= true;
142 auto sig
= sigmap(wire
);
143 for (auto c
: sig
.chunks())
144 if (c
.wire
->port_output
) {
145 flags
.is_ext_used
= true;
150 bool new_wire_port_input
= false;
151 bool new_wire_port_output
= false;
153 if (!flags
.is_int_driven
.is_fully_zero() && flags
.is_ext_used
)
154 new_wire_port_output
= true;
155 if (flags
.is_ext_driven
&& flags
.is_int_used
)
156 new_wire_port_input
= true;
158 if (!flags
.is_int_driven
.is_fully_zero() && flags
.is_ext_driven
)
159 new_wire_port_input
= true, new_wire_port_output
= true;
161 std::string new_wire_name
= wire
->name
.str();
162 if (new_wire_port_input
|| new_wire_port_output
) {
163 if (new_wire_name
[0] == '$')
165 std::string next_wire_name
= stringf("%s\\n%d", hidden_mode
? "$submod" : "", auto_name_counter
++);
166 if (all_wire_names
.count(next_wire_name
) == 0) {
167 all_wire_names
.insert(next_wire_name
);
168 new_wire_name
= next_wire_name
;
172 else if (hidden_mode
)
173 new_wire_name
= stringf("$submod%s", new_wire_name
.c_str());
176 RTLIL::Wire
*new_wire
= new_mod
->addWire(new_wire_name
, wire
->width
);
177 new_wire
->port_input
= new_wire_port_input
;
178 new_wire
->port_output
= new_wire_port_output
;
179 new_wire
->start_offset
= wire
->start_offset
;
180 new_wire
->attributes
= wire
->attributes
;
181 if (new_wire
->port_output
) {
182 new_wire
->attributes
.erase(ID(init
));
183 auto sig
= sigmap(wire
);
184 for (int i
= 0; i
< GetSize(sig
); i
++) {
185 if (flags
.is_int_driven
[i
] == State::S0
)
189 auto it
= sig
[i
].wire
->attributes
.find(ID(init
));
190 if (it
!= sig
[i
].wire
->attributes
.end()) {
191 auto jt
= new_wire
->attributes
.insert(std::make_pair(ID(init
), Const(State::Sx
, GetSize(sig
)))).first
;
192 jt
->second
[i
] = it
->second
[sig
[i
].offset
];
193 it
->second
[sig
[i
].offset
] = State::Sx
;
198 if (new_wire
->port_input
&& new_wire
->port_output
)
199 log(" signal %s: inout %s\n", wire
->name
.c_str(), new_wire
->name
.c_str());
200 else if (new_wire
->port_input
)
201 log(" signal %s: input %s\n", wire
->name
.c_str(), new_wire
->name
.c_str());
202 else if (new_wire
->port_output
)
203 log(" signal %s: output %s\n", wire
->name
.c_str(), new_wire
->name
.c_str());
205 log(" signal %s: internal\n", wire
->name
.c_str());
207 flags
.new_wire
= new_wire
;
210 new_mod
->fixup_ports();
211 ct
.setup_module(new_mod
);
213 for (RTLIL::Cell
*cell
: submod
.cells
) {
214 RTLIL::Cell
*new_cell
= new_mod
->addCell(cell
->name
, cell
);
215 for (auto &conn
: new_cell
->connections_
)
216 for (auto &bit
: conn
.second
)
217 if (bit
.wire
!= NULL
) {
218 log_assert(wire_flags
.count(bit
.wire
) > 0);
219 bit
.wire
= wire_flags
.at(bit
.wire
).new_wire
;
221 log(" cell %s (%s)\n", new_cell
->name
.c_str(), new_cell
->type
.c_str());
223 module
->remove(cell
);
225 submod
.cells
.clear();
228 RTLIL::Cell
*new_cell
= module
->addCell(submod
.full_name
, submod
.full_name
);
229 for (auto &it
: wire_flags
)
231 RTLIL::SigSpec old_sig
= sigmap(it
.first
);
232 RTLIL::Wire
*new_wire
= it
.second
.new_wire
;
233 if (new_wire
->port_id
> 0) {
234 // Prevents "ERROR: Mismatch in directionality ..." when flattening
235 if (new_wire
->port_output
)
236 old_sig
.replace(replace_const
);
237 new_cell
->setPort(new_wire
->name
, old_sig
);
243 SubmodWorker(RTLIL::Design
*design
, RTLIL::Module
*module
, bool copy_mode
= false, bool hidden_mode
= false, std::string opt_name
= std::string()) :
244 design(design
), module(module
), sigmap(module
), copy_mode(copy_mode
), hidden_mode(hidden_mode
), opt_name(opt_name
)
246 if (!design
->selected_whole_module(module
->name
) && opt_name
.empty())
249 if (module
->processes
.size() > 0) {
250 log("Skipping module %s as it contains processes (run 'proc' pass first).\n", module
->name
.c_str());
254 if (module
->memories
.size() > 0) {
255 log("Skipping module %s as it contains memories (run 'memory' pass first).\n", module
->name
.c_str());
259 ct
.setup_internals();
260 ct
.setup_internals_mem();
262 ct
.setup_stdcells_mem();
263 ct
.setup_design(design
);
265 for (auto port
: module
->ports
) {
266 auto wire
= module
->wire(port
);
267 if (wire
->port_output
)
270 auto wire
= module
->addWire(NEW_ID
);
271 replace_const
.emplace(State::S0
, wire
);
272 replace_const
.emplace(State::S1
, wire
);
273 replace_const
.emplace(State::Sx
, wire
);
274 replace_const
.emplace(State::Sz
, wire
);
276 if (opt_name
.empty())
278 for (auto &it
: module
->wires_
)
279 it
.second
->attributes
.erase("\\submod");
281 for (auto &it
: module
->cells_
)
283 RTLIL::Cell
*cell
= it
.second
;
284 if (cell
->attributes
.count("\\submod") == 0 || cell
->attributes
["\\submod"].bits
.size() == 0) {
285 cell
->attributes
.erase("\\submod");
289 std::string submod_str
= cell
->attributes
["\\submod"].decode_string();
290 cell
->attributes
.erase("\\submod");
292 if (submodules
.count(submod_str
) == 0) {
293 submodules
[submod_str
].name
= submod_str
;
294 submodules
[submod_str
].full_name
= module
->name
.str() + "_" + submod_str
;
295 while (design
->modules_
.count(submodules
[submod_str
].full_name
) != 0 ||
296 module
->count_id(submodules
[submod_str
].full_name
) != 0)
297 submodules
[submod_str
].full_name
+= "_";
300 submodules
[submod_str
].cells
.insert(cell
);
305 for (auto &it
: module
->cells_
)
307 RTLIL::Cell
*cell
= it
.second
;
308 if (!design
->selected(module
, cell
))
310 submodules
[opt_name
].name
= opt_name
;
311 submodules
[opt_name
].full_name
= RTLIL::escape_id(opt_name
);
312 submodules
[opt_name
].cells
.insert(cell
);
315 if (submodules
.size() == 0)
316 log("Nothing selected -> do nothing.\n");
319 for (auto &it
: submodules
)
320 handle_submodule(it
.second
);
324 struct SubmodPass
: public Pass
{
325 SubmodPass() : Pass("submod", "moving part of a module to a new submodule") { }
326 void help() YS_OVERRIDE
328 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
330 log(" submod [options] [selection]\n");
332 log("This pass identifies all cells with the 'submod' attribute and moves them to\n");
333 log("a newly created module. The value of the attribute is used as name for the\n");
334 log("cell that replaces the group of cells with the same attribute value.\n");
336 log("This pass can be used to create a design hierarchy in flat design. This can\n");
337 log("be useful for analyzing or reverse-engineering a design.\n");
339 log("This pass only operates on completely selected modules with no processes\n");
340 log("or memories.\n");
343 log(" by default the cells are 'moved' from the source module and the source\n");
344 log(" module will use an instance of the new module after this command is\n");
345 log(" finished. call with -copy to not modify the source module.\n");
347 log(" -name <name>\n");
348 log(" don't use the 'submod' attribute but instead use the selection. only\n");
349 log(" objects from one module might be selected. the value of the -name option\n");
350 log(" is used as the value of the 'submod' attribute instead.\n");
353 log(" instead of creating submodule ports with public names, create ports with\n");
354 log(" private names so that a subsequent 'flatten; clean' call will restore the\n");
355 log(" original module with original public names.\n");
358 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
360 log_header(design
, "Executing SUBMOD pass (moving cells to submodules as requested).\n");
363 std::string opt_name
;
364 bool copy_mode
= false;
365 bool hidden_mode
= false;
368 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
369 if (args
[argidx
] == "-name" && argidx
+1 < args
.size()) {
370 opt_name
= args
[++argidx
];
373 if (args
[argidx
] == "-copy") {
377 if (args
[argidx
] == "-hidden") {
383 extra_args(args
, argidx
, design
);
385 if (opt_name
.empty())
387 Pass::call(design
, "opt_clean");
388 log_header(design
, "Continuing SUBMOD pass.\n");
390 std::set
<RTLIL::IdString
> handled_modules
;
392 bool did_something
= true;
393 while (did_something
) {
394 did_something
= false;
395 std::vector
<RTLIL::IdString
> queued_modules
;
396 for (auto &mod_it
: design
->modules_
)
397 if (handled_modules
.count(mod_it
.first
) == 0 && design
->selected_whole_module(mod_it
.first
))
398 queued_modules
.push_back(mod_it
.first
);
399 for (auto &modname
: queued_modules
)
400 if (design
->modules_
.count(modname
) != 0) {
401 SubmodWorker
worker(design
, design
->modules_
[modname
], copy_mode
, hidden_mode
);
402 handled_modules
.insert(modname
);
403 did_something
= true;
407 Pass::call(design
, "opt_clean");
411 RTLIL::Module
*module
= NULL
;
412 for (auto &mod_it
: design
->modules_
) {
413 if (!design
->selected_module(mod_it
.first
))
416 log_cmd_error("More than one module selected: %s %s\n", module
->name
.c_str(), mod_it
.first
.c_str());
417 module
= mod_it
.second
;
420 log("Nothing selected -> do nothing.\n");
422 Pass::call_on_module(design
, module
, "opt_clean");
423 log_header(design
, "Continuing SUBMOD pass.\n");
424 SubmodWorker
worker(design
, module
, copy_mode
, hidden_mode
, opt_name
);
432 PRIVATE_NAMESPACE_END