diff options
Diffstat (limited to 'utils/regtools/lib')
-rw-r--r-- | utils/regtools/lib/Makefile | 9 | ||||
-rw-r--r-- | utils/regtools/lib/formula.cpp | 214 | ||||
-rw-r--r-- | utils/regtools/lib/soc_desc.cpp | 1530 | ||||
-rw-r--r-- | utils/regtools/lib/soc_desc.hpp | 228 | ||||
-rw-r--r-- | utils/regtools/lib/soc_desc_v1.cpp | 990 |
5 files changed, 2073 insertions, 898 deletions
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 @@ | |||
1 | CC?=gcc | 1 | CC?=gcc |
2 | CXX?=g++ | 2 | CXX?=g++ |
3 | AR?=ar | 3 | AR?=ar |
4 | CFLAGS=-Wall -O2 `xml2-config --cflags` -std=c99 -g -fPIC | 4 | INCLUDE=../include/ |
5 | CXXFLAGS=-Wall -O2 `xml2-config --cflags` -g -fPIC | 5 | CXXFLAGS=-Wall -O2 `xml2-config --cflags` -g -fPIC -I$(INCLUDE) |
6 | LIB=libsocdesc.a | 6 | LIB=libsocdesc.a |
7 | SRC=$(wildcard *.c) | 7 | SRC=$(wildcard *.c) |
8 | SRCXX=$(wildcard *.cpp) | 8 | SRCXX=$(wildcard *.cpp) |
9 | OBJ=$(SRC:.c=.o) $(SRCXX:.cpp=.o) | 9 | OBJ=$(SRCXX:.cpp=.o) |
10 | 10 | ||
11 | all: $(LIB) $(EXEC) | 11 | all: $(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 | |||
5 | using namespace soc_desc; | ||
6 | |||
7 | namespace soc_desc | ||
8 | { | ||
9 | |||
10 | namespace | ||
11 | { | ||
12 | |||
13 | struct 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 | |||
182 | struct 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 | |||
205 | bool 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 | |||
33 | namespace 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 | |||
85 | namespace | 111 | namespace |
86 | { | 112 | { |
87 | 113 | ||
88 | bool validate_string_hook(const std::string& str, std::string& s) | 114 | bool 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 | ||
94 | bool validate_sct_hook(const std::string& str, soc_reg_flags_t& flags) | 122 | std::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 | ||
101 | bool validate_unsigned_long_hook(const std::string& str, unsigned long& s) | 129 | std::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 | ||
108 | bool validate_uint32_hook(const std::string& str, uint32_t& s) | 134 | template<typename T> |
135 | bool 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 | ||
119 | bool validate_bitrange_hook(const std::string& str, unsigned& first, unsigned& last) | 142 | template<typename T> |
143 | bool 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 | ||
132 | bool parse_text_attr(xmlAttr *attr, std::string& s) | 148 | template<typename T> |
149 | bool 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 | ||
142 | bool parse_value_elem(xmlNode *node, soc_reg_field_value_t& value) | 154 | bool 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; | 161 | bool 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 | ||
153 | bool parse_field_elem(xmlNode *node, soc_reg_field_t& field) | 172 | bool 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) | 180 | bool 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; | 191 | bool 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 | ||
168 | bool parse_reg_addr_elem(xmlNode *node, soc_reg_addr_t& addr) | 199 | bool 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; | 211 | bool 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 | ||
178 | bool parse_reg_formula_elem(xmlNode *node, soc_reg_formula_t& formula) | 216 | bool 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; | 221 | bool 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 | ||
227 | bool 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 | ||
189 | bool parse_add_trivial_addr(const std::string& str, soc_reg_t& reg) | 238 | template<typename T, typename U> |
239 | bool 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 | ||
199 | bool parse_reg_elem(xmlNode *node, soc_reg_t& reg) | 251 | template<typename T> |
252 | bool 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) | 257 | template<typename T> |
210 | MATCH_ELEM_NODE("addr", reg.addr, parse_reg_addr_elem) | 258 | bool 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) | 263 | bool 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 | ||
226 | bool parse_dev_addr_elem(xmlNode *node, soc_dev_addr_t& addr) | 273 | bool 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 | ||
236 | bool parse_dev_elem(xmlNode *node, soc_dev_t& dev) | 279 | bool 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 | ||
293 | bool 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; | 311 | bool 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 | ||
253 | bool parse_soc_elem(xmlNode *node, soc_t& soc) | 324 | bool 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 | ||
335 | bool 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; | 365 | bool 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 | ||
267 | bool parse_root_elem(xmlNode *node, soc_t& soc) | 389 | bool 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 | |||
409 | bool 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 | |||
427 | bool 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 | ||
284 | bool soc_desc_parse_xml(const std::string& filename, soc_t& socs) | 451 | bool 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 | |||
300 | namespace | 472 | namespace |
301 | { | 473 | { |
302 | 474 | ||
303 | int 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 | |||
485 | int 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 | |||
335 | int 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())); | 517 | int 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 | |||
540 | int 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 | |||
556 | int 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 | |||
578 | int 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 | ||
385 | int produce_dev(xmlTextWriterPtr writer, const soc_dev_t& dev) | 593 | int 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 | ||
421 | bool soc_desc_produce_xml(const std::string& filename, const soc_t& soc) | 623 | bool 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 | ||
454 | namespace | 673 | /** |
674 | * soc_ref_t | ||
675 | */ | ||
676 | |||
677 | soc_ref_t::soc_ref_t():m_soc(0) | ||
455 | { | 678 | { |
679 | } | ||
456 | 680 | ||
457 | struct soc_sorter | 681 | soc_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 | 685 | bool 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 | 690 | soc_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 | 695 | bool 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 | 700 | node_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 | 705 | node_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 | ||
492 | void normalize(soc_reg_field_t& field) | 710 | /** |
711 | * node_ref_t */ | ||
712 | |||
713 | node_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 | ||
497 | void normalize(soc_reg_t& reg) | 717 | node_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 | ||
505 | void normalize(soc_dev_t& dev) | 722 | node_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 | ||
726 | bool node_ref_t::valid() const | ||
727 | { | ||
728 | return (m_soc.valid() && is_root()) || get() != 0; | ||
513 | } | 729 | } |
514 | 730 | ||
515 | void soc_desc_normalize(soc_t& soc) | 731 | bool 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 | ||
522 | namespace | 736 | namespace |
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) | 739 | std::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) | 747 | node_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, | 757 | node_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() ! */ |
770 | node_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) | 787 | soc_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) | 792 | node_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 | ||
584 | std::vector< soc_error_t > soc_reg_field_value_t::errors(bool recursive) | 800 | register_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 | ||
595 | std::vector< soc_error_t > soc_reg_field_t::errors(bool recursive) | 811 | node_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")); | 822 | std::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 | |||
837 | std::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 | ||
628 | std::vector< soc_error_t > soc_reg_addr_t::errors(bool recursive) | 859 | std::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 | ||
639 | std::vector< soc_error_t > soc_reg_formula_t::errors(bool recursive) | 865 | bool 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 | ||
648 | namespace | 870 | /** |
871 | * register_ref_t | ||
872 | */ | ||
873 | |||
874 | register_ref_t::register_ref_t(node_ref_t node) | ||
875 | :m_node(node) | ||
649 | { | 876 | { |
877 | } | ||
650 | 878 | ||
651 | bool field_overlap(const soc_reg_field_t& a, const soc_reg_field_t& b) | 879 | register_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 | ||
883 | bool register_ref_t::valid() const | ||
884 | { | ||
885 | return get() != 0; | ||
656 | } | 886 | } |
657 | 887 | ||
658 | std::vector< soc_error_t > soc_reg_t::errors(bool recursive) | 888 | register_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 | ||
703 | std::vector< soc_error_t > soc_dev_addr_t::errors(bool recursive) | 896 | node_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 | ||
714 | std::vector< soc_error_t > soc_dev_t::errors(bool recursive) | 901 | std::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 | ||
754 | std::vector< soc_error_t > soc_t::errors(bool recursive) | 912 | field_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 | ||
774 | namespace | 923 | /** |
924 | * field_ref_t | ||
925 | */ | ||
926 | |||
927 | field_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 | ||
777 | struct formula_evaluator | 932 | field_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, ...) | 936 | bool 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) | 941 | field_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 ®->field[i]; | ||
949 | return 0; | ||
950 | } | ||
800 | 951 | ||
801 | void adv() | 952 | register_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() | 961 | namespace |
812 | { | 962 | { |
813 | return pos >= formula.size(); | 963 | |
814 | } | 964 | const 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) | 966 | bool 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) | 991 | bool 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) | 1013 | node_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) | 1018 | node_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 | ||
941 | struct my_evaluator : public formula_evaluator | 1024 | node_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) | 1028 | bool 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) | 1033 | node_ref_t node_inst_t::node() const |
1034 | { | ||
1035 | return m_node; | ||
1036 | } | ||
1037 | |||
1038 | soc_ref_t node_inst_t::soc() const | ||
1039 | { | ||
1040 | return m_node.soc(); | ||
1041 | } | ||
1042 | |||
1043 | bool node_inst_t::is_root() const | ||
1044 | { | ||
1045 | return m_node.is_root(); | ||
1046 | } | ||
1047 | |||
1048 | node_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 | |||
1059 | instance_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 | |||
1070 | soc_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 | |||
1080 | node_inst_t node_inst_t::child(const std::string& name) const | ||
1081 | { | ||
1082 | return child(name, INST_NO_INDEX); | ||
1083 | } | ||
1084 | |||
1085 | |||
1086 | node_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 | |||
1111 | std::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 | |||
1153 | std::string node_inst_t::name() const | ||
1154 | { | ||
1155 | instance_t *inst = get(); | ||
1156 | return inst == 0 ? "" : inst->name; | ||
1157 | } | ||
960 | 1158 | ||
1159 | bool node_inst_t:: is_indexed() const | ||
1160 | { | ||
1161 | return !m_index_path.empty() && m_index_path.back() != INST_NO_INDEX; | ||
961 | } | 1162 | } |
962 | 1163 | ||
963 | bool soc_desc_evaluate_formula(const std::string& formula, | 1164 | size_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 | ||
984 | xml_parser_init __xml_parser_init; | 1183 | xml_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.hpp b/utils/regtools/lib/soc_desc.hpp deleted file mode 100644 index bb8eb4ba8d..0000000000 --- a/utils/regtools/lib/soc_desc.hpp +++ /dev/null | |||
@@ -1,228 +0,0 @@ | |||
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 | #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 | |||
30 | /** | ||
31 | * These data structures represent the SoC register in a convenient way. | ||
32 | * The basic structure is the following: | ||
33 | * - each SoC has several devices | ||
34 | * - each device has a generic name, a list of {name,address} and several registers | ||
35 | * - each register has a generic name, a list of {name,address}, flags, | ||
36 | * several fields | ||
37 | * - each field has a name, a first and last bit position, can apply either | ||
38 | * to all addresses of a register or be specific to one only and has several values | ||
39 | * - each field value has a name and a value | ||
40 | * | ||
41 | * All addresses, values and names are relative to the parents. For example a field | ||
42 | * value BV_LCDIF_CTRL_WORD_LENGTH_18_BIT is represented has: | ||
43 | * - device LCDIF, register CTRL, field WORD_LENGTH, value 16_BIT | ||
44 | * The address of CTRL is related to the address of LCDIF, the value of 16_BIT | ||
45 | * ignores the position of the WORD_LENGTH field in the register. | ||
46 | */ | ||
47 | |||
48 | #define SOCDESC_VERSION_MAJOR 1 | ||
49 | #define SOCDESC_VERSION_MINOR 4 | ||
50 | #define SOCDESC_VERSION_REV 1 | ||
51 | |||
52 | #define SOCDESC_VERSION__(maj,min,rev) #maj"."#min"."#rev | ||
53 | #define SOCDESC_VERSION_(maj,min,rev) SOCDESC_VERSION__(maj,min,rev) | ||
54 | #define SOCDESC_VERSION SOCDESC_VERSION_(SOCDESC_VERSION_MAJOR,SOCDESC_VERSION_MINOR,SOCDESC_VERSION_REV) | ||
55 | |||
56 | /** | ||
57 | * Typedef for SoC types: word, address and flags */ | ||
58 | typedef uint32_t soc_addr_t; | ||
59 | typedef uint32_t soc_word_t; | ||
60 | typedef uint32_t soc_reg_flags_t; | ||
61 | |||
62 | /** SoC error gravity level */ | ||
63 | enum soc_error_level_t | ||
64 | { | ||
65 | SOC_ERROR_WARNING, | ||
66 | SOC_ERROR_FATAL, | ||
67 | }; | ||
68 | |||
69 | /** SoC description error */ | ||
70 | struct soc_error_t | ||
71 | { | ||
72 | soc_error_level_t level; /// level (warning, fatal, ...) | ||
73 | std::string location; /// human description of the location | ||
74 | std::string message; /// message | ||
75 | }; | ||
76 | |||
77 | /** SoC register generic formula */ | ||
78 | enum soc_reg_formula_type_t | ||
79 | { | ||
80 | REG_FORMULA_NONE, /// register has no generic formula | ||
81 | REG_FORMULA_STRING, /// register has a generic formula represented by a string | ||
82 | }; | ||
83 | |||
84 | /** <soc_reg_t>.<flags> values */ | ||
85 | const soc_reg_flags_t REG_HAS_SCT = 1 << 0; /// register SCT variants | ||
86 | |||
87 | /** SoC register field named value */ | ||
88 | struct soc_reg_field_value_t | ||
89 | { | ||
90 | std::string name; /// name of the value | ||
91 | soc_word_t value; /// numeric value | ||
92 | std::string desc; /// human description | ||
93 | |||
94 | std::vector< soc_error_t > errors(bool recursive); | ||
95 | }; | ||
96 | |||
97 | /** SoC register field */ | ||
98 | struct soc_reg_field_t | ||
99 | { | ||
100 | std::string name; /// name of the field | ||
101 | std::string desc; /// human description | ||
102 | unsigned first_bit, last_bit; /// bit range of the field | ||
103 | |||
104 | soc_reg_field_t():first_bit(0), last_bit(31) {} | ||
105 | |||
106 | /** Return field bitmask in register */ | ||
107 | soc_word_t bitmask() const | ||
108 | { | ||
109 | // WARNING beware of the case where first_bit=0 and last_bit=31 | ||
110 | if(first_bit == 0 && last_bit == 31) | ||
111 | return 0xffffffff; | ||
112 | else | ||
113 | return ((1 << (last_bit - first_bit + 1)) - 1) << first_bit; | ||
114 | } | ||
115 | |||
116 | /** Extract field value from register value */ | ||
117 | soc_word_t extract(soc_word_t reg_val) const | ||
118 | { | ||
119 | return (reg_val & bitmask()) >> first_bit; | ||
120 | } | ||
121 | |||
122 | /** Replace the field value in a register value */ | ||
123 | soc_word_t replace(soc_word_t reg_val, soc_word_t field_val) const | ||
124 | { | ||
125 | return (reg_val & ~bitmask()) | ((field_val << first_bit) & bitmask()); | ||
126 | } | ||
127 | |||
128 | bool is_reserved() const | ||
129 | { | ||
130 | return name.substr(0, 4) == "RSVD" || name.substr(0, 5) == "RSRVD"; | ||
131 | } | ||
132 | |||
133 | /** Return field value index, or -1 if none */ | ||
134 | int find_value(soc_word_t v) const | ||
135 | { | ||
136 | for(size_t i = 0; i < value.size(); i++) | ||
137 | if(value[i].value == v) | ||
138 | return i; | ||
139 | return -1; | ||
140 | } | ||
141 | |||
142 | std::vector< soc_reg_field_value_t > value; | ||
143 | |||
144 | std::vector< soc_error_t > errors(bool recursive); | ||
145 | }; | ||
146 | |||
147 | /** SoC register address */ | ||
148 | struct soc_reg_addr_t | ||
149 | { | ||
150 | std::string name; /// actual register name | ||
151 | soc_addr_t addr; /// actual register address (relative to device) | ||
152 | |||
153 | std::vector< soc_error_t > errors(bool recursive); | ||
154 | }; | ||
155 | |||
156 | /** SoC register formula */ | ||
157 | struct soc_reg_formula_t | ||
158 | { | ||
159 | enum soc_reg_formula_type_t type; | ||
160 | std::string string; /// for STRING | ||
161 | |||
162 | std::vector< soc_error_t > errors(bool recursive); | ||
163 | }; | ||
164 | |||
165 | /** SoC register */ | ||
166 | struct soc_reg_t | ||
167 | { | ||
168 | std::string name; /// generic name (for multi registers) or actual name | ||
169 | std::string desc; /// human description | ||
170 | std::vector< soc_reg_addr_t > addr; /// instances of the registers | ||
171 | soc_reg_formula_t formula; /// formula for the instance addresses | ||
172 | soc_reg_flags_t flags; /// ORed value | ||
173 | |||
174 | std::vector< soc_reg_field_t > field; | ||
175 | |||
176 | std::vector< soc_error_t > errors(bool recursive); | ||
177 | }; | ||
178 | |||
179 | /** Soc device address */ | ||
180 | struct soc_dev_addr_t | ||
181 | { | ||
182 | std::string name; /// actual device name | ||
183 | soc_addr_t addr; | ||
184 | |||
185 | std::vector< soc_error_t > errors(bool recursive); | ||
186 | }; | ||
187 | |||
188 | /** SoC device */ | ||
189 | struct soc_dev_t | ||
190 | { | ||
191 | std::string name; /// generic name (of multi devices) or actual name | ||
192 | std::string long_name; /// human friendly name | ||
193 | std::string desc; /// human description | ||
194 | std::string version; /// description version | ||
195 | std::vector< soc_dev_addr_t > addr; | ||
196 | |||
197 | std::vector< soc_reg_t > reg; | ||
198 | |||
199 | std::vector< soc_error_t > errors(bool recursive); | ||
200 | }; | ||
201 | |||
202 | /** SoC */ | ||
203 | struct soc_t | ||
204 | { | ||
205 | std::string name; /// codename (rockbox) | ||
206 | std::string desc; /// SoC name | ||
207 | |||
208 | std::vector< soc_dev_t > dev; | ||
209 | |||
210 | std::vector< soc_error_t > errors(bool recursive); | ||
211 | }; | ||
212 | |||
213 | /** Parse a SoC description from a XML file, append it to <soc>. */ | ||
214 | bool soc_desc_parse_xml(const std::string& filename, soc_t& soc); | ||
215 | /** Write a SoC description to a XML file, overwriting it. A file can contain | ||
216 | * multiple Soc descriptions */ | ||
217 | bool soc_desc_produce_xml(const std::string& filename, const soc_t& soc); | ||
218 | /** Normalise a soc description by reordering elemnts so that: | ||
219 | * - devices are sorted by first name | ||
220 | * - registers are sorted by first address | ||
221 | * - fields are sorted by last bit | ||
222 | * - values are sorted by value */ | ||
223 | void soc_desc_normalize(soc_t& soc); | ||
224 | /** Formula parser: try to parse and evaluate a formula to a specific value of 'n' */ | ||
225 | bool soc_desc_evaluate_formula(const std::string& formula, | ||
226 | const std::map< std::string, soc_word_t>& var, soc_word_t& result, std::string& error); | ||
227 | |||
228 | #endif /* __SOC_DESC__ */ \ No newline at end of file | ||
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 | |||
31 | namespace 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 | |||
88 | namespace | ||
89 | { | ||
90 | |||
91 | bool validate_string_hook(const std::string& str, std::string& s) | ||
92 | { | ||
93 | s = str; | ||
94 | return true; | ||
95 | } | ||
96 | |||
97 | bool 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 | |||
104 | bool 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 | |||
111 | bool 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 | |||
122 | bool 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 | |||
135 | bool 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 | |||
145 | bool 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 | |||
156 | bool 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 | |||
171 | bool 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 | |||
181 | bool 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 | |||
192 | bool 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 | |||
202 | bool 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 | |||
229 | bool 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 | |||
239 | bool 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 | |||
256 | bool 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 | |||
270 | bool 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 | |||
287 | bool 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 | |||
303 | namespace | ||
304 | { | ||
305 | |||
306 | int 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 | |||
338 | int 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 | |||
388 | int 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 | |||
424 | bool 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 | ||
452 | Lerr: | ||
453 | xmlFreeTextWriter(writer); | ||
454 | return false; | ||
455 | } | ||
456 | |||
457 | namespace | ||
458 | { | ||
459 | |||
460 | struct 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 | |||
495 | void normalize(soc_reg_field_t& field) | ||
496 | { | ||
497 | std::sort(field.value.begin(), field.value.end(), soc_sorter()); | ||
498 | } | ||
499 | |||
500 | void 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 | |||
508 | void 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 | |||
518 | void 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 | |||
525 | namespace | ||
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 | |||
587 | std::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 | |||
598 | std::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 | |||
631 | std::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 | |||
642 | std::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 | |||
651 | namespace | ||
652 | { | ||
653 | |||
654 | bool 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 | |||
661 | std::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 | |||
706 | std::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 | |||
717 | std::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 | |||
757 | std::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 | |||
777 | namespace | ||
778 | { | ||
779 | |||
780 | struct 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 | |||
944 | struct 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 | |||
966 | bool 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 */ | ||
976 | namespace | ||
977 | { | ||
978 | class xml_parser_init | ||
979 | { | ||
980 | public: | ||
981 | xml_parser_init() | ||
982 | { | ||
983 | xmlInitParser(); | ||
984 | } | ||
985 | }; | ||
986 | |||
987 | xml_parser_init __xml_parser_init; | ||
988 | } | ||
989 | |||
990 | } // soc_desc_v1 | ||