[PATCH v2] eng: Add register block specification types

Chris Johns chrisj at rtems.org
Tue Mar 28 05:53:12 UTC 2023


On 23/3/2023 3:59 am, Sebastian Huber wrote:
> Hello Chris,
> 
> I would like to come back to this topic, because it blocks the integration of
> the sparc/gr712rc and sparc/gr740 changes we have done for the pre-qualification
> activity.
> 
> On 27.09.21 02:23, Chris Johns wrote:
>> On 24/9/21 11:09 pm, Sebastian Huber wrote:
>>> A register block may be used to specify the interface of devices which
>>> use a linear address space.  Register blocks consist of register block
>>
>> Can we please move away from the "linear address" in the definitions? As stated
>> previously it only serves a specialized version of a bus and register-block.
>> What about something like this:
>>
>> A register block specifies a word addressable set of elements in a device
>> software is required to access and manipulate. The mechanics software uses to
>> access a register element in a register-block is defined by the bus-interface.
>> The software and register may be a direct coupling to the CPU bus as found in a
>> linear cache coherent memory mapped device or the access may be indirect through
>> a bus hierarchy that may require more than one software action to complete.
>> Device and register specifications are independent of the CPU architecture and
>> connecting bus architectures.
> 
> A linear address space is just an address space in which a single integer is
> sufficient to address something. So a word addressable set of elements in a
> device is a linear address space. In contrast to for example the AArch32 system
> register space, which uses a coprocessor index, Opcode_1, CRn, CRm, and
> Opcode_2. An address space granule is the smallest block of memory that can be
> addressed. This could be a subword depending on what a word is and the bus
> system capabilities.

I am sorry I have read and reread this and I do not follow. I do not know if you
are saying the aarch64 cp access and addressing is an example for or a counter
example?

The term "linear address" offers no value. An address bus at any point in a
circuit is are collection of signals wired to the address decoder of a device so
by the nature of how that works it is going to resolve itself to a number and to
be accurate it is a whole number because the concept of negative addressing
would be interesting. The wiring of the interfacing address to a device's
address bus does not have to be 1:1 and it does not need to be continuous in the
external interface's addressing scheme. If linear is saying there is a series of
numbers then again I wonder what the value is. You can view this in datasheets
and code that maps struct to memory mapping devices because reserved (or what
ever they get called) are added. Adding these reserved etc fields is doing
nothing more than making a memory mapped struct work as you hope and I mean
hope. That logic needs a continuous address space.

> The offsets in the register block specification are just the offset you find in
> the corresponding datasheet.
> 
>>
>> I know this is just the commit message but I think this should be in the manual.
>>
>> bus-interface:
>>
>> A bus interface is the mechanics software uses to access a register word element
>> in a device. A bus interface specifies the requirements needed by software to
>> access a register word. It must consider timing, CPU word size to device word
>> size, byte ordering for word sizes greater than 8bits, cache considerations and
>> sequencing of multiple software accesses if required.
>>
>> I would like to see a bus-interface section and the device reference it. It only
>> needs to cover the type of bus interface you need to specify at this point in
>> time.
> 
> At the moment I just have a header file generator for memory-mapped devices. I
> don't think there will be major issues to adopt the generator to output
> interfaces for some bus space API.

I think the language used is too specific to memory mapped devices.

>>> use a linear address space.
>>> members specified by the ``definition`` attribute.  Register block
>>> members are either instances of registers specified by the ``registers``
>>> attribute or instances of other register blocks specified by links with
>>> the "register-block-include" link role.  Registers consists of bit
>>> fields.
>>
>> Registers are defined in terms of the device word size. The bus interface needs
>> to deal with the CPU word size to device word size.
> 
> I don't think that a single "word size" is sufficient. A device may have
> registers of different sizes. For example an array of 8-bit registers with
> priorities and a 32-bit status register. Some devices may only have 64-bit
> registers, so here using a "word" makes sense, but not in the general case.

The data size is wired and fixed. There is nothing dynamic happening here. This
is the word size of the device I am talking about. Accessing parts of device's
word size is a function of the bus it is connected to and the ability of the
device to control the data pins it outputs data on. Different buses handle this
in different ways.

