A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
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 <cstdio>
24#include <cstdlib>
25#include <map>
26#include <set>
27#include <cstring>
28#include <fstream>
29#include <sstream>
30#include <cstring>
31
32using namespace soc_desc;
33
34void print_context(const error_context_t& ctx)
35{
36 for(size_t j = 0; j < ctx.count(); j++)
37 {
38 err_t e = ctx.get(j);
39 switch(e.level())
40 {
41 case err_t::INFO: printf("[INFO]"); break;
42 case err_t::WARNING: printf("[WARN]"); break;
43 case err_t::FATAL: printf("[FATAL]"); break;
44 default: printf("[UNK]"); break;
45 }
46 if(e.location().size() != 0)
47 printf(" %s:", e.location().c_str());
48 printf(" %s\n", e.message().c_str());
49 }
50}
51
52bool convert_v1_to_v2(const soc_desc_v1::soc_reg_field_value_t& in, enum_t& out, error_context_t& ctx)
53{
54 out.name = in.name;
55 out.desc = in.desc;
56 out.value = in.value;
57 return true;
58}
59
60bool convert_v1_to_v2(const soc_desc_v1::soc_reg_field_t& in, field_t& out, error_context_t& ctx)
61{
62 out.name = in.name;
63 out.desc = in.desc;
64 out.pos = in.first_bit;
65 out.width = in.last_bit - in.first_bit + 1;
66 out.enum_.resize(in.value.size());
67 for(size_t i = 0; i < in.value.size(); i++)
68 if(!convert_v1_to_v2(in.value[i], out.enum_[i], ctx))
69 return false;
70 return true;
71}
72
73bool convert_v1_to_v2(const soc_desc_v1::soc_reg_addr_t& in, instance_t& out, error_context_t& ctx)
74{
75 out.name = in.name;
76 out.type = instance_t::SINGLE;
77 out.addr = in.addr;
78 return true;
79}
80
81bool convert_v1_to_v2(const soc_desc_v1::soc_reg_formula_t& in, range_t& out, error_context_t& ctx)
82{
83 out.type = range_t::FORMULA;
84 out.formula = in.string;
85 out.variable = "n";
86 return true;
87}
88
89bool convert_v1_to_v2(const soc_desc_v1::soc_reg_t& in, node_t& out, error_context_t& ctx,
90 std::string _loc)
91{
92 std::string loc = _loc + "." + in.name;
93 out.name = in.name;
94 if(in.formula.type == soc_desc_v1::REG_FORMULA_NONE)
95 {
96 out.instance.resize(in.addr.size());
97 for(size_t i = 0; i < in.addr.size(); i++)
98 if(!convert_v1_to_v2(in.addr[i], out.instance[i], ctx))
99 return false;
100 }
101 else
102 {
103 out.instance.resize(1);
104 out.instance[0].name = in.name;
105 out.instance[0].type = instance_t::RANGE;
106 out.instance[0].range.first = 0;
107 out.instance[0].range.count = in.addr.size();
108 /* check if formula is base/stride */
109 bool is_stride = true;
110 soc_word_t base = 0, stride = 0;
111 if(in.addr.size() <= 1)
112 {
113 ctx.add(err_t(err_t::WARNING, loc,
114 "register uses a formula but has only one instance"));
115 is_stride = false;
116 }
117 else
118 {
119 base = in.addr[0].addr;
120 stride = in.addr[1].addr - base;
121 for(size_t i = 0; i < in.addr.size(); i++)
122 if(base + i * stride != in.addr[i].addr)
123 is_stride = false;
124 }
125
126 if(is_stride)
127 {
128 ctx.add(err_t(err_t::INFO, loc, "promoted formula to base/stride"));
129 out.instance[0].range.type = range_t::STRIDE;
130 out.instance[0].range.base = base;
131 out.instance[0].range.stride = stride;
132 }
133 else if(!convert_v1_to_v2(in.formula, out.instance[0].range, ctx))
134 return false;
135 }
136 out.register_.resize(1);
137 out.register_[0].width = 32;
138 out.register_[0].desc = in.desc;
139 out.register_[0].field.resize(in.field.size());
140 for(size_t i = 0; i < in.field.size(); i++)
141 if(!convert_v1_to_v2(in.field[i], out.register_[0].field[i], ctx))
142 return false;
143 /* sct */
144 if(in.flags & soc_desc_v1::REG_HAS_SCT)
145 {
146 out.register_[0].variant.resize(3);
147 const char *names[3] = {"set", "clr", "tog"};
148 for(size_t i = 0; i < 3; i++)
149 {
150 out.register_[0].variant[i].type = names[i];
151 out.register_[0].variant[i].offset = 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(err_t(err_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(1);
175 if(in.addr.size() == 1)
176 {
177 out.instance[0].type = instance_t::SINGLE;
178 out.instance[0].name = in.addr[0].name;
179 out.instance[0].addr = in.addr[0].addr;
180 }
181 else
182 {
183 out.instance[0].type = instance_t::RANGE;
184 out.instance[0].name = in.name;
185 out.instance[0].range.type = range_t::LIST;
186 out.instance[0].range.first = 1;
187 out.instance[0].range.list.resize(in.addr.size());
188 for(size_t i = 0; i < in.addr.size(); i++)
189 out.instance[0].range.list[i] = in.addr[i].addr;
190 }
191 out.node.resize(in.reg.size());
192 for(size_t i = 0; i < in.reg.size(); i++)
193 if(!convert_v1_to_v2(in.reg[i], out.node[i], ctx, loc))
194 return false;
195 return true;
196}
197
198bool convert_v1_to_v2(const soc_desc_v1::soc_t& in, soc_t& out, error_context_t& ctx)
199{
200 out.name = in.name;
201 out.title = in.desc;
202 out.node.resize(in.dev.size());
203 for(size_t i = 0; i < in.dev.size(); i++)
204 if(!convert_v1_to_v2(in.dev[i], out.node[i], ctx, in.name))
205 return false;
206 return true;
207}
208
209int do_convert(int argc, char **argv)
210{
211 std::vector< std::string > authors;
212 std::string version;
213 while(argc >= 2)
214 {
215 if(strcmp(argv[0], "--author") == 0)
216 authors.push_back(argv[1]);
217 else if(strcmp(argv[0], "--version") == 0)
218 version = argv[1];
219 else
220 break;
221 argc -= 2;
222 argv += 2;
223 }
224 if(argc < 2)
225 return printf("convert mode expects at least one description file and an output file\n");
226 soc_desc_v1::soc_t soc;
227 if(!soc_desc_v1::parse_xml(argv[0], soc))
228 return printf("cannot read file '%s'\n", argv[0]);
229 error_context_t ctx;
230 soc_t new_soc;
231 if(!convert_v1_to_v2(soc, new_soc, ctx))
232 {
233 print_context(ctx);
234 return printf("cannot convert from v1 to v2\n");
235 }
236 new_soc.author = authors;
237 new_soc.version = version;
238 if(!produce_xml(argv[1], new_soc, ctx))
239 {
240 print_context(ctx);
241 return printf("cannot write file '%s'\n", argv[1]);
242 }
243 print_context(ctx);
244 return 0;
245}
246
247int do_read(int argc, char **argv)
248{
249 for(int i = 0; i < argc; i++)
250 {
251 error_context_t ctx;
252 soc_t soc;
253 bool ret = parse_xml(argv[i], soc, ctx);
254 if(ctx.count() != 0)
255 printf("In file %s:\n", argv[i]);
256 print_context(ctx);
257 if(!ret)
258 {
259 printf("cannot parse file '%s'\n", argv[i]);
260 continue;
261 }
262 }
263 return 0;
264}
265
266int do_eval(int argc, char **argv)
267{
268 std::map< std::string, soc_word_t > map;
269 for(int i = 0; i < argc; i++)
270 {
271 std::string formula(argv[i]);
272 soc_word_t result;
273 if(strcmp(argv[i], "--var") == 0)
274 {
275 if(i + 1 >= argc)
276 break;
277 i++;
278 std::string str(argv[i]);
279 size_t pos = str.find('=');
280 if(pos == std::string::npos)
281 {
282 printf("invalid variable string '%s'\n", str.c_str());
283 continue;
284 }
285 std::string name = str.substr(0, pos);
286 std::string val = str.substr(pos + 1);
287 char *end;
288 soc_word_t v = strtoul(val.c_str(), &end, 0);
289 if(*end)
290 {
291 printf("invalid variable string '%s'\n", str.c_str());
292 continue;
293 }
294 printf("%s = %#lx\n", name.c_str(), (unsigned long)v);
295 map[name] = v;
296 continue;
297 }
298 error_context_t ctx;
299 if(!evaluate_formula(formula, map, result, "", ctx))
300 {
301 print_context(ctx);
302 printf("cannot parse '%s'\n", formula.c_str());
303 }
304 else
305 printf("result: %lu (%#lx)\n", (unsigned long)result, (unsigned long)result);
306 }
307 return 0;
308}
309
310int do_write(int argc, char **argv)
311{
312 if(argc != 2)
313 return printf("write mode expects two arguments\n");
314 soc_t soc;
315 error_context_t ctx;
316 if(!parse_xml(argv[0], soc, ctx))
317 {
318 print_context(ctx);
319 return printf("cannot read file '%s'\n", argv[0]);
320 }
321 if(!produce_xml(argv[1], soc, ctx))
322 {
323 print_context(ctx);
324 return printf("cannot write file '%s'\n", argv[1]);
325 }
326 print_context(ctx);
327 return 0;
328}
329
330void check_name(const std::string& path, const std::string& name, error_context_t& ctx)
331{
332 if(name.empty())
333 ctx.add(err_t(err_t::FATAL, path, "name is empty"));
334 for(size_t i = 0; i < name.size(); i++)
335 if(!isalnum(name[i]) && name[i] != '_')
336 ctx.add(err_t(err_t::FATAL, path, "name '" + name +
337 "' must only contain alphanumeric characters or '_'"));
338}
339
340void check_instance(const std::string& _path, const instance_t& inst, error_context_t& ctx)
341{
342 std::string path = _path + "." + inst.name;
343 check_name(path, inst.name, ctx);
344 if(inst.type == instance_t::RANGE)
345 {
346 if(inst.range.type == range_t::FORMULA)
347 {
348 check_name(path + ".<formula variable>", inst.range.variable, ctx);
349 /* try to parse formula */
350 std::map< std::string, soc_word_t> var;
351 var[inst.range.variable] = inst.range.first;
352 soc_word_t res;
353 if(!evaluate_formula(inst.range.formula, var, res, path + ".<formula>", ctx))
354 ctx.add(err_t(err_t::FATAL, path + ".<formula>",
355 "cannot evaluate formula"));
356 }
357 }
358}
359
360void check_field(const std::string& _path, const field_t& field, error_context_t& ctx)
361{
362 std::string path = _path + "." + field.name;
363 check_name(path, field.name, ctx);
364 if(field.width == 0)
365 ctx.add(err_t(err_t::WARNING, path, "field has width 0"));
366 soc_word_t max = field.bitmask() >> field.pos;
367 std::set< std::string > names;
368 std::map< soc_word_t, std::string > map;
369 for(size_t i = 0; i < field.enum_.size(); i++)
370 {
371 soc_word_t v = field.enum_[i].value;
372 std::string n = field.enum_[i].name;
373 std::string path_ = path + "." + n;
374 check_name(path_, n, ctx);
375 if(v > max)
376 ctx.add(err_t(err_t::FATAL, path_, "value does not fit into the field"));
377 if(names.find(n) != names.end())
378 ctx.add(err_t(err_t::FATAL, path, "duplicate name '" + n + "' in enums"));
379 names.insert(n);
380 if(map.find(v) != map.end())
381 ctx.add(err_t(err_t::WARNING, path, "'" + n + "' and '" + map[v] + "' have the same value"));
382 map[v] = n;
383 }
384}
385
386void check_register(const std::string& _path, const soc_desc::register_t& reg, error_context_t& ctx)
387{
388 std::string path = _path + ".<register>";
389 if(reg.width != 8 && reg.width != 16 && reg.width != 32)
390 ctx.add(err_t(err_t::WARNING, path, "width is not 8, 16 or 32"));
391 for(size_t i = 0; i < reg.field.size(); i++)
392 check_field(path, reg.field[i], ctx);
393 std::set< std::string > names;
394 soc_word_t bitmap = 0;
395 for(size_t i = 0; i < reg.field.size(); i++)
396 {
397 std::string n = reg.field[i].name;
398 if(names.find(n) != names.end())
399 ctx.add(err_t(err_t::FATAL, path, "duplicate name '" + n + "' in fields"));
400 if(reg.field[i].pos + reg.field[i].width > reg.width)
401 ctx.add(err_t(err_t::FATAL, path, "field '" + n + "' does not fit into the register"));
402 names.insert(n);
403 if(bitmap & reg.field[i].bitmask())
404 {
405 /* find the duplicate to ease debugging */
406 for(size_t j = 0; j < i; j++)
407 if(reg.field[j].bitmask() & reg.field[i].bitmask())
408 ctx.add(err_t(err_t::FATAL, path, "overlap between fields '" +
409 reg.field[j].name + "' and '" + n + "'"));
410 }
411 bitmap |= reg.field[i].bitmask();
412 }
413}
414
415void check_nodes(const std::string& path, const std::vector< node_t >& nodes,
416 error_context_t& ctx);
417
418void check_node(const std::string& _path, const node_t& node, error_context_t& ctx)
419{
420 std::string path = _path + "." + node.name;
421 check_name(_path, node.name, ctx);
422 if(node.instance.empty())
423 ctx.add(err_t(err_t::WARNING, path, "subnode with no instances"));
424 for(size_t j = 0; j < node.instance.size(); j++)
425 check_instance(path, node.instance[j], ctx);
426 for(size_t i = 0; i < node.register_.size(); i++)
427 check_register(path, node.register_[i], ctx);
428 check_nodes(path, node.node, ctx);
429}
430
431void check_nodes(const std::string& path, const std::vector< node_t >& nodes,
432 error_context_t& ctx)
433{
434 for(size_t i = 0; i < nodes.size(); i++)
435 check_node(path, nodes[i], ctx);
436 /* gather all instance names */
437 std::set< std::string > names;
438 for(size_t i = 0; i < nodes.size(); i++)
439 for(size_t j = 0; j < nodes[i].instance.size(); j++)
440 {
441 std::string n = nodes[i].instance[j].name;
442 if(names.find(n) != names.end())
443 ctx.add(err_t(err_t::FATAL, path, "duplicate instance name '" +
444 n + "' in subnodes"));
445 names.insert(n);
446 }
447 /* gather all node names */
448 names.clear();
449 for(size_t i = 0; i < nodes.size(); i++)
450 {
451 std::string n = nodes[i].name;
452 if(names.find(n) != names.end())
453 ctx.add(err_t(err_t::FATAL, path, "duplicate node name '" + n +
454 "' in subnodes"));
455 names.insert(n);
456 }
457}
458
459void do_check(soc_t& soc, error_context_t& ctx)
460{
461 check_name(soc.name, soc.name, ctx);
462 check_nodes(soc.name, soc.node, ctx);
463}
464
465int do_check(int argc, char **argv)
466{
467 for(int i = 0; i < argc; i++)
468 {
469 error_context_t ctx;
470 soc_t soc;
471 bool ret = parse_xml(argv[i], soc, ctx);
472 if(ret)
473 do_check(soc, ctx);
474 if(ctx.count() != 0)
475 printf("In file %s:\n", argv[i]);
476 print_context(ctx);
477 if(!ret)
478 {
479 printf("cannot parse file '%s'\n", argv[i]);
480 continue;
481 }
482 }
483 return 0;
484}
485
486const unsigned DUMP_NODES = 1 << 0;
487const unsigned DUMP_INSTANCES = 1 << 1;
488const unsigned DUMP_VERBOSE = 1 << 2;
489const unsigned DUMP_REGISTERS = 1 << 3;
490
491void print_path(node_ref_t node, bool nl = true)
492{
493 printf("%s", node.soc().get()->name.c_str());
494 std::vector< std::string > path = node.path();
495 for(size_t i = 0; i < path.size(); i++)
496 printf(".%s", path[i].c_str());
497 if(nl)
498 printf("\n");
499}
500
501void print_inst(node_inst_t inst, bool end = true)
502{
503 if(!inst.is_root())
504 {
505 print_inst(inst.parent(), false);
506 printf(".%s", inst.name().c_str());
507 if(inst.is_indexed())
508 printf("[%u]", (unsigned)inst.index());
509 }
510 else
511 {
512 printf("%s", inst.soc().get()->name.c_str());
513 }
514 if(end)
515 printf(" @ %#x\n", inst.addr());
516}
517
518void print_reg(register_ref_t reg, unsigned flags)
519{
520 if(!(flags & DUMP_REGISTERS))
521 return;
522 node_ref_t node = reg.node();
523 soc_desc::register_t *r = reg.get();
524 print_path(node, false);
525 printf(":width=%u\n", (unsigned)r->width);
526 std::vector< field_ref_t > fields = reg.fields();
527 for(size_t i = 0; i < fields.size(); i++)
528 {
529 field_t *f = fields[i].get();
530 print_path(node, false);
531 if(f->width == 1)
532 printf(":[%u]=", (unsigned)f->pos);
533 else
534 printf(":[%u-%u]=", (unsigned)(f->pos + f->width - 1), (unsigned)f->pos);
535 printf("%s\n", f->name.c_str());
536 }
537 std::vector< variant_ref_t > variants = reg.variants();
538 for(size_t i = 0; i < variants.size(); i++)
539 {
540 print_path(node, false);
541 printf(":%s@+0x%x\n", variants[i].type().c_str(), variants[i].offset());
542 }
543}
544
545void do_dump(node_ref_t node, unsigned flags)
546{
547 print_path(node);
548 if(node.reg().node() == node)
549 print_reg(node.reg(), flags);
550 std::vector< node_ref_t > children = node.children();
551 for(size_t i = 0; i < children.size(); i++)
552 do_dump(children[i], flags);
553}
554
555void do_dump(node_inst_t inst, unsigned flags)
556{
557 print_inst(inst);
558 std::vector< node_inst_t > children = inst.children();
559 for(size_t i = 0; i < children.size(); i++)
560 do_dump(children[i], flags);
561}
562
563void do_dump(soc_t& soc, unsigned flags)
564{
565 soc_ref_t ref(&soc);
566 if(flags & DUMP_NODES)
567 do_dump(ref.root(), flags);
568 if(flags & DUMP_INSTANCES)
569 do_dump(ref.root_inst(), flags);
570}
571
572int do_dump(int argc, char **argv)
573{
574 unsigned flags = 0;
575 int i = 0;
576 for(; i < argc; i++)
577 {
578 if(strcmp(argv[i], "--nodes") == 0)
579 flags |= DUMP_NODES;
580 else if(strcmp(argv[i], "--instances") == 0)
581 flags |= DUMP_INSTANCES;
582 else if(strcmp(argv[i], "--verbose") == 0)
583 flags |= DUMP_VERBOSE;
584 else if(strcmp(argv[i], "--registers") == 0)
585 flags |= DUMP_REGISTERS;
586 else
587 break;
588 }
589 if(i == argc)
590 {
591 printf("you must specify at least one file\n");
592 return 1;
593 }
594 for(; i < argc; i++)
595 {
596 error_context_t ctx;
597 soc_t soc;
598 bool ret = parse_xml(argv[i], soc, ctx);
599 if(ret)
600 do_dump(soc, flags);
601 if(ctx.count() != 0)
602 printf("In file %s:\n", argv[i]);
603 print_context(ctx);
604 if(!ret)
605 {
606 printf("cannot parse file '%s'\n", argv[i]);
607 continue;
608 }
609 }
610 return 0;
611}
612
613std::string trim(const std::string& s)
614{
615 std::string ss = s.substr(s.find_first_not_of(" \t"));
616 return ss.substr(0, ss.find_last_not_of(" \t") + 1);
617}
618
619bool parse_key(const std::string& key, std::string& dev, std::string& reg)
620{
621 if(key.substr(0, 3) != "HW.")
622 return false;
623 std::string s = key.substr(3);
624 size_t idx = s.find('.');
625 if(idx == std::string::npos)
626 return false;
627 dev = s.substr(0, idx);
628 reg = s.substr(idx + 1);
629 return true;
630}
631
632bool find_addr(const soc_desc_v1::soc_dev_t& dev,
633 const std::string& reg, soc_desc_v1::soc_addr_t& addr)
634{
635 for(size_t i = 0; i < dev.reg.size(); i++)
636 for(size_t j = 0; j < dev.reg[i].addr.size(); j++)
637 if(dev.reg[i].addr[j].name == reg)
638 {
639 addr += dev.reg[i].addr[j].addr;
640 return true;
641 }
642 return false;
643}
644
645bool find_addr(const soc_desc_v1::soc_t& soc, const std::string& dev,
646 const std::string& reg, soc_desc_v1::soc_addr_t& addr)
647{
648 addr = 0;
649 for(size_t i = 0; i < soc.dev.size(); i++)
650 for(size_t j = 0; j < soc.dev[i].addr.size(); j++)
651 if(soc.dev[i].addr[j].name == dev)
652 {
653 addr += soc.dev[i].addr[j].addr;
654 return find_addr(soc.dev[i], reg, addr);
655 }
656 return false;
657}
658
659int convert_dump(const std::map< std::string, std::string >& entries,
660 const soc_desc_v1::soc_t& soc, std::ofstream& fout)
661{
662 std::map< std::string, std::string >::const_iterator it = entries.begin();
663 for(; it != entries.end(); ++it)
664 {
665 char *end;
666 soc_desc_v1::soc_word_t v = strtoul(it->second.c_str(), &end, 0);
667 if(*end != 0)
668 {
669 printf("because of invalid value '%s': ignore key '%s'\n",
670 it->second.c_str(), it->first.c_str());
671 continue;
672 }
673 std::string dev, reg;
674 if(!parse_key(it->first, dev, reg))
675 {
676 printf("invalid key format, ignore key '%s'\n", it->first.c_str());
677 continue;
678 }
679 soc_desc_v1::soc_addr_t addr;
680 if(!find_addr(soc, dev, reg, addr))
681 {
682 printf("cannot find register in description, ignore key '%s'\n",
683 it->first.c_str());
684 continue;
685 }
686 fout << "0x" << std::hex << addr << " = 0x" << std::hex << v << "\n";
687 }
688 return 0;
689}
690
691int do_convertdump(int argc, char **argv)
692{
693 if(argc < 3)
694 {
695 printf("you must specify at least one description file, one input file and one output file\n");
696 return 1;
697 }
698 std::vector< soc_desc_v1::soc_t > socs;
699 for(int i = 0; i < argc - 2; i++)
700 {
701 socs.resize(socs.size() + 1);
702 if(!parse_xml(argv[i], socs.back()))
703 {
704 socs.pop_back();
705 printf("cannot parse description file '%s'\n", argv[i]);
706 }
707 }
708 std::ifstream fin(argv[argc - 2]);
709 if(!fin)
710 {
711 printf("cannot open input file\n");
712 return 1;
713 }
714 std::map< std::string, std::string > entries;
715 std::string line;
716 while(std::getline(fin, line))
717 {
718 size_t idx = line.find('=');
719 if(idx == std::string::npos)
720 {
721 printf("ignore invalid line '%s'\n", line.c_str());
722 continue;
723 }
724 std::string key = trim(line.substr(0, idx));
725 std::string value = trim(line.substr(idx + 1));
726 entries[key] = value;
727 }
728 if(entries.find("HW") == entries.end())
729 {
730 printf("invalid dump file: missing HW key\n");
731 return 1;
732 }
733 std::string soc = entries["HW"];
734 soc_desc_v1::soc_t *psoc = 0;
735 for(size_t i = 0; i < socs.size(); i++)
736 if(socs[i].name == soc)
737 psoc = &socs[i];
738 if(psoc == 0)
739 {
740 printf("cannot convert dump: please provide the description file for the soc '%s'\n", soc.c_str());
741 return 1;
742 }
743 entries.erase(entries.find("HW"));
744 std::ofstream fout(argv[argc - 1]);
745 if(!fout)
746 {
747 printf("cannot open output file\n");
748 return 1;
749 }
750 fout << "soc = " << soc << "\n";
751 return convert_dump(entries, *psoc, fout);
752}
753
754int do_normalize(int argc, char **argv)
755{
756 if(argc != 2)
757 {
758 printf("normalize takes two arguments\n");
759 return 1;
760 }
761 error_context_t ctx;
762 soc_t soc;
763 bool ret = parse_xml(argv[0], soc, ctx);
764 if(ctx.count() != 0)
765 printf("In file %s:\n", argv[0]);
766 print_context(ctx);
767 if(!ret)
768 {
769 printf("cannot parse file '%s'\n", argv[1]);
770 return 2;
771 }
772 normalize(soc);
773 ret = produce_xml(argv[1], soc, ctx);
774 if(ctx.count() != 0)
775 printf("In file %s:\n", argv[1]);
776 print_context(ctx);
777 if(!ret)
778 {
779 printf("cannot write file '%s'\n", argv[1]);
780 return 3;
781 }
782 return 0;
783}
784
785void usage()
786{
787 printf("usage: swiss_knife <mode> [options]\n");
788 printf("modes:\n");
789 printf(" read <files...>\n");
790 printf(" write <read file> <write file>\n");
791 printf(" eval [<formula>|--var <name>=<val>]...\n");
792 printf(" convert [--author <auth>] [--version <ver>] <input file> <output file>\n");
793 printf(" check <files...>\n");
794 printf(" dump [--nodes] [--instances] [--registers] [--verbose] <files...>\n");
795 printf(" convertdump <desc file> ... <desc file> <input dump file> <output dump file>\n");
796 printf(" normalize <desc file> <output desc file>\n");
797 printf("\n");
798 printf("The following operations are performed in each mode:\n");
799 printf("* read: open and parse the files, reports any obvious errors\n");
800 printf("* write: open, parse a file and write it back, checks the parser/generator match\n");
801 printf("* eval: evaluate a formula with the formula parser\n");
802 printf("* convert: convert a description file from version 1 to version 2\n");
803 printf("* check: performs deep checks on description files\n");
804 printf("* dump: debug tool to dump internal structures\n");
805 printf("* convertdump: convert a register dump from version 1 to version 2\n");
806 printf(" NOTE: description file must be a v1 file\n");
807 printf("* normalize: normalise a description file\n");
808 exit(1);
809}
810
811int main(int argc, char **argv)
812{
813 if(argc < 2)
814 usage();
815 std::string mode = argv[1];
816 if(mode == "read")
817 return do_read(argc - 2, argv + 2);
818 else if(mode == "write")
819 return do_write(argc - 2, argv + 2);
820 else if(mode == "eval")
821 return do_eval(argc - 2, argv + 2);
822 else if(mode == "convert")
823 return do_convert(argc - 2, argv + 2);
824 else if(mode == "check")
825 return do_check(argc - 2, argv + 2);
826 else if(mode == "dump")
827 return do_dump(argc - 2, argv + 2);
828 else if(mode == "convertdump")
829 return do_convertdump(argc - 2, argv + 2);
830 else if(mode == "normalize")
831 return do_normalize(argc - 2, argv + 2);
832 else
833 usage();
834 return 0;
835}