diff options
author | Amaury Pouly <amaury.pouly@gmail.com> | 2014-12-14 11:53:55 +0100 |
---|---|---|
committer | Amaury Pouly <amaury.pouly@gmail.com> | 2015-09-11 16:40:19 +0200 |
commit | 1cada1f8339d6b5f8506277f80e62aaef77ab774 (patch) | |
tree | 8477120e97832d659d2ffc471a8bfde73ad4c36e /utils/regtools/lib/soc_desc.cpp | |
parent | c8d3638b9ebc24e4766714da1c9f961e350799c6 (diff) | |
download | rockbox-1cada1f8339d6b5f8506277f80e62aaef77ab774.tar.gz rockbox-1cada1f8339d6b5f8506277f80e62aaef77ab774.zip |
soc_desc: new version of the desc file format
Fix qeditor to use the old soc_desc_v1.
Port hwstub_shell to the new description format.
Change-Id: I9fefbff534bfaa5c3603bb3dd8307a2b76e88cfc
Diffstat (limited to 'utils/regtools/lib/soc_desc.cpp')
-rw-r--r-- | utils/regtools/lib/soc_desc.cpp | 1530 |
1 files changed, 866 insertions, 664 deletions
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 | |||