diff options
author | Amaury Pouly <amaury.pouly@gmail.com> | 2013-06-13 01:50:14 +0200 |
---|---|---|
committer | Amaury Pouly <amaury.pouly@gmail.com> | 2013-06-13 02:25:08 +0200 |
commit | 73db73dbd3c5c6a27e022a5c724136ca6fc2ffe8 (patch) | |
tree | 5e73c4b4477b2f47f4581f68d800ef4cb7b8a37a /utils/regtools/lib | |
parent | 7143ea681c377fe5901bd79801366a26ae0d394a (diff) | |
download | rockbox-73db73dbd3c5c6a27e022a5c724136ca6fc2ffe8.tar.gz rockbox-73db73dbd3c5c6a27e022a5c724136ca6fc2ffe8.zip |
regtools: modify description format and refactor tools
Change the XML description to unify multi dev/reg in a clean
fashion. Move the description parser to its own library. Fix
the tester and headergen tools to work with the new format and
library. Move the STMP3700/3780 descriptions to the new format
(and fixes many errors as well). Drop the hwemulgen tool
in favor on the upcoming hwstub tools revamp.
Change-Id: I7119a187aab5c8b083cc5228cb1b248ee29f184d
Diffstat (limited to 'utils/regtools/lib')
-rw-r--r-- | utils/regtools/lib/Makefile | 23 | ||||
-rw-r--r-- | utils/regtools/lib/soc_desc.cpp | 268 | ||||
-rw-r--r-- | utils/regtools/lib/soc_desc.hpp | 147 |
3 files changed, 438 insertions, 0 deletions
diff --git a/utils/regtools/lib/Makefile b/utils/regtools/lib/Makefile new file mode 100644 index 0000000000..ef8d4c0533 --- /dev/null +++ b/utils/regtools/lib/Makefile @@ -0,0 +1,23 @@ +CC=gcc +CXX=g++ +AR=ar +CFLAGS=-Wall -O2 `xml2-config --cflags` -std=c99 -g -fPIC +CXXFLAGS=-Wall -O2 `xml2-config --cflags` -g -fPIC +LIB=libsocdesc.a +SRC=$(wildcard *.c) +SRCXX=$(wildcard *.cpp) +OBJ=$(SRC:.c=.o) $(SRCXX:.cpp=.o) + +all: $(LIB) $(EXEC) + +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + +%.o: %.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< + +$(LIB): $(OBJ) + $(AR) rcs $@ $^ + +clean: + rm -rf $(OBJ) $(LIB)
\ No newline at end of file diff --git a/utils/regtools/lib/soc_desc.cpp b/utils/regtools/lib/soc_desc.cpp new file mode 100644 index 0000000000..413c30936f --- /dev/null +++ b/utils/regtools/lib/soc_desc.cpp @@ -0,0 +1,268 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2012 by Amaury Pouly + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "soc_desc.hpp" +#include <libxml/parser.h> +#include <libxml/tree.h> +#include <stdio.h> +#include <string.h> + +#define XML_CHAR_TO_CHAR(s) ((const char *)(s)) + +#define BEGIN_ATTR_MATCH(attr) \ + for(xmlAttr *a = attr; a; a = a->next) { + +#define MATCH_X_ATTR(attr_name, hook, ...) \ + if(strcmp(XML_CHAR_TO_CHAR(a->name), attr_name) == 0) { \ + std::string s; \ + if(!parse_text_attr(a, s) || !hook(s, __VA_ARGS__)) \ + return false; \ + } + +#define SOFT_MATCH_X_ATTR(attr_name, hook, ...) \ + if(strcmp(XML_CHAR_TO_CHAR(a->name), attr_name) == 0) { \ + std::string s; \ + if(parse_text_attr(a, s)) \ + hook(s, __VA_ARGS__); \ + } + +#define SOFT_MATCH_SCT_ATTR(attr_name, var) \ + SOFT_MATCH_X_ATTR(attr_name, validate_sct_hook, var) + +#define MATCH_TEXT_ATTR(attr_name, var) \ + MATCH_X_ATTR(attr_name, validate_string_hook, var) + +#define MATCH_UINT32_ATTR(attr_name, var) \ + MATCH_X_ATTR(attr_name, validate_uint32_hook, var) + +#define MATCH_BITRANGE_ATTR(attr_name, first, last) \ + MATCH_X_ATTR(attr_name, validate_bitrange_hook, first, last) + +#define END_ATTR_MATCH() \ + } + +#define BEGIN_NODE_MATCH(node) \ + for(xmlNode *sub = node; sub; sub = sub->next) { + +#define MATCH_ELEM_NODE(node_name, array, parse_fn) \ + if(sub->type == XML_ELEMENT_NODE && strcmp(XML_CHAR_TO_CHAR(sub->name), node_name) == 0) { \ + array.resize(array.size() + 1); \ + if(!parse_fn(sub, array[array.size() - 1])) \ + return false; \ + } + +#define SOFT_MATCH_ELEM_NODE(node_name, array, parse_fn) \ + if(sub->type == XML_ELEMENT_NODE && strcmp(XML_CHAR_TO_CHAR(sub->name), node_name) == 0) { \ + array.resize(array.size() + 1); \ + if(!parse_fn(sub, array[array.size() - 1])) \ + array.pop_back(); \ + } + +#define END_NODE_MATCH() \ + } + +bool validate_string_hook(const std::string& str, std::string& s) +{ + s = str; + return true; +} + +bool validate_sct_hook(const std::string& str, soc_reg_flags_t& flags) +{ + if(str == "yes") flags |= REG_HAS_SCT; + else if(str != "no") return false; + return true; +} + +bool validate_unsigned_long_hook(const std::string& str, unsigned long& s) +{ + char *end; + s = strtoul(str.c_str(), &end, 0); + return *end == 0; +} + +bool validate_uint32_hook(const std::string& str, uint32_t& s) +{ + unsigned long u; + if(!validate_unsigned_long_hook(str, u)) return false; +#if ULONG_MAX > UINT32_MAX + if(u > UINT32_MAX) return false; +#endif + s = u; + return true; +} + +bool validate_bitrange_hook(const std::string& str, unsigned& first, unsigned& last) +{ + unsigned long a, b; + size_t sep = str.find(':'); + if(sep == std::string::npos) return false; + if(!validate_unsigned_long_hook(str.substr(0, sep), a)) return false; + if(!validate_unsigned_long_hook(str.substr(sep + 1), b)) return false; + if(a > 31 || b > 31 || a < b) return false; + first = b; + last = a; + return true; +} + +bool parse_text_attr(xmlAttr *attr, std::string& s) +{ + if(attr->children != attr->last) + return false; + if(attr->children->type != XML_TEXT_NODE) + return false; + s = XML_CHAR_TO_CHAR(attr->children->content); + return true; +} + +bool parse_value_elem(xmlNode *node, soc_reg_field_value_t& value) +{ + BEGIN_ATTR_MATCH(node->properties) + MATCH_TEXT_ATTR("name", value.name) + MATCH_UINT32_ATTR("value", value.value) + END_ATTR_MATCH() + + return true; +} + +bool parse_field_elem(xmlNode *node, soc_reg_field_t& field) +{ + BEGIN_ATTR_MATCH(node->properties) + MATCH_TEXT_ATTR("name", field.name) + MATCH_BITRANGE_ATTR("bitrange", field.first_bit, field.last_bit) + END_ATTR_MATCH() + + BEGIN_NODE_MATCH(node->children) + SOFT_MATCH_ELEM_NODE("value", field.value, parse_value_elem) + END_NODE_MATCH() + + return true; +} + +bool parse_reg_addr_elem(xmlNode *node, soc_reg_addr_t& addr) +{ + BEGIN_ATTR_MATCH(node->properties) + MATCH_TEXT_ATTR("name", addr.name) + MATCH_UINT32_ATTR("addr", addr.addr) + END_ATTR_MATCH() + + return true; +} + +bool parse_reg_formula_elem(xmlNode *node, soc_reg_formula_t& formula) +{ + BEGIN_ATTR_MATCH(node->properties) + MATCH_TEXT_ATTR("string", formula.string) + END_ATTR_MATCH() + + formula.type = REG_FORMULA_STRING; + + return true; +} + +bool parse_reg_elem(xmlNode *node, soc_reg_t& reg) +{ + std::vector< soc_reg_formula_t > formulas; + BEGIN_ATTR_MATCH(node->properties) + MATCH_TEXT_ATTR("name", reg.name) + SOFT_MATCH_SCT_ATTR("sct", reg.flags) + END_ATTR_MATCH() + + BEGIN_NODE_MATCH(node->children) + MATCH_ELEM_NODE("addr", reg.addr, parse_reg_addr_elem) + MATCH_ELEM_NODE("formula", formulas, parse_reg_formula_elem) + MATCH_ELEM_NODE("field", reg.field, parse_field_elem) + END_NODE_MATCH() + + if(formulas.size() > 1) + { + fprintf(stderr, "Only one formula is allowed per register\n"); + return false; + } + if(formulas.size() == 1) + reg.formula = formulas[0]; + + return true; +} + +bool parse_dev_addr_elem(xmlNode *node, soc_dev_addr_t& addr) +{ + BEGIN_ATTR_MATCH(node->properties) + MATCH_TEXT_ATTR("name", addr.name) + MATCH_UINT32_ATTR("addr", addr.addr) + END_ATTR_MATCH() + + return true; +} + +bool parse_dev_elem(xmlNode *node, soc_dev_t& dev) +{ + BEGIN_ATTR_MATCH(node->properties) + MATCH_TEXT_ATTR("name", dev.name) + MATCH_TEXT_ATTR("version", dev.version) + END_ATTR_MATCH() + + BEGIN_NODE_MATCH(node->children) + MATCH_ELEM_NODE("addr", dev.addr, parse_dev_addr_elem) + MATCH_ELEM_NODE("reg", dev.reg, parse_reg_elem) + END_NODE_MATCH() + + return true; +} + +bool parse_soc_elem(xmlNode *node, soc_t& soc) +{ + BEGIN_ATTR_MATCH(node->properties) + MATCH_TEXT_ATTR("name", soc.name) + MATCH_TEXT_ATTR("desc", soc.desc) + END_ATTR_MATCH() + + BEGIN_NODE_MATCH(node->children) + MATCH_ELEM_NODE("dev", soc.dev, parse_dev_elem) + END_NODE_MATCH() + + return true; +} + +bool parse_root_elem(xmlNode *node, std::vector< soc_t >& soc) +{ + BEGIN_NODE_MATCH(node) + MATCH_ELEM_NODE("soc", soc, parse_soc_elem) + END_NODE_MATCH() + return true; +} + +bool soc_desc_parse_xml(const std::string& filename, std::vector< soc_t >& socs) +{ + LIBXML_TEST_VERSION + + xmlDoc *doc = xmlReadFile(filename.c_str(), NULL, 0); + if(doc == NULL) + return false; + + xmlNode *root_element = xmlDocGetRootElement(doc); + + bool ret = parse_root_elem(root_element, socs); + + xmlFreeDoc(doc); + xmlCleanupParser(); + + return ret; +}
\ No newline at end of file diff --git a/utils/regtools/lib/soc_desc.hpp b/utils/regtools/lib/soc_desc.hpp new file mode 100644 index 0000000000..476ea1d242 --- /dev/null +++ b/utils/regtools/lib/soc_desc.hpp @@ -0,0 +1,147 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2012 by Amaury Pouly + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef __SOC_DESC__ +#define __SOC_DESC__ + +#include <stdint.h> +#include <vector> +#include <string> + +/** + * These data structures represent the SoC register in a convenient way. + * The basic structure is the following: + * - each SoC has several devices + * - each device has a generic name, a list of {name,address} and several registers + * - each register has a generic name, a list of {name,address}, flags, + * several fields + * - each field has a name, a first and last bit position, can apply either + * to all addresses of a register or be specific to one only and has several values + * - each field value has a name and a value + * + * All addresses, values and names are relative to the parents. For example a field + * value BV_LCDIF_CTRL_WORD_LENGTH_18_BIT is represented has: + * - device LCDIF, register CTRL, field WORD_LENGTH, value 16_BIT + * The address of CTRL is related to the address of LCDIF, the value of 16_BIT + * ignores the position of the WORD_LENGTH field in the register. + */ + +/** + * Typedef for SoC types: word, address and flags */ +typedef uint32_t soc_addr_t; +typedef uint32_t soc_word_t; +typedef uint32_t soc_reg_flags_t; + +/** SoC register generic formula */ +enum soc_reg_formula_type_t +{ + REG_FORMULA_NONE, /// register has no generic formula + REG_FORMULA_STRING, /// register has a generic formula represented by a string +}; + +/** <soc_reg_t>.<flags> values */ +const soc_reg_flags_t REG_HAS_SCT = 1 << 0; /// register SCT variants + +/** SoC register field named value */ +struct soc_reg_field_value_t +{ + std::string name; + soc_word_t value; +}; + +/** SoC register field */ +struct soc_reg_field_t +{ + std::string name; + unsigned first_bit, last_bit; + + soc_word_t bitmask() const + { + // WARNING beware of the case where first_bit=0 and last_bit=31 + if(first_bit == 0 && last_bit == 31) + return 0xffffffff; + else + return ((1 << (last_bit - first_bit + 1)) - 1) << first_bit; + } + + bool is_reserved() const + { + return name.substr(0, 4) == "RSVD" || name.substr(0, 5) == "RSRVD"; + } + + std::vector< soc_reg_field_value_t > value; +}; + +/** SoC register address */ +struct soc_reg_addr_t +{ + std::string name; /// actual register name + soc_addr_t addr; +}; + +/** SoC register formula */ +struct soc_reg_formula_t +{ + enum soc_reg_formula_type_t type; + std::string string; /// for STRING +}; + +/** SoC register */ +struct soc_reg_t +{ + std::string name; /// generic name (for multi registers) or actual name + std::vector< soc_reg_addr_t > addr; + soc_reg_formula_t formula; + soc_reg_flags_t flags; /// ORed value + + std::vector< soc_reg_field_t > field; +}; + +/** Soc device address */ +struct soc_dev_addr_t +{ + std::string name; /// actual device name + soc_addr_t addr; +}; + +/** SoC device */ +struct soc_dev_t +{ + std::string name; /// generic name (of multi devices) or actual name + std::string version; /// description version + std::vector< soc_dev_addr_t > addr; + + std::vector< soc_reg_t > reg; +}; + +/** SoC */ +struct soc_t +{ + std::string name; /// codename (rockbox) + std::string desc; /// SoC name + + std::vector< soc_dev_t > dev; +}; + +/** Parse a SoC description from a XML file, append it to <soc>. A file + * can contain multiple SoC descriptions */ +bool soc_desc_parse_xml(const std::string& filename, std::vector< soc_t >& soc); + +#endif /* __SOC_DESC__ */
\ No newline at end of file |