>> Is the bit ordering the CPU architecture order or some other form of ordering?
> 
> It would be up to a bus interface specification to deal with bit orderings. For
> an isolated register block specification the bit ordering should match with the
> datasheet.
>>
>> The register block members are placed into the address space of
>>> the device relative to the base address of the register block.  Register
>>> member offests and the register block size are specified in units of the
>>> address space granule.  The address space granule is usually 8-bits also
>>> known as one byte.
>>
>> This paragraph would be much simpler and clearer if defined in terms of a bus
>> interface. The use of "usually" could be avoided.
> 
> Ok, I will move the "usually" stuff to a paragraph which states what the
> abstract terms mean if you have a memory-mapped device.
> 
>>
>>>
>>> Update #3715.
>>> ---
>>> For examples see:
>>>
>>> https://git.rtems.org/rtems-central/tree/spec/dev/grlib/if
>>>
>>> v2:
>>>
>>> Clarify wording and remove the "register-block-type" attribute.
>>>
>>>   eng/req/items.rst | 322 ++++++++++++++++++++++++++++++++++++++++++++++
>>>   1 file changed, 322 insertions(+)
>>>
>>> diff --git a/eng/req/items.rst b/eng/req/items.rst
>>> index e1b64b6..924e79d 100644
>>> --- a/eng/req/items.rst
>>> +++ b/eng/req/items.rst
>>> @@ -103,6 +103,8 @@ The specification item types have the following hierarchy:
>>>         * :ref:`SpecTypeInterfaceVariableItemType`
>>>   +    * :ref:`SpecTypeRegisterBlockItemType`
>>> +
>>>     * :ref:`SpecTypeRequirementItemType`
>>>         * :ref:`SpecTypeFunctionalRequirementItemType`
>>> @@ -1143,6 +1145,8 @@ This type is refined by the following types:
>>>     * :ref:`SpecTypeInterfaceVariableItemType`
>>>   +* :ref:`SpecTypeRegisterBlockItemType`
>>> +
>>>   .. _SpecTypeApplicationConfigurationGroupItemType:
>>>     Application Configuration Group Item Type
>>> @@ -1615,6 +1619,68 @@ name
>>>   notes
>>>       The attribute value shall be an :ref:`SpecTypeInterfaceNotes`.
>>>   +.. _SpecTypeRegisterBlockItemType:
>>> +
>>> +Register Block Item Type
>>> +^^^^^^^^^^^^^^^^^^^^^^^^
>>> +
>>> +This type refines the :ref:`SpecTypeInterfaceItemType` through the
>>> +``interface-type`` attribute if the value is ``register-block``.
>>
>> bus-interface rather than interface-type?
>>
>>> This set of
>>> +attributes specifies a register block.  A register block may be used to specify
>>> +the interface of devices which use a linear address space.
>>
>> How about ...
>>
>> A register block is a set of bus interface addressable device words. Offset
>> values are relative to the device's address bus.
>>
>>>   Register blocks
>>> +consist of register block members specified by the ``definition`` attribute.
>>> +Register block members are either instances of registers specified by the
>>> +``registers`` attribute or instances of other register blocks specified by
>>> +links with the :ref:`SpecTypeRegisterBlockIncludeRole`.  Registers consists of
>>> +bit fields (see :ref:`SpecTypeRegisterBitsDefinition`.  The register block
>>> +members are placed into the address space of the device relative to the base
>>> +address of the register block.
>>
>> This should be part of the bus-interface not the register block.
> 
> What I would like to specify is a set of registers. Each register has an address
> and contains a set of bits. I really don't understand what is the point with the
> bus interface here. All the datasheets I have seen so far use one or more
> integers (or enumerators) to identify a register and a registers contains a
> certain amount of bits. I used this register block specification also for
> network switches which are accessed through SPI.

This is true for a lot of stuff that is wired into devices like SoCs. I work
with FPGA designers and the addressing they provide is relative to their IP's
address bus and not the final wired address bus, eg A0 of a device may be wired
to A2 of a CPU.

>> Register member offests and the register block
>>> +size are specified in units of the address space granule. The address space
>>> +granule is usually 8-bits also known as one byte. All explicit attributes shall
>>> +be specified.
>>
>> This may only be true for a linear memory mapped cache coherent bus-interface.
>> The register block spec becomes much simpler with the introduction of a bus
>> interface construct as most of these words could be removed.
>>
>> And for you the bus-interface is simply "linear memory mapped cache coherent"
>> and in that you only need a simple statement on CPU word to device word mapping,
>> ie 1:1, the timing, ie timing is controlled by the CPU bus interface, and cache
>> coherence, ie the mapped address space needs to be cache coherent.
>>
>> An important aspect of this approach to the specification is the implementation
>> is not detailed and if you wish to implement volatile structs and pointers
>> (<shudder>) or alternatively inline functions you can. The specification is the
>> same.
> 
> I don't see a restriction here with the current specification approach. You can
> use a register bock specification and generate code for a particular bus system.
> You just have to know the bus system.

It is up to you to consider what I have offered. My hope is to avoid this being
a template for struct based memory mapped IO however in the end it will be what
you think you need.

>>> The explicit attributes for this type are:
>>> +
>>> +brief
>>> +    The attribute value shall be an :ref:`SpecTypeInterfaceBriefDescription`.
>>> +
>>> +definition
>>> +    The attribute value shall be a list. Each list element shall be a
>>> +    :ref:`SpecTypeRegisterBlockMemberDefinitionDirective`.
>>> +
>>> +description
>>> +    The attribute value shall be an :ref:`SpecTypeInterfaceDescription`.
>>> +
>>> +identifier
>>> +    The attribute value shall be an :ref:`SpecTypeInterfaceGroupIdentifier`.
>>> +
>>> +name
>>> +    The attribute value shall be a string. It shall be the name of the register
>>> +    block.
>>> +
>>> +notes
>>> +    The attribute value shall be an :ref:`SpecTypeInterfaceNotes`.
>>> +
>>> +register-block-group
>>> +    The attribute value shall be a string. It shall be the name of the
>>> +    interface group defined for the register block.  For the group identifier
>>> +    see the ``identifier`` attribute.
>>> +
>>> +register-block-size
>>> +    The attribute value shall be an integer number. It shall be the size of the
>>> +    register block in units of the address space granule.
>>
>> Signed or unsigned? I only ask because it seems the ability to have a negative
>> integer value does not make sense. Does signed require testing of this?
> 
> Ok, I can review the integers in the documentation and add signed/unsigned if
> necessary.

Addresses are whole numbers :)

