diff options
-rw-r--r-- | utils/regtools/desc/regs-vsoc2000.xml | 6 | ||||
-rw-r--r-- | utils/regtools/include/soc_desc.hpp | 27 | ||||
-rw-r--r-- | utils/regtools/lib/soc_desc.cpp | 41 |
3 files changed, 68 insertions, 6 deletions
diff --git a/utils/regtools/desc/regs-vsoc2000.xml b/utils/regtools/desc/regs-vsoc2000.xml index bcd6d08d38..858c13254c 100644 --- a/utils/regtools/desc/regs-vsoc2000.xml +++ b/utils/regtools/desc/regs-vsoc2000.xml | |||
@@ -390,6 +390,12 @@ | |||
390 | </instance> | 390 | </instance> |
391 | <register> | 391 | <register> |
392 | <width>8</width> | 392 | <width>8</width> |
393 | <access>read-only</access> | ||
394 | <variant> | ||
395 | <type>debug</type> | ||
396 | <offset>4</offset> | ||
397 | <access>write-only</access> | ||
398 | </variant> | ||
393 | </register> | 399 | </register> |
394 | </node> | 400 | </node> |
395 | </node> | 401 | </node> |
diff --git a/utils/regtools/include/soc_desc.hpp b/utils/regtools/include/soc_desc.hpp index 66562f80d9..99f8706789 100644 --- a/utils/regtools/include/soc_desc.hpp +++ b/utils/regtools/include/soc_desc.hpp | |||
@@ -77,6 +77,21 @@ protected: | |||
77 | * Bare representation of the format | 77 | * Bare representation of the format |
78 | */ | 78 | */ |
79 | 79 | ||
80 | /** Register access type and rules | ||
81 | * | ||
82 | * Access can be specified on registers and register variants. When left | ||
83 | * unspecified (aka DEFAULT), a register variant inherit the access from | ||
84 | * the register, and a register defaults to read-write if unspecified. | ||
85 | * When specified, the register variant access takes precedence over the register | ||
86 | * access. */ | ||
87 | enum access_t | ||
88 | { | ||
89 | UNSPECIFIED = 0, /** Register: read-write, fields: inherit from register */ | ||
90 | READ_ONLY, /** Read-only */ | ||
91 | READ_WRITE, /** Read-write */ | ||
92 | WRITE_ONLY, /** Write-only */ | ||
93 | }; | ||
94 | |||
80 | /** Enumerated value (aka named value), represents a special value for a field */ | 95 | /** Enumerated value (aka named value), represents a special value for a field */ |
81 | struct enum_t | 96 | struct enum_t |
82 | { | 97 | { |
@@ -137,33 +152,37 @@ struct field_t | |||
137 | /** Register variant information | 152 | /** Register variant information |
138 | * | 153 | * |
139 | * A register variant provides an alternative access to the register, potentially | 154 | * A register variant provides an alternative access to the register, potentially |
140 | * we special semantics. Although there are no constraints on the type string, | 155 | * with special semantics. Although there are no constraints on the type string, |
141 | * the following types have well-defined semantics: | 156 | * the following types have well-defined semantics: |
142 | * - alias: the same register at another address | 157 | * - alias: the same register at another address |
143 | * - set: writing to this register will set the 1s bits and ignore the 0s | 158 | * - set: writing to this register will set the 1s bits and ignore the 0s |
144 | * - clr: writing to this register will clear the 1s bits and ignore the 0s | 159 | * - clr: writing to this register will clear the 1s bits and ignore the 0s |
145 | * - tog: writing to this register will toggle the 1s bits and ignore the 0s | 160 | * - tog: writing to this register will toggle the 1s bits and ignore the 0s |
161 | * Note that by default, variants inherit the access type of the register but | ||
162 | * can override it. | ||
146 | */ | 163 | */ |
147 | struct variant_t | 164 | struct variant_t |
148 | { | 165 | { |
149 | soc_id_t id; /** ID (must be unique among register variants) */ | 166 | soc_id_t id; /** ID (must be unique among register variants) */ |
150 | std::string type; /** type of the variant */ | 167 | std::string type; /** type of the variant */ |
151 | soc_addr_t offset; /** offset of the variant */ | 168 | soc_addr_t offset; /** offset of the variant */ |
169 | access_t access; /** Access type */ | ||
152 | 170 | ||
153 | /** Default constructor: default ID, offset is 0 */ | 171 | /** Default constructor: default ID, offset is 0, access is unspecified */ |
154 | variant_t():id(DEFAULT_ID), offset(0) {} | 172 | variant_t():id(DEFAULT_ID), offset(0), access(UNSPECIFIED) {} |
155 | }; | 173 | }; |
156 | 174 | ||
157 | /** Register information */ | 175 | /** Register information */ |
158 | struct register_t | 176 | struct register_t |
159 | { | 177 | { |
160 | size_t width; /** Size in bits */ | 178 | size_t width; /** Size in bits */ |
179 | access_t access; /** Access type */ | ||
161 | std::string desc; /** Optional description of the register */ | 180 | std::string desc; /** Optional description of the register */ |
162 | std::vector< field_t > field; /** List of fields */ | 181 | std::vector< field_t > field; /** List of fields */ |
163 | std::vector< variant_t > variant; /** List of variants */ | 182 | std::vector< variant_t > variant; /** List of variants */ |
164 | 183 | ||
165 | /** Default constructor: width is 32 */ | 184 | /** Default constructor: width is 32 */ |
166 | register_t():width(32) {} | 185 | register_t():width(32), access(UNSPECIFIED) {} |
167 | }; | 186 | }; |
168 | 187 | ||
169 | /** Node address range information */ | 188 | /** Node address range information */ |
diff --git a/utils/regtools/lib/soc_desc.cpp b/utils/regtools/lib/soc_desc.cpp index a72e7e9f7c..b52201672f 100644 --- a/utils/regtools/lib/soc_desc.cpp +++ b/utils/regtools/lib/soc_desc.cpp | |||
@@ -262,6 +262,20 @@ bool parse_unknown_elem(xmlNode *node, error_context_t& ctx) | |||
262 | return add_fatal(ctx, node, oss.str()); | 262 | return add_fatal(ctx, node, oss.str()); |
263 | } | 263 | } |
264 | 264 | ||
265 | bool 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 | |||
265 | template<typename T, typename U> | 279 | template<typename T, typename U> |
266 | bool parse_unsigned_text(U *node, T& res, xmlChar *content, error_context_t& ctx) | 280 | bool parse_unsigned_text(U *node, T& res, xmlChar *content, error_context_t& ctx) |
267 | { | 281 | { |
@@ -348,30 +362,36 @@ bool parse_field_elem(xmlNode *node, field_t& field, error_context_t& ctx) | |||
348 | bool parse_variant_elem(xmlNode *node, variant_t& variant, error_context_t& ctx) | 362 | bool parse_variant_elem(xmlNode *node, variant_t& variant, error_context_t& ctx) |
349 | { | 363 | { |
350 | bool ret = true; | 364 | bool ret = true; |
351 | bool has_type = false, has_offset = false; | 365 | bool has_type = false, has_offset = false, has_access = false; |
352 | BEGIN_NODE_MATCH(node->children) | 366 | BEGIN_NODE_MATCH(node->children) |
353 | MATCH_UNIQUE_TEXT_NODE("type", variant.type, has_type, parse_name_elem, ctx) | 367 | MATCH_UNIQUE_TEXT_NODE("type", variant.type, has_type, parse_name_elem, ctx) |
354 | MATCH_UNIQUE_TEXT_NODE("offset", variant.offset, has_offset, parse_unsigned_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) | ||
355 | MATCH_UNUSED_NODE(parse_unknown_elem, ctx) | 370 | MATCH_UNUSED_NODE(parse_unknown_elem, ctx) |
356 | END_NODE_MATCH() | 371 | END_NODE_MATCH() |
357 | CHECK_HAS(node, "type", has_type, ctx) | 372 | CHECK_HAS(node, "type", has_type, ctx) |
358 | CHECK_HAS(node, "offset", has_offset, ctx) | 373 | CHECK_HAS(node, "offset", has_offset, ctx) |
374 | if(!has_access) | ||
375 | variant.access = UNSPECIFIED; | ||
359 | return ret; | 376 | return ret; |
360 | } | 377 | } |
361 | 378 | ||
362 | bool parse_register_elem(xmlNode *node, register_t& reg, error_context_t& ctx) | 379 | bool parse_register_elem(xmlNode *node, register_t& reg, error_context_t& ctx) |
363 | { | 380 | { |
364 | bool ret = true; | 381 | bool ret = true; |
365 | bool has_width = false, has_desc = false; | 382 | bool has_width = false, has_desc = false, has_access = false; |
366 | BEGIN_NODE_MATCH(node->children) | 383 | BEGIN_NODE_MATCH(node->children) |
367 | MATCH_UNIQUE_TEXT_NODE("desc", reg.desc, has_desc, parse_text_elem, ctx) | 384 | MATCH_UNIQUE_TEXT_NODE("desc", reg.desc, has_desc, parse_text_elem, ctx) |
368 | MATCH_UNIQUE_TEXT_NODE("width", reg.width, has_width, parse_unsigned_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) | ||
369 | MATCH_ELEM_NODE("field", reg.field, parse_field_elem, ctx) | 387 | MATCH_ELEM_NODE("field", reg.field, parse_field_elem, ctx) |
370 | MATCH_ELEM_NODE("variant", reg.variant, parse_variant_elem, ctx) | 388 | MATCH_ELEM_NODE("variant", reg.variant, parse_variant_elem, ctx) |
371 | MATCH_UNUSED_NODE(parse_unknown_elem, ctx) | 389 | MATCH_UNUSED_NODE(parse_unknown_elem, ctx) |
372 | END_NODE_MATCH() | 390 | END_NODE_MATCH() |
373 | if(!has_width) | 391 | if(!has_width) |
374 | reg.width = 32; | 392 | reg.width = 32; |
393 | if(!has_access) | ||
394 | reg.access = UNSPECIFIED; | ||
375 | return ret; | 395 | return ret; |
376 | } | 396 | } |
377 | 397 | ||
@@ -746,6 +766,17 @@ int produce_field(xmlTextWriterPtr writer, const field_t& field, error_context_t | |||
746 | return 0; | 766 | return 0; |
747 | } | 767 | } |
748 | 768 | ||
769 | const char *access_string(access_t acc) | ||
770 | { | ||
771 | switch(acc) | ||
772 | { | ||
773 | case READ_ONLY: return "read-only"; | ||
774 | case READ_WRITE: return "read-write"; | ||
775 | case WRITE_ONLY: return "write-only"; | ||
776 | default: return "bug-invalid-access"; | ||
777 | } | ||
778 | } | ||
779 | |||
749 | int produce_variant(xmlTextWriterPtr writer, const variant_t& variant, error_context_t& ctx) | 780 | int produce_variant(xmlTextWriterPtr writer, const variant_t& variant, error_context_t& ctx) |
750 | { | 781 | { |
751 | /* <variant> */ | 782 | /* <variant> */ |
@@ -754,6 +785,9 @@ int produce_variant(xmlTextWriterPtr writer, const variant_t& variant, error_con | |||
754 | SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "type", BAD_CAST variant.type.c_str())); | 785 | SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "type", BAD_CAST variant.type.c_str())); |
755 | /* <position/> */ | 786 | /* <position/> */ |
756 | SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "offset", "%lu", (unsigned long)variant.offset)); | 787 | SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "offset", "%lu", (unsigned long)variant.offset)); |
788 | /* <access/> */ | ||
789 | if(variant.access != UNSPECIFIED) | ||
790 | SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "access", BAD_CAST access_string(variant.access))); | ||
757 | /* </variant> */ | 791 | /* </variant> */ |
758 | SAFE(xmlTextWriterEndElement(writer)); | 792 | SAFE(xmlTextWriterEndElement(writer)); |
759 | return 0; | 793 | return 0; |
@@ -769,6 +803,9 @@ int produce_register(xmlTextWriterPtr writer, const register_t& reg, error_conte | |||
769 | /* <desc/> */ | 803 | /* <desc/> */ |
770 | if(!reg.desc.empty()) | 804 | if(!reg.desc.empty()) |
771 | SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "desc", BAD_CAST reg.desc.c_str())); | 805 | SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "desc", BAD_CAST reg.desc.c_str())); |
806 | /* <access/> */ | ||
807 | if(reg.access != UNSPECIFIED) | ||
808 | SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "access", BAD_CAST access_string(reg.access))); | ||
772 | /* fields */ | 809 | /* fields */ |
773 | for(size_t i = 0; i < reg.field.size(); i++) | 810 | for(size_t i = 0; i < reg.field.size(); i++) |
774 | SAFE(produce_field(writer, reg.field[i], ctx)); | 811 | SAFE(produce_field(writer, reg.field[i], ctx)); |