[rtems-central commit] interface: Add register-block support

Sebastian Huber sebh at rtems.org
Wed Jul 21 17:20:21 UTC 2021


Module:    rtems-central
Branch:    master
Commit:    72508ab04e1008d9afe278a44b688c692199f5bb
Changeset: http://git.rtems.org/rtems-central/commit/?id=72508ab04e1008d9afe278a44b688c692199f5bb

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Mon May  3 10:36:15 2021 +0200

interface: Add register-block support

---

 rtemsspec/interface.py                             | 191 +++++++++++++++++++-
 rtemsspec/tests/spec-interface/c/if/uint32_t.yml   |  17 ++
 .../tests/spec-interface/irqamp-timestamp.yml      | 123 +++++++++++++
 rtemsspec/tests/spec-interface/irqamp.yml          |  72 ++++++++
 rtemsspec/tests/spec/interface-more.yml            |   4 +
 rtemsspec/tests/test_interface.py                  | 192 ++++++++++++++++++++-
 spec/spec/interface-register-block.yml             |  26 +++
 7 files changed, 619 insertions(+), 6 deletions(-)

diff --git a/rtemsspec/interface.py b/rtemsspec/interface.py
index 6133556..4a637cf 100644
--- a/rtemsspec/interface.py
+++ b/rtemsspec/interface.py
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: BSD-2-Clause
 """ This module provides functions for the generation of interfaces. """
 
-# Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de)
+# Copyright (C) 2020, 2021 embedded brains GmbH (http://www.embedded-brains.de)
 #
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions
@@ -24,13 +24,18 @@
 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 # POSSIBILITY OF SUCH DAMAGE.
 
+import collections
 from contextlib import contextmanager
+import functools
+import itertools
 import os
-from typing import Any, Callable, Dict, Iterator, List, Optional, Union, Set
+from typing import Any, Callable, Dict, Iterator, List, NamedTuple, Optional, \
+    Union, Set, Tuple
 
 from rtemsspec.content import CContent, CInclude, enabled_by_to_exp, \
     ExpressionMapper, get_value_double_colon, get_value_doxygen_function, \
-    get_value_doxygen_group, get_value_hash, get_value_params, get_value_plural
+    get_value_doxygen_group, get_value_hash, get_value_params, \
+    get_value_plural, to_camel_case
 from rtemsspec.items import Item, ItemCache, ItemGetValueContext, \
     ItemGetValueMap, ItemMapper
 
