regtools: add register access to soc desc
Registers (and variants) can now specify the type of access supported: - unspecified: for variant means same as register, for register defaults R/W - read/write - read only - write only Backward compatibility is preserved by setting access to unspecified by default. Change-Id: I3e84ae18f962a45db62f996a542d08405d05b895
This commit is contained in:
parent
f6c61eb11a
commit
cc4c9b70bc
3 changed files with 68 additions and 6 deletions
|
@ -390,6 +390,12 @@
|
|||
</instance>
|
||||
<register>
|
||||
<width>8</width>
|
||||
<access>read-only</access>
|
||||
<variant>
|
||||
<type>debug</type>
|
||||
<offset>4</offset>
|
||||
<access>write-only</access>
|
||||
</variant>
|
||||
</register>
|
||||
</node>
|
||||
</node>
|
||||
|
|
|
@ -77,6 +77,21 @@ protected:
|
|||
* Bare representation of the format
|
||||
*/
|
||||
|
||||
/** Register access type and rules
|
||||
*
|
||||
* Access can be specified on registers and register variants. When left
|
||||
* unspecified (aka DEFAULT), a register variant inherit the access from
|
||||
* the register, and a register defaults to read-write if unspecified.
|
||||
* When specified, the register variant access takes precedence over the register
|
||||
* access. */
|
||||
enum access_t
|
||||
{
|
||||
UNSPECIFIED = 0, /** Register: read-write, fields: inherit from register */
|
||||
READ_ONLY, /** Read-only */
|
||||
READ_WRITE, /** Read-write */
|
||||
WRITE_ONLY, /** Write-only */
|
||||
};
|
||||
|
||||
/** Enumerated value (aka named value), represents a special value for a field */
|
||||
struct enum_t
|
||||
{
|
||||
|
@ -137,33 +152,37 @@ struct field_t
|
|||
/** Register variant information
|
||||
*
|
||||
* A register variant provides an alternative access to the register, potentially
|
||||
* we special semantics. Although there are no constraints on the type string,
|
||||
* with special semantics. Although there are no constraints on the type string,
|
||||
* the following types have well-defined semantics:
|
||||
* - alias: the same register at another address
|
||||
* - set: writing to this register will set the 1s bits and ignore the 0s
|
||||
* - clr: writing to this register will clear the 1s bits and ignore the 0s
|
||||
* - tog: writing to this register will toggle the 1s bits and ignore the 0s
|
||||
* Note that by default, variants inherit the access type of the register but
|
||||
* can override it.
|
||||
*/
|
||||
struct variant_t
|
||||
{
|
||||
soc_id_t id; /** ID (must be unique among register variants) */
|
||||
std::string type; /** type of the variant */
|
||||
soc_addr_t offset; /** offset of the variant */
|
||||
access_t access; /** Access type */
|
||||
|
||||
/** Default constructor: default ID, offset is 0 */
|
||||
variant_t():id(DEFAULT_ID), offset(0) {}
|
||||
/** Default constructor: default ID, offset is 0, access is unspecified */
|
||||
variant_t():id(DEFAULT_ID), offset(0), access(UNSPECIFIED) {}
|
||||
};
|
||||
|
||||
/** Register information */
|
||||
struct register_t
|
||||
{
|
||||
size_t width; /** Size in bits */
|
||||
access_t access; /** Access type */
|
||||
std::string desc; /** Optional description of the register */
|
||||
std::vector< field_t > field; /** List of fields */
|
||||
std::vector< variant_t > variant; /** List of variants */
|
||||
|
||||
/** Default constructor: width is 32 */
|
||||
register_t():width(32) {}
|
||||
register_t():width(32), access(UNSPECIFIED) {}
|
||||
};
|
||||
|
||||
/** Node address range information */
|
||||
|
|
|
@ -262,6 +262,20 @@ bool parse_unknown_elem(xmlNode *node, error_context_t& ctx)
|
|||
return add_fatal(ctx, node, oss.str());
|
||||
}
|
||||
|
||||
bool parse_access_elem(xmlNode *node, access_t& acc, xmlChar *content, error_context_t& ctx)
|
||||
{
|
||||
const char *text = XML_CHAR_TO_CHAR(content);
|
||||
if(strcmp(text, "read-only") == 0)
|
||||
acc = READ_ONLY;
|
||||
else if(strcmp(text, "read-write") == 0)
|
||||
acc = READ_WRITE;
|
||||
else if(strcmp(text, "write-only") == 0)
|
||||
acc = WRITE_ONLY;
|
||||
else
|
||||
return add_fatal(ctx, node, "unknown access type " + std::string(text));
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
bool parse_unsigned_text(U *node, T& res, xmlChar *content, error_context_t& ctx)
|
||||
{
|
||||
|
@ -348,30 +362,36 @@ bool parse_field_elem(xmlNode *node, field_t& field, error_context_t& ctx)
|
|||
bool parse_variant_elem(xmlNode *node, variant_t& variant, error_context_t& ctx)
|
||||
{
|
||||
bool ret = true;
|
||||
bool has_type = false, has_offset = false;
|
||||
bool has_type = false, has_offset = false, has_access = false;
|
||||
BEGIN_NODE_MATCH(node->children)
|
||||
MATCH_UNIQUE_TEXT_NODE("type", variant.type, has_type, parse_name_elem, ctx)
|
||||
MATCH_UNIQUE_TEXT_NODE("offset", variant.offset, has_offset, parse_unsigned_elem, ctx)
|
||||
MATCH_UNIQUE_TEXT_NODE("access", variant.access, has_access, parse_access_elem, ctx)
|
||||
MATCH_UNUSED_NODE(parse_unknown_elem, ctx)
|
||||
END_NODE_MATCH()
|
||||
CHECK_HAS(node, "type", has_type, ctx)
|
||||
CHECK_HAS(node, "offset", has_offset, ctx)
|
||||
if(!has_access)
|
||||
variant.access = UNSPECIFIED;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool parse_register_elem(xmlNode *node, register_t& reg, error_context_t& ctx)
|
||||
{
|
||||
bool ret = true;
|
||||
bool has_width = false, has_desc = false;
|
||||
bool has_width = false, has_desc = false, has_access = false;
|
||||
BEGIN_NODE_MATCH(node->children)
|
||||
MATCH_UNIQUE_TEXT_NODE("desc", reg.desc, has_desc, parse_text_elem, ctx)
|
||||
MATCH_UNIQUE_TEXT_NODE("width", reg.width, has_width, parse_unsigned_elem, ctx)
|
||||
MATCH_UNIQUE_TEXT_NODE("access", reg.access, has_access, parse_access_elem, ctx)
|
||||
MATCH_ELEM_NODE("field", reg.field, parse_field_elem, ctx)
|
||||
MATCH_ELEM_NODE("variant", reg.variant, parse_variant_elem, ctx)
|
||||
MATCH_UNUSED_NODE(parse_unknown_elem, ctx)
|
||||
END_NODE_MATCH()
|
||||
if(!has_width)
|
||||
reg.width = 32;
|
||||
if(!has_access)
|
||||
reg.access = UNSPECIFIED;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -746,6 +766,17 @@ int produce_field(xmlTextWriterPtr writer, const field_t& field, error_context_t
|
|||
return 0;
|
||||
}
|
||||
|
||||
const char *access_string(access_t acc)
|
||||
{
|
||||
switch(acc)
|
||||
{
|
||||
case READ_ONLY: return "read-only";
|
||||
case READ_WRITE: return "read-write";
|
||||
case WRITE_ONLY: return "write-only";
|
||||
default: return "bug-invalid-access";
|
||||
}
|
||||
}
|
||||
|
||||
int produce_variant(xmlTextWriterPtr writer, const variant_t& variant, error_context_t& ctx)
|
||||
{
|
||||
/* <variant> */
|
||||
|
@ -754,6 +785,9 @@ int produce_variant(xmlTextWriterPtr writer, const variant_t& variant, error_con
|
|||
SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "type", BAD_CAST variant.type.c_str()));
|
||||
/* <position/> */
|
||||
SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "offset", "%lu", (unsigned long)variant.offset));
|
||||
/* <access/> */
|
||||
if(variant.access != UNSPECIFIED)
|
||||
SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "access", BAD_CAST access_string(variant.access)));
|
||||
/* </variant> */
|
||||
SAFE(xmlTextWriterEndElement(writer));
|
||||
return 0;
|
||||
|
@ -769,6 +803,9 @@ int produce_register(xmlTextWriterPtr writer, const register_t& reg, error_conte
|
|||
/* <desc/> */
|
||||
if(!reg.desc.empty())
|
||||
SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "desc", BAD_CAST reg.desc.c_str()));
|
||||
/* <access/> */
|
||||
if(reg.access != UNSPECIFIED)
|
||||
SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "access", BAD_CAST access_string(reg.access)));
|
||||
/* fields */
|
||||
for(size_t i = 0; i < reg.field.size(); i++)
|
||||
SAFE(produce_field(writer, reg.field[i], ctx));
|
||||
|
|
Loading…
Reference in a new issue