>>> +register-prefix
>>> +    The attribute value shall be an optional string. If the value is present,
>>> +    then it will be used to prefix register bit field names, otherwise the
>>> +    value of the ``name`` attribute will be used.
>>> +
>>> +registers
>>> +    The attribute value shall be a list. Each list element shall be a
>>> +    :ref:`SpecTypeRegisterDefinition`.
>>> +
>>> +In addition to the explicit attributes, generic attributes may be specified.
>>> +Each generic attribute key shall be a :ref:`SpecTypeName`. The attribute value
>>> +may have any type.
>>> +
>>>   .. _SpecTypeRequirementItemType:
>>>     Requirement Item Type
>>> @@ -3857,6 +3923,12 @@ This type is used by the following types:
>>>     * :ref:`SpecTypeInterfaceVariableItemType`
>>>   +* :ref:`SpecTypeRegisterBitsDefinition`
>>> +
>>> +* :ref:`SpecTypeRegisterBlockItemType`
>>> +
>>> +* :ref:`SpecTypeRegisterDefinition`
>>> +
>>>   .. _SpecTypeInterfaceCompoundDefinitionKind:
>>>     Interface Compound Definition Kind
>>> @@ -4116,6 +4188,12 @@ This type is used by the following types:
>>>     * :ref:`SpecTypeInterfaceVariableItemType`
>>>   +* :ref:`SpecTypeRegisterBitsDefinition`
>>> +
>>> +* :ref:`SpecTypeRegisterBlockItemType`
>>> +
>>> +* :ref:`SpecTypeRegisterDefinition`
>>> +
>>>   .. _SpecTypeInterfaceEnabledByExpression:
>>>     Interface Enabled-By Expression
>>> @@ -4165,6 +4243,10 @@ This type is used by the following types:
>>>     * :ref:`SpecTypeInterfaceFunctionDefinitionVariant`
>>>   +* :ref:`SpecTypeRegisterBitsDefinitionVariant`
>>> +
>>> +* :ref:`SpecTypeRegisterBlockMemberDefinitionVariant`
>>> +
>>>   .. _SpecTypeInterfaceEnumDefinitionKind:
>>>     Interface Enum Definition Kind
>>> @@ -4306,6 +4388,8 @@ This type is used by the following types:
>>>     * :ref:`SpecTypeInterfaceGroupItemType`
>>>   +* :ref:`SpecTypeRegisterBlockItemType`
>>> +
>>>   .. _SpecTypeInterfaceGroupMembershipLinkRole:
>>>     Interface Group Membership Link Role
>>> @@ -4372,6 +4456,8 @@ This type is used by the following types:
>>>     * :ref:`SpecTypeInterfaceVariableItemType`
>>>   +* :ref:`SpecTypeRegisterBlockItemType`
>>> +
>>>   .. _SpecTypeInterfaceParameter:
>>>     Interface Parameter
>>> @@ -4537,6 +4623,8 @@ This type is refined by the following types:
>>>     * :ref:`SpecTypePlacementOrderLinkRole`
>>>   +* :ref:`SpecTypeRegisterBlockIncludeRole`
>>> +
>>>   * :ref:`SpecTypeRequirementRefinementLinkRole`
>>>     * :ref:`SpecTypeRequirementValidationLinkRole`
>>> @@ -4585,6 +4673,10 @@ This type is used by the following types:
>>>     * :ref:`SpecTypeNonFunctionalRequirementItemType`
>>>   +* :ref:`SpecTypeRegisterBlockItemType`
>>> +
>>> +* :ref:`SpecTypeRegisterDefinition`
>>> +
>>>   * :ref:`SpecTypeRequirementItemType`
>>>     * :ref:`SpecTypeRootItemType`
>>> @@ -4626,6 +4718,236 @@ value is ``placement-order``. This link role defines
>>> the placement order of
>>>   items in a container item (for example an interface function in a header file
>>>   or a documentation section).
>>>   +.. _SpecTypeRegisterBitsDefinition:
>>> +
>>> +Register Bits Definition
>>> +^^^^^^^^^^^^^^^^^^^^^^^^
>>> +
>>> +A value of this type shall be of one of the following variants:
>>> +
>>> +* The value may be a set of attributes. This set of attributes specifies
>>> +  register bits. All explicit attributes shall be specified. The explicit
>>> +  attributes for this type are:
>>> +
>>> +  access
>>> +      The attribute value shall be a list of strings. It shall be the list of
>>> +      access attributes.
>>> +
>>> +  brief
>>> +      The attribute value shall be an :ref:`SpecTypeInterfaceBriefDescription`.
>>> +
>>> +  description
>>> +      The attribute value shall be an :ref:`SpecTypeInterfaceDescription`.
>>> +
>>> +  name
>>> +      The attribute value shall be a string. It shall be the name of the
>>> +      register bit field.
>>> +
>>> +  start
>>> +      The attribute value shall be an integer number. It shall be the start bit
>>> +      of the bit field.  Bit ``0`` is the least-significant bit.
>>> +
>>> +  width
>>> +      The attribute value shall be an integer number. It shall be the width in
>>> +      bits of the bit field.
>>> +
>>> +* There may be no value (null).
>>> +
>>> +This type is used by the following types:
>>> +
>>> +* :ref:`SpecTypeRegisterBitsDefinitionDirective`
>>> +
>>> +* :ref:`SpecTypeRegisterBitsDefinitionVariant`
>>> +
>>> +.. _SpecTypeRegisterBitsDefinitionDirective:
>>> +
>>> +Register Bits Definition Directive
>>> +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>>> +
>>> +This set of attributes specifies a register bits directive. All explicit
>>> +attributes shall be specified. The explicit attributes for this type are:
>>> +
>>> +default
>>> +    The attribute value shall be a list. Each list element shall be a
>>> +    :ref:`SpecTypeRegisterBitsDefinition`. The default definition will be used
>>> +    if no variant-specific definition is enabled.
>>> +
>>> +variants
>>> +    The attribute value shall be a list. Each list element shall be a
>>> +    :ref:`SpecTypeRegisterBitsDefinitionVariant`.
>>> +
>>> +This type is used by the following types:
>>> +
>>> +* :ref:`SpecTypeRegisterDefinition`
>>> +
>>> +.. _SpecTypeRegisterBitsDefinitionVariant:
>>> +
>>> +Register Bits Definition Variant
>>> +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>>> +
>>> +This set of attributes specifies a register bits variant. All explicit
>>> +attributes shall be specified. The explicit attributes for this type are:
>>> +
>>> +definition
>>> +    The attribute value shall be a list. Each list element shall be a
>>> +    :ref:`SpecTypeRegisterBitsDefinition`. The definition will be used if the
>>> +    expression defined by the ``enabled-by`` attribute evaluates to true.  In
>>> +    generated header files, the expression is evaluated by the C preprocessor.
>>> +
>>> +enabled-by
>>> +    The attribute value shall be an
>>> +    :ref:`SpecTypeInterfaceEnabledByExpression`.
>>> +
>>
>> Where does read-only, write only or clear-on-read go?
> 
> This would be in the "access" attribute.
> 
>>
>>> +This type is used by the following types:
>>> +
>>> +* :ref:`SpecTypeRegisterBitsDefinitionDirective`
>>> +
>>> +.. _SpecTypeRegisterBlockIncludeRole:
>>> +
>>> +Register Block Include Role
>>> +^^^^^^^^^^^^^^^^^^^^^^^^^^^
>>> +
>>> +This type refines the :ref:`SpecTypeLink` through the ``role`` attribute if the
>>> +value is ``register-block-include``. It defines the register block include role
>>> +of links.  Links of this role are used to build register blocks using other
>>> +register blocks. All explicit attributes shall be specified. The explicit
>>> +attributes for this type are:
>>> +
>>> +name
>>> +    The attribute value shall be a string. It shall be the unique name to
>>> +    identify the included register block within the item.
>>> +
>>> +.. _SpecTypeRegisterBlockMemberDefinition:
>>> +
>>> +Register Block Member Definition
>>> +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>>> +
>>> +A value of this type shall be of one of the following variants:
>>> +
>>> +* The value may be a set of attributes. This set of attributes specifies a
>>> +  register block member definition. All explicit attributes shall be specified.
>>> +  The explicit attributes for this type are:
>>> +
>>> +  count
>>> +      The attribute value shall be an integer number. It shall be the count of
>>> +      registers of the register block member.
>>> +
>>> +  name
>>> +      The attribute value shall be a :ref:`SpecTypeRegisterName`.
>>> +
>>> +* There may be no value (null).
>>> +
>>> +This type is used by the following types:
>>> +
>>> +* :ref:`SpecTypeRegisterBlockMemberDefinitionDirective`
>>> +
>>> +* :ref:`SpecTypeRegisterBlockMemberDefinitionVariant`
>>> +
>>> +.. _SpecTypeRegisterBlockMemberDefinitionDirective:
>>> +
>>> +Register Block Member Definition Directive
>>> +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>>> +
>>> +This set of attributes specifies a register block member definition directive.
>>> +All explicit attributes shall be specified. The explicit attributes for this
>>> +type are:
>>> +
>>> +default
>>> +    The attribute value shall be a
>>> +    :ref:`SpecTypeRegisterBlockMemberDefinition`. The default definition will
>>> +    be used if no variant-specific definition is enabled.
>>> +
>>> +offset
>>> +    The attribute value shall be an integer number. It shall be the offset from
>>> +    the register block begin to the register member in units of the address
>>> +    space granule.
>>> +
>>> +variants
>>> +    The attribute value shall be a list. Each list element shall be a
>>> +    :ref:`SpecTypeRegisterBlockMemberDefinitionVariant`.
>>> +
>>> +This type is used by the following types:
>>> +
>>> +* :ref:`SpecTypeRegisterBlockItemType`
>>> +
>>> +.. _SpecTypeRegisterBlockMemberDefinitionVariant:
>>> +
>>> +Register Block Member Definition Variant
>>> +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>>> +
>>> +This set of attributes specifies a register block member definition variant.
>>> +All explicit attributes shall be specified. The explicit attributes for this
>>> +type are:
>>> +
>>> +definition
>>> +    The attribute value shall be a
>>> +    :ref:`SpecTypeRegisterBlockMemberDefinition`. The definition will be used
>>> +    if the expression defined by the ``enabled-by`` attribute evaluates to
>>> +    true.  In generated header files, the expression is evaluated by the C
>>> +    preprocessor.
>>
>> Te definitions and the implementation need to be separate headers. Currently
>> they are the same header and this seems wrong to me.
> 
> What do you mean with definitions and implementation? Currently, a generated
> header file looks like this:
> 
> https://git.rtems.org/sebh/rtems.git/tree/bsps/include/grlib/irqamp-regs.h?h=qual-82
> 

