A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 835 lines 26 kB view raw
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}