@@ -182,6 +187,35 @@ def _add_definition(node: "Node", item: Item, prefix: str,
     return content
 
 
+class _RegisterMemberContext(NamedTuple):
+    sizes: Dict[int, int]
+    regs: Dict[str, Any]
+    reg_counts: Dict[str, int]
+    reg_indices: Dict[str, int]
+
+
+def _add_register_padding(content: CContent, new_offset: int, old_offset: int,
+                          default_padding: int) -> None:
+    delta = new_offset - old_offset
+    if delta > 0:
+        padding = default_padding
+        while delta % padding != 0:
+            padding //= 2
+        count = delta // padding
+        array = f"[ {count} ]" if count > 1 else ""
+        content.add(f"uint{padding * 8}_t "
+                    f"reserved_{old_offset:x}_{new_offset:x}{array};")
+
+
+def _get_register_name(definition: Dict[str, Any]) -> Tuple[str, str]:
+    name = definition["name"]
+    try:
+        name, alias = name.split(":")
+    except ValueError:
+        alias = name
+    return name, alias
+
+
 class Node:
     """ Nodes of a header file. """
 
@@ -297,6 +331,105 @@ class Node:
         """ Generates a macro. """
         self._add_generic_definition(Node._get_macro_definition)
 
+    def _add_register_bits(self, group: str) -> _RegisterMemberContext:
+        ctx = _RegisterMemberContext({}, {}, collections.defaultdict(int),
+                                     collections.defaultdict(int))
+        for index, register in enumerate(self.item["registers"]):
+            name = register["name"]
+            group_ident = group + to_camel_case(name)
+            ctx.regs[name] = {}
+            width = register["width"]
+            assert width in [8, 16, 32, 64]
+            ctx.regs[name]["size"] = width // 8
+            ctx.regs[name]["type"] = f"uint{width}_t"
+            ctx.regs[name]["group"] = group_ident
+            with self.content.defgroup_block(group_ident, name):
+                self.content.add_brief_description(
+                    self.substitute_text(register["brief"]))
+                self.content.doxyfy(
+                    self.substitute_text(register["description"]))
+                self.content.add("@{")
+            for index_2, bits in enumerate(register["bits"]):
+                self.content.add(
+                    _add_definition(
+                        self, self.item, f"registers[{index}]/bits[{index_2}]",
+                        bits,
+                        functools.partial(Node._get_register_bits_definition,
+                                          reg_name=name)))
+            self.content.close_add_to_group()
+        return ctx
+
+    def _add_register_block_includes(self,
+                                     ctx: _RegisterMemberContext) -> None:
+        for link in self.item.links_to_parents("register-block-include"):
+            name = link["name"]
+            ctx.regs[name] = {}
+            ctx.regs[name]["size"] = link.item["register-block-size"]
+            ctx.regs[name]["type"] = link.item["name"]
+            ctx.regs[name]["group"] = link.item["identifier"]
+
+    def _get_register_member_info(self, ctx: _RegisterMemberContext) -> None:
+        offset = -1
+        for index, member in enumerate(self.item["definition"]):
+            assert member["offset"] > offset
+            offset = member["offset"]
+            default = [member["default"]] if member["default"] else []
+            for index_2, definition in enumerate(
+                    itertools.chain(default,
+                                    (variant["definition"]
+                                     for variant in member["variants"]))):
+                name, alias = _get_register_name(definition)
+                assert name.lower() != "reserved"
+                count = definition["count"]
+                if index_2 == 0:
+                    ctx.sizes[index] = ctx.regs[name]["size"] * count
+                else:
+                    assert ctx.sizes[index] == ctx.regs[name]["size"] * count
+                ctx.reg_counts[alias] += 1
+
+    def _add_register_members(self, ctx: _RegisterMemberContext) -> None:
+        default_padding = min(ctx.sizes.values())
+        with self.content.doxygen_block():
+            self.content.add_brief_description(
+                self.substitute_text(self.item["brief"]))
+            self.content.doxyfy(self.substitute_text(self.item["description"]))
+        self.content.append(f"typedef struct {self.item['name']} {{")
+        offset = 0
+        with self.content.indent():
+            for index, member in enumerate(self.item["definition"]):
+                member_offset = member["offset"]
+                _add_register_padding(self.content, member_offset, offset,
+                                      default_padding)
+                self.content.add(
+                    _add_definition(
+                        self, self.item, f"definition[{index}]", member,
+                        functools.partial(Node._get_register_member_definition,
+                                          ctx=ctx)))
+                offset = member_offset + ctx.sizes[index]
+            size = self.item["register-block-size"]
+            assert offset <= size
+            _add_register_padding(self.content, size, offset, default_padding)
+        self.content.add(f"}} {self.item['name']};")
+
+    def generate_register_block(self) -> None:
+        """ Generates a register block. """
+        self.header_file.add_includes(self.item.map("/c/if/uint32_t"))
+        for parent in self.item.parents("register-block-include"):
+            self.header_file.add_includes(parent)
+            self.header_file.add_dependency(self, parent)
+        group = self.item["identifier"]
+        name = self.item["register-block-group"]
+        with self.content.defgroup_block(group, name):
+            self.content.add_ingroup(_get_group_identifiers(self.ingroups))
+            self.content.add_brief_description(
+                f"This group contains the {name} interfaces.")
+            self.content.add("@{")
+        ctx = self._add_register_bits(group)
+        self._add_register_block_includes(ctx)
+        self._get_register_member_info(ctx)
+        self._add_register_members(ctx)
+        self.content.close_add_to_group()
+
     def generate_typedef(self) -> None:
         """ Generates a typedef. """
         self._add_generic_definition(Node._get_typedef_definition)
@@ -400,6 +533,54 @@ class Node:
         body += " \\\n  ".join(body_lines)
         return line + body
 
+    def _get_register_bits_definition(self, _item: Item, definition: Any,
+                                      reg_name: str) -> Lines:
+        lines = []  # List[str]
+        prefix = self.item["register-prefix"]
+        if prefix is None:
+            prefix = self.item["name"]
+        prefix = f"{prefix}_{reg_name}_" if prefix else f"{reg_name}_"
+        for index, bit in enumerate(definition):
+            start = bit["start"]
+            width = bit["width"]
+            end = start + width
+            sfx = "ULL" if end > 32 else "U"
+            define = f"#define {prefix.upper()}{bit['name'].upper()}"
+            if index != 0:
+                lines.append("")
+            if width == 1:
+                val = 1 << start
+                lines.append(f"{define} {val:#x}{sfx}")
+            else:
+                mask = ((1 << width) - 1) << start
+                get = (1 << width) - 1
+                lines.extend([
+                    f"{define}_SHIFT {start}", f"{define}_MASK {mask:#x}{sfx}",
+                    f"{define}_GET( _reg ) \\",
+                    f"  ( ( ( _reg ) >> {start} ) & {get:#x}{sfx} )",
+                    f"{define}( _val ) ( ( _val ) << {start} )"
+                ])
+        return lines
+
+    def _get_register_member_definition(self, _item: Item, definition: Any,
+                                        ctx: _RegisterMemberContext) -> Lines:
+        # pylint: disable=no-self-use
+        name, alias = _get_register_name(definition)
+        count = definition["count"]
+        array = f"[ {count} ]" if count > 1 else ""
+        if ctx.reg_counts[alias] > 1:
+            index = ctx.reg_indices[alias]
+            ctx.reg_indices[alias] = index + 1
+            idx = f"_{index}"
+        else:
+            idx = ""
+        content = CContent()
+        with content.doxygen_block():
+            content.add(f"@brief See @ref {ctx.regs[name]['group']}.")
+        content.append(
+            f"{ctx.regs[name]['type']} {alias.lower()}{idx}{array};")
+        return content.lines
+
     def _get_typedef_definition(self, _item: Item, definition: Any) -> Lines:
         return f"typedef {self.substitute_code(definition)};"
 
@@ -450,6 +631,7 @@ _NODE_GENERATORS = {
     "function": Node.generate_function,
     "group": Node.generate_group,
     "macro": Node.generate_macro,
+    "register-block": Node.generate_register_block,
     "struct": Node.generate_compound,
     "typedef": Node.generate_typedef,
     "union": Node.generate_compound,
@@ -585,8 +767,7 @@ class _HeaderFile:
             includes.extend([
                 CInclude(link.item["path"],
                          enabled_by_to_exp(link["enabled-by"], exp_mapper))
-                for link in self._item.links_to_parents()
-                if link.role == "interface-include"
+                for link in self._item.links_to_parents("interface-include")
             ])
             self._content.add_includes(includes)
             with self._content.extern_c():
diff --git a/rtemsspec/tests/spec-interface/c/if/uint32_t.yml b/rtemsspec/tests/spec-interface/c/if/uint32_t.yml
new file mode 100644
index 0000000..ce9cd90
--- /dev/null
+++ b/rtemsspec/tests/spec-interface/c/if/uint32_t.yml
@@ -0,0 +1,17 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+brief: null
+copyrights:
+- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de)
+definition:
+  default: unsigned
+  variants: []
+description: null
+enabled-by: true
+index-entries: []
+interface-type: define
+links:
+- role: interface-placement
+  uid: ../../stdint
+name: uint32_t
+notes: null
+type: interface
diff --git a/rtemsspec/tests/spec-interface/irqamp-timestamp.yml b/rtemsspec/tests/spec-interface/irqamp-timestamp.yml
new file mode 100644
index 0000000..9ec01ea
--- /dev/null
+++ b/rtemsspec/tests/spec-interface/irqamp-timestamp.yml
@@ -0,0 +1,123 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+brief: |
+  This structure defines the ${.:/register-block-group} register block memory
+  map.
+copyrights:
+- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de)
+description: null
+enabled-by: true
+identifier: IrqampTimestamp
+index-entries: []
+interface-type: register-block
+links:
+- role: interface-placement
+  uid: h
+definition:
+- default:
+    count: 1
+    name: ITCNT
+  offset: 0x0
+  variants: []
+- default:
+    count: 1
+    name: ITSTMPC
+  offset: 0x4
+  variants: []
+- default:
+    count: 1
+    name: ITSTMPAS
+  offset: 0x8
+  variants: []
+- default:
+    count: 1
+    name: ITSTMPAC
+  offset: 0xc
+  variants: []
+register-prefix: IRQAMP
+register-block-group: IRQ(A)MP Timestamp
+register-block-size: 16
+register-block-type: memory
+registers:
+- bits:
+  - default:
+    - access: [r]
+      brief: null
+      description: null
+      name: 'TCNT'
+      start: 0
+      width: 32
+    variants: []
+  brief: |
+    Interrupt timestamp counter n register
+  description: null
+  name: ITCNT
+  width: 32
+- bits:
+  - default:
+    - access: [r]
+      brief: null
+      description: null
+      name: 'TSTAMP'
+      start: 27
+      width: 5
+    - access: [r, w1c]
+      brief: null
+      description: null
+      name: 'S1'
+      start: 26
+      width: 1
+    - access: [r, w1c]
+      brief: null
+      description: null
+      name: 'S2'
+      start: 25
+      width: 1
+    - access: [r, w]
+      brief: null
+      description: null
+      name: 'KS'
+      start: 5
+      width: 1
+    - access: [r, w]
+      brief: null
+      description: null
+      name: 'TSISEL'
+      start: 0
+      width: 5
+    variants: []
+  brief: |
+    Interrupt timestamp n control register
+  description: null
+  name: ITSTMPC
+  width: 32
+- bits:
+  - default:
+    - access: [r]
+      brief: null
+      description: null
+      name: 'TASSERTION'
+      start: 0
+      width: 32
+    variants: []
+  brief: |
+    Interrupt Assertion Timestamp n register
+  description: null
+  name: ITSTMPAS
+  width: 32
+- bits:
+  - default:
+    - access: [r]
+      brief: null
+      description: null
+      name: 'TACKNOWLEDGE'
+      start: 0
+      width: 32
+    variants: []
+  brief: |
+    Interrupt Acknowledge Timestamp n register
+  description: null
+  name: ITSTMPAC
+  width: 32
+name: irqamp_timestamp
+notes: null
+type: interface
diff --git a/rtemsspec/tests/spec-interface/irqamp.yml b/rtemsspec/tests/spec-interface/irqamp.yml
new file mode 100644
index 0000000..beccec9
--- /dev/null
+++ b/rtemsspec/tests/spec-interface/irqamp.yml
@@ -0,0 +1,72 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+brief: |
+  This structure defines the ${.:/register-block-group} register block memory
+  map.
+copyrights:
+- Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de)
+description: null
+enabled-by: true
+identifier: Irqamp
+index-entries: []
+interface-type: register-block
+links:
+- role: interface-placement
+  uid: h
+- name: ITSTMP
+  role: register-block-include
+  uid: irqamp-timestamp
+definition:
+- default:
+    count: 1
+    name: ILEVEL:FOOBAR
+  offset: 0x0
+  variants: []
+- default:
+    count: 1
+    name: ILEVEL:FOOBAR
+  offset: 0x4
+  variants:
+  - definition:
+      count: 4
+      name: IPEND8
+    enabled-by: defined(RTEMS_SMP)
+- default:
+    count: 4
+    name: IPEND8
+  offset: 0x9
+  variants: []
+- default:
+    count: 16
+    name: ITSTMP
+  offset: 0x100
+  variants: []
+register-prefix: null
+register-block-group: IRQ(A)MP
+register-block-size: 1024
+register-block-type: memory
+registers:
+- bits:
+  - default:
+    - access: [r, w]
+      brief: null
+      description: null
+      name: 'IL_15_1'
+      start: 1
+      width: 15
+    variants: []
+  brief: |
+    Interrupt level register
+  description: null
+  name: ILEVEL
+  width: 32
+- bits:
+  - default: []
+    variants: []
+  brief: |
+    Interrupt pending register
+  description: null
+  name: IPEND8
+  width: 8
+name: irqamp
+notes: null
+type: interface
diff --git a/rtemsspec/tests/spec/interface-more.yml b/rtemsspec/tests/spec/interface-more.yml
index 9c7917e..aff1b49 100644
--- a/rtemsspec/tests/spec/interface-more.yml
+++ b/rtemsspec/tests/spec/interface-more.yml
@@ -59,6 +59,10 @@ links:
   uid: interface
 - role: spec-refinement
   spec-key: interface-type
