summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2014-12-14 11:53:55 +0100
committerAmaury Pouly <amaury.pouly@gmail.com>2015-09-11 16:40:19 +0200
commit1cada1f8339d6b5f8506277f80e62aaef77ab774 (patch)
tree8477120e97832d659d2ffc471a8bfde73ad4c36e
parentc8d3638b9ebc24e4766714da1c9f961e350799c6 (diff)
downloadrockbox-1cada1f8339d6b5f8506277f80e62aaef77ab774.tar.gz
rockbox-1cada1f8339d6b5f8506277f80e62aaef77ab774.zip
soc_desc: new version of the desc file format
Fix qeditor to use the old soc_desc_v1. Port hwstub_shell to the new description format. Change-Id: I9fefbff534bfaa5c3603bb3dd8307a2b76e88cfc
-rw-r--r--utils/hwstub/tools/Makefile5
-rw-r--r--utils/hwstub/tools/hwstub_shell.cpp374
-rw-r--r--utils/regtools/Makefile5
-rw-r--r--utils/regtools/desc/regs-example-v1.xml91
-rw-r--r--utils/regtools/desc/regs-example.xml153
-rw-r--r--utils/regtools/desc/spec-1.0.txt (renamed from utils/regtools/desc/XML.txt)0
-rw-r--r--utils/regtools/desc/spec-2.0.txt373
-rw-r--r--utils/regtools/headergen_v1.cpp (renamed from utils/regtools/headergen.cpp)6
-rw-r--r--utils/regtools/include/soc_desc.hpp384
-rw-r--r--utils/regtools/include/soc_desc_v1.hpp (renamed from utils/regtools/lib/soc_desc.hpp)32
-rw-r--r--utils/regtools/lib/Makefile9
-rw-r--r--utils/regtools/lib/formula.cpp214
-rw-r--r--utils/regtools/lib/soc_desc.cpp1530
-rw-r--r--utils/regtools/lib/soc_desc_v1.cpp990
-rw-r--r--utils/regtools/qeditor/backend.cpp4
-rw-r--r--utils/regtools/qeditor/backend.h6
-rw-r--r--utils/regtools/qeditor/mainwindow.cpp4
-rw-r--r--utils/regtools/qeditor/qeditor.pro4
-rw-r--r--utils/regtools/qeditor/regedit.cpp6
-rw-r--r--utils/regtools/qeditor/utils.cpp2
-rw-r--r--utils/regtools/swiss_knife.cpp612
-rw-r--r--utils/regtools/tester_v1.cpp (renamed from utils/regtools/tester.cpp)16
22 files changed, 3959 insertions, 861 deletions
diff --git a/utils/hwstub/tools/Makefile b/utils/hwstub/tools/Makefile
index f718300623..868ddcca79 100644
--- a/utils/hwstub/tools/Makefile
+++ b/utils/hwstub/tools/Makefile
@@ -2,9 +2,10 @@ CC=gcc
2CXX=g++ 2CXX=g++
3LD=g++ 3LD=g++
4HWSTUB_LIB_DIR=../lib 4HWSTUB_LIB_DIR=../lib
5REGTOOLS_INCLUDE_DIR=../../regtools/include
5REGTOOLS_LIB_DIR=../../regtools/lib 6REGTOOLS_LIB_DIR=../../regtools/lib
6CFLAGS=-Wall -O2 `pkg-config --cflags libusb-1.0` -std=c99 -g -I$(HWSTUB_LIB_DIR) -I$(REGTOOLS_LIB_DIR) `pkg-config --cflags lua5.2` 7CFLAGS=-Wall -O2 `pkg-config --cflags libusb-1.0` -std=c99 -g -I$(HWSTUB_LIB_DIR) -I$(REGTOOLS_INCLUDE_DIR) `pkg-config --cflags lua5.2`
7CXXFLAGS=-Wall -O2 `pkg-config --cflags libusb-1.0` -g -I$(HWSTUB_LIB_DIR) -I$(REGTOOLS_LIB_DIR) `pkg-config --cflags lua5.2` 8CXXFLAGS=-Wall -O2 `pkg-config --cflags libusb-1.0` -g -I$(HWSTUB_LIB_DIR) -I$(REGTOOLS_INCLUDE_DIR) `pkg-config --cflags lua5.2`
8LDFLAGS=`pkg-config --libs libusb-1.0` `pkg-config --libs lua5.2` -lreadline -L$(HWSTUB_LIB_DIR) -L$(REGTOOLS_LIB_DIR) -lsocdesc -lhwstub `xml2-config --libs` 9LDFLAGS=`pkg-config --libs libusb-1.0` `pkg-config --libs lua5.2` -lreadline -L$(HWSTUB_LIB_DIR) -L$(REGTOOLS_LIB_DIR) -lsocdesc -lhwstub `xml2-config --libs`
9EXEC=hwstub_shell hwstub_load 10EXEC=hwstub_shell hwstub_load
10SRC=$(wildcard *.c) 11SRC=$(wildcard *.c)
diff --git a/utils/hwstub/tools/hwstub_shell.cpp b/utils/hwstub/tools/hwstub_shell.cpp
index f59ca8b82a..dd5c20b471 100644
--- a/utils/hwstub/tools/hwstub_shell.cpp
+++ b/utils/hwstub/tools/hwstub_shell.cpp
@@ -28,11 +28,14 @@
28#include <readline/history.h> 28#include <readline/history.h>
29#include <lua.hpp> 29#include <lua.hpp>
30#include <unistd.h> 30#include <unistd.h>
31#include "soc_desc_v1.hpp"
31#include "soc_desc.hpp" 32#include "soc_desc.hpp"
32extern "C" { 33extern "C" {
33#include "prompt.h" 34#include "prompt.h"
34} 35}
35 36
37using namespace soc_desc_v1;
38
36#if LUA_VERSION_NUM < 502 39#if LUA_VERSION_NUM < 502
37#warning You need at least lua 5.2 40#warning You need at least lua 5.2
38#endif 41#endif
@@ -51,6 +54,44 @@ struct hwstub_pp_desc_t g_hwdev_pp;
51lua_State *g_lua; 54lua_State *g_lua;
52 55
53/** 56/**
57 * debug
58 */
59
60void print_context(const std::string& file, const soc_desc::error_context_t& ctx)
61{
62 for(size_t j = 0; j < ctx.count(); j++)
63 {
64 soc_desc::error_t e = ctx.get(j);
65 switch(e.level())
66 {
67 case soc_desc::error_t::INFO: printf("[INFO]"); break;
68 case soc_desc::error_t::WARNING: printf("[WARN]"); break;
69 case soc_desc::error_t::FATAL: printf("[FATAL]"); break;
70 default: printf("[UNK]"); break;
71 }
72 if(e.location().size() != 0)
73 printf(" (%s) %s:", file.c_str(), e.location().c_str());
74 printf(" %s\n", e.message().c_str());
75 }
76}
77
78void my_lua_print_stack(lua_State *state = 0, int up_to = 0)
79{
80 if(state == 0)
81 state = g_lua;
82 up_to = lua_gettop(state) - up_to;
83 printf("stack:");
84 for(int i = -1; i >= -up_to; i--)
85 {
86 if(lua_isstring(state, i))
87 printf(" <%s>", lua_tostring(state, i));
88 else
89 printf(" [%s]", lua_typename(state, lua_type(state, i)));
90 }
91 printf("\n");
92}
93
94/**
54 * hw specific 95 * hw specific
55 */ 96 */
56 97
@@ -449,7 +490,7 @@ int my_lua_write_field(lua_State *state)
449 soc_addr_t addr = lua_tounsigned(state, lua_upvalueindex(1)); 490 soc_addr_t addr = lua_tounsigned(state, lua_upvalueindex(1));
450 soc_word_t shift = lua_tounsigned(state, lua_upvalueindex(2)); 491 soc_word_t shift = lua_tounsigned(state, lua_upvalueindex(2));
451 soc_word_t mask = lua_tounsigned(state, lua_upvalueindex(3)); 492 soc_word_t mask = lua_tounsigned(state, lua_upvalueindex(3));
452 bool is_sct = lua_toboolean(state, lua_upvalueindex(5)); 493 char op = lua_tounsigned(state, lua_upvalueindex(5));
453 494
454 soc_word_t value = mask; 495 soc_word_t value = mask;
455 if(n == 1) 496 if(n == 1)
@@ -469,10 +510,17 @@ int my_lua_write_field(lua_State *state)
469 value &= mask; 510 value &= mask;
470 } 511 }
471 512
472 if(!is_sct) 513 soc_word_t old_value = hw_read32(state, addr);
473 value = value << shift | (hw_read32(state, addr) & ~(mask << shift)); 514 if(op == 'w')
515 value = value << shift | (old_value & ~(mask << shift));
516 else if(op == 's')
517 value = old_value | value << shift;
518 else if(op == 'c')
519 value = old_value & ~(value << shift);
520 else if(op == 't')
521 value = old_value ^ (value << shift);
474 else 522 else
475 value <<= shift; 523 luaL_error(state, "write_field() internal error");
476 524
477 hw_write32(state, addr, value); 525 hw_write32(state, addr, value);
478 return 0; 526 return 0;
@@ -501,222 +549,240 @@ int my_lua_sct_reg(lua_State *state)
501 return 0; 549 return 0;
502} 550}
503 551
504void my_lua_create_field(soc_addr_t addr, const soc_reg_field_t& field, bool sct) 552/* lua stack on entry/exit: <reg table> */
553void my_lua_create_field(soc_addr_t addr, soc_desc::field_ref_t field)
505{ 554{
555 soc_desc::field_t *f = field.get();
556 /** create field table */
506 lua_newtable(g_lua); 557 lua_newtable(g_lua);
558 /* lua stack: <field table> <reg table> */
507 559
508 lua_pushstring(g_lua, field.name.c_str()); 560 /** create various characteristics */
561 lua_pushstring(g_lua, f->name.c_str());
562 /* lua stack: <name> <field table> ... */
509 lua_setfield(g_lua, -2, "name"); 563 lua_setfield(g_lua, -2, "name");
564 /* lua stack: <field table> ... */
510 565
511 lua_pushunsigned(g_lua, addr); 566 lua_pushunsigned(g_lua, addr);
567 /* lua stack: <addr> <field table> ... */
512 lua_setfield(g_lua, -2, "addr"); 568 lua_setfield(g_lua, -2, "addr");
569 /* lua stack: <field table> ... */
513 570
514 lua_pushboolean(g_lua, sct); 571 lua_pushunsigned(g_lua, f->pos);
515 lua_setfield(g_lua, -2, "sct"); 572 /* lua stack: <pos> <field table> ... */
516 573 lua_setfield(g_lua, -2, "pos");
517 lua_pushunsigned(g_lua, field.first_bit); 574 /* lua stack: <field table> ... */
518 lua_setfield(g_lua, -2, "first_bit");
519 575
520 lua_pushunsigned(g_lua, field.last_bit); 576 lua_pushunsigned(g_lua, f->width);
521 lua_setfield(g_lua, -2, "last_bit"); 577 /* lua stack: <width> <field table> ... */
578 lua_setfield(g_lua, -2, "width");
579 /* lua stack: <field table> ... */
522 580
523 lua_pushunsigned(g_lua, field.bitmask()); 581 lua_pushunsigned(g_lua, f->bitmask());
582 /* lua stack: <bm> <field table> ... */
524 lua_setfield(g_lua, -2, "bitmask"); 583 lua_setfield(g_lua, -2, "bitmask");
584 /* lua stack: <field table> ... */
525 585
526 soc_word_t local_bitmask = field.bitmask() >> field.first_bit; 586 soc_word_t local_bitmask = f->bitmask() >> f->pos;
527 lua_pushunsigned(g_lua, local_bitmask); 587 lua_pushunsigned(g_lua, local_bitmask);
588 /* lua stack: <local_bm> <field table> ... */
528 lua_setfield(g_lua, -2, "local_bitmask"); 589 lua_setfield(g_lua, -2, "local_bitmask");
590 /* lua stack: <field table> ... */
529 591
592 /** create read routine */
530 lua_pushunsigned(g_lua, addr); 593 lua_pushunsigned(g_lua, addr);
531 lua_pushunsigned(g_lua, field.first_bit); 594 lua_pushunsigned(g_lua, f->pos);
532 lua_pushunsigned(g_lua, local_bitmask); 595 lua_pushunsigned(g_lua, local_bitmask);
596 /* lua stack: <local_bm> <pos> <addr> <field table> ... */
533 lua_pushcclosure(g_lua, my_lua_read_field, 3); 597 lua_pushcclosure(g_lua, my_lua_read_field, 3);
598 /* lua stack: <my_lua_read_field> <field table> ... */
534 lua_setfield(g_lua, -2, "read"); 599 lua_setfield(g_lua, -2, "read");
600 /* lua stack: <field table> ... */
535 601
536 lua_pushunsigned(g_lua, addr); 602 /** create write/set/clr/tog routines */
537 lua_pushunsigned(g_lua, field.first_bit); 603 static const char *name[] = {"write", "set", "clr", "tog"};
538 lua_pushunsigned(g_lua, local_bitmask); 604 static const char arg[] = {'w', 's', 'c', 't'};
539 lua_pushvalue(g_lua, -4); 605 for(int i = 0; i < 4; i++)
540 lua_pushboolean(g_lua, false);
541 lua_pushcclosure(g_lua, my_lua_write_field, 5);
542 lua_setfield(g_lua, -2, "write");
543
544 if(sct)
545 { 606 {
546 lua_pushunsigned(g_lua, addr + 4); 607 lua_pushunsigned(g_lua, addr);
547 lua_pushunsigned(g_lua, field.first_bit); 608 lua_pushunsigned(g_lua, f->pos);
548 lua_pushunsigned(g_lua, local_bitmask); 609 lua_pushunsigned(g_lua, local_bitmask);
610 /* lua stack: <local_bm> <pos> <addr> <field table> ... */
549 lua_pushvalue(g_lua, -4); 611 lua_pushvalue(g_lua, -4);
550 lua_pushboolean(g_lua, true); 612 /* lua stack: <field table> <local_bm> <pos> <addr> <field table> ... */
613 lua_pushunsigned(g_lua, arg[i]);
614 /* lua stack: <'wsct'> <field table> <local_bm> <pos> <addr> <field table> ... */
551 lua_pushcclosure(g_lua, my_lua_write_field, 5); 615 lua_pushcclosure(g_lua, my_lua_write_field, 5);
552 lua_setfield(g_lua, -2, "set"); 616 /* lua stack: <my_lua_write_field> <field table> ... */
553 617 lua_setfield(g_lua, -2, name[i]);
554 lua_pushunsigned(g_lua, addr + 8); 618 /* lua stack: <field table> ... */
555 lua_pushunsigned(g_lua, field.first_bit);
556 lua_pushunsigned(g_lua, local_bitmask);
557 lua_pushvalue(g_lua, -4);
558 lua_pushboolean(g_lua, true);
559 lua_pushcclosure(g_lua, my_lua_write_field, 5);
560 lua_setfield(g_lua, -2, "clr");
561
562 lua_pushunsigned(g_lua, addr + 12);
563 lua_pushunsigned(g_lua, field.first_bit);
564 lua_pushunsigned(g_lua, local_bitmask);
565 lua_pushvalue(g_lua, -4);
566 lua_pushboolean(g_lua, true);
567 lua_pushcclosure(g_lua, my_lua_write_field, 5);
568 lua_setfield(g_lua, -2, "tog");
569 } 619 }
570 620
571 for(size_t i = 0; i < field.value.size(); i++) 621 /** create values */
622 for(size_t i = 0; i < f->enum_.size(); i++)
572 { 623 {
573 lua_pushunsigned(g_lua, field.value[i].value); 624 lua_pushunsigned(g_lua, f->enum_[i].value);
574 lua_setfield(g_lua, -2, field.value[i].name.c_str()); 625 /* lua stack: <value> <field table> ... */
626 lua_setfield(g_lua, -2, f->enum_[i].name.c_str());
627 /* lua stack: <field table> ... */
575 } 628 }
629
630 /** register field */
631 lua_setfield(g_lua, -2, f->name.c_str());
632 /* lua stack: <reg table> */
576} 633}
577 634
578void my_lua_create_reg(soc_addr_t addr, size_t index, const soc_reg_t& reg) 635/* lua stack on entry/exit: <inst table> */
636void my_lua_create_reg(soc_addr_t addr, soc_desc::register_ref_t reg)
579{ 637{
580 lua_newtable(g_lua); 638 if(!reg.valid())
581 639 return;
582 lua_pushstring(g_lua, reg.addr[index].name.c_str()); 640 /** create read/write routine */
583 lua_setfield(g_lua, -2, "name"); 641 lua_pushunsigned(g_lua, addr);
584 642 /* lua stack: <addr> <inst table> */
585 lua_pushunsigned(g_lua, addr + reg.addr[index].addr);
586 lua_setfield(g_lua, -2, "addr");
587
588 lua_pushboolean(g_lua, !!(reg.flags & REG_HAS_SCT));
589 lua_setfield(g_lua, -2, "sct");
590
591 lua_pushunsigned(g_lua, addr + reg.addr[index].addr);
592 lua_pushcclosure(g_lua, my_lua_read_reg, 1); 643 lua_pushcclosure(g_lua, my_lua_read_reg, 1);
644 /* lua stack: <my_lua_read_reg> <inst table> */
593 lua_setfield(g_lua, -2, "read"); 645 lua_setfield(g_lua, -2, "read");
646 /* lua stack: <inst table> */
594 647
595 lua_pushunsigned(g_lua, addr + reg.addr[index].addr); 648 lua_pushunsigned(g_lua, addr);
649 /* lua stack: <addr> <inst table> */
596 lua_pushcclosure(g_lua, my_lua_write_reg, 1); 650 lua_pushcclosure(g_lua, my_lua_write_reg, 1);
651 /* lua stack: <my_lua_read_reg> <inst table> */
597 lua_setfield(g_lua, -2, "write"); 652 lua_setfield(g_lua, -2, "write");
653 /* lua stack: <inst table> */
598 654
599 if(reg.flags & REG_HAS_SCT) 655 /** create set/clr/tog helpers */
656 static const char *name[] = {"set", "clr", "tog"};
657 static const char arg[] = {'s', 'c', 't'};
658 for(int i = 0; i < 3; i++)
600 { 659 {
601 lua_pushunsigned(g_lua, addr + reg.addr[index].addr + 4); 660 lua_pushunsigned(g_lua, addr);
602 lua_pushcclosure(g_lua, my_lua_write_reg, 1); 661 /* lua stack: <addr> <inst table> */
603 lua_setfield(g_lua, -2, "set"); 662 lua_pushunsigned(g_lua, arg[i]);
663 /* lua stack: <'s'/'c'/'t'> <addr> <inst table> */
664 lua_pushcclosure(g_lua, my_lua_sct_reg, 2);
665 /* lua stack: <my_lua_sct_reg> <inst table> */
666 lua_setfield(g_lua, -2, name[i]);
667 /* lua stack: <inst table> */
668 }
604 669
605 lua_pushunsigned(g_lua, addr + reg.addr[index].addr + 8); 670 /** create fields */
606 lua_pushcclosure(g_lua, my_lua_write_reg, 1); 671 std::vector< soc_desc::field_ref_t > fields = reg.fields();
607 lua_setfield(g_lua, -2, "clr"); 672 for(size_t i = 0; i < fields.size(); i++)
673 my_lua_create_field(addr, fields[i]);
674}
608 675
609 lua_pushunsigned(g_lua, addr + reg.addr[index].addr + 12); 676/* lua stack on entry/exit: <parent table> */
610 lua_pushcclosure(g_lua, my_lua_write_reg, 1); 677void my_lua_create_instances(const std::vector< soc_desc::node_inst_t >& inst)
611 lua_setfield(g_lua, -2, "tog"); 678{
612 } 679 for(size_t i = 0; i < inst.size(); i++)
613 else
614 { 680 {
615 lua_pushunsigned(g_lua, addr + reg.addr[index].addr); 681 /** if the instance is indexed, find the instance table, otherwise create it */
616 lua_pushunsigned(g_lua, 's'); 682 if(inst[i].is_indexed())
617 lua_pushcclosure(g_lua, my_lua_sct_reg, 2); 683 {
618 lua_setfield(g_lua, -2, "set"); 684 /** try to get the instance table, otherwise create it */
685 lua_getfield(g_lua, -1, inst[i].name().c_str());
686 /* lua stack: <index table> <parent table> */
687 if(lua_isnil(g_lua, -1))
688 {
689 lua_pop(g_lua, 1);
690 lua_newtable(g_lua);
691 /* lua stack: <index table> <parent table> */
692 lua_pushvalue(g_lua, -1);
693 /* lua stack: <index table> <index table> <parent table> */
694 lua_setfield(g_lua, -3, inst[i].name().c_str());
695 /* lua stack: <index table> <parent table> */
696 }
697 lua_pushinteger(g_lua, inst[i].index());
698 /* lua stack: <index> <index table> <parent table> */
699 }
619 700
620 lua_pushunsigned(g_lua, addr + reg.addr[index].addr); 701 /** create a new table for the instance */
621 lua_pushunsigned(g_lua, 'c'); 702 lua_newtable(g_lua);
622 lua_pushcclosure(g_lua, my_lua_sct_reg, 2); 703 /* lua stack: <instance table> [<index> <index table>] <parent table> */
623 lua_setfield(g_lua, -2, "clr");
624 704
625 lua_pushunsigned(g_lua, addr + reg.addr[index].addr); 705 /** create name and desc fields */
626 lua_pushunsigned(g_lua, 't'); 706 lua_pushstring(g_lua, inst[i].node().get()->name.c_str());
627 lua_pushcclosure(g_lua, my_lua_sct_reg, 2); 707 /* lua stack: <node name> <instance table> ... */
628 lua_setfield(g_lua, -2, "tog"); 708 lua_setfield(g_lua, -2, "name");
629 } 709 /* lua stack: <instance table> ... */
630 710
631 for(size_t i = 0; i < reg.field.size(); i++) 711 lua_pushstring(g_lua, inst[i].node().get()->desc.c_str());
632 { 712 /* lua stack: <node desc> <instance table> ... */
633 my_lua_create_field(addr + reg.addr[index].addr, reg.field[i], 713 lua_setfield(g_lua, -2, "desc");
634 reg.flags & REG_HAS_SCT); 714 /* lua stack: <instance table> ... */
635 lua_setfield(g_lua, -2, reg.field[i].name.c_str());
636 }
637}
638 715
639void my_lua_create_dev(size_t index, const soc_dev_t& dev) 716 lua_pushstring(g_lua, inst[i].node().get()->title.c_str());
640{ 717 /* lua stack: <node title> <instance table> ... */
641 lua_newtable(g_lua); 718 lua_setfield(g_lua, -2, "title");
719 /* lua stack: <instance table> ... */
642 720
643 lua_pushstring(g_lua, dev.addr[index].name.c_str()); 721 lua_pushunsigned(g_lua, inst[i].addr());
644 lua_setfield(g_lua, -2, "name"); 722 /* lua stack: <node addr> <instance table> ... */
723 lua_setfield(g_lua, -2, "addr");
724 /* lua stack: <instance table> ... */
645 725
646 lua_pushunsigned(g_lua, dev.addr[index].addr); 726 /** create register */
647 lua_setfield(g_lua, -2, "addr"); 727 my_lua_create_reg(inst[i].addr(), inst[i].node().reg());
648 728
649 for(size_t i = 0; i < dev.reg.size(); i++) 729 /** create subinstances */
650 { 730 my_lua_create_instances(inst[i].children());
651 bool table = dev.reg[i].addr.size() > 1; 731 /* lua stack: <instance table> [<index> <index table>] <parent table> */
652 if(table)
653 lua_newtable(g_lua);
654 else
655 lua_pushnil(g_lua);
656 732
657 for(size_t k = 0; k < dev.reg[i].addr.size(); k++) 733 if(inst[i].is_indexed())
658 { 734 {
659 my_lua_create_reg(dev.addr[index].addr, k, dev.reg[i]); 735 /* lua stack: <instance table> <index> <index table> <parent table> */
660 if(table) 736 lua_settable(g_lua, -3);
661 { 737 /* lua stack: <index table> <parent table> */
662 lua_pushinteger(g_lua, k); 738 lua_pop(g_lua, 1);
663 lua_pushvalue(g_lua, -2);
664 lua_settable(g_lua, -4);
665 }
666 lua_setfield(g_lua, -3, dev.reg[i].addr[k].name.c_str());
667 } 739 }
668
669 if(table)
670 lua_setfield(g_lua, -2, dev.reg[i].name.c_str());
671 else 740 else
672 lua_pop(g_lua, 1); 741 {
742 /* lua stack: <instance table> <parent table> */
743 lua_setfield(g_lua, -2, inst[i].name().c_str());
744 }
745 /* lua stack: <parent table> */
673 } 746 }
674} 747}
675 748
676bool my_lua_import_soc(const soc_t& soc) 749bool my_lua_import_soc(soc_desc::soc_t& soc)
677{ 750{
751 /** remember old stack index to check for unbalanced stack at the end */
678 int oldtop = lua_gettop(g_lua); 752 int oldtop = lua_gettop(g_lua);
679 753
754 /** find hwstub.soc table */
680 lua_getglobal(g_lua, "hwstub"); 755 lua_getglobal(g_lua, "hwstub");
756 /* lua stack: <hwstub table> */
681 lua_getfield(g_lua, -1, "soc"); 757 lua_getfield(g_lua, -1, "soc");
758 /* lua stack: <hwstub.soc table> <hwstub table> */
682 759
760 /** create a new table for the soc */
683 lua_newtable(g_lua); 761 lua_newtable(g_lua);
762 /* lua stack: <soc table> <hwstub.soc table> <hwstub table> */
684 763
764 /** create name and desc fields */
685 lua_pushstring(g_lua, soc.name.c_str()); 765 lua_pushstring(g_lua, soc.name.c_str());
766 /* lua stack: <soc name> <soc table> <hwstub.soc table> <hwstub table> */
686 lua_setfield(g_lua, -2, "name"); 767 lua_setfield(g_lua, -2, "name");
768 /* lua stack: <soc table> <hwstub.soc table> <hwstub table> */
687 769
688 lua_pushstring(g_lua, soc.desc.c_str()); 770 lua_pushstring(g_lua, soc.desc.c_str());
771 /* lua stack: <soc desc> <soc table> <hwstub.soc table> <hwstub table> */
689 lua_setfield(g_lua, -2, "desc"); 772 lua_setfield(g_lua, -2, "desc");
773 /* lua stack: <soc table> <hwstub.soc table> <hwstub table> */
690 774
691 for(size_t i = 0; i < soc.dev.size(); i++) 775 /** create instances */
692 { 776 soc_desc::soc_ref_t rsoc(&soc);
693 bool table = soc.dev[i].addr.size() > 1; 777 my_lua_create_instances(rsoc.root_inst().children());
694 if(table) 778 /* lua stack: <soc table> <hwstub.soc table> <hwstub table> */
695 lua_newtable(g_lua);
696 else
697 lua_pushnil(g_lua);
698
699 for(size_t k = 0; k < soc.dev[i].addr.size(); k++)
700 {
701 my_lua_create_dev(k, soc.dev[i]);
702 if(table)
703 {
704 lua_pushinteger(g_lua, k + 1);
705 lua_pushvalue(g_lua, -2);
706 lua_settable(g_lua, -4);
707 }
708 lua_setfield(g_lua, -3, soc.dev[i].addr[k].name.c_str());
709 }
710
711 if(table)
712 lua_setfield(g_lua, -2, soc.dev[i].name.c_str());
713 else
714 lua_pop(g_lua, 1);
715 }
716 779
780 /** put soc table at hwstub.soc.<soc name> */
717 lua_setfield(g_lua, -2, soc.name.c_str()); 781 lua_setfield(g_lua, -2, soc.name.c_str());
782 /* lua stack: <hwstub.soc table> <hwstub table> */
718 783
719 lua_pop(g_lua, 2); 784 lua_pop(g_lua, 2);
785 /* lua stack: <> */
720 786
721 if(lua_gettop(g_lua) != oldtop) 787 if(lua_gettop(g_lua) != oldtop)
722 { 788 {
@@ -726,7 +792,7 @@ bool my_lua_import_soc(const soc_t& soc)
726 return true; 792 return true;
727} 793}
728 794
729bool my_lua_import_soc(const std::vector< soc_t >& socs) 795bool my_lua_import_soc(std::vector< soc_desc::soc_t >& socs)
730{ 796{
731 for(size_t i = 0; i < socs.size(); i++) 797 for(size_t i = 0; i < socs.size(); i++)
732 { 798 {
@@ -803,15 +869,17 @@ int main(int argc, char **argv)
803 } 869 }
804 870
805 // load register descriptions 871 // load register descriptions
806 std::vector< soc_t > socs; 872 std::vector< soc_desc::soc_t > socs;
807 for(int i = optind; i < argc; i++) 873 for(int i = optind; i < argc; i++)
808 { 874 {
809 socs.push_back(soc_t()); 875 socs.push_back(soc_desc::soc_t());
810 if(!soc_desc_parse_xml(argv[i], socs[socs.size() - 1])) 876 soc_desc::error_context_t ctx;
877 if(!soc_desc::parse_xml(argv[i], socs[socs.size() - 1], ctx))
811 { 878 {
812 printf("Cannot load description '%s'\n", argv[i]); 879 printf("Cannot load description file '%s'\n", argv[i]);
813 return 2; 880 socs.pop_back();
814 } 881 }
882 print_context(argv[i], ctx);
815 } 883 }
816 884
817 // create usb context 885 // create usb context
diff --git a/utils/regtools/Makefile b/utils/regtools/Makefile
index 5e3feafd01..fed5d8c8e5 100644
--- a/utils/regtools/Makefile
+++ b/utils/regtools/Makefile
@@ -2,8 +2,9 @@ DEFINES=
2CC?=gcc 2CC?=gcc
3CXX?=g++ 3CXX?=g++
4LD?=g++ 4LD?=g++
5CFLAGS=-g -std=c99 -Wall $(DEFINES) -Ilib 5INCLUDE=-Iinclude/
6CXXFLAGS=-g -Wall $(DEFINES) -Ilib 6CFLAGS=-g -std=c99 -Wall $(DEFINES) $(INCLUDE)
7CXXFLAGS=-g -Wall $(DEFINES) $(INCLUDE)
7LDFLAGS=-Llib -lsocdesc `xml2-config --libs` 8LDFLAGS=-Llib -lsocdesc `xml2-config --libs`
8SRC=$(wildcard *.c) 9SRC=$(wildcard *.c)
9SRCXX=$(wildcard *.cpp) 10SRCXX=$(wildcard *.cpp)
diff --git a/utils/regtools/desc/regs-example-v1.xml b/utils/regtools/desc/regs-example-v1.xml
new file mode 100644
index 0000000000..4f3cf81ff2
--- /dev/null
+++ b/utils/regtools/desc/regs-example-v1.xml
@@ -0,0 +1,91 @@
1<?xml version="1.0"?>
2<soc name="imx233" desc="i.MX233">
3 <dev name="APBH" long_name="APHB DMA" desc="AHB-to-APBH Bridge with DMA" version="3.2.0">
4 <addr name="APBH" addr="0x80004000"/>
5 <reg name="CTRL0" desc="" sct="yes">
6 <addr name="CTRL0" addr="0x0"/>
7 <field name="SFTRST" desc="" bitrange="31:31"/>
8 <field name="CLKGATE" desc="" bitrange="30:30"/>
9 <field name="AHB_BURST8_EN" desc="" bitrange="29:29"/>
10 <field name="APB_BURST4_EN" desc="" bitrange="28:28"/>
11 <field name="RSVD0" desc="" bitrange="27:24"/>
12 <field name="RESET_CHANNEL" desc="" bitrange="23:16">
13 <value name="SSP1" value="0x2" desc=""/>
14 <value name="SSP2" value="0x4" desc=""/>
15 <value name="ATA" value="0x10" desc=""/>
16 <value name="NAND0" value="0x10" desc=""/>
17 <value name="NAND1" value="0x20" desc=""/>
18 <value name="NAND2" value="0x40" desc=""/>
19 <value name="NAND3" value="0x80" desc=""/>
20 </field>
21 <field name="CLKGATE_CHANNEL" desc="" bitrange="15:8">
22 <value name="SSP1" value="0x2" desc=""/>
23 <value name="SSP2" value="0x4" desc=""/>
24 <value name="ATA" value="0x10" desc=""/>
25 <value name="NAND0" value="0x10" desc=""/>
26 <value name="NAND1" value="0x20" desc=""/>
27 <value name="NAND2" value="0x40" desc=""/>
28 <value name="NAND3" value="0x80" desc=""/>
29 </field>
30 <field name="FREEZE_CHANNEL" desc="" bitrange="7:0">
31 <value name="SSP1" value="0x2" desc=""/>
32 <value name="SSP2" value="0x4" desc=""/>
33 <value name="ATA" value="0x10" desc=""/>
34 <value name="NAND0" value="0x10" desc=""/>
35 <value name="NAND1" value="0x20" desc=""/>
36 <value name="NAND2" value="0x40" desc=""/>
37 <value name="NAND3" value="0x80" desc=""/>
38 </field>
39 </reg>
40 <reg name="CTRL1" desc="" sct="yes">
41 <addr name="CTRL1" addr="0x10"/>
42 <field name="RSVD1" desc="" bitrange="31:24"/>
43 <field name="CH_CMDCMPLT_IRQ_EN" desc="" bitrange="23:16"/>
44 <field name="RSVD0" desc="" bitrange="15:8"/>
45 <field name="CH_CMDCMPLT_IRQ" desc="" bitrange="7:0"/>
46 </reg>
47 <reg name="CHn_CMD" desc="">
48 <formula string="0x60+n*0x70"/>
49 <addr name="CH0_CMD" addr="0x60"/>
50 <addr name="CH1_CMD" addr="0xd0"/>
51 <addr name="CH2_CMD" addr="0x140"/>
52 <addr name="CH3_CMD" addr="0x1b0"/>
53 <addr name="CH4_CMD" addr="0x220"/>
54 <addr name="CH5_CMD" addr="0x290"/>
55 <addr name="CH6_CMD" addr="0x300"/>
56 <addr name="CH7_CMD" addr="0x370"/>
57 <field name="XFER_COUNT" desc="" bitrange="31:16"/>
58 <field name="CMDWORDS" desc="" bitrange="15:12"/>
59 <field name="RSVD1" desc="" bitrange="11:9"/>
60 <field name="HALTONTERMINATE" desc="" bitrange="8:8"/>
61 <field name="WAIT4ENDCMD" desc="" bitrange="7:7"/>
62 <field name="SEMAPHORE" desc="" bitrange="6:6"/>
63 <field name="NANDWAIT4READY" desc="" bitrange="5:5"/>
64 <field name="NANDLOCK" desc="" bitrange="4:4"/>
65 <field name="IRQONCMPLT" desc="" bitrange="3:3"/>
66 <field name="CHAIN" desc="" bitrange="2:2"/>
67 <field name="COMMAND" desc="" bitrange="1:0">
68 <value name="NO_DMA_XFER" value="0x0" desc=""/>
69 <value name="DMA_WRITE" value="0x1" desc=""/>
70 <value name="DMA_READ" value="0x2" desc=""/>
71 <value name="DMA_SENSE" value="0x3" desc=""/>
72 </field>
73 </reg>
74 </dev>
75 <dev name="SAIF" long_name="Sync Audio Interface" desc="Sync Audio Interface (SAIF)" version="3.2.0">
76 <addr name="SAIF1" addr="0x80042000"/>
77 <addr name="SAIF2" addr="0x80046000"/>
78 <reg name="DATA" desc="" sct="yes">
79 <addr name="DATA" addr="0x20"/>
80 <field name="PCM_RIGHT" desc="" bitrange="31:16"/>
81 <field name="PCM_LEFT" desc="" bitrange="15:0"/>
82 </reg>
83 <reg name="VERSION" desc="">
84 <addr name="VERSION" addr="0x30"/>
85 <field name="MAJOR" desc="" bitrange="31:24"/>
86 <field name="MINOR" desc="" bitrange="23:16"/>
87 <field name="STEP" desc="" bitrange="15:0"/>
88 </reg>
89 </dev>
90</soc>
91
diff --git a/utils/regtools/desc/regs-example.xml b/utils/regtools/desc/regs-example.xml
new file mode 100644
index 0000000000..6fb8f759fe
--- /dev/null
+++ b/utils/regtools/desc/regs-example.xml
@@ -0,0 +1,153 @@
1<?xml version="1.0"?>
2<soc version="2">
3 <name>vsoc</name>
4 <title>Virtual SOC</title>
5 <desc>Virtual SoC is a nice and powerful chip.</desc>
6 <author>Amaury Pouly</author>
7 <isa>ARM</isa>
8 <version>0.5</version>
9 <node>
10 <name>int</name>
11 <title>Interrupt Collector</title>
12 <desc>The interrupt collector controls the routing of interrupt to the processor</desc>
13 <instance>
14 <name>ICOLL</name>
15 <title>Interrupt collector</title>
16 <address>0x80000000</address>
17 </instance>
18 <node>
19 <name>status</name>
20 <access>read-only</access>
21 <title>Interrupt status register</title>
22 <instance>
23 <name>STATUS</name>
24 <address>0x4</address>
25 </instance>
26 <register>
27 <width>8</width>
28 <field>
29 <name>VDDIO_BO</name>
30 <desc>VDDIO brownout interrupt status</desc>
31 <position>0</position>
32 </field>
33 </register>
34 </node>
35 <node>
36 <name>enable</name>
37 <title>Interrupt enable register</title>
38 <instance>
39 <name>ENABLE</name>
40 <address>0x8</address>
41 </instance>
42 <register>
43 <width>16</width>
44 <field>
45 <name>VDDIO_BO</name>
46 <desc>VDDIO brownout interrupt enable</desc>
47 <position>0</position>
48 <width>2</width>
49 <enum>
50 <name>DISABLED</name>
51 <desc>Interrupt is disabled</desc>
52 <value>0</value>
53 </enum>
54 <enum>
55 <name>ENABLED</name>
56 <desc>Interrupt is enabled</desc>
57 <value>1</value>
58 </enum>
59 <enum>
60 <name>NMI</name>
61 <desc>Interrupt is non-maskable</desc>
62 <value>2</value>
63 </enum>
64 </field>
65 </register>
66 <variant>
67 <type>set</type>
68 <offset>4</offset>
69 </variant>
70 <variant>
71 <type>clr</type>
72 <offset>8</offset>
73 </variant>
74 </node>
75 </node>
76 <node>
77 <name>gpio</name>
78 <title>GPIO controller</title>
79 <desc>A GPIO controller manages several ports</desc>
80 <instance>
81 <name>CPU_GPIO</name>
82 <title>CPU GPIO controller 1 through 3</title>
83 <range>
84 <first>1</first>
85 <count>3</count>
86 <formula variable="n">0x80001000+(n-1)*0x1000</formula>
87 </range>
88 </instance>
89 <instance>
90 <name>COP_GPIO</name>
91 <title>Companion processor GPIO controller</title>
92 <desc>Although the companion processor GPIO controller is accessible from the CPU, it incurs an extra penalty on the bus</desc>
93 <address>0x90000000</address>
94 </instance>
95 <node>
96 <name>port</name>
97 <title>GPIO port</title>
98 <instance>
99 <name>PORT</name>
100 <range>
101 <first>0</first>
102 <count>4</count>
103 <base>0</base>
104 <stride>0x100</stride>
105 </range>
106 </instance>
107 <node>
108 <name>input</name>
109 <title>Input register</title>
110 <instance>
111 <name>IN</name>
112 <address>0</address>
113 </instance>
114 <register>
115 <width>8</width>
116 <field>
117 <name>VALUE</name>
118 <position>0</position>
119 <width>8</width>
120 </field>
121 </register>
122 </node>
123 <node>
124 <name>output_enable</name>
125 <title>Output enable register</title>
126 <instance>
127 <name>OE</name>
128 <address>0x10</address>
129 </instance>
130 <register>
131 <width>8</width>
132 <field>
133 <name>ENABLE</name>
134 <position>0</position>
135 <width>8</width>
136 </field>
137 </register>
138 <variant>
139 <type>set</type>
140 <address>4</address>
141 </variant>
142 <variant>
143 <type>clr</type>
144 <address>8</address>
145 </variant>
146 <variant>
147 <type>mask</type>
148 <address>12</address>
149 </variant>
150 </node>
151 </node>
152 </node>
153</soc> \ No newline at end of file
diff --git a/utils/regtools/desc/XML.txt b/utils/regtools/desc/spec-1.0.txt
index 3c28154a1f..3c28154a1f 100644
--- a/utils/regtools/desc/XML.txt
+++ b/utils/regtools/desc/spec-1.0.txt
diff --git a/utils/regtools/desc/spec-2.0.txt b/utils/regtools/desc/spec-2.0.txt
new file mode 100644
index 0000000000..79b9f6be44
--- /dev/null
+++ b/utils/regtools/desc/spec-2.0.txt
@@ -0,0 +1,373 @@
1This file describes the format of the register map based on XML, version 2.0.
2
31) Overview
4-----------
5
61.1) Nodes and instances
7------------------------
8
9This specification is based on the concept of "nodes". Nodes are containers
10which can contain other nodes and/or a register. Each node can have one or more
11addresses (addresses are always relative to the parent node). The idea is that
12this hierarchy of nodes generates a number of addresses recursively. The example
13below outlines this idea:
14
15<node>
16 <name>N</name>
17 <instance>
18 <name>A</name>
19 <address>X</address>
20 </instance>
21 <instance>
22 <name>B</name>
23 <address>Y</address>
24 </instance>
25 <!-- HERE -->
26</node>
27
28This example creates one node named N and two instances named A and B,
29at respective addresses X and Y. This means that all subnodes of this node will
30have two copies: one relative to X, which path will be prefixed by "A", and
31one relative to Y, which path will be prefixed by "B".
32This example below explores this idea in details:
33
34 <!-- HERE -->
35 <node>
36 <name>S_N</name>
37 <instance>
38 <name>C</name>
39 <address>U</address>
40 </instance>
41 <instance>
42 <name>D</name>
43 <address>V</address>
44 </instance>
45 </node>
46
47In this example, N generates two copies of the sub-node S_N.
48The sub-node S_N generates two instances C and D. The whole hierarchy thus generates
49four instances:
50- A.C at X+U
51- A.D at X+V
52- B.C at Y+U
53- B.D at Y+V
54
55As a note for later, notice that there really are two hierarchies in parallel:
56- the node hierarchy: it is composed of N and N.S_N
57- the instance hierarchy: it is made up of A, B, A.C, A.D, B.C and B.D
58
591.2) Ranges
60-----------
61
62To make things more useful, in particular in case of multiple copies of a register,
63we introduce the concept of range addresses with an example:
64
65<node>
66 <name>N</name>
67 <instance>
68 <name>A</name>
69 <range>
70 <first>1</first>
71 <count>5</count>
72 <base>0x1000</base>
73 <stride>0x100</stride>
74 </range>
75 </instance>
76 <node>
77 <name>NN</name>
78 <instance>
79 <name>E</name>
80 <address>0x4</address>
81 </instance>
82 </node>
83</node>
84
85A range describes a contiguous set of adresses, indexed by a number. One can
86specify the first number in the range, and the number of copies. In the case
87of a regular pattern (base + n * stride), we can specify a stride
88to compute the address of the next copy. In this example, the top-level
89nodes generates five copies which path is A[1], A[2], ..., A[5]
90and which addresses are 0x1000+1*0x100, 0x1000+2*0x100, ..., 0x1000+5*0x100.
91If we add the sub-node to the picture, for each copy we create a instance E
92we offset 0x4 from the parent. Overall this generates 5 instances:
93- A[1].E at 0x1000+1*0x100+0x4 = 0x1104
94- A[2].E at 0x1000+2*0x100+0x4 = 0x1204
95- A[3].E at 0x1000+3*0x100+0x4 = 0x1304
96- A[4].E at 0x1000+4*0x100+0x4 = 0x1404
97- A[5].E at 0x1000+5*0x100+0x4 = 0x1504
98Note that the intermediate path also define instances, so there are 5 additional
99instances in reality:
100- A[1] at 0x1100
101- A[2] at 0x1200
102- A[3] at 0x1300
103- A[4] at 0x1400
104- A[5] at 0x1500
105
106For the record, there is a more general way of specifying a range when it does
107not follow a nice regular pattern. One can specify a formula where the parameter
108is the index. There are no restrictions on the formula except that it must use
109usual arithmetic operators. The example below illustrate such a use:
110
111<node>
112 <name>N</name>
113 <instance>
114 <name>F</name>
115 <range>
116 <first>0</first>
117 <count>4</count>
118 <formula variable="n">0x50+(n/2)*0x100+(n%2)*0x10</formula>
119 </range>
120 </instance>
121</node>
122
123In this example we generate four nodes F[0], ..., F[3] with a formula. Here "/"
124is the euclidian division and "%" is the modulo operator. Note the use of an
125attribute to specify which variable represents the index. The generated addresses
126are:
127- F[0] at 0x50+(0/2)*0x100+(0%2)*0x10 = 0x50
128- F[1] at 0x50+(1/2)*0x100+(1%2)*0x10 = 0x50+0x10 = 0x60
129- F[2] at 0x50+(2/2)*0x100+(2%2)*0x10 = 0x50+0x100 = 0x150
130- F[3] at 0x50+(3/2)*0x100+(3%2)*0x10 = 0x50+0x100+0x10 = 0x160
131
1321.3) Node description
133---------------------
134
135For documentation purposes, node can of course carry some description, as well
136as instances. More precisely, nodes can have a title, that is a short description
137very much like a chapter title, and a description, this is a free form and potentially
138lengthy description of the node. Instances too can have a title and a description.
139The following example illustrates this:
140
141<node>
142 <name>icoll</name>
143 <title>DMA Controller</title>
144 <desc>The DMA controller provides uniform DMA facilities to transfer data from
145 and to peripherals. It uses memory-mapped tables and support chained
146 transfers.</desc>
147 <instance>
148 <name>AHB_DMAC</name>
149 <address>0x80000000</address>
150 <title>AHB DMA Controller</title>
151 <desc>The AHB DMA controller provides DMA facilities for the peripherals
152 on the AHB bus like the SSP and PIX engines.</desc>
153 </instance>
154 <instance>
155 <name>APB_DMAC</name>
156 <address>0x8001000</address>
157 <title>APB DMA Controller</title>
158 <desc>The APB DMA controller provides DMA facilities for the peripherals
159 on the APB bus like the I2C and PCM engines.</desc>
160 </instance>
161</node>
162
1631.4) Register description
164--------------------------
165
166The goal of the register description is of course to describe registers!
167To see how registers relate to the node hierarchy, see 1.5, this section focuses
168only the description only.
169
170A register carries a lot of information, which is organise logically. A register
171can have a width, in bits. By default registers are assumed to be 32-bit wide.
172The most useful feature of register description is to describe the fields of
173the registers. Each field has a name, a start position and a width. Fields
174can also carry a description. Finally, each field can specify enumerated values,
175that is named values, for convenience. Enumerated values have a name, a value
176and an optional description. The example below illustrates all these concepts:
177
178<register>
179 <width>8</width>
180 <field>
181 <name>MODE</name>
182 <desc>Interrupt mode</desc>
183 <position>0</position>
184 <width>2</width>
185 <enum>
186 <name>DISABLED</name>
187 <desc>Interrupt is disabled</desc>
188 <value>0</value>
189 </enum>
190 <enum>
191 <name>ENABLED</name>
192 <desc>Interrupt is enabled</desc>
193 <value>1</value>
194 </enum>
195 <enum>
196 <name>NMI</name>
197 <desc>Interrupt is non-maskable</desc>
198 <value>2</value>
199 </enum>
200 </field>
201 <field>
202 <name>PRIORITY</name>
203 <desc>Interrupt priority, lower values are more prioritized.</desc>
204 <position>2</position>
205 <width>2</width>
206 </field>
207 <field>
208 <name>ARM_MODE</name>
209 <desc>Select between ARM's FIQ and IRQ mode</desc>
210 <position>4</position>
211 <width>1</width>
212 <enum>
213 <name>IRQ</name>
214 <value>0</value>
215 </enum>
216 <enum>
217 <name>FIQ</name>
218 <value>1</value>
219 </enum>
220 </field>
221</register>
222
223In this example, the 8-bit registers has three fields:
224- MODE(1:0): it has three named values DISABLED(0), ENABLED(1) and NMI(2)
225- PRIORITY(2:1): it has no named values
226- ARM_MODE(3): it has two named values IRQ(0) and FIQ(1)
227
2281.5) Register inheritance
229-------------------------
230
231The node hierarchy specifies instances, that is pairs of (path,address),
232and the register description describes the internal of a register. The placement
233of the register descriptions in the node hierarchy will specify which registers
234can be found at each address. More precisely, if a node contains a register
235description, it means that this node's and all sub-nodes' instances are registers
236following the description. It is forbidden for a node to contain a register
237description if one of its parents already contains one. The example below
238will make this concept clearer (for readability, we omitted some of the tags):
239
240<node>
241 <name>dma</name>
242 <instance><name>DMAC</name><address>0x80000000</address></instance>
243 <node>
244 <instance><name>PCM_CHAN</name><address>0x0</address></instance>
245 <instance><name>I2C_CHAN</name><address>0x10</address></instance>
246 <register><!--- blabla --></register>
247 <node>
248 <name>sct</name>
249 <instance><name>SET</name><address>0x4</address></instance>
250 <instance><name>CLR</name><address>0x8</address></instance>
251 <instance><name>TOG</name><address>0xC</address></instance>
252 </node>
253 </node>
254</node>
255
256This example describes one register (let's call it blabla) and 9 instances:
257- DMAC at 0x80000000, no register
258- DMAC.PCM_CHAN at 0x80000000, register blabla
259- DMAC.PCM_CHAN.SET at 0x80000004, register blabla
260- DMAC.PCM_CHAN.CLR at 0x80000008, register blabla
261- DMAC.PCM_CHAN.TOG at 0x8000000C, register blabla
262- DMAC.I2C_CHAN at 0x80000010, register blabla
263- DMAC.I2C_CHAN.SET at 0x80000014, register blabla
264- DMAC.I2C_CHAN.CLR at 0x80000018, register blabla
265- DMAC.I2C_CHAN.TOG at 0x8000001C, register blabla
266
2671.6) Soc description
268--------------------
269
270The description file must also specify some information about the system-on-chip
271itself. The entire description, including nodes, is contained in a "soc" tag
272which must at least specify the soc name. It can optionally specify the title
273and description, as well as the author(s) of the description, the ISA and
274the version.
275
276<soc>
277 <name>vsoc</name>
278 <title>Virtual SOC</title>
279 <desc>Virtual SoC is a nice and powerful chip.</desc>
280 <author>Amaury Pouly</author>
281 <isa>ARM</isa>
282 <version>0.5</version>
283 <!-- put nodes below -->
284</soc>
285
2862) Specification
287----------------
288
289Root
290----
291As any XML document, the content of the file should be enclosed in a "xml" tag.
292The root element must be "soc" tag.
293
294Example:
295<?xml version="1.0"?>
296<!-- desc -->
297</xml>
298
299Element: soc
300------------
301It must contain the following tags:
302- name: name of soc, only made of alphanumerical characters
303It can contain at most one of each of the following tags:
304- title: one line description of the soc
305- desc: free form description of the soc
306- isa: instruction set assembly
307- version: version of the description
308It can contain any number of the following tags:
309- author: author of the description
310- node: node description
311
312Element: node
313-------------
314It must contain the following tags:
315- name: name of node, only made of alphanumerical characters
316It can contain at most one of each of the following tags:
317- title: one line description of the node
318- desc: free form description of the node
319- register: register description
320It can contain any number of the following tags:
321- instance: author of the description
322- node: node description
323
324Element: instance
325-----------------
326It must contain the following tags:
327- name: name of instance, only made of alphanumerical characters
328It can contain at most one of each of the following tags:
329- title: one line description of the instance
330- desc: free form description of the instance
331- address: address for a single instance (non-negative number)
332- range: address range for multiple instances
333Note that address and range are mutually exclusive, and at least one of them
334must exists.
335
336Element: range
337--------------
338It must contain the following tags:
339- first: index of the first instance (non-negative number)
340- count: number of instances (positive number)
341It can contain at most one of each of the following tags:
342- base: base address (non-negative number)
343- stride: stride (number)
344- formula: free-form formula, must have a "variable" attribute
345Note that stride and formula are mutually exclusive, and at least one of them
346must exists. If stride is specified and base is omitted, it is taken to be 0.
347
348Element: register
349-----------------
350It can contain at most one of each of the following tags:
351- width: width in bits (positive number)
352It can contain any number of the following tags:
353- field: field description
354
355Element: field
356--------------
357It must contain the following tags:
358- name: name of field, only made of alphanumerical characters
359- position: least significant bit
360It can contain at most one of each of the following tags:
361- desc: free form description of the instance
362- width: width in bits
363It can contain any number of the following tags:
364- enum: enumerated value
365If the width is not specified, it is assumed to be 1.
366
367Element: enum
368-------------
369It must contain the following tags:
370- name: name of field, only made of alphanumerical characters
371- value: value (non-negative, must fit into the field's width)
372It can contain at most one of each of the following tags:
373- desc: free form description of the instance \ No newline at end of file
diff --git a/utils/regtools/headergen.cpp b/utils/regtools/headergen_v1.cpp
index 046e8b2fd8..7b38366d5d 100644
--- a/utils/regtools/headergen.cpp
+++ b/utils/regtools/headergen_v1.cpp
@@ -18,7 +18,7 @@
18 * KIND, either express or implied. 18 * KIND, either express or implied.
19 * 19 *
20 ****************************************************************************/ 20 ****************************************************************************/
21#include "soc_desc.hpp" 21#include "soc_desc_v1.hpp"
22#include <stdio.h> 22#include <stdio.h>
23#include <stdlib.h> 23#include <stdlib.h>
24#include <algorithm> 24#include <algorithm>
@@ -28,6 +28,8 @@
28#include <sys/types.h> 28#include <sys/types.h>
29#include <getopt.h> 29#include <getopt.h>
30 30
31using namespace soc_desc_v1;
32
31#define HEADERGEN_VERSION "2.1.8" 33#define HEADERGEN_VERSION "2.1.8"
32 34
33#define error(...) do{ fprintf(stderr, __VA_ARGS__); exit(1); } while(0) 35#define error(...) do{ fprintf(stderr, __VA_ARGS__); exit(1); } while(0)
@@ -721,7 +723,7 @@ int main(int argc, char **argv)
721 for(int i = optind; i < argc - 1; i++) 723 for(int i = optind; i < argc - 1; i++)
722 { 724 {
723 soc_t s; 725 soc_t s;
724 if(!soc_desc_parse_xml(argv[i], s)) 726 if(!parse_xml(argv[i], s))
725 { 727 {
726 printf("Cannot parse %s\n", argv[i]); 728 printf("Cannot parse %s\n", argv[i]);
727 return 1; 729 return 1;
diff --git a/utils/regtools/include/soc_desc.hpp b/utils/regtools/include/soc_desc.hpp
new file mode 100644
index 0000000000..66f2e3b6e1
--- /dev/null
+++ b/utils/regtools/include/soc_desc.hpp
@@ -0,0 +1,384 @@
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#ifndef __SOC_DESC__
22#define __SOC_DESC__
23
24#include <stdint.h>
25#include <vector>
26#include <list>
27#include <string>
28#include <map>
29
30namespace soc_desc
31{
32
33const size_t MAJOR_VERSION = 2;
34const size_t MINOR_VERSION = 0;
35const size_t REVISION_VERSION = 0;
36
37/** Typedef for SoC types: word, address and flags */
38typedef uint32_t soc_addr_t;
39typedef uint32_t soc_word_t;
40typedef int soc_id_t;
41
42/** Error class */
43class error_t
44{
45public:
46 enum level_t
47 {
48 INFO,
49 WARNING,
50 FATAL
51 };
52 error_t(level_t lvl, const std::string& loc, const std::string& msg)
53 :m_level(lvl), m_loc(loc), m_msg(msg) {}
54 level_t level() const { return m_level; }
55 std::string location() const { return m_loc; }
56 std::string message() const { return m_msg; }
57protected:
58 level_t m_level;
59 std::string m_loc, m_msg;
60};
61
62/** Error context to log errors */
63class error_context_t
64{
65public:
66 void add(const error_t& err) { m_list.push_back(err); }
67 size_t count() const { return m_list.size(); }
68 error_t get(size_t i) const { return m_list[i]; }
69protected:
70 std::vector< error_t > m_list;
71};
72
73/**
74 * Bare representation of the format
75 */
76
77/** Enumerated value (aka named value), represents a special value for a field */
78struct enum_t
79{
80 soc_id_t id; /** ID (must be unique among field enums) */
81 std::string name; /** Name (must be unique among field enums) */
82 std::string desc; /** Optional description of the meaning of this value */
83 soc_word_t value; /** Value of the field */
84};
85
86/** Register field information */
87struct field_t
88{
89 soc_id_t id; /** ID (must be unique among register fields) */
90 std::string name; /** Name (must be unique among register fields) */
91 std::string desc; /** Optional description of the field */
92 size_t pos; /** Position of the least significant bit */
93 size_t width; /** Width of the field in bits */
94 std::vector< enum_t > enum_; /** List of special values */
95
96 /** Returns the bit mask of the field within the register */
97 soc_word_t bitmask() const
98 {
99 // WARNING beware of the case where width is 32
100 if(width == 32)
101 return 0xffffffff;
102 else
103 return ((1 << width) - 1) << pos;
104 }
105
106 /** Extract field value from register value */
107 soc_word_t extract(soc_word_t reg_val) const
108 {
109 return (reg_val & bitmask()) >> pos;
110 }
111
112 /** Replace the field value in a register value */
113 soc_word_t replace(soc_word_t reg_val, soc_word_t field_val) const
114 {
115 return (reg_val & ~bitmask()) | ((field_val << pos) & bitmask());
116 }
117
118 /** Return field value index, or -1 if none */
119 int find_value(soc_word_t v) const
120 {
121 for(size_t i = 0; i < enum_.size(); i++)
122 if(enum_[i].value == v)
123 return i;
124 return -1;
125 }
126};
127
128/** Register information */
129struct register_t
130{
131 size_t width; /** Size in bits */
132 std::vector< field_t > field; /** List of fields */
133};
134
135/** Node address range information */
136struct range_t
137{
138 enum type_t
139 {
140 STRIDE, /** Addresses are given by a base address and a stride */
141 FORMULA /** Addresses are given by a formula */
142 };
143
144 type_t type; /** Range type */
145 size_t first; /** First index in the range */
146 size_t count; /** Number of indexes in the range */
147 soc_word_t base; /** Base address (for STRIDE) */
148 soc_word_t stride; /** Stride value (for STRIDE) */
149 std::string formula; /** Formula (for FORMULA) */
150 std::string variable; /** Formula variable name (for FORMULA) */
151};
152
153/** Node instance information */
154struct instance_t
155{
156 enum type_t
157 {
158 SINGLE, /** There is a single instance at a specified address */
159 RANGE /** There are multiple addresses forming a range */
160 };
161
162 soc_id_t id; /** ID (must be unique among node instances) */
163 std::string name; /** Name (must be unique among node instances) */
164 std::string title; /** Optional instance human name */
165 std::string desc; /** Optional description of the instance */
166 type_t type; /** Instance type */
167 soc_word_t addr; /** Address (for SINGLE) */
168 range_t range; /** Range (for RANGE) */
169};
170
171/** Node information */
172struct node_t
173{
174 soc_id_t id; /** ID (must be unique among nodes) */
175 std::string name; /** Name (must be unique for the among nodes) */
176 std::string title; /** Optional node human name */
177 std::string desc; /** Optional description of the node */
178 std::vector< register_t> register_; /** Optional register */
179 std::vector< instance_t> instance; /** List of instances */
180 std::vector< node_t > node; /** List of sub-nodes */
181};
182
183/** System-on-chip information */
184struct soc_t
185{
186 std::string name; /** Codename of the SoC */
187 std::string title; /** Human name of the SoC */
188 std::string desc; /** Optional description of the SoC */
189 std::string isa; /** Instruction Set Assembly */
190 std::string version; /** Description version */
191 std::vector< std::string > author; /** List of authors of the description */
192 std::vector< node_t > node; /** List of nodes */
193};
194
195/** Parse a SoC description from a XML file, put it into <soc>. */
196bool parse_xml(const std::string& filename, soc_t& soc, error_context_t& error_ctx);
197/** Write a SoC description to a XML file, overwriting it. A file can contain
198 * multiple Soc descriptions */
199bool produce_xml(const std::string& filename, const soc_t& soc, error_context_t& error_ctx);
200/** Formula parser: try to parse and evaluate a formula with some variables */
201bool evaluate_formula(const std::string& formula,
202 const std::map< std::string, soc_word_t>& var, soc_word_t& result,
203 const std::string& loc, error_context_t& error_ctx);
204
205/**
206 * Convenience API to manipulate the format
207 *
208 * The idea is that *_ref_t objects are stable pointers: they stay valid even
209 * when the underlying soc changes. In particular:
210 * - modifying any structure data (except id fields) preserves all references
211 * - removing a structure invalidates all references pointing to this structure
212 * and its children
213 * - adding any structure preserves all references
214 * These references can be used to get pointers to the actual data
215 * of the representation when it needs to be read or write.
216 */
217
218class soc_ref_t;
219class node_ref_t;
220class register_ref_t;
221class field_ref_t;
222class node_inst_t;
223
224/** SoC reference */
225class soc_ref_t
226{
227 soc_t *m_soc; /* pointer to the soc */
228public:
229 /** Builds an invalid reference */
230 soc_ref_t();
231 /** Builds a reference to a soc */
232 soc_ref_t(soc_t *soc);
233 /** Checks whether this reference is valid */
234 bool valid() const;
235 /** Returns a pointer to the soc */
236 soc_t *get() const;
237 /** Returns a reference to the root node */
238 node_ref_t root() const;
239 /** Returns a reference to the root node instance */
240 node_inst_t root_inst() const;
241 /** Compare this reference to another */
242 bool operator==(const soc_ref_t& r) const;
243 inline bool operator!=(const soc_ref_t& r) const { return !operator==(r); }
244};
245
246/** SoC node reference
247 * NOTE: the root soc node is presented as a node with empty path */
248class node_ref_t
249{
250 friend class soc_ref_t;
251 friend class node_inst_t;
252 soc_ref_t m_soc; /* reference to the soc */
253 std::vector< soc_id_t > m_path; /* path from the root */
254
255 node_ref_t(soc_ref_t soc);
256 node_ref_t(soc_ref_t soc, const std::vector< soc_id_t >& path);
257public:
258 /** Builds an invalid reference */
259 node_ref_t();
260 /** Check whether this reference is valid */
261 bool valid() const;
262 /** Check whether this reference is the root node */
263 bool is_root() const;
264 /** Returns a pointer to the node, or 0 if invalid or root */
265 node_t *get() const;
266 /** Returns a reference to the soc */
267 soc_ref_t soc() const;
268 /** Returns a reference to the parent node */
269 node_ref_t parent() const;
270 /** Returns a reference to the register (which may be on a parent node) */
271 register_ref_t reg() const;
272 /** Returns a list of references to the sub-nodes */
273 std::vector< node_ref_t > children() const;
274 /** Returns a reference to a specific child */
275 node_ref_t child(const std::string& name) const;
276 /** Returns the path of the node, as the list of node names from the root */
277 std::vector< std::string > path() const;
278 /** Returns the name of the node */
279 std::string name() const;
280 /** Compare this reference to another */
281 bool operator==(const node_ref_t& r) const;
282 inline bool operator!=(const node_ref_t& r) const { return !operator==(r); }
283};
284
285/** SoC register reference */
286class register_ref_t
287{
288 friend class node_ref_t;
289 node_ref_t m_node; /* reference to the node owning the register */
290
291 register_ref_t(node_ref_t node);
292public:
293 /** Builds an invalid reference */
294 register_ref_t();
295 /** Check whether this reference is valid/exists */
296 bool valid() const;
297 /** Returns a pointer to the register, or 0 */
298 register_t *get() const;
299 /** Returns a reference to the node containing the register */
300 node_ref_t node() const;
301 /** Returns a list of references to the fields of the register */
302 std::vector< field_ref_t > fields() const;
303 /** Returns a reference to a particular field */
304 field_ref_t field(const std::string& name) const;
305 /** Compare this reference to another */
306 bool operator==(const register_ref_t& r) const;
307 inline bool operator!=(const register_ref_t& r) const { return !operator==(r); }
308};
309
310/** SoC register field reference */
311class field_ref_t
312{
313 friend class register_ref_t;
314 register_ref_t m_reg; /* reference to the register */
315 soc_id_t m_id; /* field name */
316
317 field_ref_t(register_ref_t reg, soc_id_t id);
318public:
319 /** Builds an invalid reference */
320 field_ref_t();
321 /** Check whether this reference is valid/exists */
322 bool valid() const;
323 /** Returns a pointer to the field, or 0 */
324 field_t *get() const;
325 /** Returns a reference to the register containing the field */
326 register_ref_t reg() const;
327 /** Compare this reference to another */
328 bool operator==(const field_ref_t& r) const;
329 inline bool operator!=(const field_ref_t& r) const { return !operator==(r); }
330};
331
332/** SoC node instance
333 * NOTE: the root soc node is presented as a node with a single instance at 0 */
334class node_inst_t
335{
336 friend class node_ref_t;
337 friend class soc_ref_t;
338 node_ref_t m_node; /* reference to the node */
339 std::vector< soc_id_t > m_id_path; /* list of instance IDs */
340 std::vector< size_t > m_index_path; /* list of instance indexes */
341
342 node_inst_t(soc_ref_t soc);
343 node_inst_t(node_ref_t soc, const std::vector< soc_id_t >& path,
344 const std::vector< size_t >& indexes);
345public:
346 /** Builds an invalid reference */
347 node_inst_t();
348 /** Check whether this instance is valid/exists */
349 bool valid() const;
350 /** Returns a reference to the soc */
351 soc_ref_t soc() const;
352 /** Returns a reference to the node */
353 node_ref_t node() const;
354 /** Check whether this reference is the root node instance */
355 bool is_root() const;
356 /** Returns a reference to the parent instance */
357 node_inst_t parent() const;
358 /** Returns a pointer to the instance of the node, or 0 */
359 instance_t *get() const;
360 /** Returns the address of this instance */
361 soc_addr_t addr() const;
362 /** Returns an instance to a child of this node's instance. If the subnode
363 * instance is a range, the returned reference is invalid */
364 node_inst_t child(const std::string& name) const;
365 /** Returns an instance to a child of this node's instance with a range index.
366 * If the subnode is not not a range or if the index is out of bounds,
367 * the returned reference is invalid */
368 node_inst_t child(const std::string& name, size_t index) const;
369 /** Returns a list of all instances of subnodes of this node's instance */
370 std::vector< node_inst_t > children() const;
371 /** Returns the name of the instance */
372 std::string name() const;
373 /** Checks whether this instance is indexed */
374 bool is_indexed() const;
375 /** Returns the index of the instance */
376 size_t index() const;
377 /** Compare this reference to another */
378 bool operator==(const node_inst_t& r) const;
379 inline bool operator!=(const node_inst_t& r) const { return !operator==(r); }
380};
381
382} // soc_desc
383
384#endif /* __SOC_DESC__ */
diff --git a/utils/regtools/lib/soc_desc.hpp b/utils/regtools/include/soc_desc_v1.hpp
index bb8eb4ba8d..33368e88d4 100644
--- a/utils/regtools/lib/soc_desc.hpp
+++ b/utils/regtools/include/soc_desc_v1.hpp
@@ -18,8 +18,8 @@
18 * KIND, either express or implied. 18 * KIND, either express or implied.
19 * 19 *
20 ****************************************************************************/ 20 ****************************************************************************/
21#ifndef __SOC_DESC__ 21#ifndef __SOC_DESC_V1__
22#define __SOC_DESC__ 22#define __SOC_DESC_V1__
23 23
24#include <stdint.h> 24#include <stdint.h>
25#include <vector> 25#include <vector>
@@ -45,13 +45,12 @@
45 * ignores the position of the WORD_LENGTH field in the register. 45 * ignores the position of the WORD_LENGTH field in the register.
46 */ 46 */
47 47
48#define SOCDESC_VERSION_MAJOR 1 48namespace soc_desc_v1
49#define SOCDESC_VERSION_MINOR 4 49{
50#define SOCDESC_VERSION_REV 1
51 50
52#define SOCDESC_VERSION__(maj,min,rev) #maj"."#min"."#rev 51const size_t MAJOR_VERSION = 1;
53#define SOCDESC_VERSION_(maj,min,rev) SOCDESC_VERSION__(maj,min,rev) 52const size_t MINOR_VERSION = 4;
54#define SOCDESC_VERSION SOCDESC_VERSION_(SOCDESC_VERSION_MAJOR,SOCDESC_VERSION_MINOR,SOCDESC_VERSION_REV) 53const size_t REVISION_VERSION = 1;
55 54
56/** 55/**
57 * Typedef for SoC types: word, address and flags */ 56 * Typedef for SoC types: word, address and flags */
@@ -211,18 +210,21 @@ struct soc_t
211}; 210};
212 211
213/** Parse a SoC description from a XML file, append it to <soc>. */ 212/** Parse a SoC description from a XML file, append it to <soc>. */
214bool soc_desc_parse_xml(const std::string& filename, soc_t& soc); 213bool parse_xml(const std::string& filename, soc_t& soc);
215/** Write a SoC description to a XML file, overwriting it. A file can contain 214/** Write a SoC description to a XML file, overwriting it. A file can contain
216 * multiple Soc descriptions */ 215 * multiple Soc descriptions */
217bool soc_desc_produce_xml(const std::string& filename, const soc_t& soc); 216bool produce_xml(const std::string& filename, const soc_t& soc);
218/** Normalise a soc description by reordering elemnts so that: 217/** Normalise a soc description by reordering elemnts so that:
219 * - devices are sorted by first name 218 * - devices are sorted by first name
220 * - registers are sorted by first address 219 * - registers are sorted by first address
221 * - fields are sorted by last bit 220 * - fields are sorted by last bit
222 * - values are sorted by value */ 221 * - values are sorted by value */
223void soc_desc_normalize(soc_t& soc); 222void normalize(soc_t& soc);
224/** Formula parser: try to parse and evaluate a formula to a specific value of 'n' */ 223/** Formula parser: try to parse and evaluate a formula with some variables */
225bool soc_desc_evaluate_formula(const std::string& formula, 224bool evaluate_formula(const std::string& formula,
226 const std::map< std::string, soc_word_t>& var, soc_word_t& result, std::string& error); 225 const std::map< std::string, soc_word_t>& var, soc_word_t& result,
226 std::string& error);
227
228} // soc_desc_v1
227 229
228#endif /* __SOC_DESC__ */ \ No newline at end of file 230#endif /* __SOC_DESC_V1__ */ \ No newline at end of file
diff --git a/utils/regtools/lib/Makefile b/utils/regtools/lib/Makefile
index 08021ef941..d7d6c1b07a 100644
--- a/utils/regtools/lib/Makefile
+++ b/utils/regtools/lib/Makefile
@@ -1,18 +1,15 @@
1CC?=gcc 1CC?=gcc
2CXX?=g++ 2CXX?=g++
3AR?=ar 3AR?=ar
4CFLAGS=-Wall -O2 `xml2-config --cflags` -std=c99 -g -fPIC 4INCLUDE=../include/
5CXXFLAGS=-Wall -O2 `xml2-config --cflags` -g -fPIC 5CXXFLAGS=-Wall -O2 `xml2-config --cflags` -g -fPIC -I$(INCLUDE)
6LIB=libsocdesc.a 6LIB=libsocdesc.a
7SRC=$(wildcard *.c) 7SRC=$(wildcard *.c)
8SRCXX=$(wildcard *.cpp) 8SRCXX=$(wildcard *.cpp)
9OBJ=$(SRC:.c=.o) $(SRCXX:.cpp=.o) 9OBJ=$(SRCXX:.cpp=.o)
10 10
11all: $(LIB) $(EXEC) 11all: $(LIB) $(EXEC)
12 12
13%.o: %.c
14 $(CC) $(CFLAGS) -c -o $@ $<
15
16%.o: %.cpp 13%.o: %.cpp
17 $(CXX) $(CXXFLAGS) -c -o $@ $< 14 $(CXX) $(CXXFLAGS) -c -o $@ $<
18 15
diff --git a/utils/regtools/lib/formula.cpp b/utils/regtools/lib/formula.cpp
new file mode 100644
index 0000000000..1a6b16c773
--- /dev/null
+++ b/utils/regtools/lib/formula.cpp
@@ -0,0 +1,214 @@
1#include "soc_desc.hpp"
2#include <cstdarg>
3#include <cstdio>
4
5using namespace soc_desc;
6
7namespace soc_desc
8{
9
10namespace
11{
12
13struct formula_evaluator
14{
15 std::string formula;
16 size_t pos;
17 error_context_t& ctx;
18 std::string m_loc;
19
20 bool err(const char *fmt, ...)
21 {
22 char buffer[256];
23 va_list args;
24 va_start(args, fmt);
25 vsnprintf(buffer,sizeof(buffer), fmt, args);
26 va_end(args);
27 ctx.add(error_t(error_t::FATAL, m_loc, buffer));
28 return false;
29 }
30
31 formula_evaluator(const std::string& s, error_context_t& ctx):pos(0),ctx(ctx)
32 {
33 for(size_t i = 0; i < s.size(); i++)
34 if(!isspace(s[i]))
35 formula.push_back(s[i]);
36 }
37
38 void set_location(const std::string& loc)
39 {
40 m_loc = loc;
41 }
42
43 void adv()
44 {
45 pos++;
46 }
47
48 char cur()
49 {
50 return end() ? 0 : formula[pos];
51 }
52
53 bool end()
54 {
55 return pos >= formula.size();
56 }
57
58 bool parse_digit(char c, int basis, soc_word_t& res)
59 {
60 c = tolower(c);
61 if(isdigit(c))
62 {
63 res = c - '0';
64 return true;
65 }
66 if(basis == 16 && isxdigit(c))
67 {
68 res = c + 10 - 'a';
69 return true;
70 }
71 return false;
72 }
73
74 bool parse_signed(soc_word_t& res)
75 {
76 char op = cur();
77 if(op == '+' || op == '-')
78 {
79 adv();
80 if(!parse_signed(res))
81 return false;
82 if(op == '-')
83 res *= -1;
84 return true;
85 }
86 else if(op == '(')
87 {
88 adv();
89 if(!parse_expression(res))
90 return false;
91 if(cur() != ')')
92 return err("expected ')', got '%c'", cur());
93 adv();
94 return true;
95 }
96 else if(isdigit(op))
97 {
98 res = op - '0';
99 adv();
100 int basis = 10;
101 if(op == '0' && cur() == 'x')
102 {
103 basis = 16;
104 adv();
105 }
106 soc_word_t digit = 0;
107 while(parse_digit(cur(), basis, digit))
108 {
109 res = res * basis + digit;
110 adv();
111 }
112 return true;
113 }
114 else if(isalpha(op) || op == '_')
115 {
116 std::string name;
117 while(isalnum(cur()) || cur() == '_')
118 {
119 name.push_back(cur());
120 adv();
121 }
122 return get_variable(name, res);
123 }
124 else
125 return err("express signed expression, got '%c'", op);
126 }
127
128 bool parse_term(soc_word_t& res)
129 {
130 if(!parse_signed(res))
131 return false;
132 while(cur() == '*' || cur() == '/' || cur() == '%')
133 {
134 char op = cur();
135 adv();
136 soc_word_t tmp;
137 if(!parse_signed(tmp))
138 return false;
139 if(op == '*')
140 res *= tmp;
141 else if(tmp != 0)
142 res = op == '/' ? res / tmp : res % tmp;
143 else
144 return err("division by 0");
145 }
146 return true;
147 }
148
149 bool parse_expression(soc_word_t& res)
150 {
151 if(!parse_term(res))
152 return false;
153 while(!end() && (cur() == '+' || cur() == '-'))
154 {
155 char op = cur();
156 adv();
157 soc_word_t tmp;
158 if(!parse_term(tmp))
159 return false;
160 if(op == '+')
161 res += tmp;
162 else
163 res -= tmp;
164 }
165 return true;
166 }
167
168 bool parse(soc_word_t& res)
169 {
170 bool ok = parse_expression(res);
171 if(ok && !end())
172 err("unexpected character '%c'", cur());
173 return ok && end();
174 }
175
176 virtual bool get_variable(std::string name, soc_word_t& res)
177 {
178 return err("unknown variable '%s'", name.c_str());
179 }
180};
181
182struct my_evaluator : public formula_evaluator
183{
184 const std::map< std::string, soc_word_t>& var;
185
186 my_evaluator(const std::string& formula, const std::map< std::string, soc_word_t>& _var,
187 error_context_t& ctx)
188 :formula_evaluator(formula, ctx), var(_var) {}
189
190 virtual bool get_variable(std::string name, soc_word_t& res)
191 {
192 std::map< std::string, soc_word_t>::const_iterator it = var.find(name);
193 if(it == var.end())
194 return formula_evaluator::get_variable(name, res);
195 else
196 {
197 res = it->second;
198 return true;
199 }
200 }
201};
202
203}
204
205bool evaluate_formula(const std::string& formula,
206 const std::map< std::string, soc_word_t>& var, soc_word_t& result,
207 const std::string& loc, error_context_t& error)
208{
209 my_evaluator e(formula, var, error);
210 e.set_location(loc);
211 return e.parse(result);
212}
213
214} // soc_desc
diff --git a/utils/regtools/lib/soc_desc.cpp b/utils/regtools/lib/soc_desc.cpp
index 90e4e0eb81..4e0e46f00e 100644
--- a/utils/regtools/lib/soc_desc.cpp
+++ b/utils/regtools/lib/soc_desc.cpp
@@ -7,7 +7,7 @@
7 * \/ \/ \/ \/ \/ 7 * \/ \/ \/ \/ \/
8 * $Id$ 8 * $Id$
9 * 9 *
10 * Copyright (C) 2012 by Amaury Pouly 10 * Copyright (C) 2014 by Amaury Pouly
11 * 11 *
12 * This program is free software; you can redistribute it and/or 12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License 13 * modify it under the terms of the GNU General Public License
@@ -27,261 +27,429 @@
27#include <string.h> 27#include <string.h>
28#include <algorithm> 28#include <algorithm>
29#include <cctype> 29#include <cctype>
30#include <sstream>
31#include <limits>
32
33namespace soc_desc
34{
35
36/**
37 * Parser
38 */
30 39
31#define XML_CHAR_TO_CHAR(s) ((const char *)(s)) 40#define XML_CHAR_TO_CHAR(s) ((const char *)(s))
32 41
33#define BEGIN_ATTR_MATCH(attr) \ 42#define BEGIN_ATTR_MATCH(attr) \
34 for(xmlAttr *a = attr; a; a = a->next) { 43 for(xmlAttr *a = attr; a; a = a->next) {
35 44
36#define MATCH_X_ATTR(attr_name, hook, ...) \ 45#define MATCH_UNIQUE_ATTR(attr_name, val, has, parse_fn, ctx) \
37 if(strcmp(XML_CHAR_TO_CHAR(a->name), attr_name) == 0) { \ 46 if(strcmp(XML_CHAR_TO_CHAR(a->name), attr_name) == 0) { \
38 std::string s; \ 47 if(has) \
39 if(!parse_text_attr(a, s) || !hook(s, __VA_ARGS__)) \ 48 return parse_not_unique_attr_error(a, ctx); \
40 return false; \ 49 has = true; \
50 xmlChar *str = NULL; \
51 if(!parse_text_attr_internal(a, str, ctx) || !parse_fn(a, val, str, ctx)) \
52 ret = false; \
41 } 53 }
42 54
43#define SOFT_MATCH_X_ATTR(attr_name, hook, ...) \
44 if(strcmp(XML_CHAR_TO_CHAR(a->name), attr_name) == 0) { \
45 std::string s; \
46 if(parse_text_attr(a, s)) \
47 hook(s, __VA_ARGS__); \
48 }
49
50#define SOFT_MATCH_SCT_ATTR(attr_name, var) \
51 SOFT_MATCH_X_ATTR(attr_name, validate_sct_hook, var)
52
53#define MATCH_TEXT_ATTR(attr_name, var) \
54 MATCH_X_ATTR(attr_name, validate_string_hook, var)
55
56#define MATCH_UINT32_ATTR(attr_name, var) \
57 MATCH_X_ATTR(attr_name, validate_uint32_hook, var)
58
59#define MATCH_BITRANGE_ATTR(attr_name, first, last) \
60 MATCH_X_ATTR(attr_name, validate_bitrange_hook, first, last)
61
62#define END_ATTR_MATCH() \ 55#define END_ATTR_MATCH() \
63 } 56 }
64 57
65#define BEGIN_NODE_MATCH(node) \ 58#define BEGIN_NODE_MATCH(node) \
66 for(xmlNode *sub = node; sub; sub = sub->next) { 59 for(xmlNode *sub = node; sub; sub = sub->next) {
67 60
68#define MATCH_ELEM_NODE(node_name, array, parse_fn) \ 61#define MATCH_ELEM_NODE(node_name, array, parse_fn, ctx) \
69 if(sub->type == XML_ELEMENT_NODE && strcmp(XML_CHAR_TO_CHAR(sub->name), node_name) == 0) { \ 62 if(sub->type == XML_ELEMENT_NODE && strcmp(XML_CHAR_TO_CHAR(sub->name), node_name) == 0) { \
70 array.resize(array.size() + 1); \ 63 array.resize(array.size() + 1); \
71 if(!parse_fn(sub, array.back())) \ 64 if(!parse_fn(sub, array.back(), ctx)) \
72 return false; \ 65 ret = false; \
66 array.back().id = array.size(); \
73 } 67 }
74 68
75#define SOFT_MATCH_ELEM_NODE(node_name, array, parse_fn) \ 69#define MATCH_TEXT_NODE(node_name, array, parse_fn, ctx) \
76 if(sub->type == XML_ELEMENT_NODE && strcmp(XML_CHAR_TO_CHAR(sub->name), node_name) == 0) { \ 70 if(sub->type == XML_ELEMENT_NODE && strcmp(XML_CHAR_TO_CHAR(sub->name), node_name) == 0) { \
71 if(!is_real_text_node(sub)) \
72 return parse_not_text_error(sub, ctx); \
73 xmlChar *content = xmlNodeGetContent(sub); \
77 array.resize(array.size() + 1); \ 74 array.resize(array.size() + 1); \
78 if(!parse_fn(sub, array.back())) \ 75 ret = ret && parse_fn(sub, array.back(), content, ctx); \
79 array.pop_back(); \ 76 xmlFree(content); \
77 }
78
79#define MATCH_UNIQUE_ELEM_NODE(node_name, val, has, parse_fn, ctx) \
80 if(sub->type == XML_ELEMENT_NODE && strcmp(XML_CHAR_TO_CHAR(sub->name), node_name) == 0) { \
81 if(has) \
82 return parse_not_unique_error(sub, ctx); \
83 has = true; \
84 if(!parse_fn(sub, val, ctx)) \
85 ret = false; \
86 }
87
88#define MATCH_UNIQUE_TEXT_NODE(node_name, val, has, parse_fn, ctx) \
89 if(sub->type == XML_ELEMENT_NODE && strcmp(XML_CHAR_TO_CHAR(sub->name), node_name) == 0) { \
90 if(has) \
91 return parse_not_unique_error(sub, ctx); \
92 if(!is_real_text_node(sub)) \
93 return parse_not_text_error(sub, ctx); \
94 has = true; \
95 xmlChar *content = xmlNodeGetContent(sub); \
96 ret = ret && parse_fn(sub, val, content, ctx); \
97 xmlFree(content); \
80 } 98 }
81 99
82#define END_NODE_MATCH() \ 100#define END_NODE_MATCH() \
83 } 101 }
84 102
103#define CHECK_HAS(node, node_name, has, ctx) \
104 if(!has) \
105 ret = ret && parse_missing_error(node, node_name, ctx);
106
107#define CHECK_HAS_ATTR(node, attr_name, has, ctx) \
108 if(!has) \
109 ret = ret && parse_missing_attr_error(node, attr_name, ctx);
110
85namespace 111namespace
86{ 112{
87 113
88bool validate_string_hook(const std::string& str, std::string& s) 114bool is_real_text_node(xmlNode *node)
89{ 115{
90 s = str; 116 for(xmlNode *sub = node->children; sub; sub = sub->next)
117 if(sub->type != XML_TEXT_NODE && sub->type != XML_ENTITY_REF_NODE)
118 return false;
91 return true; 119 return true;
92} 120}
93 121
94bool validate_sct_hook(const std::string& str, soc_reg_flags_t& flags) 122std::string xml_loc(xmlNode *node)
95{ 123{
96 if(str == "yes") flags |= REG_HAS_SCT; 124 std::ostringstream oss;
97 else if(str != "no") return false; 125 oss << "line " << node->line;
98 return true; 126 return oss.str();
99} 127}
100 128
101bool validate_unsigned_long_hook(const std::string& str, unsigned long& s) 129std::string xml_loc(xmlAttr *attr)
102{ 130{
103 char *end; 131 return xml_loc(attr->parent);
104 s = strtoul(str.c_str(), &end, 0);
105 return *end == 0;
106} 132}
107 133
108bool validate_uint32_hook(const std::string& str, uint32_t& s) 134template<typename T>
135bool add_error(error_context_t& ctx, error_t::level_t lvl, T *node,
136 const std::string& msg)
109{ 137{
110 unsigned long u; 138 ctx.add(error_t(lvl, xml_loc(node), msg));
111 if(!validate_unsigned_long_hook(str, u)) return false; 139 return false;
112#if ULONG_MAX > 0xffffffff
113 if(u > 0xffffffff) return false;
114#endif
115 s = u;
116 return true;
117} 140}
118 141
119bool validate_bitrange_hook(const std::string& str, unsigned& first, unsigned& last) 142template<typename T>
143bool add_fatal(error_context_t& ctx, T *node, const std::string& msg)
120{ 144{
121 unsigned long a, b; 145 return add_error(ctx, error_t::FATAL, node, msg);
122 size_t sep = str.find(':');
123 if(sep == std::string::npos) return false;
124 if(!validate_unsigned_long_hook(str.substr(0, sep), a)) return false;
125 if(!validate_unsigned_long_hook(str.substr(sep + 1), b)) return false;
126 if(a > 31 || b > 31 || a < b) return false;
127 first = b;
128 last = a;
129 return true;
130} 146}
131 147
132bool parse_text_attr(xmlAttr *attr, std::string& s) 148template<typename T>
149bool add_warning(error_context_t& ctx, T *node, const std::string& msg)
133{ 150{
134 if(attr->children != attr->last) 151 return add_error(ctx, error_t::WARNING, node, msg);
135 return false;
136 if(attr->children->type != XML_TEXT_NODE)
137 return false;
138 s = XML_CHAR_TO_CHAR(attr->children->content);
139 return true;
140} 152}
141 153
142bool parse_value_elem(xmlNode *node, soc_reg_field_value_t& value) 154bool parse_wrong_version_error(xmlNode *node, error_context_t& ctx)
143{ 155{
144 BEGIN_ATTR_MATCH(node->properties) 156 std::ostringstream oss;
145 MATCH_TEXT_ATTR("name", value.name) 157 oss << "unknown version, only version " << MAJOR_VERSION << " is supported";
146 MATCH_UINT32_ATTR("value", value.value) 158 return add_fatal(ctx, node, oss.str());
147 MATCH_TEXT_ATTR("desc", value.desc) 159}
148 END_ATTR_MATCH()
149 160
150 return true; 161bool parse_not_unique_error(xmlNode *node, error_context_t& ctx)
162{
163 std::ostringstream oss;
164 oss << "there must be a unique <" << XML_CHAR_TO_CHAR(node->name) << "> element";
165 if(node->parent->name)
166 oss << " in <" << XML_CHAR_TO_CHAR(node->parent->name) << ">";
167 else
168 oss << " at root level";
169 return add_fatal(ctx, node, oss.str());
151} 170}
152 171
153bool parse_field_elem(xmlNode *node, soc_reg_field_t& field) 172bool parse_not_unique_attr_error(xmlAttr *attr, error_context_t& ctx)
154{ 173{
155 BEGIN_ATTR_MATCH(node->properties) 174 std::ostringstream oss;
156 MATCH_TEXT_ATTR("name", field.name) 175 oss << "there must be a unique " << XML_CHAR_TO_CHAR(attr->name) << " attribute";
157 MATCH_BITRANGE_ATTR("bitrange", field.first_bit, field.last_bit) 176 oss << " in <" << XML_CHAR_TO_CHAR(attr->parent->name) << ">";
158 MATCH_TEXT_ATTR("desc", field.desc) 177 return add_fatal(ctx, attr, oss.str());
159 END_ATTR_MATCH() 178}
160 179
161 BEGIN_NODE_MATCH(node->children) 180bool parse_missing_error(xmlNode *node, const char *name, error_context_t& ctx)
162 SOFT_MATCH_ELEM_NODE("value", field.value, parse_value_elem) 181{
163 END_NODE_MATCH() 182 std::ostringstream oss;
183 oss << "missing <" << name << "> element";
184 if(node->parent->name)
185 oss << " in <" << XML_CHAR_TO_CHAR(node->parent->name) << ">";
186 else
187 oss << " at root level";
188 return add_fatal(ctx, node, oss.str());
189}
164 190
165 return true; 191bool parse_missing_attr_error(xmlNode *node, const char *name, error_context_t& ctx)
192{
193 std::ostringstream oss;
194 oss << "missing " << name << " attribute";
195 oss << " in <" << XML_CHAR_TO_CHAR(node->name) << ">";
196 return add_fatal(ctx, node, oss.str());
166} 197}
167 198
168bool parse_reg_addr_elem(xmlNode *node, soc_reg_addr_t& addr) 199bool parse_conflict_error(xmlNode *node, const char *name1, const char *name2,
200 error_context_t& ctx)
169{ 201{
170 BEGIN_ATTR_MATCH(node->properties) 202 std::ostringstream oss;
171 MATCH_TEXT_ATTR("name", addr.name) 203 oss << "conflicting <" << name1 << "> and <" << name2 << "> elements";
172 MATCH_UINT32_ATTR("addr", addr.addr) 204 if(node->parent->name)
173 END_ATTR_MATCH() 205 oss << " in <" << XML_CHAR_TO_CHAR(node->parent->name) << ">";
206 else
207 oss << " at root level";
208 return add_fatal(ctx, node, oss.str());
209}
174 210
175 return true; 211bool parse_not_text_error(xmlNode *node, error_context_t& ctx)
212{
213 return add_fatal(ctx, node, "this is not a text element");
176} 214}
177 215
178bool parse_reg_formula_elem(xmlNode *node, soc_reg_formula_t& formula) 216bool parse_not_text_attr_error(xmlAttr *attr, error_context_t& ctx)
179{ 217{
180 BEGIN_ATTR_MATCH(node->properties) 218 return add_fatal(ctx, attr, "this is not a text attribute");
181 MATCH_TEXT_ATTR("string", formula.string) 219}
182 END_ATTR_MATCH()
183 220
184 formula.type = REG_FORMULA_STRING; 221bool parse_text_elem(xmlNode *node, std::string& name, xmlChar *content, error_context_t& ctx)
222{
223 name = XML_CHAR_TO_CHAR(content);
224 return true;
225}
185 226
227bool parse_name_elem(xmlNode *node, std::string& name, xmlChar *content, error_context_t& ctx)
228{
229 name = XML_CHAR_TO_CHAR(content);
230 if(name.size() == 0)
231 return add_fatal(ctx, node, "name cannot be empty");
232 for(size_t i = 0; i < name.size(); i++)
233 if(!isalnum(name[i]) && name[i] != '_')
234 return add_fatal(ctx, node, "name must only contain alphanumeric characters or _");
186 return true; 235 return true;
187} 236}
188 237
189bool parse_add_trivial_addr(const std::string& str, soc_reg_t& reg) 238template<typename T, typename U>
239bool parse_unsigned_text(U *node, T& res, xmlChar *content, error_context_t& ctx)
190{ 240{
191 soc_reg_addr_t a; 241 char *end;
192 a.name = reg.name; 242 unsigned long uns = strtoul(XML_CHAR_TO_CHAR(content), &end, 0);
193 if(!validate_uint32_hook(str, a.addr)) 243 if(*end != 0)
194 return false; 244 return add_fatal(ctx, node, "content must be an unsigned integer");
195 reg.addr.push_back(a); 245 res = uns;
246 if(res != uns)
247 return add_fatal(ctx, node, "value does not fit into allowed range");
196 return true; 248 return true;
197} 249}
198 250
199bool parse_reg_elem(xmlNode *node, soc_reg_t& reg) 251template<typename T>
252bool parse_unsigned_elem(xmlNode *node, T& res, xmlChar *content, error_context_t& ctx)
200{ 253{
201 std::list< soc_reg_formula_t > formulas; 254 return parse_unsigned_text(node, res, content, ctx);
202 BEGIN_ATTR_MATCH(node->properties) 255}
203 MATCH_TEXT_ATTR("name", reg.name)
204 SOFT_MATCH_SCT_ATTR("sct", reg.flags)
205 SOFT_MATCH_X_ATTR("addr", parse_add_trivial_addr, reg)
206 MATCH_TEXT_ATTR("desc", reg.desc)
207 END_ATTR_MATCH()
208 256
209 BEGIN_NODE_MATCH(node->children) 257template<typename T>
210 MATCH_ELEM_NODE("addr", reg.addr, parse_reg_addr_elem) 258bool parse_unsigned_attr(xmlAttr *attr, T& res, xmlChar *content, error_context_t& ctx)
211 MATCH_ELEM_NODE("formula", formulas, parse_reg_formula_elem) 259{
212 MATCH_ELEM_NODE("field", reg.field, parse_field_elem) 260 return parse_unsigned_text(attr, res, content, ctx);
213 END_NODE_MATCH() 261}
214 262
215 if(formulas.size() > 1) 263bool parse_text_attr_internal(xmlAttr *attr, xmlChar*& res, error_context_t& ctx)
216 { 264{
217 fprintf(stderr, "Only one formula is allowed per register\n"); 265 if(attr->children != attr->last)
218 return false; 266 return false;
219 } 267 if(attr->children->type != XML_TEXT_NODE)
220 if(formulas.size() == 1) 268 return parse_not_text_attr_error(attr, ctx);
221 reg.formula = formulas.front(); 269 res = attr->children->content;
222
223 return true; 270 return true;
224} 271}
225 272
226bool parse_dev_addr_elem(xmlNode *node, soc_dev_addr_t& addr) 273bool parse_text_attr(xmlAttr *attr, std::string& res, xmlChar *content, error_context_t& ctx)
227{ 274{
228 BEGIN_ATTR_MATCH(node->properties) 275 res = XML_CHAR_TO_CHAR(content);
229 MATCH_TEXT_ATTR("name", addr.name)
230 MATCH_UINT32_ATTR("addr", addr.addr)
231 END_ATTR_MATCH()
232
233 return true; 276 return true;
234} 277}
235 278
236bool parse_dev_elem(xmlNode *node, soc_dev_t& dev) 279bool parse_enum_elem(xmlNode *node, enum_t& reg, error_context_t& ctx)
237{ 280{
238 BEGIN_ATTR_MATCH(node->properties) 281 bool ret = true;
239 MATCH_TEXT_ATTR("name", dev.name) 282 bool has_name = false, has_value = false, has_desc = false;
240 MATCH_TEXT_ATTR("long_name", dev.long_name) 283 BEGIN_NODE_MATCH(node->children)
241 MATCH_TEXT_ATTR("desc", dev.desc) 284 MATCH_UNIQUE_TEXT_NODE("name", reg.name, has_name, parse_name_elem, ctx)
242 MATCH_TEXT_ATTR("version", dev.version) 285 MATCH_UNIQUE_TEXT_NODE("value", reg.value, has_value, parse_unsigned_elem, ctx)
243 END_ATTR_MATCH() 286 MATCH_UNIQUE_TEXT_NODE("desc", reg.desc, has_desc, parse_text_elem, ctx)
287 END_NODE_MATCH()
288 CHECK_HAS(node, "name", has_name, ctx)
289 CHECK_HAS(node, "value", has_value, ctx)
290 return ret;
291}
244 292
293bool parse_field_elem(xmlNode *node, field_t& field, error_context_t& ctx)
294{
295 bool ret = true;
296 bool has_name = false, has_pos = false, has_desc = false, has_width = false;
245 BEGIN_NODE_MATCH(node->children) 297 BEGIN_NODE_MATCH(node->children)
246 MATCH_ELEM_NODE("addr", dev.addr, parse_dev_addr_elem) 298 MATCH_UNIQUE_TEXT_NODE("name", field.name, has_name, parse_name_elem, ctx)
247 MATCH_ELEM_NODE("reg", dev.reg, parse_reg_elem) 299 MATCH_UNIQUE_TEXT_NODE("position", field.pos, has_pos, parse_unsigned_elem, ctx)
300 MATCH_UNIQUE_TEXT_NODE("width", field.width, has_width, parse_unsigned_elem, ctx)
301 MATCH_UNIQUE_TEXT_NODE("desc", field.desc, has_desc, parse_text_elem, ctx)
302 MATCH_ELEM_NODE("enum", field.enum_, parse_enum_elem, ctx)
248 END_NODE_MATCH() 303 END_NODE_MATCH()
304 CHECK_HAS(node, "name", has_name, ctx)
305 CHECK_HAS(node, "position", has_pos, ctx)
306 if(!has_width)
307 field.width = 1;
308 return ret;
309}
249 310
250 return true; 311bool parse_register_elem(xmlNode *node, register_t& reg, error_context_t& ctx)
312{
313 bool ret = true;
314 bool has_width = false;
315 BEGIN_NODE_MATCH(node->children)
316 MATCH_UNIQUE_TEXT_NODE("width", reg.width, has_width, parse_unsigned_elem, ctx)
317 MATCH_ELEM_NODE("field", reg.field, parse_field_elem, ctx)
318 END_NODE_MATCH()
319 if(!has_width)
320 reg.width = 32;
321 return ret;
251} 322}
252 323
253bool parse_soc_elem(xmlNode *node, soc_t& soc) 324bool parse_formula_elem(xmlNode *node, range_t& range, error_context_t& ctx)
254{ 325{
326 bool ret = true;
327 bool has_var = false;
255 BEGIN_ATTR_MATCH(node->properties) 328 BEGIN_ATTR_MATCH(node->properties)
256 MATCH_TEXT_ATTR("name", soc.name) 329 MATCH_UNIQUE_ATTR("variable", range.variable, has_var, parse_text_attr, ctx)
257 MATCH_TEXT_ATTR("desc", soc.desc) 330 END_NODE_MATCH()
258 END_ATTR_MATCH() 331 CHECK_HAS_ATTR(node, "variable", has_var, ctx)
332 return ret;
333}
259 334
335bool parse_range_elem(xmlNode *node, range_t& range, error_context_t& ctx)
336{
337 bool ret = true;
338 bool has_first = false, has_count = false, has_stride = false, has_base = false;
339 bool has_formula = false, has_formula_attr = false;
260 BEGIN_NODE_MATCH(node->children) 340 BEGIN_NODE_MATCH(node->children)
261 MATCH_ELEM_NODE("dev", soc.dev, parse_dev_elem) 341 MATCH_UNIQUE_TEXT_NODE("first", range.first, has_first, parse_unsigned_elem, ctx)
342 MATCH_UNIQUE_TEXT_NODE("count", range.count, has_count, parse_unsigned_elem, ctx)
343 MATCH_UNIQUE_TEXT_NODE("base", range.base, has_base, parse_unsigned_elem, ctx)
344 MATCH_UNIQUE_TEXT_NODE("stride", range.stride, has_stride, parse_unsigned_elem, ctx)
345 MATCH_UNIQUE_ELEM_NODE("formula", range, has_formula_attr, parse_formula_elem, ctx)
346 MATCH_UNIQUE_TEXT_NODE("formula", range.formula, has_formula, parse_text_elem, ctx)
262 END_NODE_MATCH() 347 END_NODE_MATCH()
348 CHECK_HAS(node, "first", has_first, ctx)
349 CHECK_HAS(node, "count", has_count, ctx)
350 if(!has_base && !has_formula)
351 ret = ret && parse_missing_error(node, "base> or <formula", ctx);
352 if(has_base && has_formula)
353 return parse_conflict_error(node, "base", "formula", ctx);
354 if(has_base)
355 CHECK_HAS(node, "stride", has_stride, ctx)
356 if(has_stride && !has_base)
357 ret = ret && parse_conflict_error(node, "stride", "formula", ctx);
358 if(has_stride)
359 range.type = range_t::STRIDE;
360 else
361 range.type = range_t::FORMULA;
362 return ret;
363}
263 364
264 return true; 365bool parse_instance_elem(xmlNode *node, instance_t& inst, error_context_t& ctx)
366{
367 bool ret = true;
368 bool has_name = false, has_title = false, has_desc = false, has_range = false;
369 bool has_address = false;
370 BEGIN_NODE_MATCH(node->children)
371 MATCH_UNIQUE_TEXT_NODE("name", inst.name, has_name, parse_name_elem, ctx)
372 MATCH_UNIQUE_TEXT_NODE("title", inst.title, has_title, parse_text_elem, ctx)
373 MATCH_UNIQUE_TEXT_NODE("desc", inst.desc, has_desc, parse_text_elem, ctx)
374 MATCH_UNIQUE_TEXT_NODE("address", inst.addr, has_address, parse_unsigned_elem, ctx)
375 MATCH_UNIQUE_ELEM_NODE("range", inst.range, has_range, parse_range_elem, ctx)
376 END_NODE_MATCH()
377 CHECK_HAS(node, "name", has_name, ctx)
378 if(!has_address && !has_range)
379 ret = ret && parse_missing_error(node, "address> or <range", ctx);
380 if(has_address && has_range)
381 ret = ret && parse_conflict_error(node, "address", "range", ctx);
382 if(has_address)
383 inst.type = instance_t::SINGLE;
384 else
385 inst.type = instance_t::RANGE;
386 return ret;
265} 387}
266 388
267bool parse_root_elem(xmlNode *node, soc_t& soc) 389bool parse_node_elem(xmlNode *node_, node_t& node, error_context_t& ctx)
268{ 390{
269 std::vector< soc_t > socs; 391 bool ret = true;
270 BEGIN_NODE_MATCH(node) 392 register_t reg;
271 MATCH_ELEM_NODE("soc", socs, parse_soc_elem) 393 bool has_title = false, has_desc = false, has_register = false, has_name = false;
394 BEGIN_NODE_MATCH(node_->children)
395 MATCH_UNIQUE_TEXT_NODE("name", node.name, has_name, parse_name_elem, ctx)
396 MATCH_UNIQUE_TEXT_NODE("title", node.title, has_title, parse_text_elem, ctx)
397 MATCH_UNIQUE_TEXT_NODE("desc", node.desc, has_desc, parse_text_elem, ctx)
398 MATCH_UNIQUE_ELEM_NODE("register", reg, has_register, parse_register_elem, ctx)
399 MATCH_ELEM_NODE("node", node.node, parse_node_elem, ctx)
400 MATCH_ELEM_NODE("instance", node.instance, parse_instance_elem, ctx)
272 END_NODE_MATCH() 401 END_NODE_MATCH()
273 if(socs.size() != 1) 402 CHECK_HAS(node_, "name", has_name, ctx)
403 CHECK_HAS(node_, "instance", !node.instance.empty(), ctx)
404 if(has_register)
405 node.register_.push_back(reg);
406 return ret;
407}
408
409bool parse_soc_elem(xmlNode *node, soc_t& soc, error_context_t& ctx)
410{
411 bool ret = true;
412 bool has_name = false, has_title = false, has_desc = false, has_version = false;
413 bool has_isa = false;
414 BEGIN_NODE_MATCH(node->children)
415 MATCH_UNIQUE_TEXT_NODE("name", soc.name, has_name, parse_name_elem, ctx)
416 MATCH_UNIQUE_TEXT_NODE("title", soc.title, has_title, parse_text_elem, ctx)
417 MATCH_UNIQUE_TEXT_NODE("desc", soc.desc, has_desc, parse_text_elem, ctx)
418 MATCH_UNIQUE_TEXT_NODE("version", soc.version, has_version, parse_text_elem, ctx)
419 MATCH_UNIQUE_TEXT_NODE("isa", soc.isa, has_isa, parse_text_elem, ctx)
420 MATCH_TEXT_NODE("author", soc.author, parse_text_elem, ctx)
421 MATCH_ELEM_NODE("node", soc.node, parse_node_elem, ctx)
422 END_NODE_MATCH()
423 CHECK_HAS(node, "name", has_name, ctx)
424 return ret;
425}
426
427bool parse_root_elem(xmlNode *node, soc_t& soc, error_context_t& ctx)
428{
429 size_t ver = 0;
430 bool ret = true;
431 bool has_soc = false, has_version = false;
432 BEGIN_ATTR_MATCH(node->properties)
433 MATCH_UNIQUE_ATTR("version", ver, has_version, parse_unsigned_attr, ctx)
434 END_ATTR_MATCH()
435 if(!has_version)
274 { 436 {
275 fprintf(stderr, "A description file must contain exactly one soc element\n"); 437 ctx.add(error_t(error_t::FATAL, xml_loc(node), "no version attribute, is this a v1 file ?"));
276 return false; 438 return false;
277 } 439 }
278 soc = socs[0]; 440 if(ver != MAJOR_VERSION)
279 return true; 441 return parse_wrong_version_error(node, ctx);
442 BEGIN_NODE_MATCH(node)
443 MATCH_UNIQUE_ELEM_NODE("soc", soc, has_soc, parse_soc_elem, ctx)
444 END_NODE_MATCH()
445 CHECK_HAS(node, "soc", has_soc, ctx)
446 return ret;
280} 447}
281 448
282} 449}
283 450
284bool soc_desc_parse_xml(const std::string& filename, soc_t& socs) 451bool parse_xml(const std::string& filename, soc_t& soc,
452 error_context_t& error_ctx)
285{ 453{
286 LIBXML_TEST_VERSION 454 LIBXML_TEST_VERSION
287 455
@@ -290,156 +458,207 @@ bool soc_desc_parse_xml(const std::string& filename, soc_t& socs)
290 return false; 458 return false;
291 459
292 xmlNodePtr root_element = xmlDocGetRootElement(doc); 460 xmlNodePtr root_element = xmlDocGetRootElement(doc);
293 bool ret = parse_root_elem(root_element, socs); 461 bool ret = parse_root_elem(root_element, soc, error_ctx);
294 462
295 xmlFreeDoc(doc); 463 xmlFreeDoc(doc);
296 464
297 return ret; 465 return ret;
298} 466}
299 467
468/**
469 * Producer
470 */
471
300namespace 472namespace
301{ 473{
302 474
303int produce_field(xmlTextWriterPtr writer, const soc_reg_field_t& field) 475#define SAFE(x) \
476 do{ \
477 if((x) < 0) { \
478 std::ostringstream oss; \
479 oss << __FILE__ << ":" << __LINE__; \
480 ctx.add(error_t(error_t::FATAL, oss.str(), "write error")); \
481 return -1; \
482 } \
483 }while(0)
484
485int produce_range(xmlTextWriterPtr writer, const range_t& range, error_context_t& ctx)
304{ 486{
305#define SAFE(x) if((x) < 0) return -1; 487 /* <range> */
306 /* <field> */ 488 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "range"));
307 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "field")); 489 /* <first/> */
308 /* name */ 490 SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "first", "%lu", range.first));
309 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST field.name.c_str())); 491 /* <count/> */
310 /* desc */ 492 SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "count", "%lu", range.count));
311 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "desc", BAD_CAST field.desc.c_str())); 493 /* <base/><stride/> */
312 /* bitrange */ 494 if(range.type == range_t::STRIDE)
313 SAFE(xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "bitrange", "%d:%d",
314 field.last_bit, field.first_bit));
315 /* values */
316 for(size_t i = 0; i < field.value.size(); i++)
317 { 495 {
318 /* <value> */ 496 SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "base", "0x%x", range.base));
319 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "value")); 497 SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "stride", "0x%x", range.stride));
320 /* name */
321 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST field.value[i].name.c_str()));
322 /* value */
323 SAFE(xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "value", "0x%x", field.value[i].value));
324 /* name */
325 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "desc", BAD_CAST field.value[i].desc.c_str()));
326 /* </value> */
327 SAFE(xmlTextWriterEndElement(writer));
328 } 498 }
329 /* </field> */ 499 /* <formula> */
330 SAFE(xmlTextWriterEndElement(writer)); 500 else if(range.type == range_t::FORMULA)
331#undef SAFE
332 return 0;
333}
334
335int produce_reg(xmlTextWriterPtr writer, const soc_reg_t& reg)
336{
337#define SAFE(x) if((x) < 0) return -1;
338 /* <reg> */
339 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "reg"));
340 /* name */
341 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST reg.name.c_str()));
342 /* name */
343 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "desc", BAD_CAST reg.desc.c_str()));
344 /* flags */
345 if(reg.flags & REG_HAS_SCT)
346 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "sct", BAD_CAST "yes"));
347 /* formula */
348 if(reg.formula.type != REG_FORMULA_NONE)
349 { 501 {
350 /* <formula> */ 502 /* <formula> */
351 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "formula")); 503 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "formula"));
352 switch(reg.formula.type) 504 /* variable */
353 { 505 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "variable", BAD_CAST range.variable.c_str()));
354 case REG_FORMULA_STRING: 506 /* content */
355 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "string", 507 SAFE(xmlTextWriterWriteString(writer, BAD_CAST range.formula.c_str()));
356 BAD_CAST reg.formula.string.c_str()));
357 break;
358 default:
359 break;
360 }
361 /* </formula> */ 508 /* </formula> */
362 SAFE(xmlTextWriterEndElement(writer)); 509 SAFE(xmlTextWriterEndElement(writer));
363 } 510 }
364 /* addresses */ 511 /* </range> */
365 for(size_t i = 0; i < reg.addr.size(); i++) 512 SAFE(xmlTextWriterEndElement(writer));
366 { 513
367 /* <addr> */ 514 return 0;
368 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "addr")); 515}
369 /* name */ 516
370 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST reg.addr[i].name.c_str())); 517int produce_instance(xmlTextWriterPtr writer, const instance_t& inst, error_context_t& ctx)
371 /* addr */ 518{
372 SAFE(xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "addr", "0x%x", reg.addr[i].addr)); 519 /* <instance> */
373 /* </addr> */ 520 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "instance"));
374 SAFE(xmlTextWriterEndElement(writer)); 521 /* <name/> */
375 } 522 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "name", BAD_CAST inst.name.c_str()));
523 /* <title/> */
524 if(!inst.title.empty())
525 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "title", BAD_CAST inst.title.c_str()));
526 /* <desc/> */
527 if(!inst.desc.empty())
528 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "desc", BAD_CAST inst.desc.c_str()));
529 /* <address/> */
530 if(inst.type == instance_t::SINGLE)
531 SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "address", "0x%x", inst.addr));
532 /* <range/> */
533 else if(inst.type == instance_t::RANGE)
534 SAFE(produce_range(writer, inst.range, ctx));
535 /* </instance> */
536 SAFE(xmlTextWriterEndElement(writer));
537 return 0;
538}
539
540int produce_enum(xmlTextWriterPtr writer, const enum_t& enum_, error_context_t& ctx)
541{
542 /* <enum> */
543 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "enum"));
544 /* <name/> */
545 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "name", BAD_CAST enum_.name.c_str()));
546 /* <desc/> */
547 if(!enum_.desc.empty())
548 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "desc", BAD_CAST enum_.desc.c_str()));
549 /* <value/> */
550 SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "value", "0x%x", enum_.value));
551 /* </enum> */
552 SAFE(xmlTextWriterEndElement(writer));
553 return 0;
554}
555
556int produce_field(xmlTextWriterPtr writer, const field_t& field, error_context_t& ctx)
557{
558 /* <field> */
559 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "field"));
560 /* <name/> */
561 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "name", BAD_CAST field.name.c_str()));
562 /* <desc/> */
563 if(!field.desc.empty())
564 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "desc", BAD_CAST field.desc.c_str()));
565 /* <position/> */
566 SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "position", "%lu", field.pos));
567 /* <width/> */
568 if(field.width != 1)
569 SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "width", "%lu", field.width));
570 /* enums */
571 for(size_t i = 0; i < field.enum_.size(); i++)
572 SAFE(produce_enum(writer, field.enum_[i], ctx));
573 /* </field> */
574 SAFE(xmlTextWriterEndElement(writer));
575 return 0;
576}
577
578int produce_register(xmlTextWriterPtr writer, const register_t& reg, error_context_t& ctx)
579{
580 /* <register> */
581 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "register"));
582 /* <width/> */
583 if(reg.width != 32)
584 SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "width", "%lu", reg.width));
376 /* fields */ 585 /* fields */
377 for(size_t i = 0; i < reg.field.size(); i++) 586 for(size_t i = 0; i < reg.field.size(); i++)
378 produce_field(writer, reg.field[i]); 587 SAFE(produce_field(writer, reg.field[i], ctx));
379 /* </reg> */ 588 /* </register> */
380 SAFE(xmlTextWriterEndElement(writer)); 589 SAFE(xmlTextWriterEndElement(writer));
381#undef SAFE
382 return 0; 590 return 0;
383} 591}
384 592
385int produce_dev(xmlTextWriterPtr writer, const soc_dev_t& dev) 593int produce_node(xmlTextWriterPtr writer, const node_t& node, error_context_t& ctx)
386{ 594{
387#define SAFE(x) if((x) < 0) return -1; 595 /* <node> */
388 /* <dev> */ 596 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "node"));
389 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "dev")); 597 /* <name/> */
390 /* name */ 598 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "name", BAD_CAST node.name.c_str()));
391 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST dev.name.c_str())); 599 /* <title/> */
392 /* long_name */ 600 if(!node.title.empty())
393 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "long_name", BAD_CAST dev.long_name.c_str())); 601 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "title", BAD_CAST node.title.c_str()));
394 /* desc */ 602 /* <desc/> */
395 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "desc", BAD_CAST dev.desc.c_str())); 603 if(!node.desc.empty())
396 /* version */ 604 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "desc", BAD_CAST node.desc.c_str()));
397 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "version", BAD_CAST dev.version.c_str())); 605 /* instances */
398 /* addresses */ 606 for(size_t i = 0; i < node.instance.size(); i++)
399 for(size_t i = 0; i < dev.addr.size(); i++) 607 SAFE(produce_instance(writer, node.instance[i], ctx));
400 { 608 /* register */
401 /* <addr> */ 609 for(size_t i = 0; i < node.register_.size(); i++)
402 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "addr")); 610 SAFE(produce_register(writer, node.register_[i], ctx));
403 /* name */ 611 /* nodes */
404 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST dev.addr[i].name.c_str())); 612 for(size_t i = 0; i < node.node.size(); i++)
405 /* addr */ 613 SAFE(produce_node(writer, node.node[i], ctx));
406 SAFE(xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "addr", "0x%x", dev.addr[i].addr)); 614 /* </node> */
407 /* </addr> */
408 SAFE(xmlTextWriterEndElement(writer));
409 }
410 /* registers */
411 for(size_t i = 0; i < dev.reg.size(); i++)
412 produce_reg(writer, dev.reg[i]);
413 /* </dev> */
414 SAFE(xmlTextWriterEndElement(writer)); 615 SAFE(xmlTextWriterEndElement(writer));
415#undef SAFE
416 return 0; 616 return 0;
417} 617}
418 618
619#undef SAFE
620
419} 621}
420 622
421bool soc_desc_produce_xml(const std::string& filename, const soc_t& soc) 623bool produce_xml(const std::string& filename, const soc_t& soc, error_context_t& ctx)
422{ 624{
423 LIBXML_TEST_VERSION 625 LIBXML_TEST_VERSION
424 626
627 std::ostringstream oss;
425 xmlTextWriterPtr writer = xmlNewTextWriterFilename(filename.c_str(), 0); 628 xmlTextWriterPtr writer = xmlNewTextWriterFilename(filename.c_str(), 0);
426 if(writer == NULL) 629 if(writer == NULL)
427 return false; 630 return false;
428#define SAFE(x) if((x) < 0) goto Lerr 631#define SAFE(x) do{if((x) < 0) goto Lerr;}while(0)
429 SAFE(xmlTextWriterSetIndent(writer, 1)); 632 SAFE(xmlTextWriterSetIndent(writer, 1));
430 SAFE(xmlTextWriterSetIndentString(writer, BAD_CAST " ")); 633 SAFE(xmlTextWriterSetIndentString(writer, BAD_CAST " "));
431 /* <xml> */ 634 /* <xml> */
432 SAFE(xmlTextWriterStartDocument(writer, NULL, NULL, NULL)); 635 SAFE(xmlTextWriterStartDocument(writer, NULL, NULL, NULL));
433 /* <soc> */ 636 /* <soc> */
434 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "soc")); 637 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "soc"));
435 /* name */ 638 /* version */
436 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST soc.name.c_str())); 639 oss << MAJOR_VERSION;
437 /* desc */ 640 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "version", BAD_CAST oss.str().c_str()));
438 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "desc", BAD_CAST soc.desc.c_str())); 641 /* <name/> */
439 /* devices */ 642 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "name", BAD_CAST soc.name.c_str()));
440 for(size_t i = 0; i < soc.dev.size(); i++) 643 /* <title/> */
441 SAFE(produce_dev(writer, soc.dev[i])); 644 if(!soc.title.empty())
442 /* end <soc> */ 645 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "title", BAD_CAST soc.title.c_str()));
646 /* <desc/> */
647 if(!soc.desc.empty())
648 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "desc", BAD_CAST soc.desc.c_str()));
649 /* <author/> */
650 for(size_t i = 0; i < soc.author.size(); i++)
651 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "author", BAD_CAST soc.author[i].c_str()));
652 /* <isa/> */
653 if(!soc.isa.empty())
654 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "isa", BAD_CAST soc.isa.c_str()));
655 /* <version/> */
656 if(!soc.version.empty())
657 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "version", BAD_CAST soc.version.c_str()));
658 /* nodes */
659 for(size_t i = 0; i < soc.node.size(); i++)
660 SAFE(produce_node(writer, soc.node[i], ctx));
661 /* </soc> */
443 SAFE(xmlTextWriterEndElement(writer)); 662 SAFE(xmlTextWriterEndElement(writer));
444 /* </xml> */ 663 /* </xml> */
445 SAFE(xmlTextWriterEndDocument(writer)); 664 SAFE(xmlTextWriterEndDocument(writer));
@@ -451,520 +670,500 @@ Lerr:
451 return false; 670 return false;
452} 671}
453 672
454namespace 673/**
674 * soc_ref_t
675 */
676
677soc_ref_t::soc_ref_t():m_soc(0)
455{ 678{
679}
456 680
457struct soc_sorter 681soc_ref_t::soc_ref_t(soc_t *soc):m_soc(soc)
458{ 682{
459 bool operator()(const soc_dev_t& a, const soc_dev_t& b) const 683}
460 {
461 return a.name < b.name;
462 }
463 684
464 bool operator()(const soc_dev_addr_t& a, const soc_dev_addr_t& b) const 685bool soc_ref_t::valid() const
465 { 686{
466 return a.name < b.name; 687 return get() != 0;
467 } 688}
468 689
469 bool operator()(const soc_reg_t& a, const soc_reg_t& b) const 690soc_t *soc_ref_t::get() const
470 { 691{
471 soc_addr_t aa = a.addr.size() > 0 ? a.addr[0].addr : 0; 692 return m_soc;
472 soc_addr_t ab = b.addr.size() > 0 ? b.addr[0].addr : 0; 693}
473 return aa < ab;
474 }
475 694
476 bool operator()(const soc_reg_addr_t& a, const soc_reg_addr_t& b) const 695bool soc_ref_t::operator==(const soc_ref_t& ref) const
477 { 696{
478 return a.addr < b.addr; 697 return m_soc == ref.m_soc;
479 } 698}
480 699
481 bool operator()(const soc_reg_field_t& a, const soc_reg_field_t& b) const 700node_ref_t soc_ref_t::root() const
482 { 701{
483 return a.last_bit > b.last_bit; 702 return node_ref_t(*this);
484 } 703}
485 704
486 bool operator()(const soc_reg_field_value_t a, const soc_reg_field_value_t& b) const 705node_inst_t soc_ref_t::root_inst() const
487 { 706{
488 return a.value < b.value; 707 return node_inst_t(*this);
489 } 708}
490};
491 709
492void normalize(soc_reg_field_t& field) 710/**
711 * node_ref_t */
712
713node_ref_t::node_ref_t(soc_ref_t soc):m_soc(soc)
493{ 714{
494 std::sort(field.value.begin(), field.value.end(), soc_sorter());
495} 715}
496 716
497void normalize(soc_reg_t& reg) 717node_ref_t::node_ref_t(soc_ref_t soc, const std::vector< soc_id_t >& path)
718 :m_soc(soc), m_path(path)
498{ 719{
499 std::sort(reg.addr.begin(), reg.addr.end(), soc_sorter());
500 std::sort(reg.field.begin(), reg.field.end(), soc_sorter());
501 for(size_t i = 0; i < reg.field.size(); i++)
502 normalize(reg.field[i]);
503} 720}
504 721
505void normalize(soc_dev_t& dev) 722node_ref_t::node_ref_t()
506{ 723{
507 std::sort(dev.addr.begin(), dev.addr.end(), soc_sorter());
508 std::sort(dev.reg.begin(), dev.reg.end(), soc_sorter());
509 for(size_t i = 0; i < dev.reg.size(); i++)
510 normalize(dev.reg[i]);
511} 724}
512 725
726bool node_ref_t::valid() const
727{
728 return (m_soc.valid() && is_root()) || get() != 0;
513} 729}
514 730
515void soc_desc_normalize(soc_t& soc) 731bool node_ref_t::is_root() const
516{ 732{
517 std::sort(soc.dev.begin(), soc.dev.end(), soc_sorter()); 733 return m_path.empty();
518 for(size_t i = 0; i < soc.dev.size(); i++)
519 normalize(soc.dev[i]);
520} 734}
521 735
522namespace 736namespace
523{ 737{
524 soc_error_t make_error(soc_error_level_t lvl, std::string at, std::string what)
525 {
526 soc_error_t err;
527 err.level = lvl;
528 err.location = at;
529 err.message = what;
530 return err;
531 }
532 738
533 soc_error_t make_warning(std::string at, std::string what) 739std::vector< node_t > *get_children(node_ref_t node)
534 { 740{
535 return make_error(SOC_ERROR_WARNING, at, what); 741 if(node.is_root())
536 } 742 return &node.soc().get()->node;
537 743 node_t *n = node.get();
538 soc_error_t make_fatal(std::string at, std::string what) 744 return n == 0 ? 0 : &n->node;
539 { 745}
540 return make_error(SOC_ERROR_FATAL, at, what);
541 }
542 746
543 soc_error_t prefix(soc_error_t err, const std::string& prefix_at) 747node_t *get_child(std::vector< node_t > *nodes, soc_id_t id)
544 { 748{
545 err.location = prefix_at + "." + err.location; 749 if(nodes == 0)
546 return err; 750 return 0;
547 } 751 for(size_t i = 0; i < nodes->size(); i++)
752 if((*nodes)[i].id == id)
753 return &(*nodes)[i];
754 return 0;
755}
548 756
549 void add_errors(std::vector< soc_error_t >& errors, 757node_t *get_child(std::vector< node_t > *nodes, const std::string& name)
550 const std::vector< soc_error_t >& new_errors, const std::string& prefix_at) 758{
551 { 759 if(nodes == 0)
552 for(size_t i = 0; i < new_errors.size(); i++) 760 return 0;
553 errors.push_back(prefix(new_errors[i], prefix_at)); 761 for(size_t i = 0; i < nodes->size(); i++)
554 } 762 if((*nodes)[i].name == name)
763 return &(*nodes)[i];
764 return 0;
765}
555 766
556 std::vector< soc_error_t > no_error() 767}
557 {
558 std::vector< soc_error_t > s;
559 return s;
560 }
561 768
562 std::vector< soc_error_t > one_error(const soc_error_t& err) 769/* NOTE: valid() is implemented using get() != 0, so don't use it in get() ! */
770node_t *node_ref_t::get() const
771{
772 if(!soc().valid())
773 return 0;
774 /* we could do it recursively but it would make plenty of copies */
775 node_t *n = 0;
776 std::vector< node_t > *nodes = &soc().get()->node;
777 for(size_t i = 0; i < m_path.size(); i++)
563 { 778 {
564 std::vector< soc_error_t > s; 779 n = get_child(nodes, m_path[i]);
565 s.push_back(err); 780 if(n == 0)
566 return s; 781 return 0;
782 nodes = &n->node;
567 } 783 }
784 return n;
785}
568 786
569 bool name_valid(char c) 787soc_ref_t node_ref_t::soc() const
570 { 788{
571 return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || 789 return m_soc;
572 (c >= 'A' && c <= 'Z') || c == '_'; 790}
573 }
574 791
575 bool name_valid(const std::string& s) 792node_ref_t node_ref_t::parent() const
576 { 793{
577 for(size_t i = 0; i < s.size(); i++) 794 std::vector< soc_id_t > path = m_path;
578 if(!name_valid(s[i])) 795 if(!path.empty())
579 return false; 796 path.pop_back();
580 return true; 797 return node_ref_t(m_soc, path);
581 }
582} 798}
583 799
584std::vector< soc_error_t > soc_reg_field_value_t::errors(bool recursive) 800register_ref_t node_ref_t::reg() const
585{ 801{
586 (void) recursive; 802 node_t *n = get();
587 if(name.size() == 0) 803 if(n == 0)
588 return one_error(make_fatal(name, "empty name")); 804 return register_ref_t();
589 else if(!name_valid(name)) 805 if(n->register_.empty())
590 return one_error(make_fatal(name, "invalid name")); 806 return parent().reg();
591 else 807 else
592 return no_error(); 808 return register_ref_t(*this);
593} 809}
594 810
595std::vector< soc_error_t > soc_reg_field_t::errors(bool recursive) 811node_ref_t node_ref_t::child(const std::string& name) const
596{ 812{
597 std::vector< soc_error_t > err; 813 /* check the node exists */
598 std::string at(name); 814 node_t *n = get_child(get_children(*this), name);
599 if(name.size() == 0) 815 if(n == 0)
600 err.push_back(make_fatal(at, "empty name")); 816 return node_ref_t();
601 else if(!name_valid(name)) 817 std::vector< soc_id_t > path = m_path;
602 err.push_back(make_fatal(at, "invalid name")); 818 path.push_back(n->id);
603 if(last_bit > 31) 819 return node_ref_t(m_soc, path);
604 err.push_back(make_fatal(at, "last bit is greater than 31")); 820}
605 if(first_bit > last_bit) 821
606 err.push_back(make_fatal(at, "last bit is greater than first bit")); 822std::vector< node_ref_t > node_ref_t::children() const
607 for(size_t i = 0; i < value.size(); i++) 823{
824 std::vector< node_ref_t > nodes;
825 std::vector< node_t > *children = get_children(*this);
826 if(children == 0)
827 return nodes;
828 for(size_t i = 0; i < children->size(); i++)
608 { 829 {
609 for(size_t j = 0; j < value.size(); j++) 830 std::vector< soc_id_t > path = m_path;
831 path.push_back((*children)[i].id);
832 nodes.push_back(node_ref_t(m_soc, path));
833 }
834 return nodes;
835}
836
837std::vector< std::string > node_ref_t::path() const
838{
839 std::vector< std::string > path;
840 if(!soc().valid())
841 return path;
842 /* we could do it recursively but this is more efficient */
843 node_t *n = 0;
844 std::vector< node_t > *nodes = &soc().get()->node;
845 for(size_t i = 0; i < m_path.size(); i++)
846 {
847 n = get_child(nodes, m_path[i]);
848 if(n == 0)
610 { 849 {
611 if(i == j) 850 path.clear();
612 continue; 851 return path;
613 if(value[i].name == value[j].name)
614 err.push_back(prefix(make_fatal(value[i].name,
615 "there are several values with the same name"), at));
616 if(value[i].value == value[j].value)
617 err.push_back(prefix(make_warning(value[i].name,
618 "there are several values with the same value"), at));
619 } 852 }
620 if(value[i].value > (bitmask() >> first_bit)) 853 path.push_back(n->name);
621 err.push_back(prefix(make_warning(at, "value doesn't fit into the field"), value[i].name)); 854 nodes = &n->node;
622 if(recursive)
623 add_errors(err, value[i].errors(true), at);
624 } 855 }
625 return err; 856 return path;
626} 857}
627 858
628std::vector< soc_error_t > soc_reg_addr_t::errors(bool recursive) 859std::string node_ref_t::name() const
629{ 860{
630 (void) recursive; 861 node_t *n = get();
631 if(name.size() == 0) 862 return n == 0 ? "" : n->name;
632 return one_error(make_fatal("", "empty name"));
633 else if(!name_valid(name))
634 return one_error(make_fatal(name, "invalid name"));
635 else
636 return no_error();
637} 863}
638 864
639std::vector< soc_error_t > soc_reg_formula_t::errors(bool recursive) 865bool node_ref_t::operator==(const node_ref_t& ref) const
640{ 866{
641 (void) recursive; 867 return m_soc == ref.m_soc && m_path == ref.m_path;
642 if(type == REG_FORMULA_STRING && string.size() == 0)
643 return one_error(make_fatal("", "empty string formula"));
644 else
645 return no_error();
646} 868}
647 869
648namespace 870/**
871 * register_ref_t
872 */
873
874register_ref_t::register_ref_t(node_ref_t node)
875 :m_node(node)
649{ 876{
877}
650 878
651bool field_overlap(const soc_reg_field_t& a, const soc_reg_field_t& b) 879register_ref_t::register_ref_t()
652{ 880{
653 return !(a.first_bit > b.last_bit || b.first_bit > a.last_bit);
654} 881}
655 882
883bool register_ref_t::valid() const
884{
885 return get() != 0;
656} 886}
657 887
658std::vector< soc_error_t > soc_reg_t::errors(bool recursive) 888register_t *register_ref_t::get() const
659{ 889{
660 std::vector< soc_error_t > err; 890 node_t *n = m_node.get();
661 std::string at(name); 891 if(n == 0 || n->register_.empty())
662 if(name.size() == 0) 892 return 0;
663 err.push_back(make_fatal(at, "empty name")); 893 return &n->register_[0];
664 else if(!name_valid(name))
665 err.push_back(make_fatal(at, "invalid name"));
666 for(size_t i = 0; i < addr.size(); i++)
667 {
668 for(size_t j = 0; j < addr.size(); j++)
669 {
670 if(i == j)
671 continue;
672 if(addr[i].name == addr[j].name)
673 err.push_back(prefix(make_fatal(addr[i].name,
674 "there are several instances with the same name"), at));
675 if(addr[i].addr == addr[j].addr)
676 err.push_back(prefix(make_fatal(addr[i].name,
677 "there are several instances with the same address"), at));
678 }
679 if(recursive)
680 add_errors(err, addr[i].errors(true), at);
681 }
682 if(recursive)
683 add_errors(err, formula.errors(true), at);
684 for(size_t i = 0; i < field.size(); i++)
685 {
686 for(size_t j = 0; j < field.size(); j++)
687 {
688 if(i == j)
689 continue;
690 if(field[i].name == field[j].name)
691 err.push_back(prefix(make_fatal(field[i].name,
692 "there are several fields with the same name"), at));
693 if(field_overlap(field[i], field[j]))
694 err.push_back(prefix(make_fatal(field[i].name,
695 "there are overlapping fields"), at));
696 }
697 if(recursive)
698 add_errors(err, field[i].errors(true), at);
699 }
700 return err;
701} 894}
702 895
703std::vector< soc_error_t > soc_dev_addr_t::errors(bool recursive) 896node_ref_t register_ref_t::node() const
704{ 897{
705 (void) recursive; 898 return m_node;
706 if(name.size() == 0)
707 return one_error(make_fatal("", "empty name"));
708 else if(!name_valid(name))
709 return one_error(make_fatal(name, "invalid name"));
710 else
711 return no_error();
712} 899}
713 900
714std::vector< soc_error_t > soc_dev_t::errors(bool recursive) 901std::vector< field_ref_t > register_ref_t::fields() const
715{ 902{
716 std::vector< soc_error_t > err; 903 std::vector< field_ref_t > fields;
717 std::string at(name); 904 register_t *r = get();
718 if(name.size() == 0) 905 if(r == 0)
719 err.push_back(make_fatal(at, "empty name")); 906 return fields;
720 else if(!name_valid(name)) 907 for(size_t i = 0; i < r->field.size(); i++)
721 err.push_back(make_fatal(at, "invalid name")); 908 fields.push_back(field_ref_t(*this, r->field[i].id));
722 for(size_t i = 0; i < addr.size(); i++) 909 return fields;
723 {
724 for(size_t j = 0; j < addr.size(); j++)
725 {
726 if(i == j)
727 continue;
728 if(addr[i].name == addr[j].name)
729 err.push_back(prefix(make_fatal(addr[i].name,
730 "there are several instances with the same name"), at));
731 if(addr[i].addr == addr[j].addr)
732 err.push_back(prefix(make_fatal(addr[i].name,
733 "there are several instances with the same address"), at));
734 }
735 if(recursive)
736 add_errors(err, addr[i].errors(true), at);
737 }
738 for(size_t i = 0; i < reg.size(); i++)
739 {
740 for(size_t j = 0; j < reg.size(); j++)
741 {
742 if(i == j)
743 continue;
744 if(reg[i].name == reg[j].name)
745 err.push_back(prefix(make_fatal(reg[i].name,
746 "there are several registers with the same name"), at));
747 }
748 if(recursive)
749 add_errors(err, reg[i].errors(true), at);
750 }
751 return err;
752} 910}
753 911
754std::vector< soc_error_t > soc_t::errors(bool recursive) 912field_ref_t register_ref_t::field(const std::string& name) const
755{ 913{
756 std::vector< soc_error_t > err; 914 register_t *r = get();
757 std::string at(name); 915 if(r == 0)
758 for(size_t i = 0; i < dev.size(); i++) 916 return field_ref_t();
759 { 917 for(size_t i = 0; i < r->field.size(); i++)
760 for(size_t j = 0; j < dev.size(); j++) 918 if(r->field[i].name == name)
761 { 919 return field_ref_t(*this, r->field[i].id);
762 if(i == j) 920 return field_ref_t();
763 continue;
764 if(dev[i].name == dev[j].name)
765 err.push_back(prefix(make_fatal(dev[i].name,
766 "there are several devices with the same name"), at));
767 }
768 if(recursive)
769 add_errors(err, dev[i].errors(true), at);
770 }
771 return err;
772} 921}
773 922
774namespace 923/**
924 * field_ref_t
925 */
926
927field_ref_t::field_ref_t(register_ref_t reg, soc_id_t id)
928 :m_reg(reg), m_id(id)
775{ 929{
930}
776 931
777struct formula_evaluator 932field_ref_t::field_ref_t()
778{ 933{
779 std::string formula; 934}
780 size_t pos;
781 std::string error;
782 935
783 bool err(const char *fmt, ...) 936bool field_ref_t::valid() const
784 { 937{
785 char buffer[256]; 938 return get() != 0;
786 va_list args; 939}
787 va_start(args, fmt);
788 vsnprintf(buffer,sizeof(buffer), fmt, args);
789 va_end(args);
790 error = buffer;
791 return false;
792 }
793 940
794 formula_evaluator(const std::string& s):pos(0) 941field_t *field_ref_t::get() const
795 { 942{
796 for(size_t i = 0; i < s.size(); i++) 943 register_t *reg = m_reg.get();
797 if(!isspace(s[i])) 944 if(reg == 0)
798 formula.push_back(s[i]); 945 return 0;
799 } 946 for(size_t i = 0; i < reg->field.size(); i++)
947 if(reg->field[i].id == m_id)
948 return &reg->field[i];
949 return 0;
950}
800 951
801 void adv() 952register_ref_t field_ref_t::reg() const
802 { 953{
803 pos++; 954 return m_reg;
804 } 955}
805 956
806 char cur() 957/**
807 { 958 * node_inst_t
808 return end() ? 0 : formula[pos]; 959 */
809 }
810 960
811 bool end() 961namespace
812 { 962{
813 return pos >= formula.size(); 963
814 } 964const size_t INST_NO_INDEX = std::numeric_limits<std::size_t>::max();
815 965
816 bool parse_digit(char c, int basis, soc_word_t& res) 966bool get_inst_addr(range_t& range, size_t index, soc_addr_t& addr)
967{
968 if(index < range.first || index >= range.first + range.count)
969 return false;
970 switch(range.type)
817 { 971 {
818 c = tolower(c); 972 case range_t::STRIDE:
819 if(isdigit(c)) 973 addr += range.base + (index - range.first) * range.stride;
820 {
821 res = c - '0';
822 return true; 974 return true;
823 } 975 case range_t::FORMULA:
824 if(basis == 16 && isxdigit(c))
825 { 976 {
826 res = c + 10 - 'a'; 977 soc_word_t res;
978 std::map< std::string, soc_word_t > vars;
979 vars[range.variable] = index;
980 error_context_t ctx;
981 if(!evaluate_formula(range.formula, vars, res, "", ctx))
982 return false;
983 addr += res;
827 return true; 984 return true;
828 } 985 }
829 return err("invalid digit '%c'", c); 986 default:
987 return false;
830 } 988 }
989}
831 990
832 bool parse_signed(soc_word_t& res) 991bool get_inst_addr(instance_t *inst, size_t index, soc_addr_t& addr)
992{
993 if(inst == 0)
994 return false;
995 switch(inst->type)
833 { 996 {
834 char op = cur(); 997 case instance_t::SINGLE:
835 if(op == '+' || op == '-') 998 if(index != INST_NO_INDEX)
836 {
837 adv();
838 if(!parse_signed(res))
839 return false; 999 return false;
840 if(op == '-') 1000 addr += inst->addr;
841 res *= -1;
842 return true; 1001 return true;
843 } 1002 case instance_t::RANGE:
844 else if(op == '(') 1003 if(index == INST_NO_INDEX)
845 {
846 adv();
847 if(!parse_expression(res))
848 return false; 1004 return false;
849 if(cur() != ')') 1005 return get_inst_addr(inst->range, index, addr);
850 return err("expected ')', got '%c'", cur()); 1006 default:
851 adv();
852 return true;
853 }
854 else if(isdigit(op))
855 {
856 res = op - '0';
857 adv();
858 int basis = 10;
859 if(op == '0' && cur() == 'x')
860 {
861 basis = 16;
862 adv();
863 }
864 soc_word_t digit = 0;
865 while(parse_digit(cur(), basis, digit))
866 {
867 res = res * basis + digit;
868 adv();
869 }
870 return true;
871 }
872 else if(isalpha(op) || op == '_')
873 {
874 std::string name;
875 while(isalnum(cur()) || cur() == '_')
876 {
877 name.push_back(cur());
878 adv();
879 }
880 return get_variable(name, res);
881 }
882 else
883 return err("express signed expression, got '%c'", op);
884 }
885
886 bool parse_term(soc_word_t& res)
887 {
888 if(!parse_signed(res))
889 return false; 1007 return false;
890 while(cur() == '*' || cur() == '/' || cur() == '%')
891 {
892 char op = cur();
893 adv();
894 soc_word_t tmp;
895 if(!parse_signed(tmp))
896 return false;
897 if(op == '*')
898 res *= tmp;
899 else if(tmp != 0)
900 res = op == '/' ? res / tmp : res % tmp;
901 else
902 return err("division by 0");
903 }
904 return true;
905 } 1008 }
1009}
906 1010
907 bool parse_expression(soc_word_t& res) 1011}
908 {
909 if(!parse_term(res))
910 return false;
911 while(!end() && (cur() == '+' || cur() == '-'))
912 {
913 char op = cur();
914 adv();
915 soc_word_t tmp;
916 if(!parse_term(tmp))
917 return false;
918 if(op == '+')
919 res += tmp;
920 else
921 res -= tmp;
922 }
923 return true;
924 }
925 1012
926 bool parse(soc_word_t& res, std::string& _error) 1013node_inst_t::node_inst_t(soc_ref_t soc)
927 { 1014 :m_node(soc.root())
928 bool ok = parse_expression(res); 1015{
929 if(ok && !end()) 1016}
930 err("unexpected character '%c'", cur());
931 _error = error;
932 return ok && end();
933 }
934 1017
935 virtual bool get_variable(std::string name, soc_word_t& res) 1018node_inst_t::node_inst_t(node_ref_t node, const std::vector< soc_id_t >& ids,
936 { 1019 const std::vector< size_t >& indexes)
937 return err("unknown variable '%s'", name.c_str()); 1020 :m_node(node), m_id_path(ids), m_index_path(indexes)
938 } 1021{
939}; 1022}
940 1023
941struct my_evaluator : public formula_evaluator 1024node_inst_t::node_inst_t()
942{ 1025{
943 const std::map< std::string, soc_word_t>& var; 1026}
944 1027
945 my_evaluator(const std::string& formula, const std::map< std::string, soc_word_t>& _var) 1028bool node_inst_t::valid() const
946 :formula_evaluator(formula), var(_var) {} 1029{
1030 return is_root() || get() != 0;
1031}
947 1032
948 virtual bool get_variable(std::string name, soc_word_t& res) 1033node_ref_t node_inst_t::node() const
1034{
1035 return m_node;
1036}
1037
1038soc_ref_t node_inst_t::soc() const
1039{
1040 return m_node.soc();
1041}
1042
1043bool node_inst_t::is_root() const
1044{
1045 return m_node.is_root();
1046}
1047
1048node_inst_t node_inst_t::parent() const
1049{
1050 std::vector< soc_id_t > ids = m_id_path;
1051 std::vector< size_t > indexes = m_index_path;
1052 if(!ids.empty())
1053 ids.pop_back();
1054 if(!indexes.empty())
1055 indexes.pop_back();
1056 return node_inst_t(m_node.parent(), ids, indexes);
1057}
1058
1059instance_t *node_inst_t::get() const
1060{
1061 node_t *n = m_node.get();
1062 if(n == 0)
1063 return 0;
1064 for(size_t i = 0; i < n->instance.size(); i++)
1065 if(n->instance[i].id == m_id_path.back())
1066 return &n->instance[i];
1067 return 0;
1068}
1069
1070soc_addr_t node_inst_t::addr() const
1071{
1072 if(is_root())
1073 return 0;
1074 soc_addr_t addr = parent().addr();
1075 if(!get_inst_addr(get(), m_index_path.back(), addr))
1076 return 0;
1077 return addr;
1078}
1079
1080node_inst_t node_inst_t::child(const std::string& name) const
1081{
1082 return child(name, INST_NO_INDEX);
1083}
1084
1085
1086node_inst_t node_inst_t::child(const std::string& name, size_t index) const
1087{
1088 std::vector< node_t > *nodes = get_children(m_node);
1089 if(nodes == 0)
1090 return node_inst_t();
1091 node_ref_t child_node = m_node;
1092 for(size_t i = 0; i < nodes->size(); i++)
949 { 1093 {
950 std::map< std::string, soc_word_t>::const_iterator it = var.find(name); 1094 node_t& node = (*nodes)[i];
951 if(it == var.end()) 1095 child_node.m_path.push_back(node.id);
952 return formula_evaluator::get_variable(name, res); 1096 for(size_t j = 0; j < node.instance.size(); j++)
953 else
954 { 1097 {
955 res = it->second; 1098 if(node.instance[j].name != name)
956 return true; 1099 continue;
1100 std::vector< soc_id_t > ids = m_id_path;
1101 std::vector< size_t > indexes = m_index_path;
1102 ids.push_back(node.instance[j].id);
1103 ids.push_back(index);
1104 return node_inst_t(child_node, ids, indexes);
957 } 1105 }
1106 child_node.m_path.pop_back();
958 } 1107 }
959}; 1108 return node_inst_t();
1109}
1110
1111std::vector< node_inst_t > node_inst_t::children() const
1112{
1113 std::vector< node_inst_t > list;
1114 std::vector< node_t > *nodes = get_children(m_node);
1115 std::vector< soc_id_t > n_path = m_id_path;
1116 std::vector< size_t > i_path = m_index_path;
1117 if(nodes == 0)
1118 return list;
1119 node_ref_t child_node = m_node;
1120 for(size_t i = 0; i < nodes->size(); i++)
1121 {
1122 node_t& node = (*nodes)[i];
1123 child_node.m_path.push_back(node.id);
1124 for(size_t j = 0; j < node.instance.size(); j++)
1125 {
1126 instance_t& inst = node.instance[j];
1127 n_path.push_back(inst.id);
1128 switch(inst.type)
1129 {
1130 case instance_t::SINGLE:
1131 i_path.push_back(INST_NO_INDEX);
1132 list.push_back(node_inst_t(child_node, n_path, i_path));
1133 i_path.pop_back();
1134 break;
1135 case instance_t::RANGE:
1136 for(size_t i = 0; i < inst.range.count; i++)
1137 {
1138 i_path.push_back(inst.range.first + i);
1139 list.push_back(node_inst_t(child_node, n_path, i_path));
1140 i_path.pop_back();
1141 }
1142 break;
1143 default:
1144 break;
1145 }
1146 n_path.pop_back();
1147 }
1148 child_node.m_path.pop_back();
1149 }
1150 return list;
1151}
1152
1153std::string node_inst_t::name() const
1154{
1155 instance_t *inst = get();
1156 return inst == 0 ? "" : inst->name;
1157}
960 1158
1159bool node_inst_t:: is_indexed() const
1160{
1161 return !m_index_path.empty() && m_index_path.back() != INST_NO_INDEX;
961} 1162}
962 1163
963bool soc_desc_evaluate_formula(const std::string& formula, 1164size_t node_inst_t::index() const
964 const std::map< std::string, soc_word_t>& var, soc_word_t& result, std::string& error)
965{ 1165{
966 my_evaluator e(formula, var); 1166 return m_index_path.empty() ? INST_NO_INDEX : m_index_path.back();
967 return e.parse(result, error);
968} 1167}
969 1168
970/** WARNING we need to call xmlInitParser() to init libxml2 but it needs to 1169/** WARNING we need to call xmlInitParser() to init libxml2 but it needs to
@@ -982,4 +1181,7 @@ public:
982}; 1181};
983 1182
984xml_parser_init __xml_parser_init; 1183xml_parser_init __xml_parser_init;
985} \ No newline at end of file 1184}
1185
1186} // soc_desc_v1
1187
diff --git a/utils/regtools/lib/soc_desc_v1.cpp b/utils/regtools/lib/soc_desc_v1.cpp
new file mode 100644
index 0000000000..d585485493
--- /dev/null
+++ b/utils/regtools/lib/soc_desc_v1.cpp
@@ -0,0 +1,990 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2012 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_v1.hpp"
22#include <libxml/parser.h>
23#include <libxml/tree.h>
24#include <libxml/xmlsave.h>
25#include <libxml/xmlwriter.h>
26#include <stdio.h>
27#include <string.h>
28#include <algorithm>
29#include <cctype>
30
31namespace soc_desc_v1
32{
33
34#define XML_CHAR_TO_CHAR(s) ((const char *)(s))
35
36#define BEGIN_ATTR_MATCH(attr) \
37 for(xmlAttr *a = attr; a; a = a->next) {
38
39#define MATCH_X_ATTR(attr_name, hook, ...) \
40 if(strcmp(XML_CHAR_TO_CHAR(a->name), attr_name) == 0) { \
41 std::string s; \
42 if(!parse_text_attr(a, s) || !hook(s, __VA_ARGS__)) \
43 return false; \
44 }
45
46#define SOFT_MATCH_X_ATTR(attr_name, hook, ...) \
47 if(strcmp(XML_CHAR_TO_CHAR(a->name), attr_name) == 0) { \
48 std::string s; \
49 if(parse_text_attr(a, s)) \
50 hook(s, __VA_ARGS__); \
51 }
52
53#define SOFT_MATCH_SCT_ATTR(attr_name, var) \
54 SOFT_MATCH_X_ATTR(attr_name, validate_sct_hook, var)
55
56#define MATCH_TEXT_ATTR(attr_name, var) \
57 MATCH_X_ATTR(attr_name, validate_string_hook, var)
58
59#define MATCH_UINT32_ATTR(attr_name, var) \
60 MATCH_X_ATTR(attr_name, validate_uint32_hook, var)
61
62#define MATCH_BITRANGE_ATTR(attr_name, first, last) \
63 MATCH_X_ATTR(attr_name, validate_bitrange_hook, first, last)
64
65#define END_ATTR_MATCH() \
66 }
67
68#define BEGIN_NODE_MATCH(node) \
69 for(xmlNode *sub = node; sub; sub = sub->next) {
70
71#define MATCH_ELEM_NODE(node_name, array, parse_fn) \
72 if(sub->type == XML_ELEMENT_NODE && strcmp(XML_CHAR_TO_CHAR(sub->name), node_name) == 0) { \
73 array.resize(array.size() + 1); \
74 if(!parse_fn(sub, array.back())) \
75 return false; \
76 }
77
78#define SOFT_MATCH_ELEM_NODE(node_name, array, parse_fn) \
79 if(sub->type == XML_ELEMENT_NODE && strcmp(XML_CHAR_TO_CHAR(sub->name), node_name) == 0) { \
80 array.resize(array.size() + 1); \
81 if(!parse_fn(sub, array.back())) \
82 array.pop_back(); \
83 }
84
85#define END_NODE_MATCH() \
86 }
87
88namespace
89{
90
91bool validate_string_hook(const std::string& str, std::string& s)
92{
93 s = str;
94 return true;
95}
96
97bool validate_sct_hook(const std::string& str, soc_reg_flags_t& flags)
98{
99 if(str == "yes") flags |= REG_HAS_SCT;
100 else if(str != "no") return false;
101 return true;
102}
103
104bool validate_unsigned_long_hook(const std::string& str, unsigned long& s)
105{
106 char *end;
107 s = strtoul(str.c_str(), &end, 0);
108 return *end == 0;
109}
110
111bool validate_uint32_hook(const std::string& str, uint32_t& s)
112{
113 unsigned long u;
114 if(!validate_unsigned_long_hook(str, u)) return false;
115#if ULONG_MAX > 0xffffffff
116 if(u > 0xffffffff) return false;
117#endif
118 s = u;
119 return true;
120}
121
122bool validate_bitrange_hook(const std::string& str, unsigned& first, unsigned& last)
123{
124 unsigned long a, b;
125 size_t sep = str.find(':');
126 if(sep == std::string::npos) return false;
127 if(!validate_unsigned_long_hook(str.substr(0, sep), a)) return false;
128 if(!validate_unsigned_long_hook(str.substr(sep + 1), b)) return false;
129 if(a > 31 || b > 31 || a < b) return false;
130 first = b;
131 last = a;
132 return true;
133}
134
135bool parse_text_attr(xmlAttr *attr, std::string& s)
136{
137 if(attr->children != attr->last)
138 return false;
139 if(attr->children->type != XML_TEXT_NODE)
140 return false;
141 s = XML_CHAR_TO_CHAR(attr->children->content);
142 return true;
143}
144
145bool parse_value_elem(xmlNode *node, soc_reg_field_value_t& value)
146{
147 BEGIN_ATTR_MATCH(node->properties)
148 MATCH_TEXT_ATTR("name", value.name)
149 MATCH_UINT32_ATTR("value", value.value)
150 MATCH_TEXT_ATTR("desc", value.desc)
151 END_ATTR_MATCH()
152
153 return true;
154}
155
156bool parse_field_elem(xmlNode *node, soc_reg_field_t& field)
157{
158 BEGIN_ATTR_MATCH(node->properties)
159 MATCH_TEXT_ATTR("name", field.name)
160 MATCH_BITRANGE_ATTR("bitrange", field.first_bit, field.last_bit)
161 MATCH_TEXT_ATTR("desc", field.desc)
162 END_ATTR_MATCH()
163
164 BEGIN_NODE_MATCH(node->children)
165 SOFT_MATCH_ELEM_NODE("value", field.value, parse_value_elem)
166 END_NODE_MATCH()
167
168 return true;
169}
170
171bool parse_reg_addr_elem(xmlNode *node, soc_reg_addr_t& addr)
172{
173 BEGIN_ATTR_MATCH(node->properties)
174 MATCH_TEXT_ATTR("name", addr.name)
175 MATCH_UINT32_ATTR("addr", addr.addr)
176 END_ATTR_MATCH()
177
178 return true;
179}
180
181bool parse_reg_formula_elem(xmlNode *node, soc_reg_formula_t& formula)
182{
183 BEGIN_ATTR_MATCH(node->properties)
184 MATCH_TEXT_ATTR("string", formula.string)
185 END_ATTR_MATCH()
186
187 formula.type = REG_FORMULA_STRING;
188
189 return true;
190}
191
192bool parse_add_trivial_addr(const std::string& str, soc_reg_t& reg)
193{
194 soc_reg_addr_t a;
195 a.name = reg.name;
196 if(!validate_uint32_hook(str, a.addr))
197 return false;
198 reg.addr.push_back(a);
199 return true;
200}
201
202bool parse_reg_elem(xmlNode *node, soc_reg_t& reg)
203{
204 std::list< soc_reg_formula_t > formulas;
205 BEGIN_ATTR_MATCH(node->properties)
206 MATCH_TEXT_ATTR("name", reg.name)
207 SOFT_MATCH_SCT_ATTR("sct", reg.flags)
208 SOFT_MATCH_X_ATTR("addr", parse_add_trivial_addr, reg)
209 MATCH_TEXT_ATTR("desc", reg.desc)
210 END_ATTR_MATCH()
211
212 BEGIN_NODE_MATCH(node->children)
213 MATCH_ELEM_NODE("addr", reg.addr, parse_reg_addr_elem)
214 MATCH_ELEM_NODE("formula", formulas, parse_reg_formula_elem)
215 MATCH_ELEM_NODE("field", reg.field, parse_field_elem)
216 END_NODE_MATCH()
217
218 if(formulas.size() > 1)
219 {
220 fprintf(stderr, "Only one formula is allowed per register\n");
221 return false;
222 }
223 if(formulas.size() == 1)
224 reg.formula = formulas.front();
225
226 return true;
227}
228
229bool parse_dev_addr_elem(xmlNode *node, soc_dev_addr_t& addr)
230{
231 BEGIN_ATTR_MATCH(node->properties)
232 MATCH_TEXT_ATTR("name", addr.name)
233 MATCH_UINT32_ATTR("addr", addr.addr)
234 END_ATTR_MATCH()
235
236 return true;
237}
238
239bool parse_dev_elem(xmlNode *node, soc_dev_t& dev)
240{
241 BEGIN_ATTR_MATCH(node->properties)
242 MATCH_TEXT_ATTR("name", dev.name)
243 MATCH_TEXT_ATTR("long_name", dev.long_name)
244 MATCH_TEXT_ATTR("desc", dev.desc)
245 MATCH_TEXT_ATTR("version", dev.version)
246 END_ATTR_MATCH()
247
248 BEGIN_NODE_MATCH(node->children)
249 MATCH_ELEM_NODE("addr", dev.addr, parse_dev_addr_elem)
250 MATCH_ELEM_NODE("reg", dev.reg, parse_reg_elem)
251 END_NODE_MATCH()
252
253 return true;
254}
255
256bool parse_soc_elem(xmlNode *node, soc_t& soc)
257{
258 BEGIN_ATTR_MATCH(node->properties)
259 MATCH_TEXT_ATTR("name", soc.name)
260 MATCH_TEXT_ATTR("desc", soc.desc)
261 END_ATTR_MATCH()
262
263 BEGIN_NODE_MATCH(node->children)
264 MATCH_ELEM_NODE("dev", soc.dev, parse_dev_elem)
265 END_NODE_MATCH()
266
267 return true;
268}
269
270bool parse_root_elem(xmlNode *node, soc_t& soc)
271{
272 std::vector< soc_t > socs;
273 BEGIN_NODE_MATCH(node)
274 MATCH_ELEM_NODE("soc", socs, parse_soc_elem)
275 END_NODE_MATCH()
276 if(socs.size() != 1)
277 {
278 fprintf(stderr, "A description file must contain exactly one soc element\n");
279 return false;
280 }
281 soc = socs[0];
282 return true;
283}
284
285}
286
287bool parse_xml(const std::string& filename, soc_t& socs)
288{
289 LIBXML_TEST_VERSION
290
291 xmlDocPtr doc = xmlReadFile(filename.c_str(), NULL, 0);
292 if(doc == NULL)
293 return false;
294
295 xmlNodePtr root_element = xmlDocGetRootElement(doc);
296 bool ret = parse_root_elem(root_element, socs);
297
298 xmlFreeDoc(doc);
299
300 return ret;
301}
302
303namespace
304{
305
306int produce_field(xmlTextWriterPtr writer, const soc_reg_field_t& field)
307{
308#define SAFE(x) if((x) < 0) return -1;
309 /* <field> */
310 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "field"));
311 /* name */
312 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST field.name.c_str()));
313 /* desc */
314 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "desc", BAD_CAST field.desc.c_str()));
315 /* bitrange */
316 SAFE(xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "bitrange", "%d:%d",
317 field.last_bit, field.first_bit));
318 /* values */
319 for(size_t i = 0; i < field.value.size(); i++)
320 {
321 /* <value> */
322 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "value"));
323 /* name */
324 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST field.value[i].name.c_str()));
325 /* value */
326 SAFE(xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "value", "0x%x", field.value[i].value));
327 /* name */
328 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "desc", BAD_CAST field.value[i].desc.c_str()));
329 /* </value> */
330 SAFE(xmlTextWriterEndElement(writer));
331 }
332 /* </field> */
333 SAFE(xmlTextWriterEndElement(writer));
334#undef SAFE
335 return 0;
336}
337
338int produce_reg(xmlTextWriterPtr writer, const soc_reg_t& reg)
339{
340#define SAFE(x) if((x) < 0) return -1;
341 /* <reg> */
342 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "reg"));
343 /* name */
344 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST reg.name.c_str()));
345 /* name */
346 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "desc", BAD_CAST reg.desc.c_str()));
347 /* flags */
348 if(reg.flags & REG_HAS_SCT)
349 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "sct", BAD_CAST "yes"));
350 /* formula */
351 if(reg.formula.type != REG_FORMULA_NONE)
352 {
353 /* <formula> */
354 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "formula"));
355 switch(reg.formula.type)
356 {
357 case REG_FORMULA_STRING:
358 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "string",
359 BAD_CAST reg.formula.string.c_str()));
360 break;
361 default:
362 break;
363 }
364 /* </formula> */
365 SAFE(xmlTextWriterEndElement(writer));
366 }
367 /* addresses */
368 for(size_t i = 0; i < reg.addr.size(); i++)
369 {
370 /* <addr> */
371 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "addr"));
372 /* name */
373 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST reg.addr[i].name.c_str()));
374 /* addr */
375 SAFE(xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "addr", "0x%x", reg.addr[i].addr));
376 /* </addr> */
377 SAFE(xmlTextWriterEndElement(writer));
378 }
379 /* fields */
380 for(size_t i = 0; i < reg.field.size(); i++)
381 produce_field(writer, reg.field[i]);
382 /* </reg> */
383 SAFE(xmlTextWriterEndElement(writer));
384#undef SAFE
385 return 0;
386}
387
388int produce_dev(xmlTextWriterPtr writer, const soc_dev_t& dev)
389{
390#define SAFE(x) if((x) < 0) return -1;
391 /* <dev> */
392 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "dev"));
393 /* name */
394 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST dev.name.c_str()));
395 /* long_name */
396 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "long_name", BAD_CAST dev.long_name.c_str()));
397 /* desc */
398 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "desc", BAD_CAST dev.desc.c_str()));
399 /* version */
400 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "version", BAD_CAST dev.version.c_str()));
401 /* addresses */
402 for(size_t i = 0; i < dev.addr.size(); i++)
403 {
404 /* <addr> */
405 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "addr"));
406 /* name */
407 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST dev.addr[i].name.c_str()));
408 /* addr */
409 SAFE(xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "addr", "0x%x", dev.addr[i].addr));
410 /* </addr> */
411 SAFE(xmlTextWriterEndElement(writer));
412 }
413 /* registers */
414 for(size_t i = 0; i < dev.reg.size(); i++)
415 produce_reg(writer, dev.reg[i]);
416 /* </dev> */
417 SAFE(xmlTextWriterEndElement(writer));
418#undef SAFE
419 return 0;
420}
421
422}
423
424bool produce_xml(const std::string& filename, const soc_t& soc)
425{
426 LIBXML_TEST_VERSION
427
428 xmlTextWriterPtr writer = xmlNewTextWriterFilename(filename.c_str(), 0);
429 if(writer == NULL)
430 return false;
431#define SAFE(x) if((x) < 0) goto Lerr
432 SAFE(xmlTextWriterSetIndent(writer, 1));
433 SAFE(xmlTextWriterSetIndentString(writer, BAD_CAST " "));
434 /* <xml> */
435 SAFE(xmlTextWriterStartDocument(writer, NULL, NULL, NULL));
436 /* <soc> */
437 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "soc"));
438 /* name */
439 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST soc.name.c_str()));
440 /* desc */
441 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "desc", BAD_CAST soc.desc.c_str()));
442 /* devices */
443 for(size_t i = 0; i < soc.dev.size(); i++)
444 SAFE(produce_dev(writer, soc.dev[i]));
445 /* end <soc> */
446 SAFE(xmlTextWriterEndElement(writer));
447 /* </xml> */
448 SAFE(xmlTextWriterEndDocument(writer));
449 xmlFreeTextWriter(writer);
450 return true;
451#undef SAFE
452Lerr:
453 xmlFreeTextWriter(writer);
454 return false;
455}
456
457namespace
458{
459
460struct soc_sorter
461{
462 bool operator()(const soc_dev_t& a, const soc_dev_t& b) const
463 {
464 return a.name < b.name;
465 }
466
467 bool operator()(const soc_dev_addr_t& a, const soc_dev_addr_t& b) const
468 {
469 return a.name < b.name;
470 }
471
472 bool operator()(const soc_reg_t& a, const soc_reg_t& b) const
473 {
474 soc_addr_t aa = a.addr.size() > 0 ? a.addr[0].addr : 0;
475 soc_addr_t ab = b.addr.size() > 0 ? b.addr[0].addr : 0;
476 return aa < ab;
477 }
478
479 bool operator()(const soc_reg_addr_t& a, const soc_reg_addr_t& b) const
480 {
481 return a.addr < b.addr;
482 }
483
484 bool operator()(const soc_reg_field_t& a, const soc_reg_field_t& b) const
485 {
486 return a.last_bit > b.last_bit;
487 }
488
489 bool operator()(const soc_reg_field_value_t a, const soc_reg_field_value_t& b) const
490 {
491 return a.value < b.value;
492 }
493};
494
495void normalize(soc_reg_field_t& field)
496{
497 std::sort(field.value.begin(), field.value.end(), soc_sorter());
498}
499
500void normalize(soc_reg_t& reg)
501{
502 std::sort(reg.addr.begin(), reg.addr.end(), soc_sorter());
503 std::sort(reg.field.begin(), reg.field.end(), soc_sorter());
504 for(size_t i = 0; i < reg.field.size(); i++)
505 normalize(reg.field[i]);
506}
507
508void normalize(soc_dev_t& dev)
509{
510 std::sort(dev.addr.begin(), dev.addr.end(), soc_sorter());
511 std::sort(dev.reg.begin(), dev.reg.end(), soc_sorter());
512 for(size_t i = 0; i < dev.reg.size(); i++)
513 normalize(dev.reg[i]);
514}
515
516}
517
518void normalize(soc_t& soc)
519{
520 std::sort(soc.dev.begin(), soc.dev.end(), soc_sorter());
521 for(size_t i = 0; i < soc.dev.size(); i++)
522 normalize(soc.dev[i]);
523}
524
525namespace
526{
527 soc_error_t make_error(soc_error_level_t lvl, std::string at, std::string what)
528 {
529 soc_error_t err;
530 err.level = lvl;
531 err.location = at;
532 err.message = what;
533 return err;
534 }
535
536 soc_error_t make_warning(std::string at, std::string what)
537 {
538 return make_error(SOC_ERROR_WARNING, at, what);
539 }
540
541 soc_error_t make_fatal(std::string at, std::string what)
542 {
543 return make_error(SOC_ERROR_FATAL, at, what);
544 }
545
546 soc_error_t prefix(soc_error_t err, const std::string& prefix_at)
547 {
548 err.location = prefix_at + "." + err.location;
549 return err;
550 }
551
552 void add_errors(std::vector< soc_error_t >& errors,
553 const std::vector< soc_error_t >& new_errors, const std::string& prefix_at)
554 {
555 for(size_t i = 0; i < new_errors.size(); i++)
556 errors.push_back(prefix(new_errors[i], prefix_at));
557 }
558
559 std::vector< soc_error_t > no_error()
560 {
561 std::vector< soc_error_t > s;
562 return s;
563 }
564
565 std::vector< soc_error_t > one_error(const soc_error_t& err)
566 {
567 std::vector< soc_error_t > s;
568 s.push_back(err);
569 return s;
570 }
571
572 bool name_valid(char c)
573 {
574 return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') ||
575 (c >= 'A' && c <= 'Z') || c == '_';
576 }
577
578 bool name_valid(const std::string& s)
579 {
580 for(size_t i = 0; i < s.size(); i++)
581 if(!name_valid(s[i]))
582 return false;
583 return true;
584 }
585}
586
587std::vector< soc_error_t > soc_reg_field_value_t::errors(bool recursive)
588{
589 (void) recursive;
590 if(name.size() == 0)
591 return one_error(make_fatal(name, "empty name"));
592 else if(!name_valid(name))
593 return one_error(make_fatal(name, "invalid name"));
594 else
595 return no_error();
596}
597
598std::vector< soc_error_t > soc_reg_field_t::errors(bool recursive)
599{
600 std::vector< soc_error_t > err;
601 std::string at(name);
602 if(name.size() == 0)
603 err.push_back(make_fatal(at, "empty name"));
604 else if(!name_valid(name))
605 err.push_back(make_fatal(at, "invalid name"));
606 if(last_bit > 31)
607 err.push_back(make_fatal(at, "last bit is greater than 31"));
608 if(first_bit > last_bit)
609 err.push_back(make_fatal(at, "last bit is greater than first bit"));
610 for(size_t i = 0; i < value.size(); i++)
611 {
612 for(size_t j = 0; j < value.size(); j++)
613 {
614 if(i == j)
615 continue;
616 if(value[i].name == value[j].name)
617 err.push_back(prefix(make_fatal(value[i].name,
618 "there are several values with the same name"), at));
619 if(value[i].value == value[j].value)
620 err.push_back(prefix(make_warning(value[i].name,
621 "there are several values with the same value"), at));
622 }
623 if(value[i].value > (bitmask() >> first_bit))
624 err.push_back(prefix(make_warning(at, "value doesn't fit into the field"), value[i].name));
625 if(recursive)
626 add_errors(err, value[i].errors(true), at);
627 }
628 return err;
629}
630
631std::vector< soc_error_t > soc_reg_addr_t::errors(bool recursive)
632{
633 (void) recursive;
634 if(name.size() == 0)
635 return one_error(make_fatal("", "empty name"));
636 else if(!name_valid(name))
637 return one_error(make_fatal(name, "invalid name"));
638 else
639 return no_error();
640}
641
642std::vector< soc_error_t > soc_reg_formula_t::errors(bool recursive)
643{
644 (void) recursive;
645 if(type == REG_FORMULA_STRING && string.size() == 0)
646 return one_error(make_fatal("", "empty string formula"));
647 else
648 return no_error();
649}
650
651namespace
652{
653
654bool field_overlap(const soc_reg_field_t& a, const soc_reg_field_t& b)
655{
656 return !(a.first_bit > b.last_bit || b.first_bit > a.last_bit);
657}
658
659}
660
661std::vector< soc_error_t > soc_reg_t::errors(bool recursive)
662{
663 std::vector< soc_error_t > err;
664 std::string at(name);
665 if(name.size() == 0)
666 err.push_back(make_fatal(at, "empty name"));
667 else if(!name_valid(name))
668 err.push_back(make_fatal(at, "invalid name"));
669 for(size_t i = 0; i < addr.size(); i++)
670 {
671 for(size_t j = 0; j < addr.size(); j++)
672 {
673 if(i == j)
674 continue;
675 if(addr[i].name == addr[j].name)
676 err.push_back(prefix(make_fatal(addr[i].name,
677 "there are several instances with the same name"), at));
678 if(addr[i].addr == addr[j].addr)
679 err.push_back(prefix(make_fatal(addr[i].name,
680 "there are several instances with the same address"), at));
681 }
682 if(recursive)
683 add_errors(err, addr[i].errors(true), at);
684 }
685 if(recursive)
686 add_errors(err, formula.errors(true), at);
687 for(size_t i = 0; i < field.size(); i++)
688 {
689 for(size_t j = 0; j < field.size(); j++)
690 {
691 if(i == j)
692 continue;
693 if(field[i].name == field[j].name)
694 err.push_back(prefix(make_fatal(field[i].name,
695 "there are several fields with the same name"), at));
696 if(field_overlap(field[i], field[j]))
697 err.push_back(prefix(make_fatal(field[i].name,
698 "there are overlapping fields"), at));
699 }
700 if(recursive)
701 add_errors(err, field[i].errors(true), at);
702 }
703 return err;
704}
705
706std::vector< soc_error_t > soc_dev_addr_t::errors(bool recursive)
707{
708 (void) recursive;
709 if(name.size() == 0)
710 return one_error(make_fatal("", "empty name"));
711 else if(!name_valid(name))
712 return one_error(make_fatal(name, "invalid name"));
713 else
714 return no_error();
715}
716
717std::vector< soc_error_t > soc_dev_t::errors(bool recursive)
718{
719 std::vector< soc_error_t > err;
720 std::string at(name);
721 if(name.size() == 0)
722 err.push_back(make_fatal(at, "empty name"));
723 else if(!name_valid(name))
724 err.push_back(make_fatal(at, "invalid name"));
725 for(size_t i = 0; i < addr.size(); i++)
726 {
727 for(size_t j = 0; j < addr.size(); j++)
728 {
729 if(i == j)
730 continue;
731 if(addr[i].name == addr[j].name)
732 err.push_back(prefix(make_fatal(addr[i].name,
733 "there are several instances with the same name"), at));
734 if(addr[i].addr == addr[j].addr)
735 err.push_back(prefix(make_fatal(addr[i].name,
736 "there are several instances with the same address"), at));
737 }
738 if(recursive)
739 add_errors(err, addr[i].errors(true), at);
740 }
741 for(size_t i = 0; i < reg.size(); i++)
742 {
743 for(size_t j = 0; j < reg.size(); j++)
744 {
745 if(i == j)
746 continue;
747 if(reg[i].name == reg[j].name)
748 err.push_back(prefix(make_fatal(reg[i].name,
749 "there are several registers with the same name"), at));
750 }
751 if(recursive)
752 add_errors(err, reg[i].errors(true), at);
753 }
754 return err;
755}
756
757std::vector< soc_error_t > soc_t::errors(bool recursive)
758{
759 std::vector< soc_error_t > err;
760 std::string at(name);
761 for(size_t i = 0; i < dev.size(); i++)
762 {
763 for(size_t j = 0; j < dev.size(); j++)
764 {
765 if(i == j)
766 continue;
767 if(dev[i].name == dev[j].name)
768 err.push_back(prefix(make_fatal(dev[i].name,
769 "there are several devices with the same name"), at));
770 }
771 if(recursive)
772 add_errors(err, dev[i].errors(true), at);
773 }
774 return err;
775}
776
777namespace
778{
779
780struct formula_evaluator
781{
782 std::string formula;
783 size_t pos;
784 std::string error;
785
786 bool err(const char *fmt, ...)
787 {
788 char buffer[256];
789 va_list args;
790 va_start(args, fmt);
791 vsnprintf(buffer,sizeof(buffer), fmt, args);
792 va_end(args);
793 error = buffer;
794 return false;
795 }
796
797 formula_evaluator(const std::string& s):pos(0)
798 {
799 for(size_t i = 0; i < s.size(); i++)
800 if(!isspace(s[i]))
801 formula.push_back(s[i]);
802 }
803
804 void adv()
805 {
806 pos++;
807 }
808
809 char cur()
810 {
811 return end() ? 0 : formula[pos];
812 }
813
814 bool end()
815 {
816 return pos >= formula.size();
817 }
818
819 bool parse_digit(char c, int basis, soc_word_t& res)
820 {
821 c = tolower(c);
822 if(isdigit(c))
823 {
824 res = c - '0';
825 return true;
826 }
827 if(basis == 16 && isxdigit(c))
828 {
829 res = c + 10 - 'a';
830 return true;
831 }
832 return err("invalid digit '%c'", c);
833 }
834
835 bool parse_signed(soc_word_t& res)
836 {
837 char op = cur();
838 if(op == '+' || op == '-')
839 {
840 adv();
841 if(!parse_signed(res))
842 return false;
843 if(op == '-')
844 res *= -1;
845 return true;
846 }
847 else if(op == '(')
848 {
849 adv();
850 if(!parse_expression(res))
851 return false;
852 if(cur() != ')')
853 return err("expected ')', got '%c'", cur());
854 adv();
855 return true;
856 }
857 else if(isdigit(op))
858 {
859 res = op - '0';
860 adv();
861 int basis = 10;
862 if(op == '0' && cur() == 'x')
863 {
864 basis = 16;
865 adv();
866 }
867 soc_word_t digit = 0;
868 while(parse_digit(cur(), basis, digit))
869 {
870 res = res * basis + digit;
871 adv();
872 }
873 return true;
874 }
875 else if(isalpha(op) || op == '_')
876 {
877 std::string name;
878 while(isalnum(cur()) || cur() == '_')
879 {
880 name.push_back(cur());
881 adv();
882 }
883 return get_variable(name, res);
884 }
885 else
886 return err("express signed expression, got '%c'", op);
887 }
888
889 bool parse_term(soc_word_t& res)
890 {
891 if(!parse_signed(res))
892 return false;
893 while(cur() == '*' || cur() == '/' || cur() == '%')
894 {
895 char op = cur();
896 adv();
897 soc_word_t tmp;
898 if(!parse_signed(tmp))
899 return false;
900 if(op == '*')
901 res *= tmp;
902 else if(tmp != 0)
903 res = op == '/' ? res / tmp : res % tmp;
904 else
905 return err("division by 0");
906 }
907 return true;
908 }
909
910 bool parse_expression(soc_word_t& res)
911 {
912 if(!parse_term(res))
913 return false;
914 while(!end() && (cur() == '+' || cur() == '-'))
915 {
916 char op = cur();
917 adv();
918 soc_word_t tmp;
919 if(!parse_term(tmp))
920 return false;
921 if(op == '+')
922 res += tmp;
923 else
924 res -= tmp;
925 }
926 return true;
927 }
928
929 bool parse(soc_word_t& res, std::string& _error)
930 {
931 bool ok = parse_expression(res);
932 if(ok && !end())
933 err("unexpected character '%c'", cur());
934 _error = error;
935 return ok && end();
936 }
937
938 virtual bool get_variable(std::string name, soc_word_t& res)
939 {
940 return err("unknown variable '%s'", name.c_str());
941 }
942};
943
944struct my_evaluator : public formula_evaluator
945{
946 const std::map< std::string, soc_word_t>& var;
947
948 my_evaluator(const std::string& formula, const std::map< std::string, soc_word_t>& _var)
949 :formula_evaluator(formula), var(_var) {}
950
951 virtual bool get_variable(std::string name, soc_word_t& res)
952 {
953 std::map< std::string, soc_word_t>::const_iterator it = var.find(name);
954 if(it == var.end())
955 return formula_evaluator::get_variable(name, res);
956 else
957 {
958 res = it->second;
959 return true;
960 }
961 }
962};
963
964}
965
966bool evaluate_formula(const std::string& formula,
967 const std::map< std::string, soc_word_t>& var, soc_word_t& result, std::string& error)
968{
969 my_evaluator e(formula, var);
970 return e.parse(result, error);
971}
972
973/** WARNING we need to call xmlInitParser() to init libxml2 but it needs to
974 * called from the main thread, which is a super strong requirement, so do it
975 * using a static constructor */
976namespace
977{
978class xml_parser_init
979{
980public:
981 xml_parser_init()
982 {
983 xmlInitParser();
984 }
985};
986
987xml_parser_init __xml_parser_init;
988}
989
990} // soc_desc_v1
diff --git a/utils/regtools/qeditor/backend.cpp b/utils/regtools/qeditor/backend.cpp
index 7091a0c77f..cbaff7370d 100644
--- a/utils/regtools/qeditor/backend.cpp
+++ b/utils/regtools/qeditor/backend.cpp
@@ -35,8 +35,8 @@ SocFile::SocFile()
35SocFile::SocFile(const QString& filename) 35SocFile::SocFile(const QString& filename)
36 :m_filename(filename) 36 :m_filename(filename)
37{ 37{
38 m_valid = soc_desc_parse_xml(filename.toStdString(), m_soc); 38 m_valid = parse_xml(filename.toStdString(), m_soc);
39 soc_desc_normalize(m_soc); 39 normalize(m_soc);
40} 40}
41 41
42bool SocFile::IsValid() 42bool SocFile::IsValid()
diff --git a/utils/regtools/qeditor/backend.h b/utils/regtools/qeditor/backend.h
index b2f53c9ed5..934c1c359b 100644
--- a/utils/regtools/qeditor/backend.h
+++ b/utils/regtools/qeditor/backend.h
@@ -29,7 +29,11 @@
29#ifdef HAVE_HWSTUB 29#ifdef HAVE_HWSTUB
30#include "hwstub.h" 30#include "hwstub.h"
31#endif 31#endif
32#include "soc_desc.hpp" 32#include "soc_desc_v1.hpp"
33
34/* we don't want to import the entire soc_desc except for a few selected
35 * pieces */
36using namespace soc_desc_v1;
33 37
34class IoBackend : public QObject 38class IoBackend : public QObject
35{ 39{
diff --git a/utils/regtools/qeditor/mainwindow.cpp b/utils/regtools/qeditor/mainwindow.cpp
index 9cea728d6e..b44306d701 100644
--- a/utils/regtools/qeditor/mainwindow.cpp
+++ b/utils/regtools/qeditor/mainwindow.cpp
@@ -161,12 +161,14 @@ void MainWindow::OnQuit()
161 161
162void MainWindow::OnAbout() 162void MainWindow::OnAbout()
163{ 163{
164 QString soc_desc_ver = QString("%1.%2.%3").arg(MAJOR_VERSION)
165 .arg(MINOR_VERSION).arg(REVISION_VERSION);
164 QMessageBox::about(this, "About", 166 QMessageBox::about(this, "About",
165 "<h1>QEditor</h1>" 167 "<h1>QEditor</h1>"
166 "<h2>Version "APP_VERSION"</h2>" 168 "<h2>Version "APP_VERSION"</h2>"
167 "<p>Written by Amaury Pouly</p>" 169 "<p>Written by Amaury Pouly</p>"
168 "<p>Libraries:</p>" 170 "<p>Libraries:</p>"
169 "<ul><li>soc_desc: "SOCDESC_VERSION"</li>" 171 "<ul><li>soc_desc: " + soc_desc_ver + "</li>"
170#ifdef HAVE_HWSTUB 172#ifdef HAVE_HWSTUB
171 "<li>hwstub: "HWSTUB_VERSION"</li>" 173 "<li>hwstub: "HWSTUB_VERSION"</li>"
172#else 174#else
diff --git a/utils/regtools/qeditor/qeditor.pro b/utils/regtools/qeditor/qeditor.pro
index eecc0aba3f..265cc93171 100644
--- a/utils/regtools/qeditor/qeditor.pro
+++ b/utils/regtools/qeditor/qeditor.pro
@@ -5,14 +5,14 @@ HEADERS += mainwindow.h backend.h regtab.h analyser.h settings.h \
5SOURCES += main.cpp mainwindow.cpp regtab.cpp backend.cpp analyser.cpp \ 5SOURCES += main.cpp mainwindow.cpp regtab.cpp backend.cpp analyser.cpp \
6 std_analysers.cpp settings.cpp utils.cpp regdisplaypanel.cpp regedit.cpp 6 std_analysers.cpp settings.cpp utils.cpp regdisplaypanel.cpp regedit.cpp
7LIBS += -L../lib/ -lsocdesc -lxml2 7LIBS += -L../lib/ -lsocdesc -lxml2
8INCLUDEPATH += ../lib/ ../../hwstub/lib 8INCLUDEPATH += ../include/ ../../hwstub/lib
9DEPENDPATH += ../ 9DEPENDPATH += ../
10 10
11libsocdesc.commands = cd ../lib && make 11libsocdesc.commands = cd ../lib && make
12QMAKE_EXTRA_TARGETS += libsocdesc 12QMAKE_EXTRA_TARGETS += libsocdesc
13PRE_TARGETDEPS += libsocdesc 13PRE_TARGETDEPS += libsocdesc
14 14
15VERSION = 2.0.4 15VERSION = 2.1.0
16 16
17DEFINES += APP_VERSION=\\\"$$VERSION\\\" 17DEFINES += APP_VERSION=\\\"$$VERSION\\\"
18 18
diff --git a/utils/regtools/qeditor/regedit.cpp b/utils/regtools/qeditor/regedit.cpp
index 851e054eb0..8b4bfb7c49 100644
--- a/utils/regtools/qeditor/regedit.cpp
+++ b/utils/regtools/qeditor/regedit.cpp
@@ -421,7 +421,7 @@ void RegEditPanel::OnFormulaGenerate(bool checked)
421 map["n"] = n; 421 map["n"] = n;
422 std::string err; 422 std::string err;
423 soc_word_t res; 423 soc_word_t res;
424 if(!soc_desc_evaluate_formula(formula, map, res, err)) 424 if(!evaluate_formula(formula, map, res, err))
425 { 425 {
426 qDebug() << "Cannot evaluator " << QString::fromStdString(formula) 426 qDebug() << "Cannot evaluator " << QString::fromStdString(formula)
427 << "for n=" << n << ": " << QString::fromStdString(err); 427 << "for n=" << n << ": " << QString::fromStdString(err);
@@ -1051,8 +1051,8 @@ void RegEdit::OnNew()
1051 1051
1052bool RegEdit::SaveSocFile(const QString& filename) 1052bool RegEdit::SaveSocFile(const QString& filename)
1053{ 1053{
1054 soc_desc_normalize(m_cur_socfile.GetSoc()); 1054 normalize(m_cur_socfile.GetSoc());
1055 if(!soc_desc_produce_xml(filename.toStdString(), m_cur_socfile.GetSoc())) 1055 if(!produce_xml(filename.toStdString(), m_cur_socfile.GetSoc()))
1056 { 1056 {
1057 QMessageBox::warning(this, "The description was not saved", 1057 QMessageBox::warning(this, "The description was not saved",
1058 "There was an error when saving the file"); 1058 "There was an error when saving the file");
diff --git a/utils/regtools/qeditor/utils.cpp b/utils/regtools/qeditor/utils.cpp
index e4a872ed49..2ee1bc6db5 100644
--- a/utils/regtools/qeditor/utils.cpp
+++ b/utils/regtools/qeditor/utils.cpp
@@ -1004,7 +1004,7 @@ void MyTextEditor::SetReadOnly(bool en)
1004 if(en) 1004 if(en)
1005 m_toolbar->hide(); 1005 m_toolbar->hide();
1006 else 1006 else
1007 m_toolbar->hide(); 1007 m_toolbar->show();
1008 m_edit->setReadOnly(en); 1008 m_edit->setReadOnly(en);
1009} 1009}
1010 1010
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
diff --git a/utils/regtools/tester.cpp b/utils/regtools/tester_v1.cpp
index 1beba5fe9b..3ece431531 100644
--- a/utils/regtools/tester.cpp
+++ b/utils/regtools/tester_v1.cpp
@@ -18,12 +18,14 @@
18 * KIND, either express or implied. 18 * KIND, either express or implied.
19 * 19 *
20 ****************************************************************************/ 20 ****************************************************************************/
21#include "soc_desc.hpp" 21#include "soc_desc_v1.hpp"
22#include <stdio.h> 22#include <stdio.h>
23#include <stdlib.h> 23#include <stdlib.h>
24#include <map> 24#include <map>
25#include <cstring> 25#include <cstring>
26 26
27using namespace soc_desc_v1;
28
27template< typename T > 29template< typename T >
28bool build_map(const char *type, const std::vector< T >& vec, 30bool build_map(const char *type, const std::vector< T >& vec,
29 std::map< std::string, size_t >& map) 31 std::map< std::string, size_t >& map)
@@ -244,9 +246,9 @@ int do_compare(int argc, char **argv)
244 if(argc != 2) 246 if(argc != 2)
245 return printf("compare mode expects two arguments\n"); 247 return printf("compare mode expects two arguments\n");
246 soc_t soc[2]; 248 soc_t soc[2];
247 if(!soc_desc_parse_xml(argv[0], soc[0])) 249 if(!parse_xml(argv[0], soc[0]))
248 return printf("cannot read file '%s'\n", argv[0]); 250 return printf("cannot read file '%s'\n", argv[0]);
249 if(!soc_desc_parse_xml(argv[1], soc[1])) 251 if(!parse_xml(argv[1], soc[1]))
250 return printf("cannot read file '%s'\n", argv[1]); 252 return printf("cannot read file '%s'\n", argv[1]);
251 if(compare_soc(soc[0], soc[1])) 253 if(compare_soc(soc[0], soc[1]))
252 printf("Files are identical.\n"); 254 printf("Files are identical.\n");
@@ -258,9 +260,9 @@ int do_write(int argc, char **argv)
258 if(argc != 2) 260 if(argc != 2)
259 return printf("write mode expects two arguments\n"); 261 return printf("write mode expects two arguments\n");
260 soc_t soc; 262 soc_t soc;
261 if(!soc_desc_parse_xml(argv[0], soc)) 263 if(!parse_xml(argv[0], soc))
262 return printf("cannot read file '%s'\n", argv[0]); 264 return printf("cannot read file '%s'\n", argv[0]);
263 if(!soc_desc_produce_xml(argv[1], soc)) 265 if(!produce_xml(argv[1], soc))
264 return printf("cannot write file '%s'\n", argv[1]); 266 return printf("cannot write file '%s'\n", argv[1]);
265 return 0; 267 return 0;
266} 268}
@@ -270,7 +272,7 @@ int do_check(int argc, char **argv)
270 for(int i = 0; i < argc; i++) 272 for(int i = 0; i < argc; i++)
271 { 273 {
272 soc_t soc; 274 soc_t soc;
273 if(!soc_desc_parse_xml(argv[i], soc)) 275 if(!parse_xml(argv[i], soc))
274 { 276 {
275 printf("cannot read file '%s'\n", argv[i]); 277 printf("cannot read file '%s'\n", argv[i]);
276 continue; 278 continue;
@@ -325,7 +327,7 @@ int do_eval(int argc, char **argv)
325 map[name] = v; 327 map[name] = v;
326 continue; 328 continue;
327 } 329 }
328 if(!soc_desc_evaluate_formula(formula, map, result, error)) 330 if(!evaluate_formula(formula, map, result, error))
329 printf("error: %s\n", error.c_str()); 331 printf("error: %s\n", error.c_str());
330 else 332 else
331 printf("result: %lu (%#lx)\n", (unsigned long)result, (unsigned long)result); 333 printf("result: %lu (%#lx)\n", (unsigned long)result, (unsigned long)result);