diff options
Diffstat (limited to 'utils/regtools/lib/soc_desc_v1.cpp')
-rw-r--r-- | utils/regtools/lib/soc_desc_v1.cpp | 990 |
1 files changed, 990 insertions, 0 deletions
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 | ||