1
0
Fork 0
forked from len0rd/rockbox

headergen_v2: add floating instances and nochild flag

Floating instances don't have an address and will only generate
child nodes and registers with offsets. The 'nochild' flag will
disable generating the children for a node but will generate the
node's own address, which can be used to generate base addresses.

Change-Id: Ib1014de94531436d5708db46aa684741e7740ace
This commit is contained in:
Aidan MacDonald 2025-01-27 00:58:11 +00:00 committed by Solomon Peachy
parent 0f5c2877fe
commit 387f67cab6
5 changed files with 109 additions and 25 deletions

View file

@ -24,3 +24,4 @@ $(LIB):
clean: clean:
rm -fr $(EXEC) rm -fr $(EXEC)
make -C lib clean

View file

@ -146,7 +146,43 @@ are:
- F[2] at 0x50+(2/2)*0x100+(2%2)*0x10 = 0x50+0x100 = 0x150 - 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 - 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.
<node>
<name>N</name>
<instance>
<name>F</name>
<floating>1</floating>
</instance>
</node>
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:
<node>
<name>N</name>
<instance>
<name>F</name>
<nochild>1</nochild>
<address>0x1234</address>
</instance>
</node>
Nochild instances can use both <address> and <range> 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 For documentation purposes, node can of course carry some description, as well
@ -177,7 +213,7 @@ The following example illustrates this:
</instance> </instance>
</node> </node>
1.4) Register description 1.5) Register description
-------------------------- --------------------------
The goal of the register description is of course to describe registers! 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 - PRIORITY(2:1): it has no named values
- ARM_MODE(3): it has two named values IRQ(0) and FIQ(1) - 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), 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.CLR at 0x80000018, register blabla
- DMAC.I2C_CHAN.TOG at 0x8000001C, 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 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 - desc: free form description of the instance
- address: address for a single instance (non-negative number) - address: address for a single instance (non-negative number)
- range: address range for multiple instances - range: address range for multiple instances
Note that address and range are mutually exclusive, and at least one of them - floating: 0 or 1, if 1 then the instance is floating and has no address
must exists. - 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 Element: range
-------------- --------------

View file

