abc9_ops: still emit delay table even box has no timing
[yosys.git] / passes / techmap / attrmap.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/yosys.h"
21 #include "kernel/sigtools.h"
22
23 USING_YOSYS_NAMESPACE
24 PRIVATE_NAMESPACE_BEGIN
25
26 Const make_value(string &value)
27 {
28 if (GetSize(value) >= 2 && value.front() == '"' && value.back() == '"')
29 return Const(value.substr(1, GetSize(value)-2));
30
31 SigSpec sig;
32 SigSpec::parse(sig, nullptr, value);
33 return sig.as_const();
34 }
35
36 bool string_compare_nocase(const string &str1, const string &str2)
37 {
38 if (str1.size() != str2.size())
39 return false;
40
41 for (size_t i = 0; i < str1.size(); i++)
42 {
43 char ch1 = str1[i], ch2 = str2[i];
44 if ('a' <= ch1 && ch1 <= 'z')
45 ch1 -= 'a' - 'A';
46 if ('a' <= ch2 && ch2 <= 'z')
47 ch2 -= 'a' - 'A';
48 if (ch1 != ch2)
49 return false;
50 }
51
52 return true;
53 }
54
55 bool match_name(string &name, IdString &id, bool ignore_case=false)
56 {
57 string str1 = RTLIL::escape_id(name);
58 string str2 = id.str();
59
60 if (ignore_case)
61 return string_compare_nocase(str1, str2);
62
63 return str1 == str2;
64 }
65
66 bool match_value(string &value, Const &val, bool ignore_case=false)
67 {
68 if (ignore_case && ((val.flags & RTLIL::CONST_FLAG_STRING) != 0) && GetSize(value) && value.front() == '"' && value.back() == '"') {
69 string str1 = value.substr(1, GetSize(value)-2);
70 string str2 = val.decode_string();
71 return string_compare_nocase(str1, str2);
72 }
73
74 return make_value(value) == val;
75 }
76
77 struct AttrmapAction {
78 virtual ~AttrmapAction() { }
79 virtual bool apply(IdString &id, Const &val) = 0;
80 };
81
82 struct AttrmapTocase : AttrmapAction {
83 string name;
84 bool apply(IdString &id, Const&) YS_OVERRIDE {
85 if (match_name(name, id, true))
86 id = RTLIL::escape_id(name);
87 return true;
88 }
89 };
90
91 struct AttrmapRename : AttrmapAction {
92 string old_name, new_name;
93 bool apply(IdString &id, Const&) YS_OVERRIDE {
94 if (match_name(old_name, id))
95 id = RTLIL::escape_id(new_name);
96 return true;
97 }
98 };
99
100 struct AttrmapMap : AttrmapAction {
101 bool imap;
102 string old_name, new_name;
103 string old_value, new_value;
104 bool apply(IdString &id, Const &val) YS_OVERRIDE {
105 if (match_name(old_name, id) && match_value(old_value, val, true)) {
106 id = RTLIL::escape_id(new_name);
107 val = make_value(new_value);
108 }
109 return true;
110 }
111 };
112
113 struct AttrmapRemove : AttrmapAction {
114 bool has_value;
115 string name, value;
116 bool apply(IdString &id, Const &val) YS_OVERRIDE {
117 return !(match_name(name, id) && (!has_value || match_value(value, val)));
118 }
119 };
120
121 void attrmap_apply(string objname, vector<std::unique_ptr<AttrmapAction>> &actions, dict<RTLIL::IdString, RTLIL::Const> &attributes)
122 {
123 dict<RTLIL::IdString, RTLIL::Const> new_attributes;
124
125 for (auto attr : attributes)
126 {
127 auto new_attr = attr;
128 for (auto &action : actions)
129 if (!action->apply(new_attr.first, new_attr.second))
130 goto delete_this_attr;
131
132 if (new_attr != attr)
133 log("Changed attribute on %s: %s=%s -> %s=%s\n", objname.c_str(),
134 log_id(attr.first), log_const(attr.second), log_id(new_attr.first), log_const(new_attr.second));
135
136 new_attributes[new_attr.first] = new_attr.second;
137
138 if (0)
139 delete_this_attr:
140 log("Removed attribute on %s: %s=%s\n", objname.c_str(), log_id(attr.first), log_const(attr.second));
141 }
142
143 attributes.swap(new_attributes);
144 }
145
146 void log_attrmap_paramap_options()
147 {
148 log(" -tocase <name>\n");
149 log(" Match attribute names case-insensitively and set it to the specified\n");
150 log(" name.\n");
151 log("\n");
152 log(" -rename <old_name> <new_name>\n");
153 log(" Rename attributes as specified\n");
154 log("\n");
155 log(" -map <old_name>=<old_value> <new_name>=<new_value>\n");
156 log(" Map key/value pairs as indicated.\n");
157 log("\n");
158 log(" -imap <old_name>=<old_value> <new_name>=<new_value>\n");
159 log(" Like -map, but use case-insensitive match for <old_value> when\n");
160 log(" it is a string value.\n");
161 log("\n");
162 log(" -remove <name>=<value>\n");
163 log(" Remove attributes matching this pattern.\n");
164 }
165
166 bool parse_attrmap_paramap_options(size_t &argidx, std::vector<std::string> &args, vector<std::unique_ptr<AttrmapAction>> &actions)
167 {
168 std::string arg = args[argidx];
169 if (arg == "-tocase" && argidx+1 < args.size()) {
170 auto action = new AttrmapTocase;
171 action->name = args[++argidx];
172 actions.push_back(std::unique_ptr<AttrmapAction>(action));
173 return true;
174 }
175 if (arg == "-rename" && argidx+2 < args.size()) {
176 auto action = new AttrmapRename;
177 action->old_name = args[++argidx];
178 action->new_name = args[++argidx];
179 actions.push_back(std::unique_ptr<AttrmapAction>(action));
180 return true;
181 }
182 if ((arg == "-map" || arg == "-imap") && argidx+2 < args.size()) {
183 string arg1 = args[++argidx];
184 string arg2 = args[++argidx];
185 string val1, val2;
186 size_t p = arg1.find("=");
187 if (p != string::npos) {
188 val1 = arg1.substr(p+1);
189 arg1 = arg1.substr(0, p);
190 }
191 p = arg2.find("=");
192 if (p != string::npos) {
193 val2 = arg2.substr(p+1);
194 arg2 = arg2.substr(0, p);
195 }
196 auto action = new AttrmapMap;
197 action->imap = (arg == "-map");
198 action->old_name = arg1;
199 action->new_name = arg2;
200 action->old_value = val1;
201 action->new_value = val2;
202 actions.push_back(std::unique_ptr<AttrmapAction>(action));
203 return true;
204 }
205 if (arg == "-remove" && argidx+1 < args.size()) {
206 string arg1 = args[++argidx], val1;
207 size_t p = arg1.find("=");
208 if (p != string::npos) {
209 val1 = arg1.substr(p+1);
210 arg1 = arg1.substr(0, p);
211 }
212 auto action = new AttrmapRemove;
213 action->name = arg1;
214 action->has_value = (p != string::npos);
215 action->value = val1;
216 actions.push_back(std::unique_ptr<AttrmapAction>(action));
217 return true;
218 }
219 return false;
220 }
221
222 struct AttrmapPass : public Pass {
223 AttrmapPass() : Pass("attrmap", "renaming attributes") { }
224 void help() YS_OVERRIDE
225 {
226 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
227 log("\n");
228 log(" attrmap [options] [selection]\n");
229 log("\n");
230 log("This command renames attributes and/or maps key/value pairs to\n");
231 log("other key/value pairs.\n");
232 log("\n");
233 log_attrmap_paramap_options();
234 log("\n");
235 log(" -modattr\n");
236 log(" Operate on module attributes instead of attributes on wires and cells.\n");
237 log("\n");
238 log("For example, mapping Xilinx-style \"keep\" attributes to Yosys-style:\n");
239 log("\n");
240 log(" attrmap -tocase keep -imap keep=\"true\" keep=1 \\\n");
241 log(" -imap keep=\"false\" keep=0 -remove keep=0\n");
242 log("\n");
243 }
244 void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
245 {
246 log_header(design, "Executing ATTRMAP pass (move or copy attributes).\n");
247
248 bool modattr_mode = false;
249 vector<std::unique_ptr<AttrmapAction>> actions;
250
251 size_t argidx;
252 for (argidx = 1; argidx < args.size(); argidx++)
253 {
254 if (parse_attrmap_paramap_options(argidx, args, actions))
255 continue;
256 if (args[argidx] == "-modattr") {
257 modattr_mode = true;
258 continue;
259 }
260 break;
261 }
262 extra_args(args, argidx, design);
263
264 if (modattr_mode)
265 {
266 for (auto module : design->selected_whole_modules())
267 attrmap_apply(stringf("%s", log_id(module)), actions, module->attributes);
268 }
269 else
270 {
271 for (auto module : design->selected_modules())
272 {
273 for (auto wire : module->selected_wires())
274 attrmap_apply(stringf("%s.%s", log_id(module), log_id(wire)), actions, wire->attributes);
275
276 for (auto cell : module->selected_cells())
277 attrmap_apply(stringf("%s.%s", log_id(module), log_id(cell)), actions, cell->attributes);
278
279 for (auto proc : module->processes)
280 {
281 if (!design->selected(module, proc.second))
282 continue;
283 attrmap_apply(stringf("%s.%s", log_id(module), log_id(proc.first)), actions, proc.second->attributes);
284
285 std::vector<RTLIL::CaseRule*> all_cases = {&proc.second->root_case};
286 while (!all_cases.empty()) {
287 RTLIL::CaseRule *cs = all_cases.back();
288 all_cases.pop_back();
289 attrmap_apply(stringf("%s.%s (case)", log_id(module), log_id(proc.first)), actions, cs->attributes);
290
291 for (auto &sw : cs->switches) {
292 attrmap_apply(stringf("%s.%s (switch)", log_id(module), log_id(proc.first)), actions, sw->attributes);
293 all_cases.insert(all_cases.end(), sw->cases.begin(), sw->cases.end());
294 }
295 }
296 }
297 }
298 }
299 }
300 } AttrmapPass;
301
302 struct ParamapPass : public Pass {
303 ParamapPass() : Pass("paramap", "renaming cell parameters") { }
304 void help() YS_OVERRIDE
305 {
306 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
307 log("\n");
308 log(" paramap [options] [selection]\n");
309 log("\n");
310 log("This command renames cell parameters and/or maps key/value pairs to\n");
311 log("other key/value pairs.\n");
312 log("\n");
313 log_attrmap_paramap_options();
314 log("\n");
315 log("For example, mapping Diamond-style ECP5 \"init\" attributes to Yosys-style:\n");
316 log("\n");
317 log(" paramap -tocase INIT t:LUT4\n");
318 log("\n");
319 }
320 void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
321 {
322 log_header(design, "Executing PARAMAP pass (move or copy cell parameters).\n");
323
324 vector<std::unique_ptr<AttrmapAction>> actions;
325
326 size_t argidx;
327 for (argidx = 1; argidx < args.size(); argidx++)
328 {
329 if (parse_attrmap_paramap_options(argidx, args, actions))
330 continue;
331 break;
332 }
333 extra_args(args, argidx, design);
334
335 for (auto module : design->selected_modules())
336 for (auto cell : module->selected_cells())
337 attrmap_apply(stringf("%s.%s", log_id(module), log_id(cell)), actions, cell->parameters);
338 }
339 } ParamapPass;
340
341 PRIVATE_NAMESPACE_END