2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
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/yosys.h"
21 #include "kernel/sigtools.h"
24 PRIVATE_NAMESPACE_BEGIN
26 Const
make_value(string
&value
)
28 if (GetSize(value
) >= 2 && value
.front() == '"' && value
.back() == '"')
29 return Const(value
.substr(1, GetSize(value
)-2));
32 SigSpec::parse(sig
, nullptr, value
);
33 return sig
.as_const();
36 bool string_compare_nocase(const string
&str1
, const string
&str2
)
38 if (str1
.size() != str2
.size())
41 for (size_t i
= 0; i
< str1
.size(); i
++)
43 char ch1
= str1
[i
], ch2
= str2
[i
];
44 if ('a' <= ch1
&& ch1
<= 'z')
46 if ('a' <= ch2
&& ch2
<= 'z')
55 bool match_name(string
&name
, IdString
&id
, bool ignore_case
=false)
57 string str1
= RTLIL::escape_id(name
);
58 string str2
= id
.str();
61 return string_compare_nocase(str1
, str2
);
66 bool match_value(string
&value
, Const
&val
, bool ignore_case
=false)
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
);
74 return make_value(value
) == val
;
77 struct AttrmapAction
{
78 virtual ~AttrmapAction() { }
79 virtual bool apply(IdString
&id
, Const
&val
) = 0;
82 struct AttrmapTocase
: AttrmapAction
{
84 bool apply(IdString
&id
, Const
&) override
{
85 if (match_name(name
, id
, true))
86 id
= RTLIL::escape_id(name
);
91 struct AttrmapRename
: AttrmapAction
{
92 string old_name
, new_name
;
93 bool apply(IdString
&id
, Const
&) override
{
94 if (match_name(old_name
, id
))
95 id
= RTLIL::escape_id(new_name
);
100 struct AttrmapMap
: AttrmapAction
{
102 string old_name
, new_name
;
103 string old_value
, new_value
;
104 bool apply(IdString
&id
, Const
&val
) 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
);
113 struct AttrmapRemove
: AttrmapAction
{
116 bool apply(IdString
&id
, Const
&val
) override
{
117 return !(match_name(name
, id
) && (!has_value
|| match_value(value
, val
)));
121 void attrmap_apply(string objname
, vector
<std::unique_ptr
<AttrmapAction
>> &actions
, dict
<RTLIL::IdString
, RTLIL::Const
> &attributes
)
123 dict
<RTLIL::IdString
, RTLIL::Const
> new_attributes
;
125 for (auto attr
: attributes
)
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
;
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
));
136 new_attributes
[new_attr
.first
] = new_attr
.second
;
140 log("Removed attribute on %s: %s=%s\n", objname
.c_str(), log_id(attr
.first
), log_const(attr
.second
));
143 attributes
.swap(new_attributes
);
146 void log_attrmap_paramap_options()
148 log(" -tocase <name>\n");
149 log(" Match attribute names case-insensitively and set it to the specified\n");
152 log(" -rename <old_name> <new_name>\n");
153 log(" Rename attributes as specified\n");
155 log(" -map <old_name>=<old_value> <new_name>=<new_value>\n");
156 log(" Map key/value pairs as indicated.\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");
162 log(" -remove <name>=<value>\n");
163 log(" Remove attributes matching this pattern.\n");
166 bool parse_attrmap_paramap_options(size_t &argidx
, std::vector
<std::string
> &args
, vector
<std::unique_ptr
<AttrmapAction
>> &actions
)
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
));
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
));
182 if ((arg
== "-map" || arg
== "-imap") && argidx
+2 < args
.size()) {
183 string arg1
= args
[++argidx
];
184 string arg2
= args
[++argidx
];
186 size_t p
= arg1
.find("=");
187 if (p
!= string::npos
) {
188 val1
= arg1
.substr(p
+1);
189 arg1
= arg1
.substr(0, p
);
192 if (p
!= string::npos
) {
193 val2
= arg2
.substr(p
+1);
194 arg2
= arg2
.substr(0, p
);
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
));
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
);
212 auto action
= new AttrmapRemove
;
214 action
->has_value
= (p
!= string::npos
);
215 action
->value
= val1
;
216 actions
.push_back(std::unique_ptr
<AttrmapAction
>(action
));
222 struct AttrmapPass
: public Pass
{
223 AttrmapPass() : Pass("attrmap", "renaming attributes") { }
226 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
228 log(" attrmap [options] [selection]\n");
230 log("This command renames attributes and/or maps key/value pairs to\n");
231 log("other key/value pairs.\n");
233 log_attrmap_paramap_options();
236 log(" Operate on module attributes instead of attributes on wires and cells.\n");
238 log("For example, mapping Xilinx-style \"keep\" attributes to Yosys-style:\n");
240 log(" attrmap -tocase keep -imap keep=\"true\" keep=1 \\\n");
241 log(" -imap keep=\"false\" keep=0 -remove keep=0\n");
244 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) override
246 log_header(design
, "Executing ATTRMAP pass (move or copy attributes).\n");
248 bool modattr_mode
= false;
249 vector
<std::unique_ptr
<AttrmapAction
>> actions
;
252 for (argidx
= 1; argidx
< args
.size(); argidx
++)
254 if (parse_attrmap_paramap_options(argidx
, args
, actions
))
256 if (args
[argidx
] == "-modattr") {
262 extra_args(args
, argidx
, design
);
266 for (auto module
: design
->selected_whole_modules())
267 attrmap_apply(stringf("%s", log_id(module
)), actions
, module
->attributes
);
271 for (auto module
: design
->selected_modules())
273 for (auto wire
: module
->selected_wires())
274 attrmap_apply(stringf("%s.%s", log_id(module
), log_id(wire
)), actions
, wire
->attributes
);
276 for (auto cell
: module
->selected_cells())
277 attrmap_apply(stringf("%s.%s", log_id(module
), log_id(cell
)), actions
, cell
->attributes
);
279 for (auto proc
: module
->processes
)
281 if (!design
->selected(module
, proc
.second
))
283 attrmap_apply(stringf("%s.%s", log_id(module
), log_id(proc
.first
)), actions
, proc
.second
->attributes
);
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
);
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());
302 struct ParamapPass
: public Pass
{
303 ParamapPass() : Pass("paramap", "renaming cell parameters") { }
306 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
308 log(" paramap [options] [selection]\n");
310 log("This command renames cell parameters and/or maps key/value pairs to\n");
311 log("other key/value pairs.\n");
313 log_attrmap_paramap_options();
315 log("For example, mapping Diamond-style ECP5 \"init\" attributes to Yosys-style:\n");
317 log(" paramap -tocase INIT t:LUT4\n");
320 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) override
322 log_header(design
, "Executing PARAMAP pass (move or copy cell parameters).\n");
324 vector
<std::unique_ptr
<AttrmapAction
>> actions
;
327 for (argidx
= 1; argidx
< args
.size(); argidx
++)
329 if (parse_attrmap_paramap_options(argidx
, args
, actions
))
333 extra_args(args
, argidx
, design
);
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
);
341 PRIVATE_NAMESPACE_END