@ -887,6 +887,8 @@ std::string common_generator::register_address(const pseudo_node_inst_t& reg,
} }
else if(inst.type == instance_t::SINGLE) else if(inst.type == instance_t::SINGLE)
oss << to_hex(inst.addr); oss << to_hex(inst.addr);
else if (inst.type == instance_t::FLOATING)
return "";
else else
return "#error unknown instance type"; 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 bfm_prefix = macro_basename(reg, MT_FIELD_BFM) + field_prefix();
std::string bfv_prefix = macro_basename(reg, MT_FIELD_BFV) + 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(); 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(); register_ref_t regr = reg.inst.node().reg();
/* handle register the same way as variants */ /* handle register the same way as variants */
@ -923,6 +926,7 @@ bool common_generator::generate_register(std::ostream& os, const pseudo_node_ins
var_prefix.push_back(""); var_prefix.push_back("");
var_suffix.push_back(""); var_suffix.push_back("");
var_access.push_back(register_access("", regr.get()->access)); var_access.push_back(register_access("", regr.get()->access));
if(has_addr)
var_addr.push_back(addr); var_addr.push_back(addr);
var_offset.push_back(offset); var_offset.push_back(offset);
@ -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_prefix.push_back(variant_xfix(variants[i].type(), true));
var_suffix.push_back(variant_xfix(variants[i].type(), false)); var_suffix.push_back(variant_xfix(variants[i].type(), false));
if (has_addr)
{
var_addr.push_back("(" + type_xfix(MT_REG_ADDR, true) + basename + var_addr.push_back("(" + type_xfix(MT_REG_ADDR, true) + basename +
type_xfix(MT_REG_ADDR, false) + addr_param_str + " + " + type_xfix(MT_REG_ADDR, false) + addr_param_str + " + " +
to_hex(variants[i].offset()) + ")"); to_hex(variants[i].offset()) + ")");
}
var_offset.push_back("(" + type_xfix(MT_REG_OFFSET, true) + basename + var_offset.push_back("(" + type_xfix(MT_REG_OFFSET, true) + basename +
type_xfix(MT_REG_OFFSET, false) + offset_param_str + " + " + type_xfix(MT_REG_OFFSET, false) + offset_param_str + " + " +
to_hex(variants[i].offset())); 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) * if we have support macros then we generate something like HW(basename)
* where HW is some support macros to support complex operations. Otherwise * where HW is some support macros to support complex operations. Otherwise
* we just generate something like (*(volatile unsigned uintN_t)basename_addr) */ * we just generate something like (*(volatile unsigned uintN_t)basename_addr) */
if (has_addr)
{
if(!has_support_macros()) if(!has_support_macros())
{ {
std::ostringstream oss; std::ostringstream oss;
oss << "(*(volatile uint" << regr.get()->width << "_t *)" << macro_addr + addr_param_str << ")"; oss << "(*(volatile uint" << regr.get()->width << "_t *)" <<
macro_addr + addr_param_str << ")";
ctx.add(macro_var + addr_param_str, oss.str()); ctx.add(macro_var + addr_param_str, oss.str());
} }
else else
ctx.add(macro_var + addr_param_str, macro_name(MN_VARIABLE) + "(" + var_basename + addr_param_str + ")"); {
ctx.add(macro_var + addr_param_str, macro_name(MN_VARIABLE) +
"(" + var_basename + addr_param_str + ")");
}
/* print ADDR macro */ /* print ADDR macro */
ctx.add(macro_addr + addr_param_str, var_addr[i]); 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 + ")");
if(has_offsets()) 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) bool common_generator::generate_node(std::ostream& os, const pseudo_node_inst_t& node)
{ {
os << "\n";
define_align_context_t ctx; define_align_context_t ctx;
std::vector< std::string > params; std::vector< std::string > params;
std::string addr = register_address(node, 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 param_str = generate_param_str(params);
std::string macro_addr = type_xfix(MT_NODE_ADDR, true) + basename + std::string macro_addr = type_xfix(MT_NODE_ADDR, true) + basename +
type_xfix(MT_NODE_ADDR, false); type_xfix(MT_NODE_ADDR, false);
bool has_addr = !addr.empty();
if (has_addr)
{
os << "\n";
ctx.add(macro_addr + param_str, addr); ctx.add(macro_addr + param_str, addr);
}
ctx.print(os); ctx.print(os);
return true; return true;

View file

@ -230,7 +230,8 @@ struct instance_t
enum type_t enum type_t
{ {
SINGLE, /** There is a single instance at a specified address */ 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) */ soc_id_t id; /** ID (must be unique among node instances) */
@ -240,9 +241,10 @@ struct instance_t
type_t type; /** Instance type */ type_t type; /** Instance type */
soc_word_t addr; /** Address (for SINGLE) */ soc_word_t addr; /** Address (for SINGLE) */
range_t range; /** Range (for RANGE) */ range_t range; /** Range (for RANGE) */
bool nochild; /** Disable child node generation if set */
/** Default constructor: single instance at 0 */ /** 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 */ /** Node information */
@ -544,6 +546,8 @@ public:
node_inst_t child(const std::string& name, size_t index) const; 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 */ /** Returns a list of all instances of subnodes of this node's instance */
std::vector< node_inst_t > children() const; 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 */ /** Returns the name of the instance */
std::string name() const; std::string name() const;
/** Checks whether this instance is indexed */ /** Checks whether this instance is indexed */

View file

@ -458,24 +458,37 @@ bool parse_instance_elem(xmlNode *node, instance_t& inst, error_context_t& ctx)
{ {
bool ret = true; bool ret = true;
bool has_name = false, has_title = false, has_desc = false, has_range = false; 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) BEGIN_NODE_MATCH(node->children)
MATCH_UNIQUE_TEXT_NODE("name", inst.name, has_name, parse_name_elem, ctx) 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("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("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_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_UNIQUE_ELEM_NODE("range", inst.range, has_range, parse_range_elem, ctx)
MATCH_UNUSED_NODE(parse_unknown_elem, ctx) MATCH_UNUSED_NODE(parse_unknown_elem, ctx)
END_NODE_MATCH() END_NODE_MATCH()
CHECK_HAS(node, "name", has_name, ctx) 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 <range", ctx); ret = ret && parse_missing_error(node, "address> or <range", ctx);
if(has_address && has_range) if(has_address && has_range)
ret = ret && parse_conflict_error(node, "address", "range", ctx); ret = ret && parse_conflict_error(node, "address", "range", ctx);
if(has_address) if(floating && has_address)
ret = ret && parse_conflict_error(node, "floating", "address", ctx);
if(floating && has_range)
ret = ret && parse_conflict_error(node, "floating", "range", ctx);
if(floating && nochild)
ret = ret && parse_conflict_error(node, "floating", "nochild", ctx);
if(floating)
inst.type = instance_t::FLOATING;
else if(has_address)
inst.type = instance_t::SINGLE; inst.type = instance_t::SINGLE;
else else
inst.type = instance_t::RANGE; inst.type = instance_t::RANGE;
if (nochild)
inst.nochild = true;
return ret; return ret;
} }
@ -1620,7 +1633,7 @@ node_inst_t node_inst_t::child(const std::string& name) const
node_inst_t node_inst_t::child(const std::string& name, size_t index) const node_inst_t node_inst_t::child(const std::string& name, size_t index) const
{ {
std::vector< node_t > *nodes = get_children(m_node); std::vector< node_t > *nodes = get_children(m_node);
if(nodes == 0) if(nodes == 0 || is_nochild())
return node_inst_t(); return node_inst_t();
node_ref_t child_node = m_node; node_ref_t child_node = m_node;
for(size_t i = 0; i < nodes->size(); i++) 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< node_t > *nodes = get_children(m_node);
std::vector< soc_id_t > n_path = m_id_path; std::vector< soc_id_t > n_path = m_id_path;
std::vector< size_t > i_path = m_index_path; std::vector< size_t > i_path = m_index_path;
if(nodes == 0) if(nodes == 0 || is_nochild())
return list; return list;
node_ref_t child_node = m_node; node_ref_t child_node = m_node;
for(size_t i = 0; i < nodes->size(); i++) 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); n_path.push_back(inst.id);
switch(inst.type) switch(inst.type)
{ {
case instance_t::FLOATING:
case instance_t::SINGLE: case instance_t::SINGLE:
i_path.push_back(INST_NO_INDEX); i_path.push_back(INST_NO_INDEX);
list.push_back(node_inst_t(child_node, n_path, i_path)); 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; 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 std::string node_inst_t::name() const
{ {
instance_t *inst = get(); instance_t *inst = get();