+  spec-value: register-block
+  uid: interface
+- role: spec-refinement
+  spec-key: interface-type
   spec-value: typedef
   uid: interface
 - role: spec-refinement
diff --git a/rtemsspec/tests/test_interface.py b/rtemsspec/tests/test_interface.py
index b7b0fee..9e23bb3 100644
--- a/rtemsspec/tests/test_interface.py
+++ b/rtemsspec/tests/test_interface.py
@@ -61,7 +61,7 @@ def test_interface(tmpdir):
  */
 
 /*
- * Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de)
+ * Copyright (C) 2020, 2021 embedded brains GmbH (http://www.embedded-brains.de)
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -242,6 +242,196 @@ void Function(
 /* Generated from spec:/func6 */
 void Function6( int Param0 );
 
+/* Generated from spec:/irqamp-timestamp */
+
+/**
+ * @defgroup IrqampTimestamp IRQ(A)MP Timestamp
+ *
+ * @brief This group contains the IRQ(A)MP Timestamp interfaces.
+ *
+ * @{
+ */
+
+/**
+ * @defgroup IrqampTimestampITCNT ITCNT
+ *
+ * @brief Interrupt timestamp counter n register
+ *
+ * @{
+ */
+
+#define IRQAMP_ITCNT_TCNT_SHIFT 0
+#define IRQAMP_ITCNT_TCNT_MASK 0xffffffffU
+#define IRQAMP_ITCNT_TCNT_GET( _reg ) \\
+  ( ( ( _reg ) >> 0 ) & 0xffffffffU )
+#define IRQAMP_ITCNT_TCNT( _val ) ( ( _val ) << 0 )
+
+/** @} */
+
+/**
+ * @defgroup IrqampTimestampITSTMPC ITSTMPC
+ *
+ * @brief Interrupt timestamp n control register
+ *
+ * @{
+ */
+
+#define IRQAMP_ITSTMPC_TSTAMP_SHIFT 27
+#define IRQAMP_ITSTMPC_TSTAMP_MASK 0xf8000000U
+#define IRQAMP_ITSTMPC_TSTAMP_GET( _reg ) \\
+  ( ( ( _reg ) >> 27 ) & 0x1fU )
+#define IRQAMP_ITSTMPC_TSTAMP( _val ) ( ( _val ) << 27 )
+
+#define IRQAMP_ITSTMPC_S1 0x4000000U
+
+#define IRQAMP_ITSTMPC_S2 0x2000000U
+
+#define IRQAMP_ITSTMPC_KS 0x20U
+
+#define IRQAMP_ITSTMPC_TSISEL_SHIFT 0
+#define IRQAMP_ITSTMPC_TSISEL_MASK 0x1fU
+#define IRQAMP_ITSTMPC_TSISEL_GET( _reg ) \\
+  ( ( ( _reg ) >> 0 ) & 0x1fU )
+#define IRQAMP_ITSTMPC_TSISEL( _val ) ( ( _val ) << 0 )
+
+/** @} */
+
+/**
+ * @defgroup IrqampTimestampITSTMPAS ITSTMPAS
+ *
+ * @brief Interrupt Assertion Timestamp n register
+ *
+ * @{
+ */
+
+#define IRQAMP_ITSTMPAS_TASSERTION_SHIFT 0
+#define IRQAMP_ITSTMPAS_TASSERTION_MASK 0xffffffffU
+#define IRQAMP_ITSTMPAS_TASSERTION_GET( _reg ) \\
+  ( ( ( _reg ) >> 0 ) & 0xffffffffU )
+#define IRQAMP_ITSTMPAS_TASSERTION( _val ) ( ( _val ) << 0 )
+
+/** @} */
+
+/**
+ * @defgroup IrqampTimestampITSTMPAC ITSTMPAC
+ *
+ * @brief Interrupt Acknowledge Timestamp n register
+ *
+ * @{
+ */
+
+#define IRQAMP_ITSTMPAC_TACKNOWLEDGE_SHIFT 0
+#define IRQAMP_ITSTMPAC_TACKNOWLEDGE_MASK 0xffffffffU
+#define IRQAMP_ITSTMPAC_TACKNOWLEDGE_GET( _reg ) \\
+  ( ( ( _reg ) >> 0 ) & 0xffffffffU )
+#define IRQAMP_ITSTMPAC_TACKNOWLEDGE( _val ) ( ( _val ) << 0 )
+
+/** @} */
+
+/**
+ * @brief This structure defines the IRQ(A)MP Timestamp register block memory
+ *   map.
+ */
+typedef struct irqamp_timestamp {
+  /**
+   * @brief See @ref IrqampTimestampITCNT.
+   */
+  uint32_t itcnt;
+
+  /**
+   * @brief See @ref IrqampTimestampITSTMPC.
+   */
+  uint32_t itstmpc;
+
+  /**
+   * @brief See @ref IrqampTimestampITSTMPAS.
+   */
+  uint32_t itstmpas;
+
+  /**
+   * @brief See @ref IrqampTimestampITSTMPAC.
+   */
+  uint32_t itstmpac;
+} irqamp_timestamp;
+
+/** @} */
+
+/* Generated from spec:/irqamp */
+
+/**
+ * @defgroup Irqamp IRQ(A)MP
+ *
+ * @brief This group contains the IRQ(A)MP interfaces.
+ *
+ * @{
+ */
+
+/**
+ * @defgroup IrqampILEVEL ILEVEL
+ *
+ * @brief Interrupt level register
+ *
+ * @{
+ */
+
+#define IRQAMP_ILEVEL_IL_15_1_SHIFT 1
+#define IRQAMP_ILEVEL_IL_15_1_MASK 0xfffeU
+#define IRQAMP_ILEVEL_IL_15_1_GET( _reg ) \\
+  ( ( ( _reg ) >> 1 ) & 0x7fffU )
+#define IRQAMP_ILEVEL_IL_15_1( _val ) ( ( _val ) << 1 )
+
+/** @} */
+
+/**
+ * @defgroup IrqampIPEND8 IPEND8
+ *
+ * @brief Interrupt pending register
+ *
+ * @{
+ */
+
+/** @} */
+
+/**
+ * @brief This structure defines the IRQ(A)MP register block memory map.
+ */
+typedef struct irqamp {
+  /**
+   * @brief See @ref IrqampILEVEL.
+   */
+  uint32_t foobar_0;
+
+  #if defined(RTEMS_SMP)
+    /**
+     * @brief See @ref IrqampIPEND8.
+     */
+    uint8_t ipend8_0[ 4 ];
+  #else
+    /**
+     * @brief See @ref IrqampILEVEL.
+     */
+    uint32_t foobar_1;
+  #endif
+
+  uint8_t reserved_8_9;
+
+  /**
+   * @brief See @ref IrqampIPEND8.
+   */
+  uint8_t ipend8_1[ 4 ];
+
+  uint8_t reserved_d_100[ 243 ];
+
+  /**
+   * @brief See @ref IrqampTimestamp.
+   */
+  irqamp_timestamp itstmp[ 16 ];
+
+  uint32_t reserved_200_400[ 128 ];
+} irqamp;
+
+/** @} */
+
 /* Generated from spec:/macro */
 
 /**
diff --git a/spec/spec/interface-register-block.yml b/spec/spec/interface-register-block.yml
new file mode 100644
index 0000000..23f3ef4
--- /dev/null
+++ b/spec/spec/interface-register-block.yml
@@ -0,0 +1,26 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+copyrights:
+- Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de)
+enabled-by: true
+links:
+- role: spec-member
+  uid: root
+- role: spec-refinement
+  spec-key: interface-type
+  spec-value: register-block
+  uid: interface
+spec-description: null
+spec-example: null
+spec-info:
+  dict:
+    attributes: {}
+    description: |
+      This set of attributes defines a register block.
+    generic-attributes:
+      description: null
+      key-spec-type: name
+      value-spec-type: any
+    mandatory-attributes: all
+spec-name: Interface Register Block Item Type
+spec-type: interface-register-block
+type: spec



More information about the vc mailing list