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/log.h"
28 struct generate_port_decl_t
{
35 static void generate(RTLIL::Design
*design
, const std::vector
<std::string
> &celltypes
, const std::vector
<generate_port_decl_t
> &portdecls
)
37 std::set
<std::string
> found_celltypes
;
39 for (auto i1
: design
->modules
)
40 for (auto i2
: i1
.second
->cells
)
42 RTLIL::Cell
*cell
= i2
.second
;
43 if (cell
->type
[0] == '$' || design
->modules
.count(cell
->type
) > 0)
45 for (auto &pattern
: celltypes
)
46 if (!fnmatch(pattern
.c_str(), RTLIL::unescape_id(cell
->type
).c_str(), FNM_NOESCAPE
))
47 found_celltypes
.insert(cell
->type
);
50 for (auto &celltype
: found_celltypes
)
52 std::set
<std::string
> portnames
;
53 std::set
<std::string
> parameters
;
54 std::map
<std::string
, int> portwidths
;
55 log("Generate module for cell type %s:\n", celltype
.c_str());
57 for (auto i1
: design
->modules
)
58 for (auto i2
: i1
.second
->cells
)
59 if (i2
.second
->type
== celltype
) {
60 for (auto &conn
: i2
.second
->connections
) {
61 if (conn
.first
[0] != '$')
62 portnames
.insert(conn
.first
);
63 portwidths
[conn
.first
] = std::max(portwidths
[conn
.first
], conn
.second
.width
);
65 for (auto ¶
: i2
.second
->parameters
)
66 parameters
.insert(para
.first
);
69 for (auto &decl
: portdecls
)
71 portnames
.insert(decl
.portname
);
73 std::set
<int> indices
;
74 for (int i
= 0; i
< int(portnames
.size()); i
++)
77 std::vector
<generate_port_decl_t
> ports(portnames
.size());
79 for (auto &decl
: portdecls
)
81 portwidths
[decl
.portname
] = std::max(portwidths
[decl
.portname
], 1);
82 portwidths
[decl
.portname
] = std::max(portwidths
[decl
.portname
], portwidths
[stringf("$%d", decl
.index
)]);
83 log(" port %d: %s [%d:0] %s\n", decl
.index
, decl
.input
? decl
.output
? "inout" : "input" : "output", portwidths
[decl
.portname
]-1, RTLIL::id2cstr(decl
.portname
));
84 if (indices
.count(decl
.index
) > ports
.size())
85 log_error("Port index (%d) exceeds number of found ports (%d).\n", decl
.index
, int(ports
.size()));
86 if (indices
.count(decl
.index
) == 0)
87 log_error("Conflict on port index %d.\n", decl
.index
);
88 indices
.erase(decl
.index
);
89 portnames
.erase(decl
.portname
);
90 ports
[decl
.index
-1] = decl
;
93 while (portnames
.size() > 0) {
94 std::string portname
= *portnames
.begin();
95 for (auto &decl
: portdecls
)
96 if (decl
.index
== 0 && !fnmatch(decl
.portname
.c_str(), RTLIL::unescape_id(portname
).c_str(), FNM_NOESCAPE
)) {
97 generate_port_decl_t d
= decl
;
98 d
.portname
= portname
;
99 d
.index
= *indices
.begin();
100 assert(!indices
.empty());
101 indices
.erase(d
.index
);
102 ports
[d
.index
-1] = d
;
103 portwidths
[d
.portname
] = std::max(portwidths
[d
.portname
], 1);
104 log(" port %d: %s [%d:0] %s\n", d
.index
, d
.input
? d
.output
? "inout" : "input" : "output", portwidths
[d
.portname
]-1, RTLIL::id2cstr(d
.portname
));
105 goto found_matching_decl
;
107 log_error("Can't match port %s.\n", RTLIL::id2cstr(portname
));
108 found_matching_decl
:;
109 portnames
.erase(portname
);
112 assert(indices
.empty());
114 RTLIL::Module
*mod
= new RTLIL::Module
;
115 mod
->name
= celltype
;
116 mod
->attributes
["\\placeholder"] = RTLIL::Const(0, 0);
117 design
->modules
[mod
->name
] = mod
;
119 for (auto &decl
: ports
) {
120 RTLIL::Wire
*wire
= new RTLIL::Wire
;
121 wire
->name
= decl
.portname
;
122 wire
->width
= portwidths
.at(decl
.portname
);
123 wire
->port_id
= decl
.index
;
124 wire
->port_input
= decl
.input
;
125 wire
->port_output
= decl
.output
;
129 for (auto ¶
: parameters
)
130 log(" ignoring parameter %s.\n", RTLIL::id2cstr(para
));
132 log(" module %s created.\n", RTLIL::id2cstr(mod
->name
));
136 static bool expand_module(RTLIL::Design
*design
, RTLIL::Module
*module
, bool flag_check
)
138 bool did_something
= false;
140 for (auto &cell_it
: module
->cells
) {
141 RTLIL::Cell
*cell
= cell_it
.second
;
142 if (design
->modules
.count(cell
->type
) == 0) {
143 if (flag_check
&& cell
->type
[0] != '$')
144 log_error("Module `%s' referenced in module `%s' in cell `%s' is not part of the design.\n",
145 cell
->type
.c_str(), module
->name
.c_str(), cell
->name
.c_str());
148 if (cell
->parameters
.size() == 0)
150 if (design
->modules
.at(cell
->type
)->attributes
.count("\\placeholder") > 0)
152 RTLIL::Module
*mod
= design
->modules
[cell
->type
];
153 cell
->type
= mod
->derive(design
, cell
->parameters
);
154 cell
->parameters
.clear();
155 did_something
= true;
159 return did_something
;
161 std::map
<RTLIL::SigSpec
, int> auto_wires
;
163 for (auto &wire_it
: module
->wires
) {
164 if (wire_it
.second
->auto_width
)
165 auto_wires
[RTLIL::SigSpec(wire_it
.second
)] = -1;
168 for (auto &cell_it
: module
->cells
)
169 for (auto &conn
: cell_it
.second
->connections
)
170 for (auto &awit
: auto_wires
) {
171 if (awit
.second
>= 0 || conn
.second
!= awit
.first
)
173 if (design
->modules
.count(cell_it
.second
->type
) == 0) {
174 log("WARNING: Module `%s' used in auto-delaration of the wire `%s.%s' cannot be found.\n",
175 cell_it
.second
->type
.c_str(), module
->name
.c_str(), log_signal(awit
.first
));
178 RTLIL::Module
*mod
= design
->modules
[cell_it
.second
->type
];
179 RTLIL::Wire
*wire
= NULL
;
180 if (mod
->wires
.count(conn
.first
) == 0) {
181 for (auto &wire_it
: mod
->wires
) {
182 if (wire_it
.second
->port_id
== 0)
185 snprintf(buffer
, 100, "$%d", wire_it
.second
->port_id
);
186 if (buffer
== conn
.first
) {
187 wire
= wire_it
.second
;
192 wire
= mod
->wires
[conn
.first
];
193 if (!wire
|| wire
->port_id
== 0)
194 log_error("No port `%s' found in `%s' but used by instanciation in `%s'!\n",
195 conn
.first
.c_str(), mod
->name
.c_str(), module
->name
.c_str());
196 if (wire
->auto_width
)
197 log_error("Signal `%s' found in `%s' and used by instanciation in `%s' for an auto wire is an auto-wire itself!\n",
198 log_signal(awit
.first
), mod
->name
.c_str(), module
->name
.c_str());
199 awit
.second
= wire
->width
;
202 std::map
<RTLIL::IdString
, int> auto_sizes
;
203 for (auto &awit
: auto_wires
) {
205 log("Can't further resolve auto-wire `%s.%s' (width %d) using cell ports.\n",
206 module
->name
.c_str(), awit
.first
.chunks
[0].wire
->name
.c_str(),
207 awit
.first
.chunks
[0].wire
->width
);
209 auto_sizes
[awit
.first
.chunks
[0].wire
->name
] = awit
.second
;
212 if (auto_sizes
.size() > 0) {
213 module
->update_auto_wires(auto_sizes
);
214 log_header("Continuing HIERARCHY pass.\n");
215 did_something
= true;
218 return did_something
;
221 static void hierarchy_worker(RTLIL::Design
*design
, std::set
<RTLIL::Module
*> &used
, RTLIL::Module
*mod
, bool is_top
= false)
223 if (used
.count(mod
) > 0)
226 log("%s module: %s\n", is_top
? "Top" : "Used", mod
->name
.c_str());
229 for (auto &it
: mod
->cells
) {
230 if (design
->modules
.count(it
.second
->type
) > 0)
231 hierarchy_worker(design
, used
, design
->modules
[it
.second
->type
]);
235 static void hierarchy(RTLIL::Design
*design
, RTLIL::Module
*top
)
237 std::set
<RTLIL::Module
*> used
;
238 hierarchy_worker(design
, used
, top
, true);
240 std::vector
<RTLIL::Module
*> del_modules
;
241 for (auto &it
: design
->modules
)
242 if (used
.count(it
.second
) == 0)
243 del_modules
.push_back(it
.second
);
245 for (auto mod
: del_modules
) {
246 log("Removing unused module `%s'.\n", mod
->name
.c_str());
247 design
->modules
.erase(mod
->name
);
251 log("Removed %zd unused modules.\n", del_modules
.size());
254 struct HierarchyPass
: public Pass
{
255 HierarchyPass() : Pass("hierarchy", "check, expand and clean up design hierarchy") { }
258 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
260 log(" hierarchy [-check] [-top <module>]\n");
261 log(" hierarchy -generate <cell-types> <port-decls>\n");
263 log("In parametric designs, a module might exists in serveral variations with\n");
264 log("different parameter values. This pass looks at all modules in the current\n");
265 log("design an re-runs the language frontends for the parametric modules as\n");
269 log(" also check the design hierarchy. this generates an error when\n");
270 log(" an unknown module is used as cell type.\n");
272 log(" -top <module>\n");
273 log(" use the specified top module to built a design hierarchy. modules\n");
274 log(" outside this tree (unused modules) are removed.\n");
276 log("In -generate mode this pass generates placeholder modules for the given cell\n");
277 log("types (wildcards supported). For this the design is searched for cells that\n");
278 log("match the given types and then the given port declarations are used to\n");
279 log("determine the direction of the ports. The syntax for a port declaration is:\n");
281 log(" {i|o|io}[@<num>]:<portname>\n");
283 log("Input ports are specified with the 'i' prefix, output ports with the 'o'\n");
284 log("prefix and inout ports with the 'io' prefix. The optional <num> specifies\n");
285 log("the position of the port in the parameter list (needed when instanciated\n");
286 log("using positional arguments). When <num> is not specified, the <portname> can\n");
287 log("also contain wildcard characters.\n");
289 log("This pass ignores the current selection and always operates on all modules\n");
290 log("in the current design.\n");
293 virtual void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
)
295 log_header("Executing HIERARCHY pass (managing design hierarchy).\n");
297 bool flag_check
= false;
298 RTLIL::Module
*top_mod
= NULL
;
300 bool generate_mode
= false;
301 std::vector
<std::string
> generate_cells
;
302 std::vector
<generate_port_decl_t
> generate_ports
;
305 for (argidx
= 1; argidx
< args
.size(); argidx
++)
307 if (args
[argidx
] == "-generate" && !flag_check
&& !top_mod
) {
308 generate_mode
= true;
309 log("Entering generate mode.\n");
310 while (++argidx
< args
.size()) {
311 const char *p
= args
[argidx
].c_str();
312 generate_port_decl_t decl
;
313 if (p
[0] == 'i' && p
[1] == 'o')
314 decl
.input
= true, decl
.output
= true, p
+= 2;
316 decl
.input
= true, decl
.output
= false, p
++;
318 decl
.input
= false, decl
.output
= true, p
++;
323 decl
.index
= strtol(++p
, &endptr
, 10);
334 log("Port declaration: %s", decl
.input
? decl
.output
? "inout" : "input" : "output");
336 log(" [at position %d]", decl
.index
);
337 log(" %s\n", decl
.portname
.c_str());
338 generate_ports
.push_back(decl
);
341 log("Celltype: %s\n", args
[argidx
].c_str());
342 generate_cells
.push_back(RTLIL::unescape_id(args
[argidx
]));
346 if (args
[argidx
] == "-check") {
350 if (args
[argidx
] == "-top") {
351 if (++argidx
>= args
.size())
352 log_cmd_error("Option -top requires an additional argument!\n");
353 if (args
[argidx
][0] != '$' && args
[argidx
][0] != '\\')
354 top_mod
= design
->modules
.count("\\" + args
[argidx
]) > 0 ? design
->modules
["\\" + args
[argidx
]] : NULL
;
356 top_mod
= design
->modules
.count(args
[argidx
]) > 0 ? design
->modules
[args
[argidx
]] : NULL
;
358 log_cmd_error("Module `%s' not found!\n", args
[argidx
].c_str());
363 extra_args(args
, argidx
, design
, false);
366 generate(design
, generate_cells
, generate_ports
);
371 hierarchy(design
, top_mod
);
373 bool did_something
= true;
374 while (did_something
) {
375 did_something
= false;
376 std::vector
<std::string
> modnames
;
377 modnames
.reserve(design
->modules
.size());
378 for (auto &mod_it
: design
->modules
)
379 modnames
.push_back(mod_it
.first
);
380 for (auto &modname
: modnames
) {
381 if (design
->modules
.count(modname
) == 0)
383 if (expand_module(design
, design
->modules
[modname
], flag_check
))
384 did_something
= true;
389 hierarchy(design
, top_mod
);