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();