A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2014 by Amaury Pouly
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include "soc_desc.hpp"
22#include <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#include <sstream>
31#include <limits>
32
33namespace soc_desc
34{
35
36/**
37 * Parser
38 */
39
40#define XML_CHAR_TO_CHAR(s) ((const char *)(s))
41
42#define BEGIN_ATTR_MATCH(attr) \
43 for(xmlAttr *a = attr; a; a = a->next) { \
44 bool used = false;
45
46#define MATCH_UNIQUE_ATTR(attr_name, val, has, parse_fn, ctx) \
47 if(strcmp(XML_CHAR_TO_CHAR(a->name), attr_name) == 0) { \
48 if(has) \
49 return parse_not_unique_attr_error(a, ctx); \
50 has = true; \
51 xmlChar *str = NULL; \
52 if(!parse_text_attr_internal(a, str, ctx) || !parse_fn(a, val, str, ctx)) \
53 ret = false; \
54 used = true; \
55 }
56
57#define MATCH_UNUSED_ATTR(parse_fn, ctx) \
58 if(!used) { \
59 ret = ret && parse_fn(a, ctx); \
60 }
61
62#define END_ATTR_MATCH() \
63 }
64
65#define BEGIN_NODE_MATCH(node) \
66 for(xmlNode *sub = node; sub; sub = sub->next) { \
67 bool used = false; \
68
69#define MATCH_ELEM_NODE(node_name, array, parse_fn, ctx) \
70 if(sub->type == XML_ELEMENT_NODE && strcmp(XML_CHAR_TO_CHAR(sub->name), node_name) == 0) { \
71 array.resize(array.size() + 1); \
72 if(!parse_fn(sub, array.back(), ctx)) \
73 ret = false; \
74 array.back().id = array.size(); \
75 used = true; \
76 }
77
78#define MATCH_TEXT_NODE(node_name, array, parse_fn, ctx) \
79 if(sub->type == XML_ELEMENT_NODE && strcmp(XML_CHAR_TO_CHAR(sub->name), node_name) == 0) { \
80 if(!is_real_text_node(sub)) \
81 return parse_not_text_error(sub, ctx); \
82 xmlChar *content = xmlNodeGetContent(sub); \
83 array.resize(array.size() + 1); \
84 ret = ret && parse_fn(sub, array.back(), content, ctx); \
85 xmlFree(content); \
86 used = true; \
87 }
88
89#define MATCH_UNIQUE_ELEM_NODE(node_name, val, has, parse_fn, ctx) \
90 if(sub->type == XML_ELEMENT_NODE && strcmp(XML_CHAR_TO_CHAR(sub->name), node_name) == 0) { \
91 if(has) \
92 return parse_not_unique_error(sub, ctx); \
93 has = true; \
94 if(!parse_fn(sub, val, ctx)) \
95 ret = false; \
96 used = true; \
97 }
98
99#define MATCH_UNIQUE_TEXT_NODE(node_name, val, has, parse_fn, ctx) \
100 if(sub->type == XML_ELEMENT_NODE && strcmp(XML_CHAR_TO_CHAR(sub->name), node_name) == 0) { \
101 if(has) \
102 return parse_not_unique_error(sub, ctx); \
103 if(!is_real_text_node(sub)) \
104 return parse_not_text_error(sub, ctx); \
105 has = true; \
106 xmlChar *content = xmlNodeGetContent(sub); \
107 ret = ret && parse_fn(sub, val, content, ctx); \
108 xmlFree(content); \
109 used = true; \
110 }
111
112#define MATCH_UNUSED_NODE(parse_fn, ctx) \
113 if(!used) { \
114 ret = ret && parse_fn(sub, ctx); \
115 }
116
117#define END_NODE_MATCH() \
118 }
119
120#define CHECK_HAS(node, node_name, has, ctx) \
121 if(!has) \
122 ret = ret && parse_missing_error(node, node_name, ctx);
123
124#define CHECK_HAS_ATTR(node, attr_name, has, ctx) \
125 if(!has) \
126 ret = ret && parse_missing_attr_error(node, attr_name, ctx);
127
128namespace
129{
130
131bool is_real_text_node(xmlNode *node)
132{
133 for(xmlNode *sub = node->children; sub; sub = sub->next)
134 if(sub->type != XML_TEXT_NODE && sub->type != XML_ENTITY_REF_NODE)
135 return false;
136 return true;
137}
138
139std::string xml_loc(xmlNode *node)
140{
141 std::ostringstream oss;
142 oss << "line " << node->line;
143 return oss.str();
144}
145
146std::string xml_loc(xmlAttr *attr)
147{
148 return xml_loc(attr->parent);
149}
150
151template<typename T>
152bool add_error(error_context_t& ctx, err_t::level_t lvl, T *node,
153 const std::string& msg)
154{
155 ctx.add(err_t(lvl, xml_loc(node), msg));
156 return false;
157}
158
159template<typename T>
160bool add_fatal(error_context_t& ctx, T *node, const std::string& msg)
161{
162 return add_error(ctx, err_t::FATAL, node, msg);
163}
164
165template<typename T>
166bool add_warning(error_context_t& ctx, T *node, const std::string& msg)
167{
168 return add_error(ctx, err_t::WARNING, node, msg);
169}
170
171bool parse_wrong_version_error(xmlNode *node, error_context_t& ctx)
172{
173 std::ostringstream oss;
174 oss << "unknown version, only version " << MAJOR_VERSION << " is supported";
175 return add_fatal(ctx, node, oss.str());
176}
177
178bool parse_not_unique_error(xmlNode *node, error_context_t& ctx)
179{
180 std::ostringstream oss;
181 oss << "there must be a unique <" << XML_CHAR_TO_CHAR(node->name) << "> element";
182 if(node->parent->name)
183 oss << " in <" << XML_CHAR_TO_CHAR(node->parent->name) << ">";
184 else
185 oss << " at root level";
186 return add_fatal(ctx, node, oss.str());
187}
188
189bool parse_not_unique_attr_error(xmlAttr *attr, error_context_t& ctx)
190{
191 std::ostringstream oss;
192 oss << "there must be a unique " << XML_CHAR_TO_CHAR(attr->name) << " attribute";
193 oss << " in <" << XML_CHAR_TO_CHAR(attr->parent->name) << ">";
194 return add_fatal(ctx, attr, oss.str());
195}
196
197bool parse_missing_error(xmlNode *node, const char *name, error_context_t& ctx)
198{
199 std::ostringstream oss;
200 oss << "missing <" << name << "> element";
201 if(node->parent->name)
202 oss << " in <" << XML_CHAR_TO_CHAR(node->parent->name) << ">";
203 else
204 oss << " at root level";
205 return add_fatal(ctx, node, oss.str());
206}
207
208bool parse_missing_attr_error(xmlNode *node, const char *name, error_context_t& ctx)
209{
210 std::ostringstream oss;
211 oss << "missing " << name << " attribute";
212 oss << " in <" << XML_CHAR_TO_CHAR(node->name) << ">";
213 return add_fatal(ctx, node, oss.str());
214}
215
216bool parse_conflict_error(xmlNode *node, const char *name1, const char *name2,
217 error_context_t& ctx)
218{
219 std::ostringstream oss;
220 oss << "conflicting <" << name1 << "> and <" << name2 << "> elements";
221 if(node->parent->name)
222 oss << " in <" << XML_CHAR_TO_CHAR(node->parent->name) << ">";
223 else
224 oss << " at root level";
225 return add_fatal(ctx, node, oss.str());
226}
227
228bool parse_not_text_error(xmlNode *node, error_context_t& ctx)
229{
230 return add_fatal(ctx, node, "this is not a text element");
231}
232
233bool parse_not_text_attr_error(xmlAttr *attr, error_context_t& ctx)
234{
235 return add_fatal(ctx, attr, "this is not a text attribute");
236}
237
238bool parse_text_elem(xmlNode *node, std::string& name, xmlChar *content, error_context_t& ctx)
239{
240 name = XML_CHAR_TO_CHAR(content);
241 return true;
242}
243
244bool parse_name_elem(xmlNode *node, std::string& name, xmlChar *content, error_context_t& ctx)
245{
246 name = XML_CHAR_TO_CHAR(content);
247 if(name.size() == 0)
248 return add_fatal(ctx, node, "name cannot be empty");
249 for(size_t i = 0; i < name.size(); i++)
250 if(!isalnum(name[i]) && name[i] != '_')
251 return add_fatal(ctx, node, "name must only contain alphanumeric characters or _");
252 return true;
253}
254
255bool parse_unknown_elem(xmlNode *node, error_context_t& ctx)
256{
257 /* ignore blank nodes */
258 if(xmlIsBlankNode(node))
259 return true;
260 std::ostringstream oss;
261 oss << "unknown <" << XML_CHAR_TO_CHAR(node->name) << "> element";
262 return add_fatal(ctx, node, oss.str());
263}
264
265bool parse_access_elem(xmlNode *node, access_t& acc, xmlChar *content, error_context_t& ctx)
266{
267 const char *text = XML_CHAR_TO_CHAR(content);
268 if(strcmp(text, "read-only") == 0)
269 acc = READ_ONLY;
270 else if(strcmp(text, "read-write") == 0)
271 acc = READ_WRITE;
272 else if(strcmp(text, "write-only") == 0)
273 acc = WRITE_ONLY;
274 else
275 return add_fatal(ctx, node, "unknown access type " + std::string(text));
276 return true;
277}
278
279template<typename T, typename U>
280bool parse_unsigned_text(U *node, T& res, xmlChar *content, error_context_t& ctx)
281{
282 char *end;
283 unsigned long uns = strtoul(XML_CHAR_TO_CHAR(content), &end, 0);
284 if(*end != 0)
285 return add_fatal(ctx, node, "content must be an unsigned integer");
286 res = uns;
287 if(res != uns)
288 return add_fatal(ctx, node, "value does not fit into allowed range");
289 return true;
290}
291
292template<typename T>
293bool parse_unsigned_elem(xmlNode *node, T& res, xmlChar *content, error_context_t& ctx)
294{
295 return parse_unsigned_text(node, res, content, ctx);
296}
297
298template<typename T>
299bool parse_unsigned_attr(xmlAttr *attr, T& res, xmlChar *content, error_context_t& ctx)
300{
301 return parse_unsigned_text(attr, res, content, ctx);
302}
303
304bool parse_text_attr_internal(xmlAttr *attr, xmlChar*& res, error_context_t& ctx)
305{
306 if(attr->children != attr->last)
307 return false;
308 if(attr->children->type != XML_TEXT_NODE)
309 return parse_not_text_attr_error(attr, ctx);
310 res = attr->children->content;
311 return true;
312}
313
314bool parse_text_attr(xmlAttr *attr, std::string& res, xmlChar *content, error_context_t& ctx)
315{
316 res = XML_CHAR_TO_CHAR(content);
317 return true;
318}
319
320bool parse_unknown_attr(xmlAttr *attr, error_context_t& ctx)
321{
322 std::ostringstream oss;
323 oss << "unknown '" << XML_CHAR_TO_CHAR(attr->name) << "' attribute";
324 return add_fatal(ctx, attr, oss.str());
325}
326
327
328bool parse_enum_elem(xmlNode *node, enum_t& reg, error_context_t& ctx)
329{
330 bool ret = true;
331 bool has_name = false, has_value = false, has_desc = false;
332 BEGIN_NODE_MATCH(node->children)
333 MATCH_UNIQUE_TEXT_NODE("name", reg.name, has_name, parse_name_elem, ctx)
334 MATCH_UNIQUE_TEXT_NODE("value", reg.value, has_value, parse_unsigned_elem, ctx)
335 MATCH_UNIQUE_TEXT_NODE("desc", reg.desc, has_desc, parse_text_elem, ctx)
336 MATCH_UNUSED_NODE(parse_unknown_elem, ctx)
337 END_NODE_MATCH()
338 CHECK_HAS(node, "name", has_name, ctx)
339 CHECK_HAS(node, "value", has_value, ctx)
340 return ret;
341}
342
343bool parse_field_elem(xmlNode *node, field_t& field, error_context_t& ctx)
344{
345 bool ret = true;
346 bool has_name = false, has_pos = false, has_desc = false, has_width = false;
347 BEGIN_NODE_MATCH(node->children)
348 MATCH_UNIQUE_TEXT_NODE("name", field.name, has_name, parse_name_elem, ctx)
349 MATCH_UNIQUE_TEXT_NODE("position", field.pos, has_pos, parse_unsigned_elem, ctx)
350 MATCH_UNIQUE_TEXT_NODE("width", field.width, has_width, parse_unsigned_elem, ctx)
351 MATCH_UNIQUE_TEXT_NODE("desc", field.desc, has_desc, parse_text_elem, ctx)
352 MATCH_ELEM_NODE("enum", field.enum_, parse_enum_elem, ctx)
353 MATCH_UNUSED_NODE(parse_unknown_elem, ctx)
354 END_NODE_MATCH()
355 CHECK_HAS(node, "name", has_name, ctx)
356 CHECK_HAS(node, "position", has_pos, ctx)
357 if(!has_width)
358 field.width = 1;
359 return ret;
360}
361
362bool parse_variant_elem(xmlNode *node, variant_t& variant, error_context_t& ctx)
363{
364 bool ret = true;
365 bool has_type = false, has_offset = false, has_access = false;
366 BEGIN_NODE_MATCH(node->children)
367 MATCH_UNIQUE_TEXT_NODE("type", variant.type, has_type, parse_name_elem, ctx)
368 MATCH_UNIQUE_TEXT_NODE("offset", variant.offset, has_offset, parse_unsigned_elem, ctx)
369 MATCH_UNIQUE_TEXT_NODE("access", variant.access, has_access, parse_access_elem, ctx)
370 MATCH_UNUSED_NODE(parse_unknown_elem, ctx)
371 END_NODE_MATCH()
372 CHECK_HAS(node, "type", has_type, ctx)
373 CHECK_HAS(node, "offset", has_offset, ctx)
374 if(!has_access)
375 variant.access = UNSPECIFIED;
376 return ret;
377}
378
379bool parse_register_elem(xmlNode *node, register_t& reg, error_context_t& ctx)
380{
381 bool ret = true;
382 bool has_width = false, has_desc = false, has_access = false;
383 BEGIN_NODE_MATCH(node->children)
384 MATCH_UNIQUE_TEXT_NODE("desc", reg.desc, has_desc, parse_text_elem, ctx)
385 MATCH_UNIQUE_TEXT_NODE("width", reg.width, has_width, parse_unsigned_elem, ctx)
386 MATCH_UNIQUE_TEXT_NODE("access", reg.access, has_access, parse_access_elem, ctx)
387 MATCH_ELEM_NODE("field", reg.field, parse_field_elem, ctx)
388 MATCH_ELEM_NODE("variant", reg.variant, parse_variant_elem, ctx)
389 MATCH_UNUSED_NODE(parse_unknown_elem, ctx)
390 END_NODE_MATCH()
391 if(!has_width)
392 reg.width = 32;
393 if(!has_access)
394 reg.access = UNSPECIFIED;
395 return ret;
396}
397
398bool parse_formula_elem(xmlNode *node, range_t& range, error_context_t& ctx)
399{
400 bool ret = true;
401 bool has_var = false;
402 BEGIN_ATTR_MATCH(node->properties)
403 MATCH_UNIQUE_ATTR("variable", range.variable, has_var, parse_text_attr, ctx)
404 MATCH_UNUSED_ATTR(parse_unknown_attr, ctx)
405 END_NODE_MATCH()
406 CHECK_HAS_ATTR(node, "variable", has_var, ctx)
407 return ret;
408}
409
410bool parse_range_elem(xmlNode *node, range_t& range, error_context_t& ctx)
411{
412 bool ret = true;
413 bool has_first = false, has_count = false, has_stride = false, has_base = false;
414 bool has_formula = false, has_formula_attr = false;
415 BEGIN_NODE_MATCH(node->children)
416 MATCH_UNIQUE_TEXT_NODE("first", range.first, has_first, parse_unsigned_elem, ctx)
417 MATCH_UNIQUE_TEXT_NODE("count", range.count, has_count, parse_unsigned_elem, ctx)
418 MATCH_UNIQUE_TEXT_NODE("base", range.base, has_base, parse_unsigned_elem, ctx)
419 MATCH_UNIQUE_TEXT_NODE("stride", range.stride, has_stride, parse_unsigned_elem, ctx)
420 MATCH_UNIQUE_ELEM_NODE("formula", range, has_formula_attr, parse_formula_elem, ctx)
421 MATCH_UNIQUE_TEXT_NODE("formula", range.formula, has_formula, parse_text_elem, ctx)
422 MATCH_TEXT_NODE("address", range.list, parse_unsigned_elem, ctx)
423 MATCH_UNUSED_NODE(parse_unknown_elem, ctx)
424 END_NODE_MATCH()
425 CHECK_HAS(node, "first", has_first, ctx)
426 if(range.list.size() == 0)
427 {
428 CHECK_HAS(node, "count", has_count, ctx)
429 if(!has_base && !has_formula)
430 ret = ret && parse_missing_error(node, "base> or <formula", ctx);
431 if(has_base && has_formula)
432 return parse_conflict_error(node, "base", "formula", ctx);
433 if(has_base)
434 CHECK_HAS(node, "stride", has_stride, ctx)
435 if(has_stride && !has_base)
436 ret = ret && parse_conflict_error(node, "stride", "formula", ctx);
437 if(has_stride)
438 range.type = range_t::STRIDE;
439 else
440 range.type = range_t::FORMULA;
441 }
442 else
443 {
444 if(has_base)
445 ret = ret && parse_conflict_error(node, "base", "addr", ctx);
446 if(has_count)
447 ret = ret && parse_conflict_error(node, "count", "addr", ctx);
448 if(has_formula)
449 ret = ret && parse_conflict_error(node, "formula", "addr", ctx);
450 if(has_stride)
451 ret = ret && parse_conflict_error(node, "stride", "addr", ctx);
452 range.type = range_t::LIST;
453 }
454 return ret;
455}
456
457bool parse_instance_elem(xmlNode *node, instance_t& inst, error_context_t& ctx)
458{
459 bool ret = true;
460 bool has_name = false, has_title = false, has_desc = false, has_range = false;
461 bool has_address = false, has_floating = false, has_nochild = false;
462 unsigned floating = 0, nochild = 0;
463 BEGIN_NODE_MATCH(node->children)
464 MATCH_UNIQUE_TEXT_NODE("name", inst.name, has_name, parse_name_elem, ctx)
465 MATCH_UNIQUE_TEXT_NODE("title", inst.title, has_title, parse_text_elem, ctx)
466 MATCH_UNIQUE_TEXT_NODE("desc", inst.desc, has_desc, parse_text_elem, ctx)
467 MATCH_UNIQUE_TEXT_NODE("nochild", nochild, has_nochild, parse_unsigned_elem, ctx)
468 MATCH_UNIQUE_TEXT_NODE("floating", floating, has_floating, parse_unsigned_elem, ctx)
469 MATCH_UNIQUE_TEXT_NODE("address", inst.addr, has_address, parse_unsigned_elem, ctx)
470 MATCH_UNIQUE_ELEM_NODE("range", inst.range, has_range, parse_range_elem, ctx)
471 MATCH_UNUSED_NODE(parse_unknown_elem, ctx)
472 END_NODE_MATCH()
473 CHECK_HAS(node, "name", has_name, ctx)
474 if(!has_address && !has_range && !floating)
475 ret = ret && parse_missing_error(node, "address> or <range", ctx);
476 if(has_address && has_range)
477 ret = ret && parse_conflict_error(node, "address", "range", ctx);
478 if(floating && has_address)
479 ret = ret && parse_conflict_error(node, "floating", "address", ctx);
480 if(floating && has_range)
481 ret = ret && parse_conflict_error(node, "floating", "range", ctx);
482 if(floating && nochild)
483 ret = ret && parse_conflict_error(node, "floating", "nochild", ctx);
484 if(floating)
485 inst.type = instance_t::FLOATING;
486 else if(has_address)
487 inst.type = instance_t::SINGLE;
488 else
489 inst.type = instance_t::RANGE;
490 if (nochild)
491 inst.nochild = true;
492 return ret;
493}
494
495bool parse_node_elem(xmlNode *node_, node_t& node, error_context_t& ctx)
496{
497 bool ret = true;
498 register_t reg;
499 bool has_title = false, has_desc = false, has_register = false, has_name = false;
500 BEGIN_NODE_MATCH(node_->children)
501 MATCH_UNIQUE_TEXT_NODE("name", node.name, has_name, parse_name_elem, ctx)
502 MATCH_UNIQUE_TEXT_NODE("title", node.title, has_title, parse_text_elem, ctx)
503 MATCH_UNIQUE_TEXT_NODE("desc", node.desc, has_desc, parse_text_elem, ctx)
504 MATCH_UNIQUE_ELEM_NODE("register", reg, has_register, parse_register_elem, ctx)
505 MATCH_ELEM_NODE("node", node.node, parse_node_elem, ctx)
506 MATCH_ELEM_NODE("instance", node.instance, parse_instance_elem, ctx)
507 MATCH_UNUSED_NODE(parse_unknown_elem, ctx)
508 END_NODE_MATCH()
509 CHECK_HAS(node_, "name", has_name, ctx)
510 if(has_register)
511 node.register_.push_back(reg);
512 return ret;
513}
514
515bool parse_soc_elem(xmlNode *node, soc_t& soc, error_context_t& ctx)
516{
517 bool ret = true;
518 bool has_name = false, has_title = false, has_desc = false, has_version = false;
519 bool has_isa = false;
520 BEGIN_NODE_MATCH(node->children)
521 MATCH_UNIQUE_TEXT_NODE("name", soc.name, has_name, parse_name_elem, ctx)
522 MATCH_UNIQUE_TEXT_NODE("title", soc.title, has_title, parse_text_elem, ctx)
523 MATCH_UNIQUE_TEXT_NODE("desc", soc.desc, has_desc, parse_text_elem, ctx)
524 MATCH_UNIQUE_TEXT_NODE("version", soc.version, has_version, parse_text_elem, ctx)
525 MATCH_UNIQUE_TEXT_NODE("isa", soc.isa, has_isa, parse_text_elem, ctx)
526 MATCH_TEXT_NODE("author", soc.author, parse_text_elem, ctx)
527 MATCH_ELEM_NODE("node", soc.node, parse_node_elem, ctx)
528 MATCH_UNUSED_NODE(parse_unknown_elem, ctx)
529 END_NODE_MATCH()
530 CHECK_HAS(node, "name", has_name, ctx)
531 return ret;
532}
533
534bool parse_root_elem(xmlNode *node, soc_t& soc, error_context_t& ctx)
535{
536 size_t ver = 0;
537 bool ret = true;
538 bool has_soc = false, has_version = false;
539 BEGIN_ATTR_MATCH(node->properties)
540 MATCH_UNIQUE_ATTR("version", ver, has_version, parse_unsigned_attr, ctx)
541 MATCH_UNUSED_ATTR(parse_unknown_attr, ctx)
542 END_ATTR_MATCH()
543 if(!has_version)
544 {
545 ctx.add(err_t(err_t::FATAL, xml_loc(node), "no version attribute, is this a v1 file ?"));
546 return false;
547 }
548 if(ver != MAJOR_VERSION)
549 return parse_wrong_version_error(node, ctx);
550 BEGIN_NODE_MATCH(node)
551 MATCH_UNIQUE_ELEM_NODE("soc", soc, has_soc, parse_soc_elem, ctx)
552 MATCH_UNUSED_NODE(parse_unknown_elem, ctx)
553 END_NODE_MATCH()
554 CHECK_HAS(node, "soc", has_soc, ctx)
555 return ret;
556}
557
558}
559
560bool parse_xml(const std::string& filename, soc_t& soc,
561 error_context_t& error_ctx)
562{
563 LIBXML_TEST_VERSION
564
565 xmlDocPtr doc = xmlReadFile(filename.c_str(), NULL, 0);
566 if(doc == NULL)
567 return false;
568
569 xmlNodePtr root_element = xmlDocGetRootElement(doc);
570 bool ret = parse_root_elem(root_element, soc, error_ctx);
571
572 xmlFreeDoc(doc);
573
574 return ret;
575}
576
577/**
578 * Normalizer
579 */
580
581namespace
582{
583
584struct soc_sorter
585{
586 /* returns the lowest address of an instance, or 0 if none
587 * and 0xffffffff if cannot evaluate */
588 soc_addr_t first_addr(const instance_t& inst) const
589 {
590 if(inst.type == instance_t::SINGLE)
591 return inst.addr;
592 /* sanity check */
593 if(inst.type != instance_t::RANGE)
594 {
595 printf("Warning: unknown instance type %d\n", inst.type);
596 return 0;
597 }
598 if(inst.range.type == range_t::STRIDE)
599 return inst.range.base; /* assume positive stride */
600 if(inst.range.type == range_t::LIST)
601 {
602 soc_addr_t min = 0xffffffff;
603 for(size_t i = 0; i < inst.range.list.size(); i++)
604 if(inst.range.list[i] < min)
605 min = inst.range.list[i];
606 return min;
607 }
608 /* sanity check */
609 if(inst.range.type != range_t::FORMULA)
610 {
611 printf("Warning: unknown range type %d\n", inst.range.type);
612 return 0;
613 }
614 soc_addr_t min = 0xffffffff;
615 std::map< std::string, soc_word_t > vars;
616 for(size_t i = 0; i < inst.range.count; i++)
617 {
618 soc_word_t res;
619 vars[inst.range.variable] = inst.range.first;
620 error_context_t ctx;
621 if(evaluate_formula(inst.range.formula, vars, res, "", ctx) && res < min)
622 min = res;
623 }
624 return min;
625 }
626
627 /* return smallest address among all instances */
628 soc_addr_t first_addr(const node_t& node) const
629 {
630 soc_addr_t min = 0xffffffff;
631 for(size_t i = 0; i < node.instance.size(); i++)
632 min = std::min(min, first_addr(node.instance[i]));
633 return min;
634 }
635
636 /* sort instances by first address */
637 bool operator()(const instance_t& a, const instance_t& b) const
638 {
639 return first_addr(a) < first_addr(b);
640 }
641
642 /* sort nodes by first address of first instance (which is the lowest of
643 * any instance if instances are sorted) */
644 bool operator()(const node_t& a, const node_t& b) const
645 {
646 soc_addr_t addr_a = first_addr(a);
647 soc_addr_t addr_b = first_addr(b);
648 /* It may happen that two nodes have the same first instance address,
649 * for example if one logically splits a block into two blocks with
650 * the same base. In this case, sort by name */
651 if(addr_a == addr_b)
652 return a.name < b.name;
653 return addr_a < addr_b;
654 }
655
656 /* sort fields by decreasing position */
657 bool operator()(const field_t& a, const field_t& b) const
658 {
659 /* in the unlikely case where two fields have the same position, use name */
660 if(a.pos == b.pos)
661 return a.name < b.name;
662 return a.pos > b.pos;
663 }
664
665 /* sort enum values by value, then by name */
666 bool operator()(const enum_t& a, const enum_t& b) const
667 {
668 if(a.value == b.value)
669 return a.name < b.name;
670 return a.value < b.value;
671 }
672};
673
674void normalize(field_t& field)
675{
676 std::sort(field.enum_.begin(), field.enum_.end(), soc_sorter());
677}
678
679void normalize(register_t& reg)
680{
681 for(size_t i = 0; i < reg.field.size(); i++)
682 normalize(reg.field[i]);
683 std::sort(reg.field.begin(), reg.field.end(), soc_sorter());
684}
685
686void normalize(node_t& node)
687{
688 for(size_t i = 0; i < node.register_.size(); i++)
689 normalize(node.register_[i]);
690 for(size_t i = 0; i < node.node.size(); i++)
691 normalize(node.node[i]);
692 std::sort(node.node.begin(), node.node.end(), soc_sorter());
693 std::sort(node.instance.begin(), node.instance.end(), soc_sorter());
694}
695
696} /* namespace */
697
698void normalize(soc_t& soc)
699{
700 for(size_t i = 0; i < soc.node.size(); i++)
701 normalize(soc.node[i]);
702 std::sort(soc.node.begin(), soc.node.end(), soc_sorter());
703}
704
705/**
706 * Producer
707 */
708
709namespace
710{
711
712#define SAFE(x) \
713 do{ \
714 if((x) < 0) { \
715 std::ostringstream oss; \
716 oss << __FILE__ << ":" << __LINE__; \
717 ctx.add(err_t(err_t::FATAL, oss.str(), "write error")); \
718 return -1; \
719 } \
720 }while(0)
721
722int produce_range(xmlTextWriterPtr writer, const range_t& range, error_context_t& ctx)
723{
724 /* <range> */
725 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "range"));
726 /* <first/> */
727 SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "first", "%lu", range.first));
728 if(range.type == range_t::STRIDE)
729 {
730 /* <count/> */
731 SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "count", "%lu", range.count));
732 /* <base/> */
733 SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "base", "0x%x", range.base));
734 /* <stride/> */
735 SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "stride", "0x%x", range.stride));
736 }
737 /* <formula> */
738 else if(range.type == range_t::FORMULA)
739 {
740 /* <count/> */
741 SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "count", "%lu", range.count));
742 /* <formula> */
743 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "formula"));
744 /* variable */
745 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "variable", BAD_CAST range.variable.c_str()));
746 /* content */
747 SAFE(xmlTextWriterWriteString(writer, BAD_CAST range.formula.c_str()));
748 /* </formula> */
749 SAFE(xmlTextWriterEndElement(writer));
750 }
751 else if(range.type == range_t::LIST)
752 {
753 for(size_t i = 0; i < range.list.size(); i++)
754 SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "address", "0x%x", range.list[i]));
755 }
756 /* </range> */
757 SAFE(xmlTextWriterEndElement(writer));
758
759 return 0;
760}
761
762int produce_instance(xmlTextWriterPtr writer, const instance_t& inst, error_context_t& ctx)
763{
764 /* <instance> */
765 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "instance"));
766 /* <name/> */
767 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "name", BAD_CAST inst.name.c_str()));
768 /* <title/> */
769 if(!inst.title.empty())
770 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "title", BAD_CAST inst.title.c_str()));
771 /* <desc/> */
772 if(!inst.desc.empty())
773 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "desc", BAD_CAST inst.desc.c_str()));
774 /* <address/> */
775 if(inst.type == instance_t::SINGLE)
776 SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "address", "0x%x", inst.addr));
777 /* <range/> */
778 else if(inst.type == instance_t::RANGE)
779 SAFE(produce_range(writer, inst.range, ctx));
780 /* </instance> */
781 SAFE(xmlTextWriterEndElement(writer));
782 return 0;
783}
784
785int produce_enum(xmlTextWriterPtr writer, const enum_t& enum_, error_context_t& ctx)
786{
787 /* <enum> */
788 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "enum"));
789 /* <name/> */
790 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "name", BAD_CAST enum_.name.c_str()));
791 /* <desc/> */
792 if(!enum_.desc.empty())
793 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "desc", BAD_CAST enum_.desc.c_str()));
794 /* <value/> */
795 SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "value", "0x%x", enum_.value));
796 /* </enum> */
797 SAFE(xmlTextWriterEndElement(writer));
798 return 0;
799}
800
801int produce_field(xmlTextWriterPtr writer, const field_t& field, error_context_t& ctx)
802{
803 /* <field> */
804 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "field"));
805 /* <name/> */
806 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "name", BAD_CAST field.name.c_str()));
807 /* <desc/> */
808 if(!field.desc.empty())
809 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "desc", BAD_CAST field.desc.c_str()));
810 /* <position/> */
811 SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "position", "%lu", field.pos));
812 /* <width/> */
813 if(field.width != 1)
814 SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "width", "%lu", field.width));
815 /* enums */
816 for(size_t i = 0; i < field.enum_.size(); i++)
817 SAFE(produce_enum(writer, field.enum_[i], ctx));
818 /* </field> */
819 SAFE(xmlTextWriterEndElement(writer));
820 return 0;
821}
822
823const char *access_string(access_t acc)
824{
825 switch(acc)
826 {
827 case READ_ONLY: return "read-only";
828 case READ_WRITE: return "read-write";
829 case WRITE_ONLY: return "write-only";
830 default: return "bug-invalid-access";
831 }
832}
833
834int produce_variant(xmlTextWriterPtr writer, const variant_t& variant, error_context_t& ctx)
835{
836 /* <variant> */
837 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "variant"));
838 /* <name/> */
839 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "type", BAD_CAST variant.type.c_str()));
840 /* <position/> */
841 SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "offset", "%lu", (unsigned long)variant.offset));
842 /* <access/> */
843 if(variant.access != UNSPECIFIED)
844 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "access", BAD_CAST access_string(variant.access)));
845 /* </variant> */
846 SAFE(xmlTextWriterEndElement(writer));
847 return 0;
848}
849
850int produce_register(xmlTextWriterPtr writer, const register_t& reg, error_context_t& ctx)
851{
852 /* <register> */
853 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "register"));
854 /* <width/> */
855 if(reg.width != 32)
856 SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "width", "%lu", reg.width));
857 /* <desc/> */
858 if(!reg.desc.empty())
859 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "desc", BAD_CAST reg.desc.c_str()));
860 /* <access/> */
861 if(reg.access != UNSPECIFIED)
862 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "access", BAD_CAST access_string(reg.access)));
863 /* fields */
864 for(size_t i = 0; i < reg.field.size(); i++)
865 SAFE(produce_field(writer, reg.field[i], ctx));
866 /* variants */
867 for(size_t i = 0; i < reg.variant.size(); i++)
868 SAFE(produce_variant(writer, reg.variant[i], ctx));
869 /* </register> */
870 SAFE(xmlTextWriterEndElement(writer));
871 return 0;
872}
873
874int produce_node(xmlTextWriterPtr writer, const node_t& node, error_context_t& ctx)
875{
876 /* <node> */
877 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "node"));
878 /* <name/> */
879 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "name", BAD_CAST node.name.c_str()));
880 /* <title/> */
881 if(!node.title.empty())
882 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "title", BAD_CAST node.title.c_str()));
883 /* <desc/> */
884 if(!node.desc.empty())
885 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "desc", BAD_CAST node.desc.c_str()));
886 /* instances */
887 for(size_t i = 0; i < node.instance.size(); i++)
888 SAFE(produce_instance(writer, node.instance[i], ctx));
889 /* register */
890 for(size_t i = 0; i < node.register_.size(); i++)
891 SAFE(produce_register(writer, node.register_[i], ctx));
892 /* nodes */
893 for(size_t i = 0; i < node.node.size(); i++)
894 SAFE(produce_node(writer, node.node[i], ctx));
895 /* </node> */
896 SAFE(xmlTextWriterEndElement(writer));
897 return 0;
898}
899
900#undef SAFE
901
902}
903
904bool produce_xml(const std::string& filename, const soc_t& soc, error_context_t& ctx)
905{
906 LIBXML_TEST_VERSION
907
908 std::ostringstream oss;
909 xmlTextWriterPtr writer = xmlNewTextWriterFilename(filename.c_str(), 0);
910 if(writer == NULL)
911 return false;
912#define SAFE(x) do{if((x) < 0) goto Lerr;}while(0)
913 SAFE(xmlTextWriterSetIndent(writer, 1));
914 SAFE(xmlTextWriterSetIndentString(writer, BAD_CAST " "));
915 /* <xml> */
916 SAFE(xmlTextWriterStartDocument(writer, NULL, NULL, NULL));
917 /* <soc> */
918 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "soc"));
919 /* version */
920 oss << MAJOR_VERSION;
921 SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "version", BAD_CAST oss.str().c_str()));
922 /* <name/> */
923 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "name", BAD_CAST soc.name.c_str()));
924 /* <title/> */
925 if(!soc.title.empty())
926 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "title", BAD_CAST soc.title.c_str()));
927 /* <desc/> */
928 if(!soc.desc.empty())
929 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "desc", BAD_CAST soc.desc.c_str()));
930 /* <author/> */
931 for(size_t i = 0; i < soc.author.size(); i++)
932 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "author", BAD_CAST soc.author[i].c_str()));
933 /* <isa/> */
934 if(!soc.isa.empty())
935 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "isa", BAD_CAST soc.isa.c_str()));
936 /* <version/> */
937 if(!soc.version.empty())
938 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "version", BAD_CAST soc.version.c_str()));
939 /* nodes */
940 for(size_t i = 0; i < soc.node.size(); i++)
941 SAFE(produce_node(writer, soc.node[i], ctx));
942 /* </soc> */
943 SAFE(xmlTextWriterEndElement(writer));
944 /* </xml> */
945 SAFE(xmlTextWriterEndDocument(writer));
946 xmlFreeTextWriter(writer);
947 return true;
948#undef SAFE
949Lerr:
950 xmlFreeTextWriter(writer);
951 return false;
952}
953
954/**
955 * utils
956 */
957
958namespace
959{
960
961template< typename T >
962soc_id_t gen_fresh_id(const std::vector< T >& list)
963{
964 soc_id_t id = 0;
965 for(size_t i = 0; i < list.size(); i++)
966 id = std::max(id, list[i].id);
967 return id + 1;
968}
969
970}
971
972/**
973 * soc_ref_t
974 */
975
976soc_ref_t::soc_ref_t():m_soc(0)
977{
978}
979
980soc_ref_t::soc_ref_t(soc_t *soc):m_soc(soc)
981{
982}
983
984bool soc_ref_t::valid() const
985{
986 return get() != 0;
987}
988
989soc_t *soc_ref_t::get() const
990{
991 return m_soc;
992}
993
994bool soc_ref_t::operator==(const soc_ref_t& ref) const
995{
996 return m_soc == ref.m_soc;
997}
998
999node_ref_t soc_ref_t::root() const
1000{
1001 return node_ref_t(*this);
1002}
1003
1004node_inst_t soc_ref_t::root_inst() const
1005{
1006 return node_inst_t(*this);
1007}
1008
1009void soc_ref_t::reset()
1010{
1011 m_soc = 0;
1012}
1013
1014/**
1015 * node_ref_t */
1016
1017node_ref_t::node_ref_t(soc_ref_t soc):m_soc(soc)
1018{
1019}
1020
1021node_ref_t::node_ref_t(soc_ref_t soc, const std::vector< soc_id_t >& path)
1022 :m_soc(soc), m_path(path)
1023{
1024}
1025
1026node_ref_t::node_ref_t()
1027{
1028}
1029
1030bool node_ref_t::valid() const
1031{
1032 return (m_soc.valid() && is_root()) || get() != 0;
1033}
1034
1035bool node_ref_t::is_root() const
1036{
1037 return m_path.empty();
1038}
1039
1040void node_ref_t::reset()
1041{
1042 m_soc.reset();
1043}
1044
1045namespace
1046{
1047
1048std::vector< node_t > *get_children(node_ref_t node)
1049{
1050 if(node.is_root())
1051 return node.soc().valid() ? &node.soc().get()->node : 0;
1052 node_t *n = node.get();
1053 return n == 0 ? 0 : &n->node;
1054}
1055
1056node_t *get_child(std::vector< node_t > *nodes, soc_id_t id)
1057{
1058 if(nodes == 0)
1059 return 0;
1060 for(size_t i = 0; i < nodes->size(); i++)
1061 if((*nodes)[i].id == id)
1062 return &(*nodes)[i];
1063 return 0;
1064}
1065
1066node_t *get_child(std::vector< node_t > *nodes, const std::string& name)
1067{
1068 if(nodes == 0)
1069 return 0;
1070 for(size_t i = 0; i < nodes->size(); i++)
1071 if((*nodes)[i].name == name)
1072 return &(*nodes)[i];
1073 return 0;
1074}
1075
1076}
1077
1078/* NOTE: valid() is implemented using get() != 0, so don't use it in get() ! */
1079node_t *node_ref_t::get() const
1080{
1081 if(!soc().valid())
1082 return 0;
1083 /* we could do it recursively but it would make plenty of copies */
1084 node_t *n = 0;
1085 std::vector< node_t > *nodes = &soc().get()->node;
1086 for(size_t i = 0; i < m_path.size(); i++)
1087 {
1088 n = get_child(nodes, m_path[i]);
1089 if(n == 0)
1090 return 0;
1091 nodes = &n->node;
1092 }
1093 return n;
1094}
1095
1096soc_ref_t node_ref_t::soc() const
1097{
1098 return m_soc;
1099}
1100
1101node_ref_t node_ref_t::parent(unsigned level) const
1102{
1103 if(level > depth())
1104 return node_ref_t();
1105 std::vector< soc_id_t > path = m_path;
1106 path.resize(depth() - level);
1107 return node_ref_t(m_soc, path);
1108}
1109
1110unsigned node_ref_t::depth() const
1111{
1112 return m_path.size();
1113}
1114
1115register_ref_t node_ref_t::reg() const
1116{
1117 node_t *n = get();
1118 if(n == 0)
1119 return register_ref_t();
1120 if(n->register_.empty())
1121 return parent().reg();
1122 else
1123 return register_ref_t(*this);
1124}
1125
1126register_ref_t node_ref_t::create_reg(size_t width) const
1127{
1128 node_t *n = get();
1129 if(n == 0)
1130 return register_ref_t();
1131 if(!n->register_.empty())
1132 return register_ref_t();
1133 n->register_.resize(1);
1134 n->register_[0].width = width;
1135 return register_ref_t(*this);
1136}
1137
1138node_ref_t node_ref_t::child(const std::string& name) const
1139{
1140 /* check the node exists */
1141 node_t *n = get_child(get_children(*this), name);
1142 if(n == 0)
1143 return node_ref_t();
1144 std::vector< soc_id_t > path = m_path;
1145 path.push_back(n->id);
1146 return node_ref_t(m_soc, path);
1147}
1148
1149std::vector< node_ref_t > node_ref_t::children() const
1150{
1151 std::vector< node_ref_t > nodes;
1152 std::vector< node_t > *children = get_children(*this);
1153 if(children == 0)
1154 return nodes;
1155 for(size_t i = 0; i < children->size(); i++)
1156 {
1157 std::vector< soc_id_t > path = m_path;
1158 path.push_back((*children)[i].id);
1159 nodes.push_back(node_ref_t(m_soc, path));
1160 }
1161 return nodes;
1162}
1163
1164std::vector< std::string > node_ref_t::path() const
1165{
1166 std::vector< std::string > path;
1167 if(!soc().valid())
1168 return path;
1169 /* we could do it recursively but this is more efficient */
1170 node_t *n = 0;
1171 std::vector< node_t > *nodes = &soc().get()->node;
1172 for(size_t i = 0; i < m_path.size(); i++)
1173 {
1174 n = get_child(nodes, m_path[i]);
1175 if(n == 0)
1176 {
1177 path.clear();
1178 return path;
1179 }
1180 path.push_back(n->name);
1181 nodes = &n->node;
1182 }
1183 return path;
1184}
1185
1186std::string node_ref_t::name() const
1187{
1188 node_t *n = get();
1189 return n == 0 ? "" : n->name;
1190}
1191
1192bool node_ref_t::operator==(const node_ref_t& ref) const
1193{
1194 return m_soc == ref.m_soc && m_path == ref.m_path;
1195}
1196
1197void node_ref_t::remove()
1198{
1199 if(is_root())
1200 {
1201 soc_t *s = soc().get();
1202 if(s)
1203 s->node.clear();
1204 }
1205 else
1206 {
1207 std::vector< node_t > *list = get_children(parent());
1208 if(list == 0)
1209 return;
1210 for(size_t i = 0; i < list->size(); i++)
1211 if((*list)[i].id == m_path.back())
1212 {
1213 list->erase(list->begin() + i);
1214 return;
1215 }
1216 }
1217}
1218
1219node_ref_t node_ref_t::create() const
1220{
1221 std::vector< node_t > *list = get_children(*this);
1222 if(list == 0)
1223 return node_ref_t();
1224 node_t n;
1225 n.id = gen_fresh_id(*list);
1226 list->push_back(n);
1227 std::vector< soc_id_t > path = m_path;
1228 path.push_back(n.id);
1229 return node_ref_t(soc(), path);
1230}
1231
1232/**
1233 * register_ref_t
1234 */
1235
1236register_ref_t::register_ref_t(node_ref_t node)
1237 :m_node(node)
1238{
1239}
1240
1241register_ref_t::register_ref_t()
1242{
1243}
1244
1245bool register_ref_t::valid() const
1246{
1247 return get() != 0;
1248}
1249
1250void register_ref_t::reset()
1251{
1252 m_node.reset();
1253}
1254
1255register_t *register_ref_t::get() const
1256{
1257 node_t *n = m_node.get();
1258 if(n == 0 || n->register_.empty())
1259 return 0;
1260 return &n->register_[0];
1261}
1262
1263node_ref_t register_ref_t::node() const
1264{
1265 return m_node;
1266}
1267
1268std::vector< field_ref_t > register_ref_t::fields() const
1269{
1270 std::vector< field_ref_t > fields;
1271 register_t *r = get();
1272 if(r == 0)
1273 return fields;
1274 for(size_t i = 0; i < r->field.size(); i++)
1275 fields.push_back(field_ref_t(*this, r->field[i].id));
1276 return fields;
1277}
1278
1279std::vector< variant_ref_t > register_ref_t::variants() const
1280{
1281 std::vector< variant_ref_t > variants;
1282 register_t *r = get();
1283 if(r == 0)
1284 return variants;
1285 for(size_t i = 0; i < r->variant.size(); i++)
1286 variants.push_back(variant_ref_t(*this, r->variant[i].id));
1287 return variants;
1288}
1289
1290field_ref_t register_ref_t::field(const std::string& name) const
1291{
1292 register_t *r = get();
1293 if(r == 0)
1294 return field_ref_t();
1295 for(size_t i = 0; i < r->field.size(); i++)
1296 if(r->field[i].name == name)
1297 return field_ref_t(*this, r->field[i].id);
1298 return field_ref_t();
1299}
1300
1301variant_ref_t register_ref_t::variant(const std::string& type) const
1302{
1303 register_t *r = get();
1304 if(r == 0)
1305 return variant_ref_t();
1306 for(size_t i = 0; i < r->variant.size(); i++)
1307 if(r->variant[i].type == type)
1308 return variant_ref_t(*this, r->variant[i].id);
1309 return variant_ref_t();
1310}
1311
1312void register_ref_t::remove()
1313{
1314 node_t *n = node().get();
1315 if(n)
1316 n->register_.clear();
1317}
1318
1319field_ref_t register_ref_t::create_field() const
1320{
1321 register_t *r = get();
1322 if(r == 0)
1323 return field_ref_t();
1324 field_t f;
1325 f.id = gen_fresh_id(r->field);
1326 r->field.push_back(f);
1327 return field_ref_t(*this, f.id);
1328}
1329
1330variant_ref_t register_ref_t::create_variant() const
1331{
1332 register_t *r = get();
1333 if(r == 0)
1334 return variant_ref_t();
1335 variant_t v;
1336 v.id = gen_fresh_id(r->variant);
1337 r->variant.push_back(v);
1338 return variant_ref_t(*this, v.id);
1339}
1340
1341/**
1342 * field_ref_t
1343 */
1344
1345field_ref_t::field_ref_t(register_ref_t reg, soc_id_t id)
1346 :m_reg(reg), m_id(id)
1347{
1348}
1349
1350field_ref_t::field_ref_t()
1351{
1352}
1353
1354bool field_ref_t::valid() const
1355{
1356 return get() != 0;
1357}
1358
1359void field_ref_t::reset()
1360{
1361 m_reg.reset();
1362}
1363
1364field_t *field_ref_t::get() const
1365{
1366 register_t *reg = m_reg.get();
1367 if(reg == 0)
1368 return 0;
1369 for(size_t i = 0; i < reg->field.size(); i++)
1370 if(reg->field[i].id == m_id)
1371 return ®->field[i];
1372 return 0;
1373}
1374
1375std::vector< enum_ref_t > field_ref_t::enums() const
1376{
1377 std::vector< enum_ref_t > enums;
1378 field_t *f = get();
1379 if(f == 0)
1380 return enums;
1381 for(size_t i = 0; i < f->enum_.size(); i++)
1382 enums.push_back(enum_ref_t(*this, f->enum_[i].id));
1383 return enums;
1384}
1385
1386register_ref_t field_ref_t::reg() const
1387{
1388 return m_reg;
1389}
1390
1391enum_ref_t field_ref_t::create_enum() const
1392{
1393 field_t *f = get();
1394 if(f == 0)
1395 return enum_ref_t();
1396 enum_t e;
1397 e.id = gen_fresh_id(f->enum_);
1398 f->enum_.push_back(e);
1399 return enum_ref_t(*this, e.id);
1400}
1401
1402/**
1403 * enum_ref_t
1404 */
1405
1406enum_ref_t::enum_ref_t(field_ref_t field, soc_id_t id)
1407 :m_field(field), m_id(id)
1408{
1409}
1410
1411enum_ref_t::enum_ref_t()
1412{
1413}
1414
1415bool enum_ref_t::valid() const
1416{
1417 return get() != 0;
1418}
1419
1420void enum_ref_t::reset()
1421{
1422 m_field.reset();
1423}
1424
1425enum_t *enum_ref_t::get() const
1426{
1427 field_t *field = m_field.get();
1428 if(field == 0)
1429 return 0;
1430 for(size_t i = 0; i < field->enum_.size(); i++)
1431 if(field->enum_[i].id == m_id)
1432 return &field->enum_[i];
1433 return 0;
1434}
1435
1436field_ref_t enum_ref_t::field() const
1437{
1438 return m_field;
1439}
1440
1441/**
1442 * variant_ref_t
1443 */
1444
1445variant_ref_t::variant_ref_t(register_ref_t reg, soc_id_t id)
1446 :m_reg(reg), m_id(id)
1447{
1448}
1449
1450variant_ref_t::variant_ref_t()
1451{
1452}
1453
1454bool variant_ref_t::valid() const
1455{
1456 return get() != 0;
1457}
1458
1459void variant_ref_t::reset()
1460{
1461 m_reg.reset();
1462}
1463
1464variant_t *variant_ref_t::get() const
1465{
1466 register_t *reg = m_reg.get();
1467 if(reg == 0)
1468 return 0;
1469 for(size_t i = 0; i < reg->variant.size(); i++)
1470 if(reg->variant[i].id == m_id)
1471 return ®->variant[i];
1472 return 0;
1473}
1474
1475register_ref_t variant_ref_t::reg() const
1476{
1477 return m_reg;
1478}
1479
1480std::string variant_ref_t::type() const
1481{
1482 variant_t *v = get();
1483 return v ? v->type : std::string();
1484}
1485
1486soc_word_t variant_ref_t::offset() const
1487{
1488 variant_t *v = get();
1489 return v ? v->offset : 0;
1490}
1491
1492/**
1493 * node_inst_t
1494 */
1495
1496namespace
1497{
1498
1499const size_t INST_NO_INDEX = std::numeric_limits<std::size_t>::max();
1500
1501bool get_inst_addr(range_t& range, size_t index, soc_addr_t& addr)
1502{
1503 if(index < range.first || index >= range.first + range.size())
1504 return false;
1505 switch(range.type)
1506 {
1507 case range_t::STRIDE:
1508 addr += range.base + (index - range.first) * range.stride;
1509 return true;
1510 case range_t::FORMULA:
1511 {
1512 soc_word_t res;
1513 std::map< std::string, soc_word_t > vars;
1514 vars[range.variable] = index;
1515 error_context_t ctx;
1516 if(!evaluate_formula(range.formula, vars, res, "", ctx))
1517 return false;
1518 addr += res;
1519 return true;
1520 }
1521 case range_t::LIST:
1522 addr += range.list[index - range.first];
1523 return true;
1524 default:
1525 return false;
1526 }
1527}
1528
1529bool get_inst_addr(instance_t *inst, size_t index, soc_addr_t& addr)
1530{
1531 if(inst == 0)
1532 return false;
1533 switch(inst->type)
1534 {
1535 case instance_t::SINGLE:
1536 if(index != INST_NO_INDEX)
1537 return false;
1538 addr += inst->addr;
1539 return true;
1540 case instance_t::RANGE:
1541 if(index == INST_NO_INDEX)
1542 return false;
1543 return get_inst_addr(inst->range, index, addr);
1544 default:
1545 return false;
1546 }
1547}
1548
1549}
1550
1551node_inst_t::node_inst_t(soc_ref_t soc)
1552 :m_node(soc.root())
1553{
1554}
1555
1556node_inst_t::node_inst_t(node_ref_t node, const std::vector< soc_id_t >& ids,
1557 const std::vector< size_t >& indexes)
1558 :m_node(node), m_id_path(ids), m_index_path(indexes)
1559{
1560}
1561
1562node_inst_t::node_inst_t()
1563{
1564}
1565
1566bool node_inst_t::valid() const
1567{
1568 return (is_root() && node().valid()) || get() != 0;
1569}
1570
1571void node_inst_t::reset()
1572{
1573 m_node.reset();
1574}
1575
1576node_ref_t node_inst_t::node() const
1577{
1578 return m_node;
1579}
1580
1581soc_ref_t node_inst_t::soc() const
1582{
1583 return m_node.soc();
1584}
1585
1586bool node_inst_t::is_root() const
1587{
1588 return m_node.is_root();
1589}
1590
1591node_inst_t node_inst_t::parent(unsigned level) const
1592{
1593 if(level > depth())
1594 return node_inst_t();
1595 std::vector< soc_id_t > ids = m_id_path;
1596 std::vector< size_t > indexes = m_index_path;
1597 ids.resize(depth() - level);
1598 indexes.resize(depth() - level);
1599 return node_inst_t(m_node.parent(level), ids, indexes);
1600}
1601
1602unsigned node_inst_t::depth() const
1603{
1604 return m_id_path.size();
1605}
1606
1607instance_t *node_inst_t::get() const
1608{
1609 node_t *n = m_node.get();
1610 if(n == 0)
1611 return 0;
1612 for(size_t i = 0; i < n->instance.size(); i++)
1613 if(n->instance[i].id == m_id_path.back())
1614 return &n->instance[i];
1615 return 0;
1616}
1617
1618soc_addr_t node_inst_t::addr() const
1619{
1620 if(!valid() || is_root())
1621 return 0;
1622 soc_addr_t addr = parent().addr();
1623 if(!get_inst_addr(get(), m_index_path.back(), addr))
1624 return 0;
1625 return addr;
1626}
1627
1628node_inst_t node_inst_t::child(const std::string& name) const
1629{
1630 return child(name, INST_NO_INDEX);
1631}
1632
1633node_inst_t node_inst_t::child(const std::string& name, size_t index) const
1634{
1635 std::vector< node_t > *nodes = get_children(m_node);
1636 if(nodes == 0 || is_nochild())
1637 return node_inst_t();
1638 node_ref_t child_node = m_node;
1639 for(size_t i = 0; i < nodes->size(); i++)
1640 {
1641 node_t& node = (*nodes)[i];
1642 child_node.m_path.push_back(node.id);
1643 for(size_t j = 0; j < node.instance.size(); j++)
1644 {
1645 if(node.instance[j].name != name)
1646 continue;
1647 std::vector< soc_id_t > ids = m_id_path;
1648 std::vector< size_t > indexes = m_index_path;
1649 ids.push_back(node.instance[j].id);
1650 indexes.push_back(index);
1651 return node_inst_t(child_node, ids, indexes);
1652 }
1653 child_node.m_path.pop_back();
1654 }
1655 return node_inst_t();
1656}
1657
1658std::vector< node_inst_t > node_inst_t::children() const
1659{
1660 std::vector< node_inst_t > list;
1661 std::vector< node_t > *nodes = get_children(m_node);
1662 std::vector< soc_id_t > n_path = m_id_path;
1663 std::vector< size_t > i_path = m_index_path;
1664 if(nodes == 0 || is_nochild())
1665 return list;
1666 node_ref_t child_node = m_node;
1667 for(size_t i = 0; i < nodes->size(); i++)
1668 {
1669 node_t& node = (*nodes)[i];
1670 child_node.m_path.push_back(node.id);
1671 for(size_t j = 0; j < node.instance.size(); j++)
1672 {
1673 instance_t& inst = node.instance[j];
1674 n_path.push_back(inst.id);
1675 switch(inst.type)
1676 {
1677 case instance_t::FLOATING:
1678 case instance_t::SINGLE:
1679 i_path.push_back(INST_NO_INDEX);
1680 list.push_back(node_inst_t(child_node, n_path, i_path));
1681 i_path.pop_back();
1682 break;
1683 case instance_t::RANGE:
1684 for(size_t i = 0; i < inst.range.size(); i++)
1685 {
1686 i_path.push_back(inst.range.first + i);
1687 list.push_back(node_inst_t(child_node, n_path, i_path));
1688 i_path.pop_back();
1689 }
1690 break;
1691 default:
1692 break;
1693 }
1694 n_path.pop_back();
1695 }
1696 child_node.m_path.pop_back();
1697 }
1698 return list;
1699}
1700
1701bool node_inst_t::is_nochild() const
1702{
1703 instance_t *inst = get();
1704 return inst == 0 ? false : inst->nochild;
1705}
1706
1707std::string node_inst_t::name() const
1708{
1709 instance_t *inst = get();
1710 return inst == 0 ? "" : inst->name;
1711}
1712
1713bool node_inst_t:: is_indexed() const
1714{
1715 return !m_index_path.empty() && m_index_path.back() != INST_NO_INDEX;
1716}
1717
1718size_t node_inst_t::index() const
1719{
1720 return m_index_path.empty() ? INST_NO_INDEX : m_index_path.back();
1721}
1722
1723/** WARNING we need to call xmlInitParser() to init libxml2 but it needs to
1724 * called from the main thread, which is a super strong requirement, so do it
1725 * using a static constructor */
1726namespace
1727{
1728class xml_parser_init
1729{
1730public:
1731 xml_parser_init()
1732 {
1733 xmlInitParser();
1734 }
1735};
1736
1737xml_parser_init __xml_parser_init;
1738}
1739
1740} // soc_desc_v1
1741