diff --git a/utils/regtools/Makefile b/utils/regtools/Makefile
index 647a5b42ef..0be3d00421 100644
--- a/utils/regtools/Makefile
+++ b/utils/regtools/Makefile
@@ -24,3 +24,4 @@ $(LIB):
clean:
rm -fr $(EXEC)
+ make -C lib clean
diff --git a/utils/regtools/desc/spec-2.0.txt b/utils/regtools/desc/spec-2.0.txt
index be97fbc41a..e4b2748d92 100644
--- a/utils/regtools/desc/spec-2.0.txt
+++ b/utils/regtools/desc/spec-2.0.txt
@@ -146,7 +146,43 @@ are:
- F[2] at 0x50+(2/2)*0x100+(2%2)*0x10 = 0x50+0x100 = 0x150
- F[3] at 0x50+(3/2)*0x100+(3%2)*0x10 = 0x50+0x100+0x10 = 0x160
-1.3) Node description
+1.3) Floating and 'nochild' instances
+-------------------------------------
+
+Floating instances do not have an fixed address and instead "float" relative
+to a base address provided at runtime. Child nodes and registers are generated
+as usual, except that their addresses will not be defined, only their offsets
+relative to their floating parent node.
+
+
+ N
+
+ F
+ 1
+
+
+
+Instances with the 'nochild' flag will emit their own base address, but won't
+generate any child nodes or registers themselves. They can be used alongside
+floating nodes to provide the base addresses for SoC peripheral instances:
+
+
+ N
+
+ F
+ 1
+ 0x1234
+
+
+
+Nochild instances can use both
and for specifying their
+address.
+
+For generic code, storing the base address and computing offsets can generate
+more efficient code compared to indexed macros that calculate the base address,
+especially when the addresses don't follow a simple formula.
+
+1.4) Node description
---------------------
For documentation purposes, node can of course carry some description, as well
@@ -177,7 +213,7 @@ The following example illustrates this:
-1.4) Register description
+1.5) Register description
--------------------------
The goal of the register description is of course to describe registers!
@@ -247,7 +283,7 @@ In this example, the 8-bit registers has three fields:
- PRIORITY(2:1): it has no named values
- ARM_MODE(3): it has two named values IRQ(0) and FIQ(1)
-1.5) Register inheritance
+1.6) Register inheritance
-------------------------
The node hierarchy specifies instances, that is pairs of (path,address),
@@ -286,7 +322,7 @@ This example describes one register (let's call it blabla) and 9 instances:
- DMAC.I2C_CHAN.CLR at 0x80000018, register blabla
- DMAC.I2C_CHAN.TOG at 0x8000001C, register blabla
-1.6) Soc description
+1.7) Soc description
--------------------
The description file must also specify some information about the system-on-chip
@@ -352,8 +388,10 @@ It can contain at most one of each of the following tags:
- desc: free form description of the instance
- address: address for a single instance (non-negative number)
- range: address range for multiple instances
-Note that address and range are mutually exclusive, and at least one of them
-must exists.
+- floating: 0 or 1, if 1 then the instance is floating and has no address
+- nochild: 0 or 1, if 1 then no child instances/registers are generated
+Note that address, range, and floating are mutually exclusive, and at least
+one of them must exist. An instance cannot be both floating and nochild.
Element: range
--------------
diff --git a/utils/regtools/headergen_v2.cpp b/utils/regtools/headergen_v2.cpp
index 18dc818ce6..0ceb547edb 100644
--- a/utils/regtools/headergen_v2.cpp
+++ b/utils/regtools/headergen_v2.cpp
@@ -887,6 +887,8 @@ std::string common_generator::register_address(const pseudo_node_inst_t& reg,
}
else if(inst.type == instance_t::SINGLE)
oss << to_hex(inst.addr);
+ else if (inst.type == instance_t::FLOATING)
+ return "";
else
return "#error unknown instance type";
}
@@ -911,6 +913,7 @@ bool common_generator::generate_register(std::ostream& os, const pseudo_node_ins
std::string bfm_prefix = macro_basename(reg, MT_FIELD_BFM) + field_prefix();
std::string bfv_prefix = macro_basename(reg, MT_FIELD_BFV) + field_prefix();
std::string bfmv_prefix = macro_basename(reg, MT_FIELD_BFMV) + field_prefix();
+ bool has_addr = !addr.empty();
register_ref_t regr = reg.inst.node().reg();
/* handle register the same way as variants */
@@ -923,7 +926,8 @@ bool common_generator::generate_register(std::ostream& os, const pseudo_node_ins
var_prefix.push_back("");
var_suffix.push_back("");
var_access.push_back(register_access("", regr.get()->access));
- var_addr.push_back(addr);
+ if(has_addr)
+ var_addr.push_back(addr);
var_offset.push_back(offset);
std::vector< variant_ref_t > variants = regr.variants();
@@ -931,9 +935,12 @@ bool common_generator::generate_register(std::ostream& os, const pseudo_node_ins
{
var_prefix.push_back(variant_xfix(variants[i].type(), true));
var_suffix.push_back(variant_xfix(variants[i].type(), false));
- var_addr.push_back("(" + type_xfix(MT_REG_ADDR, true) + basename +
- type_xfix(MT_REG_ADDR, false) + addr_param_str + " + " +
- to_hex(variants[i].offset()) + ")");
+ if (has_addr)
+ {
+ var_addr.push_back("(" + type_xfix(MT_REG_ADDR, true) + basename +
+ type_xfix(MT_REG_ADDR, false) + addr_param_str + " + " +
+ to_hex(variants[i].offset()) + ")");
+ }
var_offset.push_back("(" + type_xfix(MT_REG_OFFSET, true) + basename +
type_xfix(MT_REG_OFFSET, false) + offset_param_str + " + " +
to_hex(variants[i].offset()));
@@ -962,16 +969,26 @@ bool common_generator::generate_register(std::ostream& os, const pseudo_node_ins
* if we have support macros then we generate something like HW(basename)
* where HW is some support macros to support complex operations. Otherwise
* we just generate something like (*(volatile unsigned uintN_t)basename_addr) */
- if(!has_support_macros())
+ if (has_addr)
{
- std::ostringstream oss;
- oss << "(*(volatile uint" << regr.get()->width << "_t *)" << macro_addr + addr_param_str << ")";
- ctx.add(macro_var + addr_param_str, oss.str());
+ if(!has_support_macros())
+ {
+ std::ostringstream oss;
+ oss << "(*(volatile uint" << regr.get()->width << "_t *)" <<
+ macro_addr + addr_param_str << ")";
+ ctx.add(macro_var + addr_param_str, oss.str());
+ }
+ else
+ {
+ ctx.add(macro_var + addr_param_str, macro_name(MN_VARIABLE) +
+ "(" + var_basename + addr_param_str + ")");
+ }
+
+ /* print ADDR macro */
+ ctx.add(macro_addr + addr_param_str, var_addr[i]);
}
else
ctx.add(macro_var + addr_param_str, macro_name(MN_VARIABLE) + "(" + var_basename + addr_param_str + ")");
- /* print ADDR macro */
- ctx.add(macro_addr + addr_param_str, var_addr[i]);
if(has_offsets())
{
@@ -1030,7 +1047,6 @@ bool common_generator::generate_register(std::ostream& os, const pseudo_node_ins
bool common_generator::generate_node(std::ostream& os, const pseudo_node_inst_t& node)
{
- os << "\n";
define_align_context_t ctx;
std::vector< std::string > params;
std::string addr = register_address(node, params);
@@ -1038,8 +1054,13 @@ bool common_generator::generate_node(std::ostream& os, const pseudo_node_inst_t&
std::string param_str = generate_param_str(params);
std::string macro_addr = type_xfix(MT_NODE_ADDR, true) + basename +
type_xfix(MT_NODE_ADDR, false);
+ bool has_addr = !addr.empty();
- ctx.add(macro_addr + param_str, addr);
+ if (has_addr)
+ {
+ os << "\n";
+ ctx.add(macro_addr + param_str, addr);
+ }
ctx.print(os);
return true;
diff --git a/utils/regtools/include/soc_desc.hpp b/utils/regtools/include/soc_desc.hpp
index 3d8481f963..8afc8f56c0 100644
--- a/utils/regtools/include/soc_desc.hpp
+++ b/utils/regtools/include/soc_desc.hpp
@@ -230,7 +230,8 @@ struct instance_t
enum type_t
{
SINGLE, /** There is a single instance at a specified address */
- RANGE /** There are multiple addresses forming a range */
+ RANGE, /** There are multiple addresses forming a range */
+ FLOATING, /** Instance generates child register offsets/fields only */
};
soc_id_t id; /** ID (must be unique among node instances) */
@@ -240,9 +241,10 @@ struct instance_t
type_t type; /** Instance type */
soc_word_t addr; /** Address (for SINGLE) */
range_t range; /** Range (for RANGE) */
+ bool nochild; /** Disable child node generation if set */
/** Default constructor: single instance at 0 */
- instance_t():id(DEFAULT_ID), type(SINGLE), addr(0) {}
+ instance_t():id(DEFAULT_ID), type(SINGLE), addr(0), nochild(false) {}
};
/** Node information */
@@ -544,6 +546,8 @@ public:
node_inst_t child(const std::string& name, size_t index) const;
/** Returns a list of all instances of subnodes of this node's instance */
std::vector< node_inst_t > children() const;
+ /** Check if the instance's nochild flag is set */
+ bool is_nochild() const;
/** Returns the name of the instance */
std::string name() const;
/** Checks whether this instance is indexed */
diff --git a/utils/regtools/lib/soc_desc.cpp b/utils/regtools/lib/soc_desc.cpp
index 113d6b1dd4..d85a1366da 100644
--- a/utils/regtools/lib/soc_desc.cpp
+++ b/utils/regtools/lib/soc_desc.cpp
@@ -458,24 +458,37 @@ bool parse_instance_elem(xmlNode *node, instance_t& inst, error_context_t& ctx)
{
bool ret = true;
bool has_name = false, has_title = false, has_desc = false, has_range = false;
- bool has_address = false;
+ bool has_address = false, has_floating = false, has_nochild = false;
+ unsigned floating = 0, nochild = 0;
BEGIN_NODE_MATCH(node->children)
MATCH_UNIQUE_TEXT_NODE("name", inst.name, has_name, parse_name_elem, ctx)
MATCH_UNIQUE_TEXT_NODE("title", inst.title, has_title, parse_text_elem, ctx)
MATCH_UNIQUE_TEXT_NODE("desc", inst.desc, has_desc, parse_text_elem, ctx)
+ MATCH_UNIQUE_TEXT_NODE("nochild", nochild, has_nochild, parse_unsigned_elem, ctx)
+ MATCH_UNIQUE_TEXT_NODE("floating", floating, has_floating, parse_unsigned_elem, ctx)
MATCH_UNIQUE_TEXT_NODE("address", inst.addr, has_address, parse_unsigned_elem, ctx)
MATCH_UNIQUE_ELEM_NODE("range", inst.range, has_range, parse_range_elem, ctx)
MATCH_UNUSED_NODE(parse_unknown_elem, ctx)
END_NODE_MATCH()
CHECK_HAS(node, "name", has_name, ctx)
- if(!has_address && !has_range)
+ if(!has_address && !has_range && !floating)
ret = ret && parse_missing_error(node, "address> or *nodes = get_children(m_node);
- if(nodes == 0)
+ if(nodes == 0 || is_nochild())
return node_inst_t();
node_ref_t child_node = m_node;
for(size_t i = 0; i < nodes->size(); i++)
@@ -1648,7 +1661,7 @@ std::vector< node_inst_t > node_inst_t::children() const
std::vector< node_t > *nodes = get_children(m_node);
std::vector< soc_id_t > n_path = m_id_path;
std::vector< size_t > i_path = m_index_path;
- if(nodes == 0)
+ if(nodes == 0 || is_nochild())
return list;
node_ref_t child_node = m_node;
for(size_t i = 0; i < nodes->size(); i++)
@@ -1661,6 +1674,7 @@ std::vector< node_inst_t > node_inst_t::children() const
n_path.push_back(inst.id);
switch(inst.type)
{
+ case instance_t::FLOATING:
case instance_t::SINGLE:
i_path.push_back(INST_NO_INDEX);
list.push_back(node_inst_t(child_node, n_path, i_path));
@@ -1684,6 +1698,12 @@ std::vector< node_inst_t > node_inst_t::children() const
return list;
}
+bool node_inst_t::is_nochild() const
+{
+ instance_t *inst = get();
+ return inst == 0 ? false : inst->nochild;
+}
+
std::string node_inst_t::name() const
{
instance_t *inst = get();