Added support for module->connections to select %ci, %co and %x handling
[yosys.git] / passes / cmds / select.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5 *
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.
9 *
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.
17 *
18 */
19
20 #include "kernel/register.h"
21 #include "kernel/celltypes.h"
22 #include "kernel/log.h"
23 #include <string.h>
24 #include <fnmatch.h>
25
26 using RTLIL::id2cstr;
27
28 static std::vector<RTLIL::Selection> work_stack;
29
30 static bool match_ids(RTLIL::IdString id, std::string pattern)
31 {
32 if (id == pattern)
33 return true;
34 if (id.size() > 0 && id[0] == '\\' && id.substr(1) == pattern)
35 return true;
36 if (!fnmatch(pattern.c_str(), id.c_str(), 0))
37 return true;
38 if (id.size() > 0 && id[0] == '\\' && !fnmatch(pattern.c_str(), id.substr(1).c_str(), 0))
39 return true;
40 if (id.size() > 0 && id[0] == '$' && pattern.size() > 0 && pattern[0] == '$') {
41 const char *p = id.c_str();
42 const char *q = strrchr(p, '$');
43 if (pattern == q)
44 return true;
45 }
46 return false;
47 }
48
49 static bool match_attr_val(const RTLIL::Const &value, std::string pattern)
50 {
51 if ((value.flags & RTLIL::CONST_FLAG_STRING) == 0)
52 return false;
53 if (!fnmatch(pattern.c_str(), value.decode_string().c_str(), FNM_NOESCAPE))
54 return true;
55 return false;
56 }
57
58 static bool match_attr(const std::map<RTLIL::IdString, RTLIL::Const> &attributes, std::string name_pat, std::string value_pat, bool use_value_pat)
59 {
60 if (name_pat.find('*') != std::string::npos || name_pat.find('?') != std::string::npos || name_pat.find('[') != std::string::npos) {
61 for (auto &it : attributes) {
62 if (!fnmatch(name_pat.c_str(), it.first.c_str(), FNM_NOESCAPE) && (!use_value_pat || match_attr_val(it.second, value_pat)))
63 return true;
64 if (it.first.size() > 0 && it.first[0] == '\\' && !fnmatch(name_pat.c_str(), it.first.substr(1).c_str(), FNM_NOESCAPE) && (!use_value_pat || match_attr_val(it.second, value_pat)))
65 return true;
66 }
67 } else {
68 if (name_pat.size() > 0 && (name_pat[0] == '\\' || name_pat[0] == '$') && attributes.count(name_pat) && (!use_value_pat || match_attr_val(attributes.at(name_pat), value_pat)))
69 return true;
70 if (attributes.count("\\" + name_pat) && (!use_value_pat || match_attr_val(attributes.at("\\" + name_pat), value_pat)))
71 return true;
72 }
73 return false;
74 }
75
76 static void select_op_neg(RTLIL::Design *design, RTLIL::Selection &lhs)
77 {
78 if (lhs.full_selection) {
79 lhs.full_selection = false;
80 lhs.selected_modules.clear();
81 lhs.selected_members.clear();
82 return;
83 }
84
85 if (lhs.selected_modules.size() == 0 && lhs.selected_members.size() == 0) {
86 lhs.full_selection = true;
87 return;
88 }
89
90 RTLIL::Selection new_sel(false);
91
92 for (auto &mod_it : design->modules)
93 {
94 if (lhs.selected_whole_module(mod_it.first))
95 continue;
96 if (!lhs.selected_module(mod_it.first)) {
97 new_sel.selected_modules.insert(mod_it.first);
98 continue;
99 }
100
101 RTLIL::Module *mod = mod_it.second;
102 for (auto &it : mod->wires)
103 if (!lhs.selected_member(mod_it.first, it.first))
104 new_sel.selected_members[mod->name].insert(it.first);
105 for (auto &it : mod->memories)
106 if (!lhs.selected_member(mod_it.first, it.first))
107 new_sel.selected_members[mod->name].insert(it.first);
108 for (auto &it : mod->cells)
109 if (!lhs.selected_member(mod_it.first, it.first))
110 new_sel.selected_members[mod->name].insert(it.first);
111 for (auto &it : mod->processes)
112 if (!lhs.selected_member(mod_it.first, it.first))
113 new_sel.selected_members[mod->name].insert(it.first);
114 }
115
116 lhs.selected_modules.swap(new_sel.selected_modules);
117 lhs.selected_members.swap(new_sel.selected_members);
118 }
119
120 static void select_op_union(RTLIL::Design*, RTLIL::Selection &lhs, const RTLIL::Selection &rhs)
121 {
122 if (rhs.full_selection) {
123 lhs.full_selection = true;
124 lhs.selected_modules.clear();
125 lhs.selected_members.clear();
126 return;
127 }
128
129 if (lhs.full_selection)
130 return;
131
132 for (auto &it : rhs.selected_members)
133 for (auto &it2 : it.second)
134 lhs.selected_members[it.first].insert(it2);
135
136 for (auto &it : rhs.selected_modules) {
137 lhs.selected_modules.insert(it);
138 lhs.selected_members.erase(it);
139 }
140 }
141
142 static void select_op_diff(RTLIL::Design *design, RTLIL::Selection &lhs, const RTLIL::Selection &rhs)
143 {
144 if (rhs.full_selection) {
145 lhs.full_selection = false;
146 lhs.selected_modules.clear();
147 lhs.selected_members.clear();
148 return;
149 }
150
151 if (lhs.full_selection) {
152 if (!rhs.full_selection && rhs.selected_modules.size() == 0 && rhs.selected_members.size() == 0)
153 return;
154 lhs.full_selection = false;
155 for (auto &it : design->modules)
156 lhs.selected_modules.insert(it.first);
157 }
158
159 for (auto &it : rhs.selected_modules) {
160 lhs.selected_modules.erase(it);
161 lhs.selected_members.erase(it);
162 }
163
164 for (auto &it : rhs.selected_members)
165 {
166 if (design->modules.count(it.first) == 0)
167 continue;
168
169 RTLIL::Module *mod = design->modules[it.first];
170
171 if (lhs.selected_modules.count(mod->name) > 0)
172 {
173 for (auto &it : mod->wires)
174 lhs.selected_members[mod->name].insert(it.first);
175 for (auto &it : mod->memories)
176 lhs.selected_members[mod->name].insert(it.first);
177 for (auto &it : mod->cells)
178 lhs.selected_members[mod->name].insert(it.first);
179 for (auto &it : mod->processes)
180 lhs.selected_members[mod->name].insert(it.first);
181 lhs.selected_modules.erase(mod->name);
182 }
183
184 if (lhs.selected_members.count(mod->name) == 0)
185 continue;
186
187 for (auto &it2 : it.second)
188 lhs.selected_members[mod->name].erase(it2);
189 }
190 }
191
192 static void select_op_intersect(RTLIL::Design *design, RTLIL::Selection &lhs, const RTLIL::Selection &rhs)
193 {
194 if (rhs.full_selection)
195 return;
196
197 if (lhs.full_selection) {
198 lhs.full_selection = false;
199 for (auto &it : design->modules)
200 lhs.selected_modules.insert(it.first);
201 }
202
203 std::vector<RTLIL::IdString> del_list;
204
205 for (auto &it : lhs.selected_modules)
206 if (rhs.selected_modules.count(it) == 0) {
207 if (rhs.selected_members.count(it) > 0)
208 for (auto &it2 : rhs.selected_members.at(it))
209 lhs.selected_members[it].insert(it2);
210 del_list.push_back(it);
211 }
212 for (auto &it : del_list)
213 lhs.selected_modules.erase(it);
214
215 del_list.clear();
216 for (auto &it : lhs.selected_members) {
217 if (rhs.selected_modules.count(it.first) > 0)
218 continue;
219 if (rhs.selected_members.count(it.first) == 0) {
220 del_list.push_back(it.first);
221 continue;
222 }
223 std::vector<RTLIL::IdString> del_list2;
224 for (auto &it2 : it.second)
225 if (rhs.selected_members.at(it.first).count(it2) == 0)
226 del_list2.push_back(it2);
227 for (auto &it2 : del_list2)
228 it.second.erase(it2);
229 if (it.second.size() == 0)
230 del_list.push_back(it.first);
231 }
232 for (auto &it : del_list)
233 lhs.selected_members.erase(it);
234 }
235
236 namespace {
237 struct expand_rule_t {
238 char mode;
239 std::set<RTLIL::IdString> cell_types, port_names;
240 };
241 }
242
243 static int parse_comma_list(std::set<RTLIL::IdString> &tokens, std::string str, size_t pos, std::string stopchar)
244 {
245 stopchar += ',';
246 while (1) {
247 size_t endpos = str.find_first_of(stopchar, pos);
248 if (endpos == std::string::npos)
249 endpos = str.size();
250 if (endpos != pos)
251 tokens.insert(RTLIL::escape_id(str.substr(pos, endpos-pos)));
252 pos = endpos;
253 if (pos == str.size() || str[pos] != ',')
254 return pos;
255 pos++;
256 }
257 }
258
259 static int select_op_expand(RTLIL::Design *design, RTLIL::Selection &lhs, std::vector<expand_rule_t> &rules, std::set<RTLIL::IdString> &limits, int max_objects, char mode, CellTypes &ct)
260 {
261 int sel_objects = 0;
262 bool is_input, is_output;
263 for (auto &mod_it : design->modules)
264 {
265 if (lhs.selected_whole_module(mod_it.first) || !lhs.selected_module(mod_it.first))
266 continue;
267
268 RTLIL::Module *mod = mod_it.second;
269 std::set<RTLIL::Wire*> selected_wires;
270
271 for (auto &it : mod->wires)
272 if (lhs.selected_member(mod_it.first, it.first) && limits.count(it.first) == 0)
273 selected_wires.insert(it.second);
274
275 for (auto &conn : mod->connections)
276 {
277 std::vector<RTLIL::SigBit> conn_lhs = conn.first.to_sigbit_vector();
278 std::vector<RTLIL::SigBit> conn_rhs = conn.second.to_sigbit_vector();
279
280 for (size_t i = 0; i < conn_lhs.size(); i++) {
281 if (conn_lhs[i].wire == NULL || conn_rhs[i].wire == NULL)
282 continue;
283 if (mode != 'i' && selected_wires.count(conn_rhs[i].wire) && lhs.selected_members[mod->name].count(conn_lhs[i].wire->name) == 0)
284 lhs.selected_members[mod->name].insert(conn_lhs[i].wire->name), sel_objects++, max_objects--;
285 if (mode != 'o' && selected_wires.count(conn_lhs[i].wire) && lhs.selected_members[mod->name].count(conn_rhs[i].wire->name) == 0)
286 lhs.selected_members[mod->name].insert(conn_rhs[i].wire->name), sel_objects++, max_objects--;
287 }
288 }
289
290 for (auto &cell : mod->cells)
291 for (auto &conn : cell.second->connections)
292 {
293 char last_mode = '-';
294 for (auto &rule : rules) {
295 last_mode = rule.mode;
296 if (rule.cell_types.size() > 0 && rule.cell_types.count(cell.second->type) == 0)
297 continue;
298 if (rule.port_names.size() > 0 && rule.port_names.count(conn.first) == 0)
299 continue;
300 if (rule.mode == '+')
301 goto include_match;
302 else
303 goto exclude_match;
304 }
305 if (last_mode == '+')
306 goto exclude_match;
307 include_match:
308 is_input = mode == 'x' || ct.cell_input(cell.second->type, conn.first);
309 is_output = mode == 'x' || ct.cell_output(cell.second->type, conn.first);
310 for (auto &chunk : conn.second.chunks)
311 if (chunk.wire != NULL) {
312 if (max_objects != 0 && selected_wires.count(chunk.wire) > 0 && lhs.selected_members[mod->name].count(cell.first) == 0)
313 if (mode == 'x' || (mode == 'i' && is_output) || (mode == 'o' && is_input))
314 lhs.selected_members[mod->name].insert(cell.first), sel_objects++, max_objects--;
315 if (max_objects != 0 && lhs.selected_members[mod->name].count(cell.first) > 0 && limits.count(cell.first) == 0 && lhs.selected_members[mod->name].count(chunk.wire->name) == 0)
316 if (mode == 'x' || (mode == 'i' && is_input) || (mode == 'o' && is_output))
317 lhs.selected_members[mod->name].insert(chunk.wire->name), sel_objects++, max_objects--;
318 }
319 exclude_match:;
320 }
321 }
322
323 return sel_objects;
324 }
325
326 static void select_op_expand(RTLIL::Design *design, std::string arg, char mode)
327 {
328 int pos = mode == 'x' ? 2 : 3, levels = 1, rem_objects = -1;
329 std::vector<expand_rule_t> rules;
330 std::set<RTLIL::IdString> limits;
331
332 CellTypes ct;
333
334 if (mode != 'x')
335 ct.setup(design);
336
337 if (pos < int(arg.size()) && arg[pos] == '*') {
338 levels = 1000000;
339 pos++;
340 } else
341 if (pos < int(arg.size()) && '0' <= arg[pos] && arg[pos] <= '9') {
342 size_t endpos = arg.find_first_not_of("0123456789", pos);
343 if (endpos == std::string::npos)
344 endpos = arg.size();
345 levels = atoi(arg.substr(pos, endpos-pos).c_str());
346 pos = endpos;
347 }
348
349 if (pos < int(arg.size()) && arg[pos] == '.') {
350 size_t endpos = arg.find_first_not_of("0123456789", ++pos);
351 if (endpos == std::string::npos)
352 endpos = arg.size();
353 if (int(endpos) > pos)
354 rem_objects = atoi(arg.substr(pos, endpos-pos).c_str());
355 pos = endpos;
356 }
357
358 while (pos < int(arg.size())) {
359 if (arg[pos] != ':' || pos+1 == int(arg.size()))
360 log_cmd_error("Syntax error in expand operator '%s'.\n", arg.c_str());
361 pos++;
362 if (arg[pos] == '+' || arg[pos] == '-') {
363 expand_rule_t rule;
364 rule.mode = arg[pos++];
365 pos = parse_comma_list(rule.cell_types, arg, pos, "[:");
366 if (pos < int(arg.size()) && arg[pos] == '[') {
367 pos = parse_comma_list(rule.port_names, arg, pos+1, "]:");
368 if (pos < int(arg.size()) && arg[pos] == ']')
369 pos++;
370 }
371 rules.push_back(rule);
372 } else {
373 size_t endpos = arg.find(':', pos);
374 if (endpos == std::string::npos)
375 endpos = arg.size();
376 if (int(endpos) > pos) {
377 std::string str = arg.substr(pos, endpos-pos);
378 if (str[0] == '@') {
379 str = RTLIL::escape_id(str.substr(1));
380 if (design->selection_vars.count(str) > 0) {
381 for (auto i1 : design->selection_vars.at(str).selected_members)
382 for (auto i2 : i1.second)
383 limits.insert(i2);
384 }
385 } else
386 limits.insert(RTLIL::escape_id(str));
387 }
388 pos = endpos;
389 }
390 }
391
392 #if 0
393 log("expand by %d levels (max. %d objects):\n", levels, rem_objects);
394 for (auto &rule : rules) {
395 log(" rule (%c):\n", rule.mode);
396 if (rule.cell_types.size() > 0) {
397 log(" cell types:");
398 for (auto &it : rule.cell_types)
399 log(" %s", it.c_str());
400 log("\n");
401 }
402 if (rule.port_names.size() > 0) {
403 log(" port names:");
404 for (auto &it : rule.port_names)
405 log(" %s", it.c_str());
406 log("\n");
407 }
408 }
409 if (limits.size() > 0) {
410 log(" limits:");
411 for (auto &it : limits)
412 log(" %s", it.c_str());
413 log("\n");
414 }
415 #endif
416
417 while (levels-- > 0 && rem_objects != 0) {
418 int num_objects = select_op_expand(design, work_stack.back(), rules, limits, rem_objects, mode, ct);
419 if (num_objects == 0)
420 break;
421 rem_objects -= num_objects;
422 }
423
424 if (rem_objects == 0)
425 log("Warning: reached configured limit at `%s'.\n", arg.c_str());
426 }
427
428 static void select_filter_active_mod(RTLIL::Design *design, RTLIL::Selection &sel)
429 {
430 if (design->selected_active_module.empty())
431 return;
432
433 if (sel.full_selection) {
434 sel.full_selection = false;
435 sel.selected_modules.clear();
436 sel.selected_members.clear();
437 sel.selected_modules.insert(design->selected_active_module);
438 return;
439 }
440
441 std::vector<std::string> del_list;
442 for (auto mod_name : sel.selected_modules)
443 if (mod_name != design->selected_active_module)
444 del_list.push_back(mod_name);
445 for (auto &it : sel.selected_members)
446 if (it.first != design->selected_active_module)
447 del_list.push_back(it.first);
448 for (auto mod_name : del_list) {
449 sel.selected_modules.erase(mod_name);
450 sel.selected_members.erase(mod_name);
451 }
452 }
453
454 static void select_stmt(RTLIL::Design *design, std::string arg)
455 {
456 std::string arg_mod, arg_memb;
457
458 if (arg.size() == 0)
459 return;
460
461 if (arg[0] == '%') {
462 if (arg == "%") {
463 if (design->selection_stack.size() > 0)
464 work_stack.push_back(design->selection_stack.back());
465 } else
466 if (arg == "%%") {
467 while (work_stack.size() > 1) {
468 select_op_union(design, work_stack.front(), work_stack.back());
469 work_stack.pop_back();
470 }
471 } else
472 if (arg == "%n") {
473 if (work_stack.size() < 1)
474 log_cmd_error("Must have at least one element on the stack for operator %%n.\n");
475 select_op_neg(design, work_stack[work_stack.size()-1]);
476 } else
477 if (arg == "%u") {
478 if (work_stack.size() < 2)
479 log_cmd_error("Must have at least two elements on the stack for operator %%u.\n");
480 select_op_union(design, work_stack[work_stack.size()-2], work_stack[work_stack.size()-1]);
481 work_stack.pop_back();
482 } else
483 if (arg == "%d") {
484 if (work_stack.size() < 2)
485 log_cmd_error("Must have at least two elements on the stack for operator %%d.\n");
486 select_op_diff(design, work_stack[work_stack.size()-2], work_stack[work_stack.size()-1]);
487 work_stack.pop_back();
488 } else
489 if (arg == "%i") {
490 if (work_stack.size() < 2)
491 log_cmd_error("Must have at least two elements on the stack for operator %%i.\n");
492 select_op_intersect(design, work_stack[work_stack.size()-2], work_stack[work_stack.size()-1]);
493 work_stack.pop_back();
494 } else
495 if (arg == "%x" || (arg.size() > 2 && arg.substr(0, 2) == "%x" && (arg[2] == ':' || arg[2] == '*' || arg[2] == '.' || ('0' <= arg[2] && arg[2] <= '9')))) {
496 if (work_stack.size() < 1)
497 log_cmd_error("Must have at least one element on the stack for operator %%x.\n");
498 select_op_expand(design, arg, 'x');
499 } else
500 if (arg == "%ci" || (arg.size() > 3 && arg.substr(0, 3) == "%ci" && (arg[3] == ':' || arg[3] == '*' || arg[3] == '.' || ('0' <= arg[3] && arg[3] <= '9')))) {
501 if (work_stack.size() < 1)
502 log_cmd_error("Must have at least one element on the stack for operator %%ci.\n");
503 select_op_expand(design, arg, 'i');
504 } else
505 if (arg == "%co" || (arg.size() > 3 && arg.substr(0, 3) == "%co" && (arg[3] == ':' || arg[3] == '*' || arg[3] == '.' || ('0' <= arg[3] && arg[3] <= '9')))) {
506 if (work_stack.size() < 1)
507 log_cmd_error("Must have at least one element on the stack for operator %%co.\n");
508 select_op_expand(design, arg, 'o');
509 } else
510 log_cmd_error("Unknown selection operator '%s'.\n", arg.c_str());
511 if (work_stack.size() >= 1)
512 select_filter_active_mod(design, work_stack.back());
513 return;
514 }
515
516 if (arg[0] == '@') {
517 std::string set_name = RTLIL::escape_id(arg.substr(1));
518 if (design->selection_vars.count(set_name) > 0)
519 work_stack.push_back(design->selection_vars[set_name]);
520 else
521 work_stack.push_back(RTLIL::Selection(false));
522 select_filter_active_mod(design, work_stack.back());
523 return;
524 }
525
526 if (!design->selected_active_module.empty()) {
527 arg_mod = design->selected_active_module;
528 arg_memb = arg;
529 } else {
530 size_t pos = arg.find('/');
531 if (pos == std::string::npos) {
532 arg_mod = arg;
533 } else {
534 arg_mod = arg.substr(0, pos);
535 arg_memb = arg.substr(pos+1);
536 }
537 }
538
539 work_stack.push_back(RTLIL::Selection());
540 RTLIL::Selection &sel = work_stack.back();
541
542 if (arg == "*" && arg_mod == "*") {
543 select_filter_active_mod(design, work_stack.back());
544 return;
545 }
546
547 sel.full_selection = false;
548 for (auto &mod_it : design->modules)
549 {
550 if (!match_ids(mod_it.first, arg_mod))
551 continue;
552
553 if (arg_memb == "") {
554 sel.selected_modules.insert(mod_it.first);
555 continue;
556 }
557
558 RTLIL::Module *mod = mod_it.second;
559 if (arg_memb.substr(0, 2) == "w:") {
560 for (auto &it : mod->wires)
561 if (match_ids(it.first, arg_memb.substr(2)))
562 sel.selected_members[mod->name].insert(it.first);
563 } else
564 if (arg_memb.substr(0, 2) == "m:") {
565 for (auto &it : mod->memories)
566 if (match_ids(it.first, arg_memb.substr(2)))
567 sel.selected_members[mod->name].insert(it.first);
568 } else
569 if (arg_memb.substr(0, 2) == "c:") {
570 for (auto &it : mod->cells)
571 if (match_ids(it.first, arg_memb.substr(2)))
572 sel.selected_members[mod->name].insert(it.first);
573 } else
574 if (arg_memb.substr(0, 2) == "t:") {
575 for (auto &it : mod->cells)
576 if (match_ids(it.second->type, arg_memb.substr(2)))
577 sel.selected_members[mod->name].insert(it.first);
578 } else
579 if (arg_memb.substr(0, 2) == "p:") {
580 for (auto &it : mod->processes)
581 if (match_ids(it.first, arg_memb.substr(2)))
582 sel.selected_members[mod->name].insert(it.first);
583 } else
584 if (arg_memb.substr(0, 2) == "a:") {
585 bool use_value_pat = false;
586 std::string name_pat = arg_memb.substr(2);
587 std::string value_pat;
588 if (name_pat.find('=') != std::string::npos) {
589 value_pat = name_pat.substr(name_pat.find('=')+1);
590 name_pat = name_pat.substr(0, name_pat.find('='));
591 use_value_pat = true;
592 }
593 for (auto &it : mod->wires)
594 if (match_attr(it.second->attributes, name_pat, value_pat, use_value_pat))
595 sel.selected_members[mod->name].insert(it.first);
596 for (auto &it : mod->memories)
597 if (match_attr(it.second->attributes, name_pat, value_pat, use_value_pat))
598 sel.selected_members[mod->name].insert(it.first);
599 for (auto &it : mod->cells)
600 if (match_attr(it.second->attributes, name_pat, value_pat, use_value_pat))
601 sel.selected_members[mod->name].insert(it.first);
602 for (auto &it : mod->processes)
603 if (match_attr(it.second->attributes, name_pat, value_pat, use_value_pat))
604 sel.selected_members[mod->name].insert(it.first);
605 } else {
606 if (arg_memb.substr(0, 2) == "n:")
607 arg_memb = arg_memb.substr(2);
608 for (auto &it : mod->wires)
609 if (match_ids(it.first, arg_memb))
610 sel.selected_members[mod->name].insert(it.first);
611 for (auto &it : mod->memories)
612 if (match_ids(it.first, arg_memb))
613 sel.selected_members[mod->name].insert(it.first);
614 for (auto &it : mod->cells)
615 if (match_ids(it.first, arg_memb))
616 sel.selected_members[mod->name].insert(it.first);
617 for (auto &it : mod->processes)
618 if (match_ids(it.first, arg_memb))
619 sel.selected_members[mod->name].insert(it.first);
620 }
621 }
622
623 select_filter_active_mod(design, work_stack.back());
624 }
625
626 // used in kernel/register.cc and maybe other locations, extern decl. in register.h
627 void handle_extra_select_args(Pass *pass, std::vector<std::string> args, size_t argidx, size_t args_size, RTLIL::Design *design)
628 {
629 work_stack.clear();
630 for (; argidx < args_size; argidx++) {
631 if (args[argidx].substr(0, 1) == "-") {
632 if (pass != NULL)
633 pass->cmd_error(args, argidx, "Unexpected option in selection arguments.");
634 else
635 log_cmd_error("Unexpected option in selection arguments.");
636 }
637 select_stmt(design, args[argidx]);
638 }
639 while (work_stack.size() > 1) {
640 select_op_union(design, work_stack.front(), work_stack.back());
641 work_stack.pop_back();
642 }
643 if (work_stack.size() > 0)
644 design->selection_stack.push_back(work_stack.back());
645 else
646 design->selection_stack.push_back(RTLIL::Selection(false));
647 }
648
649 struct SelectPass : public Pass {
650 SelectPass() : Pass("select", "modify and view the list of selected objects") { }
651 virtual void help()
652 {
653 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
654 log("\n");
655 log(" select [ -add | -del | -set <name> ] <selection>\n");
656 log(" select [ -list | -write <filename> | -count | -clear ]\n");
657 log(" select -module <modname>\n");
658 log("\n");
659 log("Most commands use the list of currently selected objects to determine which part\n");
660 log("of the design to operate on. This command can be used to modify and view this\n");
661 log("list of selected objects.\n");
662 log("\n");
663 log("Note that many commands support an optional [selection] argument that can be\n");
664 log("used to override the global selection for the command. The syntax of this\n");
665 log("optional argument is identical to the syntax of the <selection> argument\n");
666 log("described here.\n");
667 log("\n");
668 log(" -add, -del\n");
669 log(" add or remove the given objects to the current selection.\n");
670 log(" without this options the current selection is replaced.\n");
671 log("\n");
672 log(" -set <name>\n");
673 log(" do not modify the current selection. instead save the new selection\n");
674 log(" under the given name (see @<name> below).\n");
675 log("\n");
676 log(" -list\n");
677 log(" list all objects in the current selection\n");
678 log("\n");
679 log(" -write <filename>\n");
680 log(" like -list but write the output to the specified file\n");
681 log("\n");
682 log(" -count\n");
683 log(" count all objects in the current selection\n");
684 log("\n");
685 log(" -clear\n");
686 log(" clear the current selection. this effectively selects the\n");
687 log(" whole design.\n");
688 log("\n");
689 log(" -module <modname>\n");
690 log(" limit the current scope to the specified module.\n");
691 log(" the difference between this and simply selecting the module\n");
692 log(" is that all object names are interpreted relative to this\n");
693 log(" module after this command until the selection is cleared again.\n");
694 log("\n");
695 log("When this command is called without an argument, the current selection\n");
696 log("is displayed in a compact form (i.e. only the module name when a whole module\n");
697 log("is selected).\n");
698 log("\n");
699 log("The <selection> argument itself is a series of commands for a simple stack\n");
700 log("machine. Each element on the stack represents a set of selected objects.\n");
701 log("After this commands have been executed, the union of all remaining sets\n");
702 log("on the stack is computed and used as selection for the command.\n");
703 log("\n");
704 log("Pushing (selecting) object when not in -module mode:\n");
705 log("\n");
706 log(" <mod_pattern>\n");
707 log(" select the specified module(s)\n");
708 log("\n");
709 log(" <mod_pattern>/<obj_pattern>\n");
710 log(" select the specified object(s) from the module(s)\n");
711 log("\n");
712 log("Pushing (selecting) object when in -module mode:\n");
713 log("\n");
714 log(" <obj_pattern>\n");
715 log(" select the specified object(s) from the current module\n");
716 log("\n");
717 log("A <mod_pattern> can be a module name or wildcard expression (*, ?, [..])\n");
718 log("matching module names.\n");
719 log("\n");
720 log("An <obj_pattern> can be an object name, wildcard expression, or one of\n");
721 log("the following:\n");
722 log("\n");
723 log(" w:<pattern>\n");
724 log(" all wires with a name matching the given wildcard pattern\n");
725 log("\n");
726 log(" m:<pattern>\n");
727 log(" all memories with a name matching the given pattern\n");
728 log("\n");
729 log(" c:<pattern>\n");
730 log(" all cells with a name matching the given pattern\n");
731 log("\n");
732 log(" t:<pattern>\n");
733 log(" all cells with a type matching the given pattern\n");
734 log("\n");
735 log(" p:<pattern>\n");
736 log(" all processes with a name matching the given pattern\n");
737 log("\n");
738 log(" a:<pattern>\n");
739 log(" all objects with an attribute name matching the given pattern\n");
740 log("\n");
741 log(" a:<pattern>=<pattern>\n");
742 log(" all objects with a matching attribute name-value-pair\n");
743 log("\n");
744 log(" n:<pattern>\n");
745 log(" all objects with a name matching the given pattern\n");
746 log(" (i.e. 'n:' is optional as it is the default matching rule)\n");
747 log("\n");
748 log(" @<name>\n");
749 log(" push the selection saved prior with 'select -set <name> ...'\n");
750 log("\n");
751 log("The following actions can be performed on the top sets on the stack:\n");
752 log("\n");
753 log(" %%\n");
754 log(" push a copy of the current selection to the stack\n");
755 log("\n");
756 log(" %%%%\n");
757 log(" replace the stack with a union of all elements on it\n");
758 log("\n");
759 log(" %%n\n");
760 log(" replace top set with its invert\n");
761 log("\n");
762 log(" %%u\n");
763 log(" replace the two top sets on the stack with their union\n");
764 log("\n");
765 log(" %%i\n");
766 log(" replace the two top sets on the stack with their intersection\n");
767 log("\n");
768 log(" %%d\n");
769 log(" pop the top set from the stack and subtract it from the new top\n");
770 log("\n");
771 log(" %%x[<num1>|*][.<num2>][:<rule>[:<rule>..]]\n");
772 log(" expand top set <num1> num times according to the specified rules.\n");
773 log(" (i.e. select all cells connected to selected wires and select all\n");
774 log(" wires connected to selected cells) The rules specify which cell\n");
775 log(" ports to use for this. the syntax for a rule is a '-' for exclusion\n");
776 log(" and a '+' for inclusion, followed by an optional comma seperated\n");
777 log(" list of cell types followed by an optional comma separated list of\n");
778 log(" cell ports in square brackets. a rule can also be just a cell or wire\n");
779 log(" name that limits the expansion (is included but does not go beyond).\n");
780 log(" select at most <num2> objects. a warning message is printed when this\n");
781 log(" limit is reached. When '*' is used instead of <num1> then the process\n");
782 log(" is repeated until no further object are selected.\n");
783 log("\n");
784 log(" %%ci[<num1>|*][.<num2>][:<rule>[:<rule>..]]\n");
785 log(" %%co[<num1>|*][.<num2>][:<rule>[:<rule>..]]\n");
786 log(" simmilar to %%x, but only select input (%%ci) or output cones (%%co)\n");
787 log("\n");
788 log("Example: the following command selects all wires that are connected to a\n");
789 log("'GATE' input of a 'SWITCH' cell:\n");
790 log("\n");
791 log(" select */t:SWITCH %%x:+[GATE] */t:SWITCH %%d\n");
792 log("\n");
793 }
794 virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
795 {
796 bool add_mode = false;
797 bool del_mode = false;
798 bool clear_mode = false;
799 bool list_mode = false;
800 bool count_mode = false;
801 bool got_module = false;
802 std::string write_file;
803 std::string set_name;
804
805 work_stack.clear();
806
807 size_t argidx;
808 for (argidx = 1; argidx < args.size(); argidx++)
809 {
810 std::string arg = args[argidx];
811 if (arg == "-add") {
812 add_mode = true;
813 continue;
814 }
815 if (arg == "-del") {
816 del_mode = true;
817 continue;
818 }
819 if (arg == "-clear") {
820 clear_mode = true;
821 continue;
822 }
823 if (arg == "-list") {
824 list_mode = true;
825 continue;
826 }
827 if (arg == "-write" && argidx+1 < args.size()) {
828 write_file = args[++argidx];
829 continue;
830 }
831 if (arg == "-count") {
832 count_mode = true;
833 continue;
834 }
835 if (arg == "-module" && argidx+1 < args.size()) {
836 RTLIL::IdString mod_name = RTLIL::escape_id(args[++argidx]);
837 if (design->modules.count(mod_name) == 0)
838 log_cmd_error("No such module: %s\n", id2cstr(mod_name));
839 design->selected_active_module = mod_name;
840 got_module = true;
841 continue;
842 }
843 if (arg == "-set" && argidx+1 < args.size()) {
844 set_name = RTLIL::escape_id(args[++argidx]);
845 continue;
846 }
847 if (arg.size() > 0 && arg[0] == '-')
848 log_cmd_error("Unkown option %s.\n", arg.c_str());
849 select_stmt(design, arg);
850 }
851
852 if (clear_mode && args.size() != 2)
853 log_cmd_error("Option -clear can not be combined with other options.\n");
854
855 if (add_mode && del_mode)
856 log_cmd_error("Options -add and -del can not be combined.\n");
857
858 if ((list_mode || !write_file.empty() || count_mode) && (add_mode || del_mode))
859 log_cmd_error("Options -list, -write and -count can not be combined with -add or -del.\n");
860
861 if (!set_name.empty() && (list_mode || !write_file.empty() || count_mode || add_mode || del_mode))
862 log_cmd_error("Option -set can not be combined with -list, -write, -count, -add or -del.\n");
863
864 if (work_stack.size() == 0 && got_module) {
865 RTLIL::Selection sel;
866 select_filter_active_mod(design, sel);
867 work_stack.push_back(sel);
868 }
869
870 while (work_stack.size() > 1) {
871 select_op_union(design, work_stack.front(), work_stack.back());
872 work_stack.pop_back();
873 }
874
875 assert(design->selection_stack.size() > 0);
876
877 if (clear_mode)
878 {
879 design->selection_stack.back() = RTLIL::Selection(true);
880 design->selected_active_module = std::string();
881 return;
882 }
883
884 if (list_mode || count_mode || !write_file.empty())
885 {
886 #define LOG_OBJECT(...) do { if (list_mode) log(__VA_ARGS__); if (f != NULL) fprintf(f, __VA_ARGS__); total_count++; } while (0)
887 int total_count = 0;
888 FILE *f = NULL;
889 if (!write_file.empty()) {
890 f = fopen(write_file.c_str(), "w");
891 if (f == NULL)
892 log_error("Can't open '%s' for writing: %s\n", write_file.c_str(), strerror(errno));
893 }
894 RTLIL::Selection *sel = &design->selection_stack.back();
895 if (work_stack.size() > 0)
896 sel = &work_stack.back();
897 sel->optimize(design);
898 for (auto mod_it : design->modules)
899 {
900 if (sel->selected_whole_module(mod_it.first) && list_mode)
901 log("%s\n", id2cstr(mod_it.first));
902 if (sel->selected_module(mod_it.first)) {
903 for (auto &it : mod_it.second->wires)
904 if (sel->selected_member(mod_it.first, it.first))
905 LOG_OBJECT("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first));
906 for (auto &it : mod_it.second->memories)
907 if (sel->selected_member(mod_it.first, it.first))
908 LOG_OBJECT("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first));
909 for (auto &it : mod_it.second->cells)
910 if (sel->selected_member(mod_it.first, it.first))
911 LOG_OBJECT("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first));
912 for (auto &it : mod_it.second->processes)
913 if (sel->selected_member(mod_it.first, it.first))
914 LOG_OBJECT("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first));
915 }
916 }
917 if (count_mode)
918 log("%d objects.\n", total_count);
919 if (f != NULL)
920 fclose(f);
921 #undef LOG_OBJECT
922 return;
923 }
924
925 if (add_mode)
926 {
927 if (work_stack.size() == 0)
928 log_cmd_error("Nothing to add to selection.\n");
929 select_op_union(design, design->selection_stack.back(), work_stack.back());
930 design->selection_stack.back().optimize(design);
931 return;
932 }
933
934 if (del_mode)
935 {
936 if (work_stack.size() == 0)
937 log_cmd_error("Nothing to delete from selection.\n");
938 select_op_diff(design, design->selection_stack.back(), work_stack.back());
939 design->selection_stack.back().optimize(design);
940 return;
941 }
942
943 if (!set_name.empty())
944 {
945 if (work_stack.size() == 0)
946 design->selection_vars.erase(set_name);
947 else
948 design->selection_vars[set_name] = work_stack.back();
949 return;
950 }
951
952 if (work_stack.size() == 0) {
953 RTLIL::Selection &sel = design->selection_stack.back();
954 if (sel.full_selection)
955 log("*\n");
956 for (auto &it : sel.selected_modules)
957 log("%s\n", id2cstr(it));
958 for (auto &it : sel.selected_members)
959 for (auto &it2 : it.second)
960 log("%s/%s\n", id2cstr(it.first), id2cstr(it2));
961 return;
962 }
963
964 design->selection_stack.back() = work_stack.back();
965 design->selection_stack.back().optimize(design);
966 }
967 } SelectPass;
968
969 struct CdPass : public Pass {
970 CdPass() : Pass("cd", "a shortcut for 'select -module <name>'") { }
971 virtual void help()
972 {
973 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
974 log("\n");
975 log(" cd <modname>\n");
976 log("\n");
977 log("This is just a shortcut for 'select -module <modname>'.\n");
978 log("\n");
979 log("\n");
980 log(" cd <cellname>\n");
981 log("\n");
982 log("When no module with the specified name is found, but there is a cell\n");
983 log("with the specified name in the current module, then this is equivialent\n");
984 log("to 'cd <celltype>'.\n");
985 log("\n");
986 log(" cd ..\n");
987 log("\n");
988 log("This is just a shortcut for 'select -clear'.\n");
989 log("\n");
990 }
991 virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
992 {
993 if (args.size() != 2)
994 log_cmd_error("Invalid number of arguments.\n");
995
996 if (args[1] == "..") {
997 design->selection_stack.back() = RTLIL::Selection(true);
998 design->selected_active_module = std::string();
999 return;
1000 }
1001
1002 std::string modname = RTLIL::escape_id(args[1]);
1003
1004 if (design->modules.count(modname) == 0 && !design->selected_active_module.empty()) {
1005 RTLIL::Module *module = NULL;
1006 if (design->modules.count(design->selected_active_module) > 0)
1007 module = design->modules.at(design->selected_active_module);
1008 if (module != NULL && module->cells.count(modname) > 0)
1009 modname = module->cells.at(modname)->type;
1010 }
1011
1012 if (design->modules.count(modname) > 0) {
1013 design->selected_active_module = modname;
1014 design->selection_stack.back() = RTLIL::Selection();
1015 select_filter_active_mod(design, design->selection_stack.back());
1016 design->selection_stack.back().optimize(design);
1017 return;
1018 }
1019
1020 log_cmd_error("No such module `%s' found!\n", RTLIL::id2cstr(modname));
1021 }
1022 } CdPass;
1023
1024 template<typename T>
1025 static int log_matches(const char *title, std::string pattern, T list)
1026 {
1027 std::vector<std::string> matches;
1028
1029 for (auto &it : list)
1030 if (pattern.empty() || match_ids(it.first, pattern))
1031 matches.push_back(it.first);
1032
1033 if (matches.empty())
1034 return 0;
1035
1036 log("\n%d %s:\n", int(matches.size()), title);
1037 for (auto &id : matches)
1038 log(" %s\n", RTLIL::id2cstr(id));
1039 return matches.size();
1040 }
1041
1042 struct LsPass : public Pass {
1043 LsPass() : Pass("ls", "list modules or objects in modules") { }
1044 virtual void help()
1045 {
1046 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1047 log("\n");
1048 log(" ls [pattern]\n");
1049 log("\n");
1050 log("When no active module is selected, this prints a list of all modules.\n");
1051 log("\n");
1052 log("When an active module is selected, this prints a list of objects in the module.\n");
1053 log("\n");
1054 log("If a pattern is given, the objects matching the pattern are printed\n");
1055 log("\n");
1056 log("Note that this command does not use the selection mechanism and always operates\n");
1057 log("on the whole design or whole active module. Use 'select -list' to show a list\n");
1058 log("of currently selected objects.\n");
1059 log("\n");
1060 }
1061 virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
1062 {
1063 std::string pattern;
1064 int counter = 0;
1065
1066 if (args.size() != 1 && args.size() != 2)
1067 log_cmd_error("Invalid number of arguments.\n");
1068 if (args.size() == 2)
1069 pattern = args.at(1);
1070
1071 if (design->selected_active_module.empty())
1072 {
1073 counter += log_matches("modules", pattern, design->modules);
1074 }
1075 else
1076 if (design->modules.count(design->selected_active_module) > 0)
1077 {
1078 RTLIL::Module *module = design->modules.at(design->selected_active_module);
1079 counter += log_matches("wires", pattern, module->wires);
1080 counter += log_matches("memories", pattern, module->memories);
1081 counter += log_matches("cells", pattern, module->cells);
1082 counter += log_matches("processes", pattern, module->processes);
1083 }
1084
1085 // log("\nfound %d item%s.\n", counter, counter == 1 ? "" : "s");
1086 }
1087 } LsPass;
1088