summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2017-01-26 15:26:10 +0100
committerAmaury Pouly <amaury.pouly@gmail.com>2017-02-04 17:18:13 +0100
commit6f0f1193e549245f3b4ac77c8875a40652286d1e (patch)
treeb262e7942ca690c31946ee1dff880261e6b0d56a
parentc156c5f5e57ee0ae5fc1dbba92550f80f9eaf4a8 (diff)
downloadrockbox-6f0f1193e549245f3b4ac77c8875a40652286d1e.tar.gz
rockbox-6f0f1193e549245f3b4ac77c8875a40652286d1e.zip
regtools: add new tool list/find/describe registers
Change-Id: I2d93d24bd421e1a2ea6d27b8f7cfd17311e6d458
-rw-r--r--utils/regtools/Makefile2
-rw-r--r--utils/regtools/regtool.cpp630
2 files changed, 631 insertions, 1 deletions
diff --git a/utils/regtools/Makefile b/utils/regtools/Makefile
index fed5d8c8e5..647a5b42ef 100644
--- a/utils/regtools/Makefile
+++ b/utils/regtools/Makefile
@@ -4,7 +4,7 @@ CXX?=g++
4LD?=g++ 4LD?=g++
5INCLUDE=-Iinclude/ 5INCLUDE=-Iinclude/
6CFLAGS=-g -std=c99 -Wall $(DEFINES) $(INCLUDE) 6CFLAGS=-g -std=c99 -Wall $(DEFINES) $(INCLUDE)
7CXXFLAGS=-g -Wall $(DEFINES) $(INCLUDE) 7CXXFLAGS=-g -std=c++11 -Wall $(DEFINES) $(INCLUDE)
8LDFLAGS=-Llib -lsocdesc `xml2-config --libs` 8LDFLAGS=-Llib -lsocdesc `xml2-config --libs`
9SRC=$(wildcard *.c) 9SRC=$(wildcard *.c)
10SRCXX=$(wildcard *.cpp) 10SRCXX=$(wildcard *.cpp)
diff --git a/utils/regtools/regtool.cpp b/utils/regtools/regtool.cpp
new file mode 100644
index 0000000000..2f7f04b956
--- /dev/null
+++ b/utils/regtools/regtool.cpp
@@ -0,0 +1,630 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2016 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 <cstdio>
24#include <cstdlib>
25#include <map>
26#include <set>
27#include <cstring>
28#include <fstream>
29#include <sstream>
30#include <cstring>
31#include <dirent.h>
32#include <getopt.h>
33#include <regex>
34
35using namespace soc_desc;
36int g_verbose = 0;
37bool g_inline = false;
38bool g_print_zero = false;
39bool g_regex_mode = false;
40std::regex_constants::syntax_option_type g_regex_flags;
41
42std::regex_constants::syntax_option_type parse_regex_mode(const std::string& mode)
43{
44 std::regex_constants::syntax_option_type flags;
45 size_t index = 0;
46 while(index < mode.size())
47 {
48 size_t end = mode.find(',', index);
49 if(end == std::string::npos)
50 end = mode.size();
51 std::string opt = mode.substr(index, end - index);
52 if(opt == "icase")
53 flags |= std::regex_constants::icase;
54 else if(opt == "ECMAScript")
55 flags |= std::regex_constants::ECMAScript;
56 else if(opt == "basic")
57 flags |= std::regex_constants::basic;
58 else if(opt == "extended")
59 flags |= std::regex_constants::extended;
60 else if(opt == "awk")
61 flags |= std::regex_constants::awk;
62 else if(opt == "grep")
63 flags |= std::regex_constants::grep;
64 else if(opt == "egrep")
65 flags |= std::regex_constants::egrep;
66 else
67 {
68 fprintf(stderr, "Invalid regex option '%s'\n", opt.c_str());
69 exit(1);
70 }
71 index = end + 1;
72 }
73 return flags;
74}
75
76void print_path(node_ref_t node, bool nl = true)
77{
78 printf("%s", node.soc().get()->name.c_str());
79 std::vector< std::string > path = node.path();
80 for(size_t i = 0; i < path.size(); i++)
81 printf(".%s", path[i].c_str());
82 if(nl)
83 printf("\n");
84}
85
86template<typename T>
87std::string to_str(const T& t)
88{
89 std::ostringstream oss;
90 oss << t;
91 return oss.str();
92}
93
94std::string get_path(node_inst_t inst)
95{
96 if(!inst.is_root())
97 {
98 std::string path = get_path(inst.parent()) + "." + inst.name();
99 if(inst.is_indexed())
100 path += "[" + to_str(inst.index()) + "]";
101 return path;
102 }
103 else
104 return inst.soc().get()->name;
105}
106
107void print_inst(node_inst_t inst, bool addr = true, bool nl = true)
108{
109 if(!inst.is_root())
110 {
111 print_inst(inst.parent(), false);
112 printf(".%s", inst.name().c_str());
113 if(inst.is_indexed())
114 printf("[%u]", (unsigned)inst.index());
115 }
116 else
117 printf("%s", inst.soc().get()->name.c_str());
118 if(addr)
119 {
120 printf(" @ %#x", inst.addr());
121 if(nl)
122 printf("\n");
123 }
124}
125
126void find_insts(std::vector< node_inst_t >& list, node_inst_t inst, soc_addr_t addr)
127{
128 if(inst.addr() == addr)
129 {
130 /* only keep matches that are registers */
131 if(inst.node().reg().valid())
132 list.push_back(inst);
133 }
134 std::vector< node_inst_t > children = inst.children();
135 for(size_t i = 0; i < children.size(); i++)
136 find_insts(list, children[i], addr);
137}
138
139void find_insts(std::vector< node_inst_t >& insts,
140 std::vector< soc_t >& soc_list, soc_addr_t addr)
141{
142 for(size_t i = 0; i < soc_list.size(); i++)
143 find_insts(insts, soc_ref_t(&soc_list[i]).root_inst(), addr);
144}
145
146const size_t NO_INDEX = (size_t)-1;
147/* index is set to NO_INDEX if there is no index */
148bool parse_name(std::string& name, std::string& component, size_t& index)
149{
150 size_t i = 0;
151 /* name must be of the form [a-zA-Z0-9_]+ */
152 while(i < name.size() && (isalnum(name[i]) || name[i] == '_'))
153 i++;
154 if(i == 0)
155 return false;
156 component = name.substr(0, i);
157 /* must stop at the end, or on '.' or on '[' */
158 if(name.size() == i)
159 {
160 index = NO_INDEX;
161 name = name.substr(i);
162 return true;
163 }
164 else if(name[i] == '.')
165 {
166 index = NO_INDEX;
167 name = name.substr(i + 1);
168 return true;
169 }
170 else if(name[i] == '[')
171 {
172 /* parse index */
173 char *end;
174 index = strtoul(name.c_str() + i + 1, &end, 0);
175 /* must stop on ']'. Also strtoul is happy with an empty string, check for this */
176 if(*end != ']' || end == name.c_str() + i + 1)
177 return false;
178 i = end + 1 - name.c_str();
179 /* check if we have a '.' after that, or the end */
180 if(i < name.size() && name[i] != '.')
181 return false;
182 name = name.substr(i + 1);
183 return true;
184 }
185 else
186 return false;
187}
188
189int find_insts(std::vector< node_inst_t >& matches, node_inst_t inst, std::regex& regex)
190{
191 /* only keep matches that are registers */
192 if(inst.node().reg().valid())
193 {
194 std::string path = get_path(inst);
195 if(regex_match(path, regex))
196 matches.push_back(inst);
197 }
198 std::vector< node_inst_t > children = inst.children();
199 for(size_t i = 0; i < children.size(); i++)
200 find_insts(matches, children[i], regex);
201 return 0;
202}
203
204int find_insts_regex(std::vector< node_inst_t >& matches, std::vector< soc_t >& soc_list, std::string str)
205{
206 auto flags = g_regex_flags | std::regex_constants::optimize; /* we will match a lot */
207 /* any error during construction or mayching will throw exception, and print
208 * an error message so don't catch them */
209 std::regex regex(str, flags);
210 for(size_t i = 0; i < soc_list.size(); i++)
211 if(find_insts(matches, soc_ref_t(&soc_list[i]).root_inst(), regex) != 0)
212 return 1;
213 return 0;
214}
215
216int find_insts(std::vector< node_inst_t >& matches, node_inst_t inst, std::string name)
217{
218 if(name.empty())
219 {
220 if(inst.node().reg().valid())
221 matches.push_back(inst);
222 return 0;
223 }
224 std::string component;
225 size_t index;
226 bool ok = parse_name(name, component, index);
227 if(!ok)
228 {
229 fprintf(stderr, "invalid name '%s'\n", name.c_str());
230 return 1;
231 }
232 if(index == NO_INDEX)
233 inst = inst.child(component);
234 else
235 inst = inst.child(component, index);
236 if(inst.valid())
237 return find_insts(matches, inst, name);
238 else
239 return 0;
240}
241
242int find_insts(std::vector< node_inst_t >& matches, soc_t& soc, std::string name)
243{
244 return find_insts(matches, soc_ref_t(&soc).root_inst(), name);
245}
246
247int find_insts(std::vector< node_inst_t >& matches, std::vector< soc_t >& soc_list,
248 std::string name)
249{
250 /* regex mode is special */
251 if(g_regex_mode)
252 return find_insts_regex(matches, soc_list, name);
253 /* if name is an integer, parse it */
254 char *end;
255 unsigned long addr = strtoul(name.c_str(), &end, 0);
256 if(*end == 0)
257 {
258 find_insts(matches, soc_list, addr);
259 return 0;
260 }
261 /* else assume it's a name */
262 std::string name_copy = name;
263 std::string component;
264 size_t index;
265 bool ok = parse_name(name_copy, component, index);
266 if(!ok)
267 {
268 fprintf(stderr, "invalid name '%s'\n", name.c_str());
269 return 1;
270 }
271 /* a soc cannot be indexed */
272 for(size_t i = 0; i < soc_list.size(); i++)
273 {
274 int ret;
275 if(index == NO_INDEX && soc_list[i].name == component)
276 ret = find_insts(matches, soc_list[i], name_copy);
277 else
278 ret = find_insts(matches, soc_list[i], name);
279 if(ret != 0)
280 return ret;
281 }
282 return 0;
283}
284
285void do_describe(node_inst_t inst, soc_word_t *decode_val)
286{
287 if(decode_val)
288 printf(" = %#lx", (unsigned long)*decode_val);
289 if(g_inline)
290 printf(" {");
291 else
292 printf("\n");
293 std::vector< field_ref_t > fields = inst.node().reg().fields();
294 bool first = true;
295 soc_word_t mask = 0; /* mask of all decoded bits */
296 /* special index fields.size() means "undecoded bits" */
297 for(size_t i = 0; i <= fields.size(); i++)
298 {
299 unsigned long val = 0;
300 bool dont_print = false;
301 field_t f;
302 if(i == fields.size())
303 {
304 /* create fake field */
305 f.name = "undecoded bits";
306 f.pos = 0;
307 f.width = inst.node().reg().get()->width;
308 val = decode_val ? *decode_val & ~mask : 0;
309 /* only print if decoding and something was left */
310 dont_print = (val == 0);
311 }
312 else
313 {
314 f = *fields[i].get();
315 val = decode_val ? f.extract(*decode_val) : 0;
316 /* don't print zero fields unless asked */
317 dont_print = decode_val && !g_print_zero && val == 0;
318 }
319 if(dont_print)
320 continue;
321 if(g_inline)
322 printf("%s", first ? " " : ", ");
323 else
324 printf(" ");
325 printf("%s", f.name.c_str());
326 first = false;
327 if(f.width == 1)
328 printf("[%zu]", f.pos);
329 else
330 printf("[%zu:%zu]", f.pos + f.width - 1, f.pos);
331 /* decode if needed */
332 if(decode_val)
333 {
334 /* track what we decoded */
335 mask |= ~f.bitmask();
336 printf(" = %#lx", val);
337 }
338 /* newline if need */
339 if(!g_inline)
340 printf("\n");
341 }
342 if(g_inline)
343 printf(" }\n");
344}
345
346int do_find(std::vector< soc_t >& soc_list, int argc, char **argv, bool describe,
347 soc_word_t *decode_val = nullptr)
348{
349 if(argc != 1)
350 {
351 fprintf(stderr, "action 'find' takes on argument: the name or address of a register\n");
352 return 1;
353 }
354 std::vector< node_inst_t > matches;
355 int ret = find_insts(matches, soc_list, argv[0]);
356 if(ret != 0)
357 return 0;
358 /* print matches */
359 if(matches.size() > 0)
360 {
361 for(size_t i = 0; i < matches.size(); i++)
362 {
363 print_inst(matches[i], true, !describe);
364 if(describe)
365 do_describe(matches[i], decode_val);
366 }
367 return 0;
368 }
369 else
370 {
371 fprintf(stderr, "No matches\n");
372 return 1;
373 }
374 return 0;
375}
376
377int do_decode(std::vector< soc_t >& soc_list, int argc, char **argv)
378{
379 if(argc != 2)
380 {
381 fprintf(stderr, "action 'decode' takes two arguments: the register and the value\n");
382 return 1;
383 }
384 char *end;
385 soc_word_t val = strtoul(argv[1], &end, 0);
386 if(*end)
387 {
388 fprintf(stderr, "invalid value '%s'\n", argv[1]);
389 return 1;
390 }
391 return do_find(soc_list, argc - 1, argv, true, &val);
392}
393
394void print_context(const error_context_t& ctx)
395{
396 for(size_t j = 0; j < ctx.count(); j++)
397 {
398 err_t e = ctx.get(j);
399 switch(e.level())
400 {
401 case err_t::INFO: printf("[INFO]"); break;
402 case err_t::WARNING: printf("[WARN]"); break;
403 case err_t::FATAL: printf("[FATAL]"); break;
404 default: printf("[UNK]"); break;
405 }
406 if(e.location().size() != 0)
407 printf(" %s:", e.location().c_str());
408 printf(" %s\n", e.message().c_str());
409 }
410}
411
412int usage()
413{
414 printf("usage: regtool [options] <action> [args]\n");
415 printf("options:\n");
416 printf(" -h Display this help\n");
417 printf(" -f <regfile> Load a register file\n");
418 printf(" -d <regdir> Specify a directory where to look for register files\n");
419 printf(" -v Increase verbosity level\n");
420 printf(" -s <soc list> Limit search to a one or more socs (comma separated)\n");
421 printf(" -i Describe/decode in one line\n");
422 printf(" -z Print fields even when the value is zero\n");
423 printf(" -r <mode> Enable regex mode\n");
424 printf("\n");
425 printf("actions:\n");
426 printf(" find <addr> Find all registers that match this address\n");
427 printf(" find <name> Find the registers that match this name\n");
428 printf(" describe <reg> Describe a register (either found by address or name)\n");
429 printf(" decode <reg> <val> Decode a register value\n");
430 printf("By default, regtool will look for register files in desc/, but if\n");
431 printf("any file or directory is specified, regtool will ignore the default directory\n");
432 printf("Adresses can be in decimal or hexadecimal (using 0x prefix).\n");
433 printf("Names can be fully qualified with a soc name or left ambiguous.\n");
434 printf(" <reg> ::= <soc>.<regpath> | <regpath>\n");
435 printf(" <regpath> ::= (<regcomp>.)*<regcomp>\n");
436 printf(" <regcomp> ::= <name> | <name>[<index>]\n");
437 printf("In regex mode, all commands expect a regular expression that is matched\n");
438 printf("against the full path (<soc>.<regpath>) of every register. The regex must\n");
439 printf("follow the C++11 standard and accepts the following, comma-separated options:\n");
440 printf(" icase Case insensitive match\n");
441 printf(" ECMAScript Use ECMAScript grammar\n");
442 printf(" basic Use basic POSIX grammar\n");
443 printf(" extended Use extended basic grammar\n");
444 printf(" awk Use awk grammar\n");
445 printf(" grep Use grep grammar\n");
446 printf(" egrep Use egrep grammar\n");
447 printf("Examples:\n");
448 printf(" regtool -d desc/ -s stmp3700,imx233 find 0x8001c310\n");
449 printf(" regtool find DIGCTL.CHIPID\n");
450 printf(" regtool describe imx233.DIGCTL.CHIPID\n");
451 printf(" regtool -f desc/regs-stmp3780.xml decode 0x8001c310 0x37800001\n");
452 printf(" regtool -r awk find 'imx233\\.LCDIF\\..*'\n");
453 return 1;
454}
455
456std::string my_dirname(const std::string& filename)
457{
458 size_t idx = filename.find_last_of("/\\");
459 if(idx == std::string::npos)
460 return filename;
461 else
462 return filename.substr(0, idx);
463}
464
465/* warn controls whether we warn about error at lowest verbosity: we warn
466 * for files explicitely loaded but not the one listed in directories */
467bool load_file(std::vector< soc_t >& soc_list, const std::string& file, bool user_load)
468{
469 if(g_verbose >= 2)
470 fprintf(stderr, "Loading file '%s'...\n", file.c_str());
471 error_context_t ctx;
472 soc_t s;
473 bool ret = parse_xml(file.c_str(), s, ctx);
474 if(g_verbose >= 1 || user_load)
475 {
476 if(ctx.count() != 0)
477 fprintf(stderr, "In file %s:\n", file.c_str());
478 print_context(ctx);
479 }
480 if(!ret)
481 {
482 if(g_verbose >= 1 || user_load)
483 fprintf(stderr, "Cannot parse file '%s'\n", file.c_str());
484 return !user_load; /* error only if user loaded */
485 }
486 soc_list.push_back(s);
487 return true;
488}
489
490bool load_dir(std::vector< soc_t >& soc_list, const std::string& dirname, bool user_load)
491{
492 if(g_verbose >= 2)
493 fprintf(stderr, "Loading directory '%s'...\n", dirname.c_str());
494 DIR *dir = opendir(dirname.c_str());
495 if(dir == NULL)
496 {
497 if(g_verbose >= 1 || user_load)
498 fprintf(stderr, "Warning: cannot open directory '%s'\n", dirname.c_str());
499 return !user_load; /* error only if user loaded */
500 }
501 struct dirent *ent;
502 while((ent = readdir(dir)))
503 {
504 std::string name(ent->d_name);
505 /* only list *.xml */
506 if(name.size() < 4 || name.substr(name.size() - 4) != ".xml")
507 continue;
508 if(!load_file(soc_list, dirname + "/" + name, false))
509 {
510 closedir(dir);
511 return false;
512 }
513 }
514 closedir(dir);
515 return true;
516}
517
518void add_socs_to_list(std::set< std::string >& soc_list, const std::string& list)
519{
520 size_t idx = 0;
521 while(idx < list.size())
522 {
523 size_t next = list.find(',', idx);
524 if(next == std::string::npos)
525 next = list.size();
526 soc_list.insert(list.substr(idx, next - idx));
527 idx = next + 1;
528 }
529}
530
531int main(int argc, char **argv)
532{
533 std::vector< std::string > g_soc_dir;
534 std::vector< std::string > g_soc_files;
535 std::vector< soc_t > g_soc_list;
536 std::set< std::string> g_allowed_soc;
537
538 if(argc <= 1)
539 return usage();
540 while(1)
541 {
542 static struct option long_options[] =
543 {
544 {"help", no_argument, 0, 'h'},
545 {0, 0, 0, 0}
546 };
547
548 int c = getopt_long(argc, argv, "hf:d:vs:izr:", long_options, NULL);
549 if(c == -1)
550 break;
551 switch(c)
552 {
553 case -1:
554 break;
555 case 'h':
556 return usage();
557 case 's':
558 add_socs_to_list(g_allowed_soc, optarg);
559 break;
560 case 'd':
561 g_soc_dir.push_back(std::string(optarg));
562 break;
563 case 'f':
564 g_soc_files.push_back(std::string(optarg));
565 break;
566 case 'v':
567 g_verbose++;
568 break;
569 case 'i':
570 g_inline = true;
571 break;
572 case 'z':
573 g_print_zero = true;
574 break;
575 case 'r':
576 g_regex_mode = true;
577 g_regex_flags = parse_regex_mode(optarg);
578 break;
579 default:
580 abort();
581 }
582 }
583 if(argc == optind)
584 {
585 fprintf(stderr, "You need at least one action\n");
586 return 2;
587 }
588 /* if no file or directory, add default */
589 if(g_soc_files.empty() && g_soc_dir.empty())
590 load_dir(g_soc_list, my_dirname(argv[0]) + "/desc", false);
591 /* load directories */
592 for(size_t i = 0; i < g_soc_dir.size(); i++)
593 load_dir(g_soc_list, g_soc_dir[i], true);
594 /* load files */
595 for(size_t i = 0; i < g_soc_files.size(); i++)
596 load_file(g_soc_list, g_soc_files[i], true);
597 /* filter soc list */
598 if(g_allowed_soc.size() > 0)
599 {
600 for(size_t i = 0; i < g_soc_list.size(); i++)
601 {
602 if(g_allowed_soc.find(g_soc_list[i].name) == g_allowed_soc.end())
603 {
604 std::swap(g_soc_list[i], g_soc_list.back());
605 g_soc_list.pop_back();
606 i--;
607 }
608 }
609 }
610 /* print */
611 if(g_verbose >= 1)
612 {
613 fprintf(stderr, "Available socs after filtering:");
614 for(size_t i = 0; i < g_soc_list.size(); i++)
615 fprintf(stderr, " %s", g_soc_list[i].name.c_str());
616 fprintf(stderr, "\n");
617 }
618
619 std::string action = argv[optind];
620 argc -= optind + 1;
621 argv += optind + 1;
622 if(action == "find")
623 return do_find(g_soc_list, argc, argv, false);
624 if(action == "describe")
625 return do_find(g_soc_list, argc, argv, true);
626 if(action == "decode")
627 return do_decode(g_soc_list, argc, argv);
628 fprintf(stderr, "unknown action '%s'\n", action.c_str());
629 return 1;
630}