I am sorry I cannot remember. It has been too long.

>>> +enabled-by
>>> +    The attribute value shall be an
>>> +    :ref:`SpecTypeInterfaceEnabledByExpression`.
>>> +
>>> +This type is used by the following types:
>>> +
>>> +* :ref:`SpecTypeRegisterBlockMemberDefinitionDirective`
>>> +
>>> +.. _SpecTypeRegisterDefinition:
>>> +
>>> +Register Definition
>>> +^^^^^^^^^^^^^^^^^^^
>>> +
>>> +This set of attributes specifies a register. All explicit attributes shall be
>>> +specified. The explicit attributes for this type are:
>>> +
>>> +bits
>>> +    The attribute value shall be a list. Each list element shall be a
>>> +    :ref:`SpecTypeRegisterBitsDefinitionDirective`.
>>> +
>>> +brief
>>> +    The attribute value shall be an :ref:`SpecTypeInterfaceBriefDescription`.
>>> +
>>> +description
>>> +    The attribute value shall be an :ref:`SpecTypeInterfaceDescription`.
>>> +
>>> +name
>>> +    The attribute value shall be a string. It shall be the unique name to
>>> +    identify the register definition.
>>> +
>>> +width
>>> +    The attribute value shall be an integer number. It shall be the width of
>>> +    the register in bits.
>>
>> Are you sure you want to vary the size of registers in a block? It implies
>> different addressing modes for the bus and that sort of specification is
>> complicated.
> 
> Yes, this is necessary. I have seen devices with 8-bit and 32-bit registers.

Just remember this is an abstraction clever hardware makes for you. Someone at
some point designed it to do this. The device's word size it fixed by the number
of wires connected to it's data bus and in my view that is important and how we
should be defining this stuff at the base level.

Have a look at D8(O) vs D8(EO) in https://www.vita.com/page-1855177.

>> For example in a memory mapped struct with uint32_t, uint16_t and uint8_t fields
>> the compiler may generating different size bus cycles. It may be a requirement
>> the 16bit and 8bit registers are accessed as 32bit device word reads and writes.
>> A constraint like this limits the use of volatile struct pointers.
> 
> For grlib, there are IO functions like this:
> 
> https://git.rtems.org/sebh/rtems.git/tree/bsps/sparc/include/grlib/io.h?h=qual-82
> 
> It seems that the compiler generates the right load/store instructions. This
> could be changed to inline assembly if needed.

Yeap gcc will do this because of the amount of code that exists and it's
developers making sure it still works. Personally I cannot be bothered wondering.

> We don't have a bus space API in RTEMS. It would be good to have one, however, I
> don't have one right now.

Agreed.

Chris


More information about the devel mailing list