summaryrefslogtreecommitdiff
path: root/utils/regtools/lib/soc_desc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'utils/regtools/lib/soc_desc.cpp')
-rw-r--r--utils/regtools/lib/soc_desc.cpp1530
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
33namespace 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
85namespace 111namespace
86{ 112{
87 113
88bool validate_string_hook(const std::string& str, std::string& s) 114bool 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
94bool validate_sct_hook(const std::string& str, soc_reg_flags_t& flags) 122std::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
101bool validate_unsigned_long_hook(const std::string& str, unsigned long& s) 129std::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
108bool validate_uint32_hook(const std::string& str, uint32_t& s) 134template<typename T>
135bool 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
119bool validate_bitrange_hook(const std::string& str, unsigned& first, unsigned& last) 142template<typename T>
143bool 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
132bool parse_text_attr(xmlAttr *attr, std::string& s) 148template<typename T>
149bool 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
142bool parse_value_elem(xmlNode *node, soc_reg_field_value_t& value) 154bool 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; 161bool 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
153bool parse_field_elem(xmlNode *node, soc_reg_field_t& field) 172bool 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) 180bool 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; 191bool 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
168bool parse_reg_addr_elem(xmlNode *node, soc_reg_addr_t& addr) 199bool 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; 211bool 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
178bool parse_reg_formula_elem(xmlNode *node, soc_reg_formula_t& formula) 216bool 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; 221bool 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
227bool 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
189bool parse_add_trivial_addr(const std::string& str, soc_reg_t& reg) 238template<typename T, typename U>
239bool 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
199bool parse_reg_elem(xmlNode *node, soc_reg_t& reg) 251template<typename T>
252bool 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) 257template<typename T>
210 MATCH_ELEM_NODE("addr", reg.addr, parse_reg_addr_elem) 258bool 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) 263bool 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
226bool parse_dev_addr_elem(xmlNode *node, soc_dev_addr_t& addr) 273bool 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
236bool parse_dev_elem(xmlNode *node, soc_dev_t& dev) 279bool 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
293bool 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; 311bool 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
253bool parse_soc_elem(xmlNode *node, soc_t& soc) 324bool 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
335bool 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; 365bool 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
267bool parse_root_elem(xmlNode *node, soc_t& soc) 389bool 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
409bool 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
427bool 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
284bool soc_desc_parse_xml(const std::string& filename, soc_t& socs) 451bool 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
300namespace 472namespace
301{ 473{
302 474
303int 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
485int 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
335int 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())); 517int 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
540int 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
556int 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
578int 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
385int produce_dev(xmlTextWriterPtr writer, const soc_dev_t& dev) 593int 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
421bool soc_desc_produce_xml(const std::string& filename, const soc_t& soc) 623bool 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
454namespace 673/**
674 * soc_ref_t
675 */
676
677soc_ref_t::soc_ref_t():m_soc(0)
455{ 678{
679}
456 680
457struct soc_sorter 681soc_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 685bool 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 690soc_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 695bool 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 700node_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 705node_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
492void normalize(soc_reg_field_t& field) 710/**
711 * node_ref_t */
712
713node_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
497void normalize(soc_reg_t& reg) 717node_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
505void normalize(soc_dev_t& dev) 722node_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
726bool node_ref_t::valid() const
727{
728 return (m_soc.valid() && is_root()) || get() != 0;
513} 729}
514 730
515void soc_desc_normalize(soc_t& soc) 731bool 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
522namespace 736namespace
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) 739std::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) 747node_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, 757node_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() ! */
770node_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) 787soc_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) 792node_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
584std::vector< soc_error_t > soc_reg_field_value_t::errors(bool recursive) 800register_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
595std::vector< soc_error_t > soc_reg_field_t::errors(bool recursive) 811node_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")); 822std::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
837std::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
628std::vector< soc_error_t > soc_reg_addr_t::errors(bool recursive) 859std::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
639std::vector< soc_error_t > soc_reg_formula_t::errors(bool recursive) 865bool 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
648namespace 870/**
871 * register_ref_t
872 */
873
874register_ref_t::register_ref_t(node_ref_t node)
875 :m_node(node)
649{ 876{
877}
650 878
651bool field_overlap(const soc_reg_field_t& a, const soc_reg_field_t& b) 879register_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
883bool register_ref_t::valid() const
884{
885 return get() != 0;
656} 886}
657 887
658std::vector< soc_error_t > soc_reg_t::errors(bool recursive) 888register_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
703std::vector< soc_error_t > soc_dev_addr_t::errors(bool recursive) 896node_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
714std::vector< soc_error_t > soc_dev_t::errors(bool recursive) 901std::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
754std::vector< soc_error_t > soc_t::errors(bool recursive) 912field_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
774namespace 923/**
924 * field_ref_t
925 */
926
927field_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
777struct formula_evaluator 932field_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, ...) 936bool 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) 941field_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 &reg->field[i];
949 return 0;
950}
800 951
801 void adv() 952register_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() 961namespace
812 { 962{
813 return pos >= formula.size(); 963
814 } 964const 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) 966bool 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) 991bool 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) 1013node_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) 1018node_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
941struct my_evaluator : public formula_evaluator 1024node_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) 1028bool 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) 1033node_ref_t node_inst_t::node() const
1034{
1035 return m_node;
1036}
1037
1038soc_ref_t node_inst_t::soc() const
1039{
1040 return m_node.soc();
1041}
1042
1043bool node_inst_t::is_root() const
1044{
1045 return m_node.is_root();
1046}
1047
1048node_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
1059instance_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
1070soc_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
1080node_inst_t node_inst_t::child(const std::string& name) const
1081{
1082 return child(name, INST_NO_INDEX);
1083}
1084
1085
1086node_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
1111std::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
1153std::string node_inst_t::name() const
1154{
1155 instance_t *inst = get();
1156 return inst == 0 ? "" : inst->name;
1157}
960 1158
1159bool node_inst_t:: is_indexed() const
1160{
1161 return !m_index_path.empty() && m_index_path.back() != INST_NO_INDEX;
961} 1162}
962 1163
963bool soc_desc_evaluate_formula(const std::string& formula, 1164size_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
984xml_parser_init __xml_parser_init; 1183xml_parser_init __xml_parser_init;
985} \ No newline at end of file 1184}
1185
1186} // soc_desc_v1
1187