summaryrefslogtreecommitdiff
path: root/utils/regtools/swiss_knife.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'utils/regtools/swiss_knife.cpp')
-rw-r--r--utils/regtools/swiss_knife.cpp612
1 files changed, 612 insertions, 0 deletions
diff --git a/utils/regtools/swiss_knife.cpp b/utils/regtools/swiss_knife.cpp
new file mode 100644
index 0000000000..eaa2519a27
--- /dev/null
+++ b/utils/regtools/swiss_knife.cpp
@@ -0,0 +1,612 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2014 by Amaury Pouly
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include "soc_desc.hpp"
22#include "soc_desc_v1.hpp"
23#include <stdio.h>
24#include <stdlib.h>
25#include <map>
26#include <set>
27#include <cstring>
28
29using namespace soc_desc;
30
31void print_context(const error_context_t& ctx)
32{
33 for(size_t j = 0; j < ctx.count(); j++)
34 {
35 error_t e = ctx.get(j);
36 switch(e.level())
37 {
38 case error_t::INFO: printf("[INFO]"); break;
39 case error_t::WARNING: printf("[WARN]"); break;
40 case error_t::FATAL: printf("[FATAL]"); break;
41 default: printf("[UNK]"); break;
42 }
43 if(e.location().size() != 0)
44 printf(" %s:", e.location().c_str());
45 printf(" %s\n", e.message().c_str());
46 }
47}
48
49bool convert_v1_to_v2(const soc_desc_v1::soc_reg_field_value_t& in, enum_t& out, error_context_t& ctx)
50{
51 out.name = in.name;
52 out.desc = in.desc;
53 out.value = in.value;
54 return true;
55}
56
57bool convert_v1_to_v2(const soc_desc_v1::soc_reg_field_t& in, field_t& out, error_context_t& ctx)
58{
59 out.name = in.name;
60 out.desc = in.desc;
61 out.pos = in.first_bit;
62 out.width = in.last_bit - in.first_bit + 1;
63 out.enum_.resize(in.value.size());
64 for(size_t i = 0; i < in.value.size(); i++)
65 if(!convert_v1_to_v2(in.value[i], out.enum_[i], ctx))
66 return false;
67 return true;
68}
69
70bool convert_v1_to_v2(const soc_desc_v1::soc_reg_addr_t& in, instance_t& out, error_context_t& ctx)
71{
72 out.name = in.name;
73 out.type = instance_t::SINGLE;
74 out.addr = in.addr;
75 return true;
76}
77
78bool convert_v1_to_v2(const soc_desc_v1::soc_reg_formula_t& in, range_t& out, error_context_t& ctx)
79{
80 out.type = range_t::FORMULA;
81 out.formula = in.string;
82 out.variable = "n";
83 return true;
84}
85
86bool convert_v1_to_v2(const soc_desc_v1::soc_reg_t& in, node_t& out, error_context_t& ctx,
87 std::string _loc)
88{
89 std::string loc = _loc + "." + in.name;
90 out.name = in.name;
91 out.desc = in.desc;
92 if(in.formula.type == soc_desc_v1::REG_FORMULA_NONE)
93 {
94 out.instance.resize(in.addr.size());
95 for(size_t i = 0; i < in.addr.size(); i++)
96 if(!convert_v1_to_v2(in.addr[i], out.instance[i], ctx))
97 return false;
98 }
99 else
100 {
101 out.instance.resize(1);
102 out.instance[0].name = in.name;
103 out.instance[0].type = instance_t::RANGE;
104 out.instance[0].range.first = 0;
105 out.instance[0].range.count = in.addr.size();
106 /* check if formula is base/stride */
107 bool is_stride = true;
108 soc_word_t base = 0, stride = 0;
109 if(in.addr.size() <= 1)
110 {
111 ctx.add(error_t(error_t::WARNING, loc,
112 "register uses a formula but has only one instance"));
113 is_stride = false;
114 }
115 else
116 {
117 base = in.addr[0].addr;
118 stride = in.addr[1].addr - base;
119 for(size_t i = 0; i < in.addr.size(); i++)
120 if(base + i * stride != in.addr[i].addr)
121 is_stride = false;
122 }
123
124 if(is_stride)
125 {
126 ctx.add(error_t(error_t::INFO, loc, "promoted formula to base/stride"));
127 out.instance[0].range.type = range_t::STRIDE;
128 out.instance[0].range.base = base;
129 out.instance[0].range.stride = stride;
130 }
131 else if(!convert_v1_to_v2(in.formula, out.instance[0].range, ctx))
132 return false;
133 }
134 out.register_.resize(1);
135 out.register_[0].width = 32;
136 out.register_[0].field.resize(in.field.size());
137 for(size_t i = 0; i < in.field.size(); i++)
138 if(!convert_v1_to_v2(in.field[i], out.register_[0].field[i], ctx))
139 return false;
140 /* sct */
141 if(in.flags & soc_desc_v1::REG_HAS_SCT)
142 {
143 out.node.resize(1);
144 out.node[0].name = "SCT";
145 out.node[0].instance.resize(3);
146 const char *names[3] = {"SET", "CLR", "TOG"};
147 for(size_t i = 0; i < 3; i++)
148 {
149 out.node[0].instance[i].name = names[i];
150 out.node[0].instance[i].type = instance_t::SINGLE;
151 out.node[0].instance[i].addr = 4 + i *4;
152 }
153 }
154 return true;
155}
156
157bool convert_v1_to_v2(const soc_desc_v1::soc_dev_addr_t& in, instance_t& out, error_context_t& ctx)
158{
159 out.name = in.name;
160 out.type = instance_t::SINGLE;
161 out.addr = in.addr;
162 return true;
163}
164
165bool convert_v1_to_v2(const soc_desc_v1::soc_dev_t& in, node_t& out, error_context_t& ctx,
166 std::string _loc)
167{
168 std::string loc = _loc + "." + in.name;
169 if(!in.version.empty())
170 ctx.add(error_t(error_t::INFO, loc, "dropped version"));
171 out.name = in.name;
172 out.title = in.long_name;
173 out.desc = in.desc;
174 out.instance.resize(in.addr.size());
175 for(size_t i = 0; i < in.addr.size(); i++)
176 if(!convert_v1_to_v2(in.addr[i], out.instance[i], ctx))
177 return false;
178 out.node.resize(in.reg.size());
179 for(size_t i = 0; i < in.reg.size(); i++)
180 if(!convert_v1_to_v2(in.reg[i], out.node[i], ctx, loc))
181 return false;
182 return true;
183}
184
185bool convert_v1_to_v2(const soc_desc_v1::soc_t& in, soc_t& out, error_context_t& ctx)
186{
187 out.name = in.name;
188 out.title = in.desc;
189 out.node.resize(in.dev.size());
190 for(size_t i = 0; i < in.dev.size(); i++)
191 if(!convert_v1_to_v2(in.dev[i], out.node[i], ctx, in.name))
192 return false;
193 return true;
194}
195
196int do_convert(int argc, char **argv)
197{
198 if(argc != 2)
199 return printf("convert mode expects two arguments\n");
200 soc_desc_v1::soc_t soc;
201 if(!soc_desc_v1::parse_xml(argv[0], soc))
202 return printf("cannot read file '%s'\n", argv[0]);
203 error_context_t ctx;
204 soc_t new_soc;
205 if(!convert_v1_to_v2(soc, new_soc, ctx))
206 {
207 print_context(ctx);
208 return printf("cannot convert from v1 to v2\n");
209 }
210 if(!produce_xml(argv[1], new_soc, ctx))
211 {
212 print_context(ctx);
213 return printf("cannot write file '%s'\n", argv[1]);
214 }
215 print_context(ctx);
216 return 0;
217}
218
219int do_read(int argc, char **argv)
220{
221 for(int i = 0; i < argc; i++)
222 {
223 error_context_t ctx;
224 soc_t soc;
225 bool ret = parse_xml(argv[i], soc, ctx);
226 if(ctx.count() != 0)
227 printf("In file %s:\n", argv[i]);
228 print_context(ctx);
229 if(!ret)
230 {
231 printf("cannot parse file '%s'\n", argv[i]);
232 continue;
233 }
234 }
235 return 0;
236}
237
238int do_eval(int argc, char **argv)
239{
240 std::map< std::string, soc_word_t > map;
241 for(int i = 0; i < argc; i++)
242 {
243 std::string formula(argv[i]);
244 soc_word_t result;
245 if(strcmp(argv[i], "--var") == 0)
246 {
247 if(i + 1 >= argc)
248 break;
249 i++;
250 std::string str(argv[i]);
251 size_t pos = str.find('=');
252 if(pos == std::string::npos)
253 {
254 printf("invalid variable string '%s'\n", str.c_str());
255 continue;
256 }
257 std::string name = str.substr(0, pos);
258 std::string val = str.substr(pos + 1);
259 char *end;
260 soc_word_t v = strtoul(val.c_str(), &end, 0);
261 if(*end)
262 {
263 printf("invalid variable string '%s'\n", str.c_str());
264 continue;
265 }
266 printf("%s = %#lx\n", name.c_str(), (unsigned long)v);
267 map[name] = v;
268 continue;
269 }
270 error_context_t ctx;
271 if(!evaluate_formula(formula, map, result, "", ctx))
272 {
273 print_context(ctx);
274 printf("cannot parse '%s'\n", formula.c_str());
275 }
276 else
277 printf("result: %lu (%#lx)\n", (unsigned long)result, (unsigned long)result);
278 }
279 return 0;
280}
281
282int do_write(int argc, char **argv)
283{
284 if(argc != 2)
285 return printf("write mode expects two arguments\n");
286 soc_t soc;
287 error_context_t ctx;
288 if(!parse_xml(argv[0], soc, ctx))
289 {
290 print_context(ctx);
291 return printf("cannot read file '%s'\n", argv[0]);
292 }
293 if(!produce_xml(argv[1], soc, ctx))
294 {
295 print_context(ctx);
296 return printf("cannot write file '%s'\n", argv[1]);
297 }
298 print_context(ctx);
299 return 0;
300}
301
302void check_name(const std::string& path, const std::string& name, error_context_t& ctx)
303{
304 if(name.empty())
305 ctx.add(error_t(error_t::FATAL, path, "name is empty"));
306 for(size_t i = 0; i < name.size(); i++)
307 if(!isalnum(name[i]) && name[i] != '_')
308 ctx.add(error_t(error_t::FATAL, path, "name '" + name +
309 "' must only contain alphanumeric characters or '_'"));
310}
311
312void check_instance(const std::string& _path, const instance_t& inst, error_context_t& ctx)
313{
314 std::string path = _path + "." + inst.name;
315 check_name(path, inst.name, ctx);
316 if(inst.type == instance_t::RANGE)
317 {
318 if(inst.range.type == range_t::FORMULA)
319 {
320 check_name(path + ".<formula variable>", inst.range.variable, ctx);
321 /* try to parse formula */
322 std::map< std::string, soc_word_t> var;
323 var[inst.range.variable] = inst.range.first;
324 soc_word_t res;
325 if(!evaluate_formula(inst.range.formula, var, res, path + ".<formula>", ctx))
326 ctx.add(error_t(error_t::FATAL, path + ".<formula>",
327 "cannot evaluate formula"));
328 }
329 }
330}
331
332void check_field(const std::string& _path, const field_t& field, error_context_t& ctx)
333{
334 std::string path = _path + "." + field.name;
335 check_name(path, field.name, ctx);
336 if(field.width == 0)
337 ctx.add(error_t(error_t::WARNING, path, "field has width 0"));
338 soc_word_t max = field.bitmask() >> field.pos;
339 std::set< std::string > names;
340 std::map< soc_word_t, std::string > map;
341 for(size_t i = 0; i < field.enum_.size(); i++)
342 {
343 soc_word_t v = field.enum_[i].value;
344 std::string n = field.enum_[i].name;
345 std::string path_ = path + "." + n;
346 check_name(path_, n, ctx);
347 if(v > max)
348 ctx.add(error_t(error_t::FATAL, path_, "value does not fit into the field"));
349 if(names.find(n) != names.end())
350 ctx.add(error_t(error_t::FATAL, path, "duplicate name '" + n + "' in enums"));
351 names.insert(n);
352 if(map.find(v) != map.end())
353 ctx.add(error_t(error_t::WARNING, path, "'" + n + "' and '" + map[v] + "' have the same value"));
354 map[v] = n;
355 }
356}
357
358void check_register(const std::string& _path, const soc_desc::register_t& reg, error_context_t& ctx)
359{
360 std::string path = _path + ".<register>";
361 if(reg.width != 8 && reg.width != 16 && reg.width != 32)
362 ctx.add(error_t(error_t::WARNING, path, "width is not 8, 16 or 32"));
363 for(size_t i = 0; i < reg.field.size(); i++)
364 check_field(path, reg.field[i], ctx);
365 std::set< std::string > names;
366 soc_word_t bitmap = 0;
367 for(size_t i = 0; i < reg.field.size(); i++)
368 {
369 std::string n = reg.field[i].name;
370 if(names.find(n) != names.end())
371 ctx.add(error_t(error_t::FATAL, path, "duplicate name '" + n + "' in fields"));
372 if(reg.field[i].pos + reg.field[i].width > reg.width)
373 ctx.add(error_t(error_t::FATAL, path, "field '" + n + "' does not fit into the register"));
374 names.insert(n);
375 if(bitmap & reg.field[i].bitmask())
376 {
377 /* find the duplicate to ease debugging */
378 for(size_t j = 0; j < i; j++)
379 if(reg.field[j].bitmask() & reg.field[i].bitmask())
380 ctx.add(error_t(error_t::FATAL, path, "overlap between fields '" +
381 reg.field[j].name + "' and '" + n + "'"));
382 }
383 bitmap |= reg.field[i].bitmask();
384 }
385}
386
387void check_nodes(const std::string& path, const std::vector< node_t >& nodes,
388 error_context_t& ctx);
389
390void check_node(const std::string& _path, const node_t& node, error_context_t& ctx)
391{
392 std::string path = _path + "." + node.name;
393 check_name(_path, node.name, ctx);
394 if(node.instance.empty())
395 ctx.add(error_t(error_t::FATAL, path, "subnode with no instances"));
396 for(size_t j = 0; j < node.instance.size(); j++)
397 check_instance(path, node.instance[j], ctx);
398 for(size_t i = 0; i < node.register_.size(); i++)
399 check_register(path, node.register_[i], ctx);
400 check_nodes(path, node.node, ctx);
401}
402
403void check_nodes(const std::string& path, const std::vector< node_t >& nodes,
404 error_context_t& ctx)
405{
406 for(size_t i = 0; i < nodes.size(); i++)
407 check_node(path, nodes[i], ctx);
408 /* gather all instance names */
409 std::set< std::string > names;
410 for(size_t i = 0; i < nodes.size(); i++)
411 for(size_t j = 0; j < nodes[i].instance.size(); j++)
412 {
413 std::string n = nodes[i].instance[j].name;
414 if(names.find(n) != names.end())
415 ctx.add(error_t(error_t::FATAL, path, "duplicate instance name '" +
416 n + "' in subnodes"));
417 names.insert(n);
418 }
419 /* gather all node names */
420 names.clear();
421 for(size_t i = 0; i < nodes.size(); i++)
422 {
423 std::string n = nodes[i].name;
424 if(names.find(n) != names.end())
425 ctx.add(error_t(error_t::FATAL, path, "duplicate node name '" + n +
426 "' in subnodes"));
427 names.insert(n);
428 }
429}
430
431void do_check(soc_t& soc, error_context_t& ctx)
432{
433 check_name(soc.name, soc.name, ctx);
434 check_nodes(soc.name, soc.node, ctx);
435}
436
437int do_check(int argc, char **argv)
438{
439 for(int i = 0; i < argc; i++)
440 {
441 error_context_t ctx;
442 soc_t soc;
443 bool ret = parse_xml(argv[i], soc, ctx);
444 if(ret)
445 do_check(soc, ctx);
446 if(ctx.count() != 0)
447 printf("In file %s:\n", argv[i]);
448 print_context(ctx);
449 if(!ret)
450 {
451 printf("cannot parse file '%s'\n", argv[i]);
452 continue;
453 }
454 }
455 return 0;
456}
457
458const unsigned DUMP_NODES = 1 << 0;
459const unsigned DUMP_INSTANCES = 1 << 1;
460const unsigned DUMP_VERBOSE = 1 << 2;
461const unsigned DUMP_REGISTERS = 1 << 3;
462
463void print_path(node_ref_t node, bool nl = true)
464{
465 printf("%s", node.soc().get()->name.c_str());
466 std::vector< std::string > path = node.path();
467 for(size_t i = 0; i < path.size(); i++)
468 printf(".%s", path[i].c_str());
469 if(nl)
470 printf("\n");
471}
472
473void print_inst(node_inst_t inst, bool end = true)
474{
475 if(!inst.is_root())
476 {
477 print_inst(inst.parent(), false);
478 printf(".%s", inst.name().c_str());
479 if(inst.is_indexed())
480 printf("[%u]", (unsigned)inst.index());
481 }
482 else
483 {
484 printf("%s", inst.soc().get()->name.c_str());
485 }
486 if(end)
487 printf(" @ %#x\n", inst.addr());
488}
489
490void print_reg(register_ref_t reg, unsigned flags)
491{
492 if(!(flags & DUMP_REGISTERS))
493 return;
494 node_ref_t node = reg.node();
495 soc_desc::register_t *r = reg.get();
496 print_path(node, false);
497 printf(":width=%u\n", (unsigned)r->width);
498 std::vector< field_ref_t > fields = reg.fields();
499 for(size_t i = 0; i < fields.size(); i++)
500 {
501 field_t *f = fields[i].get();
502 print_path(node, false);
503 if(f->width == 1)
504 printf(":[%u]=", (unsigned)f->pos);
505 else
506 printf(":[%u-%u]=", (unsigned)(f->pos + f->width - 1), (unsigned)f->pos);
507 printf("%s\n", f->name.c_str());
508 }
509}
510
511void do_dump(node_ref_t node, unsigned flags)
512{
513 print_path(node);
514 if(node.reg().node() == node)
515 print_reg(node.reg(), flags);
516 std::vector< node_ref_t > children = node.children();
517 for(size_t i = 0; i < children.size(); i++)
518 do_dump(children[i], flags);
519}
520
521void do_dump(node_inst_t inst, unsigned flags)
522{
523 print_inst(inst);
524 std::vector< node_inst_t > children = inst.children();
525 for(size_t i = 0; i < children.size(); i++)
526 do_dump(children[i], flags);
527}
528
529void do_dump(soc_t& soc, unsigned flags)
530{
531 soc_ref_t ref(&soc);
532 if(flags & DUMP_NODES)
533 do_dump(ref.root(), flags);
534 if(flags & DUMP_INSTANCES)
535 do_dump(ref.root_inst(), flags);
536}
537
538int do_dump(int argc, char **argv)
539{
540 unsigned flags = 0;
541 int i = 0;
542 for(; i < argc; i++)
543 {
544 if(strcmp(argv[i], "--nodes") == 0)
545 flags |= DUMP_NODES;
546 else if(strcmp(argv[i], "--instances") == 0)
547 flags |= DUMP_INSTANCES;
548 else if(strcmp(argv[i], "--verbose") == 0)
549 flags |= DUMP_VERBOSE;
550 else if(strcmp(argv[i], "--registers") == 0)
551 flags |= DUMP_REGISTERS;
552 else
553 break;
554 }
555 if(i == argc)
556 {
557 printf("you must specify at least one file\n");
558 return 1;
559 }
560 for(; i < argc; i++)
561 {
562 error_context_t ctx;
563 soc_t soc;
564 bool ret = parse_xml(argv[i], soc, ctx);
565 if(ret)
566 do_dump(soc, flags);
567 if(ctx.count() != 0)
568 printf("In file %s:\n", argv[i]);
569 print_context(ctx);
570 if(!ret)
571 {
572 printf("cannot parse file '%s'\n", argv[i]);
573 continue;
574 }
575 }
576 return 0;
577}
578
579void usage()
580{
581 printf("usage: swiss_knife <mode> [options]\n");
582 printf("modes:\n");
583 printf(" read <files...>\n");
584 printf(" write <read file> <write file>\n");
585 printf(" eval [<formula>|--var <name>=<val>]...\n");
586 printf(" convert <input file> <output file>\n");
587 printf(" check <files...>\n");
588 printf(" dump [--nodes] [--instances] [--registers] [--verbose] <files...>\n");
589 exit(1);
590}
591
592int main(int argc, char **argv)
593{
594 if(argc < 2)
595 usage();
596 std::string mode = argv[1];
597 if(mode == "read")
598 return do_read(argc - 2, argv + 2);
599 else if(mode == "write")
600 return do_write(argc - 2, argv + 2);
601 else if(mode == "eval")
602 return do_eval(argc - 2, argv + 2);
603 else if(mode == "convert")
604 return do_convert(argc - 2, argv + 2);
605 else if(mode == "check")
606 return do_check(argc - 2, argv + 2);
607 else if(mode == "dump")
608 return do_dump(argc - 2, argv + 2);
609 else
610 usage();
611 return 0;
612} \ No newline at end of file