C++ generator

A complete C++ class can be generated with methods to read/write the registers or fields.

  • CppInterfaceGenerator creates an abstract interface header that can be used for mocking in a unit test environment. Contains method declarations, register attributes, and register constant values.

  • CppHeaderGenerator creates a class header which inherits the abstract class.

  • CppImplementationGenerator creates a class implementation with setters and getters.

C++ code is generated by running the Python code below. Note that it will parse and generate artifacts from the TOML file used in the TOML Format example.

Python code that parses the example TOML file and generates the C++ code we need.
 1import sys
 2from pathlib import Path
 3
 4from hdl_registers.generator.cpp.header import CppHeaderGenerator
 5from hdl_registers.generator.cpp.implementation import CppImplementationGenerator
 6from hdl_registers.generator.cpp.interface import CppInterfaceGenerator
 7from hdl_registers.parser.toml import from_toml
 8
 9THIS_DIR = Path(__file__).parent
10
11
12def main(output_folder: Path) -> None:
13    """
14    Create register C++ artifacts from the TOML example file.
15    """
16    register_list = from_toml(
17        name="example",
18        toml_file=THIS_DIR.parent.parent / "user_guide" / "toml" / "toml_format.toml",
19    )
20
21    CppInterfaceGenerator(
22        register_list=register_list, output_folder=output_folder / "include"
23    ).create()
24
25    CppHeaderGenerator(
26        register_list=register_list, output_folder=output_folder / "include"
27    ).create()
28
29    CppImplementationGenerator(register_list=register_list, output_folder=output_folder).create()
30
31
32if __name__ == "__main__":
33    main(output_folder=Path(sys.argv[1]))

Getters

It can be noted in the Interface header below that there are two ways to read a register field:

  1. The method that reads the whole register, e.g. get_conf(), which returns a struct with all field values.

  2. The method that reads the register and returns the specific field value, e.g. get_conf_enable().

Method (2) is the most convenient in most cases. However if we want to read out more than one field from a register it would be very inefficient to read the register value more than once over the register bus, which would be the result of calling (2) multiple times. Instead we can call (1) once and then select the field values from the struct.

Apart from the methods discussed above, these is also a raw register getter available, e.g. get_conf_raw(). This will read the whole register value and return it without any type conversion. Can be convenient in some special cases, for example when working with interrupt registers.

Setters

Conversely there are two ways to write a register field:

  1. The method that writes the whole register, e.g. set_conf(), which takes a struct of field values as argument.

  2. The method that reads the register, updates the value of the field, and then writes the register back, e.g. set_conf_enable().

Method (2) is the most convenient in most cases. However if we want to update more than one field of a register it would be very inefficient to read and write the register more than once over the register bus, which would be the result of calling (2) multiple times. Instead we can call a register getter once, e.g. get_conf(), update our field values in the variable, and then call (1) once.

Apart from the methods discussed above, these is also a raw register setter available, e.g. set_conf_raw(). This will write the whole register value without any type conversion. Can be convenient in some special cases, for example when working with interrupt registers.

Exceptions

The discussion about read-modify-write field setters is valid for “read write” mode registers, which is arguably the most common type. However there are three register modes where the previously written register value can not be read back over the bus and then modified: “write only”, “write pulse”, and “read, write pulse”. The field setters for these registers will write all bits outside of the current field as their default value. This can for example be seen in the setter set_channels_conf_enable() in the generated code below.

Assertion macros

There are a few register-related things that can go wrong in an embedded system:

  1. An error in hardware might result in reading a field value that is out of bounds. This is mostly possible for enumeration and integer fields.

  2. Conversely, an error in software might result in writing a field value that is out of bounds.

  3. An error in software might result in a register array read/write with an index that is out of bounds.

The generated C++ implementation checks for these errors using custom assertion macros. Meaning, they can be detected at runtime as well as in unit tests.

If an assertion fails a user-specified handler function is called. In this function, the user could e.g. call a custom logger, perform a controlled shutdown, throw exceptions, etc. One argument is provided that contains a descriptive error message. The function must return a boolean true.

This error handler function must be provided to the constructor of the generated class.

Minimal example

A minimal and somewhat unrealistic handler function is shown below. More advanced handler functions are left to the user.

uintptr_t base_address = 0x43C00000;

bool register_assert_fail_handler(const std::string *diagnostic_message)
{
  std::cerr << *diagnostic_message << std::endl;
  std::exit(EXIT_FAILURE);
  return true;
}

fpga_regs::Example example(base_address, register_assert_fail_handler);

Disabling assertions

The assertions add to the binary size and to the runtime of the program. The user can disable the assertions by defining the following macros (usually with the -D compiler flag):

  1. NO_REGISTER_GETTER_ASSERT

  2. NO_REGISTER_SETTER_ASSERT

  3. NO_REGISTER_ARRAY_INDEX_ASSERT

This should result in no overhead.

Interface header

Below is the resulting abstract interface header code, generated from the TOML Format example. This contains the public API of the class.

Note that all register constants as well as field attributes are included here. It can also be seen that when a register is part of an array, the setters/getters take a second argument array_index. There is an assert in the Implementation that user-provided array indexes are within bounds.

Example interface header
  1// -----------------------------------------------------------------------------
  2// This file is automatically generated by hdl-registers version 7.3.1-dev.
  3// Code generator CppInterfaceGenerator version 1.0.0.
  4// Generated 2025-04-18 20:51 from file toml_format.toml at Git commit dff379d0eb3e.
  5// Register hash bb6496bff8f74abb3efe59e498c2b2a3f7b4149a.
  6// -----------------------------------------------------------------------------
  7
  8#pragma once
  9
 10#include <sstream>
 11#include <cstdint>
 12#include <cstdlib>
 13
 14namespace fpga_regs
 15{
 16
 17  namespace example
 18  {
 19
 20    // Attributes for the 'conf' register.
 21    namespace conf {
 22      // Attributes for the 'enable' field.
 23      namespace enable
 24      {
 25        // The number of bits that the field occupies.
 26        static const size_t width = 1;
 27        // The bit index of the lowest bit in the field.
 28        static const size_t shift = 0;
 29        // The bit mask of the field, at index zero.
 30        static const uint32_t mask_at_base = (1uLL << width) - 1;
 31        // The bit mask of the field, at the field's bit index.
 32        static const uint32_t mask_shifted = mask_at_base << shift;
 33
 34        // Initial value of the field at device startup/reset.
 35        static const bool default_value = true;
 36        // Raw representation of the initial value, at the the field's bit index.
 37        static const uint32_t default_value_raw = 1 << shift;
 38      }
 39
 40      // Attributes for the 'direction' field.
 41      namespace direction
 42      {
 43        // The number of bits that the field occupies.
 44        static const size_t width = 2;
 45        // The bit index of the lowest bit in the field.
 46        static const size_t shift = 1;
 47        // The bit mask of the field, at index zero.
 48        static const uint32_t mask_at_base = (1uLL << width) - 1;
 49        // The bit mask of the field, at the field's bit index.
 50        static const uint32_t mask_shifted = mask_at_base << shift;
 51
 52        // The valid elements for this enumeration field.
 53        enum Enumeration
 54        {
 55          data_in = 0,
 56          high_z = 1,
 57          data_out = 2,
 58        };
 59
 60        // Initial value of the field at device startup/reset.
 61        static const Enumeration default_value = Enumeration::high_z;
 62        // Raw representation of the initial value, at the the field's bit index.
 63        static const uint32_t default_value_raw = 1uL << shift;
 64      }
 65
 66      // Struct that holds the value of each field in the register,
 67      // in a native C++ representation.
 68      struct Value {
 69        bool enable;
 70        direction::Enumeration direction;
 71      };
 72      // Initial value of the register at device startup/reset.
 73      const Value default_value = {
 74        enable::default_value,
 75        direction::default_value,
 76      };
 77    }
 78
 79    // Attributes for the 'channels' register array.
 80    namespace channels
 81    {
 82      // Number of times the registers of the array are repeated.
 83      static const auto array_length = 4;
 84
 85      // Attributes for the 'conf' register.
 86      namespace conf {
 87        // Attributes for the 'enable' field.
 88        namespace enable
 89        {
 90          // The number of bits that the field occupies.
 91          static const size_t width = 1;
 92          // The bit index of the lowest bit in the field.
 93          static const size_t shift = 0;
 94          // The bit mask of the field, at index zero.
 95          static const uint32_t mask_at_base = (1uLL << width) - 1;
 96          // The bit mask of the field, at the field's bit index.
 97          static const uint32_t mask_shifted = mask_at_base << shift;
 98
 99          // Initial value of the field at device startup/reset.
100          static const bool default_value = false;
101          // Raw representation of the initial value, at the the field's bit index.
102          static const uint32_t default_value_raw = 0 << shift;
103        }
104
105        // Attributes for the 'tuser' field.
106        namespace tuser
107        {
108          // The number of bits that the field occupies.
109          static const size_t width = 8;
110          // The bit index of the lowest bit in the field.
111          static const size_t shift = 1;
112          // The bit mask of the field, at index zero.
113          static const uint32_t mask_at_base = (1uLL << width) - 1;
114          // The bit mask of the field, at the field's bit index.
115          static const uint32_t mask_shifted = mask_at_base << shift;
116
117          // Initial value of the field at device startup/reset.
118          static const uint32_t default_value = 0;
119          // Raw representation of the initial value, at the the field's bit index.
120          static const uint32_t default_value_raw = 0b00000000uL << shift;
121        }
122
123        // Struct that holds the value of each field in the register,
124        // in a native C++ representation.
125        struct Value {
126          bool enable;
127          uint32_t tuser;
128        };
129        // Initial value of the register at device startup/reset.
130        const Value default_value = {
131          enable::default_value,
132          tuser::default_value,
133        };
134      }
135    }
136
137  } // namespace example
138
139  class IExample
140  {
141  public:
142    // Register constant.
143    static const int axi_data_width = 64;
144    // Register constant.
145    static constexpr double clock_rate_hz = 156250000.0;
146
147    // Number of registers within this register list.
148    static const size_t num_registers = 10uL;
149
150    virtual ~IExample() {}
151
152    // -------------------------------------------------------------------------
153    // Methods for the 'conf' register.
154    // Mode 'Read, Write'.
155    // -------------------------------------------------------------------------
156    // Read the whole register value over the register bus.
157    virtual example::conf::Value get_conf() const = 0;
158
159    // Read the whole register value over the register bus.
160    // This method returns the raw register value without any type conversion.
161    virtual uint32_t get_conf_raw() const = 0;
162
163    // Read the register and slice out the 'enable' field value.
164    virtual bool get_conf_enable() const = 0;
165
166    // Read the register and slice out the 'direction' field value.
167    virtual example::conf::direction::Enumeration get_conf_direction() const = 0;
168
169    // Write the whole register value over the register bus.
170    virtual void set_conf(
171      example::conf::Value register_value
172    ) const = 0;
173
174    // Write the whole register value over the register bus.
175    // This method takes a raw register value and does not perform any type conversion.
176    virtual void set_conf_raw(
177      uint32_t register_value
178    ) const = 0;
179
180    // Write the 'enable' field value.
181    // Will read-modify-write the register.
182    virtual void set_conf_enable(
183      bool field_value
184    ) const = 0;
185
186    // Write the 'direction' field value.
187    // Will read-modify-write the register.
188    virtual void set_conf_direction(
189      example::conf::direction::Enumeration field_value
190    ) const = 0;
191    // -------------------------------------------------------------------------
192
193    // -------------------------------------------------------------------------
194    // Methods for the 'status' register.
195    // Mode 'Read'.
196    // -------------------------------------------------------------------------
197    // Read the whole register value over the register bus.
198    virtual uint32_t get_status() const = 0;
199    // -------------------------------------------------------------------------
200
201    // -------------------------------------------------------------------------
202    // Methods for the 'read_address' register within the 'channels' register array.
203    // Mode 'Read, Write'.
204    // -------------------------------------------------------------------------
205    // Read the whole register value over the register bus.
206    virtual uint32_t get_channels_read_address(
207      size_t array_index
208    ) const = 0;
209
210    // Write the whole register value over the register bus.
211    virtual void set_channels_read_address(
212      size_t array_index,
213      uint32_t register_value
214    ) const = 0;
215    // -------------------------------------------------------------------------
216
217    // -------------------------------------------------------------------------
218    // Methods for the 'conf' register within the 'channels' register array.
219    // Mode 'Write'.
220    // -------------------------------------------------------------------------
221    // Write the whole register value over the register bus.
222    virtual void set_channels_conf(
223      size_t array_index,
224      example::channels::conf::Value register_value
225    ) const = 0;
226
227    // Write the whole register value over the register bus.
228    // This method takes a raw register value and does not perform any type conversion.
229    virtual void set_channels_conf_raw(
230      size_t array_index,
231      uint32_t register_value
232    ) const = 0;
233
234    // Write the 'enable' field value.
235    // Will write the register with all other fields set as default.
236    virtual void set_channels_conf_enable(
237      size_t array_index,
238      bool field_value
239    ) const = 0;
240
241    // Write the 'tuser' field value.
242    // Will write the register with all other fields set as default.
243    virtual void set_channels_conf_tuser(
244      size_t array_index,
245      uint32_t field_value
246    ) const = 0;
247    // -------------------------------------------------------------------------
248  };
249
250} // namespace fpga_regs

Class header

Below is the generated class header. This overrides from the interface header and adds some internal private methods.

Example class header
  1// -----------------------------------------------------------------------------
  2// This file is automatically generated by hdl-registers version 7.3.1-dev.
  3// Code generator CppHeaderGenerator version 1.0.0.
  4// Generated 2025-04-18 20:51 from file toml_format.toml at Git commit dff379d0eb3e.
  5// Register hash bb6496bff8f74abb3efe59e498c2b2a3f7b4149a.
  6// -----------------------------------------------------------------------------
  7
  8#pragma once
  9
 10#include "i_example.h"
 11
 12namespace fpga_regs
 13{
 14
 15  class Example : public IExample
 16  {
 17  public:
 18    /**
 19     * Class constructor.
 20     * @param base_address Byte address where these registers are memory mapped.
 21     *                     Can be e.g. '0x43C00000' in bare metal, or e.g.
 22     *                     'reinterpret_cast<uintptr_t>(mmap(...))' in Linux.
 23     *                     When using an operating system, care must be taken to pass the
 24     *                     virtual address, not the physical address.
 25     *                     When using bare metal, these are the same.
 26     * @param assertion_handler Function to call when an assertion fails.
 27     *                          Function takes a string pointer as an argument, where the string
 28     *                          will contain an error diagnostic message.
 29     *                          Function must return a boolean 'true'.
 30     */
 31    Example(uintptr_t base_address, bool (*assertion_handler) (const std::string*));
 32
 33    virtual ~Example() {}
 34
 35    // -------------------------------------------------------------------------
 36    // Methods for the 'conf' register.
 37    // Mode 'Read, Write'.
 38    // -------------------------------------------------------------------------
 39    // Read the whole register value over the register bus.
 40    virtual example::conf::Value get_conf() const override;
 41
 42    // Read the whole register value over the register bus.
 43    // This method returns the raw register value without any type conversion.
 44    virtual uint32_t get_conf_raw() const override;
 45
 46    // Read the register and slice out the 'enable' field value.
 47    virtual bool get_conf_enable() const override;
 48
 49    // Read the register and slice out the 'direction' field value.
 50    virtual example::conf::direction::Enumeration get_conf_direction() const override;
 51
 52    // Write the whole register value over the register bus.
 53    virtual void set_conf(
 54      example::conf::Value register_value
 55    ) const override;
 56
 57    // Write the whole register value over the register bus.
 58    // This method takes a raw register value and does not perform any type conversion.
 59    virtual void set_conf_raw(
 60      uint32_t register_value
 61    ) const override;
 62
 63    // Write the 'enable' field value.
 64    // Will read-modify-write the register.
 65    virtual void set_conf_enable(
 66      bool field_value
 67    ) const override;
 68
 69    // Write the 'direction' field value.
 70    // Will read-modify-write the register.
 71    virtual void set_conf_direction(
 72      example::conf::direction::Enumeration field_value
 73    ) const override;
 74    // -------------------------------------------------------------------------
 75
 76    // -------------------------------------------------------------------------
 77    // Methods for the 'status' register.
 78    // Mode 'Read'.
 79    // -------------------------------------------------------------------------
 80    // Read the whole register value over the register bus.
 81    virtual uint32_t get_status() const override;
 82    // -------------------------------------------------------------------------
 83
 84    // -------------------------------------------------------------------------
 85    // Methods for the 'read_address' register within the 'channels' register array.
 86    // Mode 'Read, Write'.
 87    // -------------------------------------------------------------------------
 88    // Read the whole register value over the register bus.
 89    virtual uint32_t get_channels_read_address(
 90      size_t array_index
 91    ) const override;
 92
 93    // Write the whole register value over the register bus.
 94    virtual void set_channels_read_address(
 95      size_t array_index,
 96      uint32_t register_value
 97    ) const override;
 98    // -------------------------------------------------------------------------
 99
100    // -------------------------------------------------------------------------
101    // Methods for the 'conf' register within the 'channels' register array.
102    // Mode 'Write'.
103    // -------------------------------------------------------------------------
104    // Write the whole register value over the register bus.
105    virtual void set_channels_conf(
106      size_t array_index,
107      example::channels::conf::Value register_value
108    ) const override;
109
110    // Write the whole register value over the register bus.
111    // This method takes a raw register value and does not perform any type conversion.
112    virtual void set_channels_conf_raw(
113      size_t array_index,
114      uint32_t register_value
115    ) const override;
116
117    // Write the 'enable' field value.
118    // Will write the register with all other fields set as default.
119    virtual void set_channels_conf_enable(
120      size_t array_index,
121      bool field_value
122    ) const override;
123
124    // Write the 'tuser' field value.
125    // Will write the register with all other fields set as default.
126    virtual void set_channels_conf_tuser(
127      size_t array_index,
128      uint32_t field_value
129    ) const override;
130    // -------------------------------------------------------------------------
131
132  private:
133    volatile uint32_t *m_registers;
134    bool (*m_assertion_handler) (const std::string*);
135
136    // -------------------------------------------------------------------------
137    // Methods for the 'conf' register.
138    // Mode 'Read, Write'.
139    // -------------------------------------------------------------------------
140    // Slice out the 'enable' field value from a given raw register value.
141    // Performs no operation on the register bus.
142    bool get_conf_enable_from_raw(
143      uint32_t register_value
144    ) const;
145
146    // Slice out the 'direction' field value from a given raw register value.
147    // Performs no operation on the register bus.
148    example::conf::direction::Enumeration get_conf_direction_from_raw(
149      uint32_t register_value
150    ) const;
151
152    // Get the raw representation of a given 'enable' field value.
153    // Performs no operation on the register bus.
154    uint32_t get_conf_enable_to_raw(bool field_value) const;
155
156    // Get the raw representation of a given 'direction' field value.
157    // Performs no operation on the register bus.
158    uint32_t get_conf_direction_to_raw(example::conf::direction::Enumeration field_value) const;
159    // -------------------------------------------------------------------------
160
161    // -------------------------------------------------------------------------
162    // Methods for the 'conf' register within the 'channels' register array.
163    // Mode 'Write'.
164    // -------------------------------------------------------------------------
165    // Get the raw representation of a given 'enable' field value.
166    // Performs no operation on the register bus.
167    uint32_t get_channels_conf_enable_to_raw(bool field_value) const;
168
169    // Get the raw representation of a given 'tuser' field value.
170    // Performs no operation on the register bus.
171    uint32_t get_channels_conf_tuser_to_raw(uint32_t field_value) const;
172    // -------------------------------------------------------------------------
173  };
174
175} // namespace fpga_regs

Implementation

Below is the generated class implementation. This implements all the methods of the class, whether public from the Interface header or private from the Class header.

Example class implementation
  1// -----------------------------------------------------------------------------
  2// This file is automatically generated by hdl-registers version 7.3.1-dev.
  3// Code generator CppImplementationGenerator version 2.0.2.
  4// Generated 2025-04-18 20:51 from file toml_format.toml at Git commit dff379d0eb3e.
  5// Register hash bb6496bff8f74abb3efe59e498c2b2a3f7b4149a.
  6// -----------------------------------------------------------------------------
  7
  8#include "include/example.h"
  9
 10namespace fpga_regs
 11{
 12
 13#ifdef NO_REGISTER_SETTER_ASSERT
 14
 15#define _SETTER_ASSERT_TRUE(expression, message) ((void)0)
 16
 17#else // Not NO_REGISTER_SETTER_ASSERT.
 18
 19// This macro is called by the register code to check for runtime errors.
 20#define _SETTER_ASSERT_TRUE(expression, message)                                 \
 21  {                                                                              \
 22    if (!static_cast<bool>(expression)) {                                        \
 23      std::ostringstream diagnostics;                                            \
 24      diagnostics << "example.cpp:" << __LINE__                                  \
 25                  << ": " << message << ".";                                     \
 26      std::string diagnostic_message = diagnostics.str();                        \
 27      m_assertion_handler(&diagnostic_message);                                  \
 28    }                                                                            \
 29  }
 30
 31#endif // NO_REGISTER_SETTER_ASSERT.
 32
 33#ifdef NO_REGISTER_GETTER_ASSERT
 34
 35#define _GETTER_ASSERT_TRUE(expression, message) ((void)0)
 36
 37#else // Not NO_REGISTER_GETTER_ASSERT.
 38
 39// This macro is called by the register code to check for runtime errors.
 40#define _GETTER_ASSERT_TRUE(expression, message)                                 \
 41  {                                                                              \
 42    if (!static_cast<bool>(expression)) {                                        \
 43      std::ostringstream diagnostics;                                            \
 44      diagnostics << "example.cpp:" << __LINE__                                  \
 45                  << ": " << message << ".";                                     \
 46      std::string diagnostic_message = diagnostics.str();                        \
 47      m_assertion_handler(&diagnostic_message);                                  \
 48    }                                                                            \
 49  }
 50
 51#endif // NO_REGISTER_GETTER_ASSERT.
 52
 53#ifdef NO_REGISTER_ARRAY_INDEX_ASSERT
 54
 55#define _ARRAY_INDEX_ASSERT_TRUE(expression, message) ((void)0)
 56
 57#else // Not NO_REGISTER_ARRAY_INDEX_ASSERT.
 58
 59// This macro is called by the register code to check for runtime errors.
 60#define _ARRAY_INDEX_ASSERT_TRUE(expression, message)                            \
 61  {                                                                              \
 62    if (!static_cast<bool>(expression)) {                                        \
 63      std::ostringstream diagnostics;                                            \
 64      diagnostics << "example.cpp:" << __LINE__                                  \
 65                  << ": " << message << ".";                                     \
 66      std::string diagnostic_message = diagnostics.str();                        \
 67      m_assertion_handler(&diagnostic_message);                                  \
 68    }                                                                            \
 69  }
 70
 71#endif // NO_REGISTER_ARRAY_INDEX_ASSERT.
 72
 73  Example::Example(uintptr_t base_address, bool (*assertion_handler) (const std::string*))
 74      : m_registers(reinterpret_cast<volatile uint32_t *>(base_address)),
 75        m_assertion_handler(assertion_handler)
 76  {
 77    // Empty
 78  }
 79
 80  // ---------------------------------------------------------------------------
 81  // Methods for the 'conf' register.
 82  // Mode 'Read, Write'.
 83  // ---------------------------------------------------------------------------
 84  // Read the whole register value over the register bus.
 85  example::conf::Value Example::get_conf() const
 86  {
 87    const uint32_t raw_value = get_conf_raw();
 88
 89    const bool enable_value = get_conf_enable_from_raw(raw_value);
 90    const example::conf::direction::Enumeration direction_value = get_conf_direction_from_raw(raw_value);
 91
 92    return {enable_value, direction_value};
 93  }
 94
 95  // Read the whole register value over the register bus.
 96  // This method returns the raw register value without any type conversion.
 97  uint32_t Example::get_conf_raw() const
 98  {
 99    const size_t index = 0;
100    const uint32_t raw_value = m_registers[index];
101
102    return raw_value;
103  }
104
105  // Read the register and slice out the 'enable' field value.
106  bool Example::get_conf_enable() const
107  {
108    const uint32_t raw_value = get_conf_raw();
109
110    return get_conf_enable_from_raw(raw_value);
111  }
112
113  // Slice out the 'enable' field value from a given raw register value.
114  // Performs no operation on the register bus.
115  bool Example::get_conf_enable_from_raw(
116    uint32_t register_value
117  ) const
118  {
119    const uint32_t result_masked = register_value & example::conf::enable::mask_shifted;
120    const uint32_t result_shifted = result_masked >> example::conf::enable::shift;
121
122    // Convert to the result type.
123    const bool field_value = static_cast<bool>(result_shifted);
124
125    return field_value;
126  }
127
128  // Read the register and slice out the 'direction' field value.
129  example::conf::direction::Enumeration Example::get_conf_direction() const
130  {
131    const uint32_t raw_value = get_conf_raw();
132
133    return get_conf_direction_from_raw(raw_value);
134  }
135
136  // Slice out the 'direction' field value from a given raw register value.
137  // Performs no operation on the register bus.
138  example::conf::direction::Enumeration Example::get_conf_direction_from_raw(
139    uint32_t register_value
140  ) const
141  {
142    const uint32_t result_masked = register_value & example::conf::direction::mask_shifted;
143    const uint32_t result_shifted = result_masked >> example::conf::direction::shift;
144
145    // "Cast" to the enum type.
146    const auto field_value = example::conf::direction::Enumeration(result_shifted);
147
148    return field_value;
149  }
150
151  // Write the whole register value over the register bus.
152  void Example::set_conf(
153    example::conf::Value register_value
154  ) const
155  {
156    const uint32_t enable_value = get_conf_enable_to_raw(register_value.enable);
157    const uint32_t direction_value = get_conf_direction_to_raw(register_value.direction);
158    const uint32_t raw_value = enable_value | direction_value;
159
160    set_conf_raw(raw_value);
161  }
162
163  // Write the whole register value over the register bus.
164  // This method takes a raw register value and does not perform any type conversion.
165  void Example::set_conf_raw(
166    uint32_t register_value
167  ) const
168  {
169    const size_t index = 0;
170    m_registers[index] = register_value;
171  }
172
173  // Write the 'enable' field value.
174  // Will read-modify-write the register.
175  void Example::set_conf_enable(
176    bool field_value
177  ) const
178  {
179    const size_t index = 0;
180
181    const uint32_t raw_value = m_registers[index];
182    const uint32_t mask_shifted_inverse = ~example::conf::enable::mask_shifted;
183    const uint32_t base_value = raw_value & mask_shifted_inverse;
184
185    const uint32_t field_value_raw = get_conf_enable_to_raw(field_value);
186    const uint32_t register_value = base_value | field_value_raw;
187
188    m_registers[index] = register_value;
189  }
190
191  // Get the raw representation of a given 'enable' field value.
192  // Performs no operation on the register bus.
193  uint32_t Example::get_conf_enable_to_raw(bool field_value) const
194  {
195    const uint32_t field_value_casted = static_cast<uint32_t>(field_value);
196    const uint32_t field_value_shifted = field_value_casted << example::conf::enable::shift;
197
198    return field_value_shifted;
199  }
200
201  // Write the 'direction' field value.
202  // Will read-modify-write the register.
203  void Example::set_conf_direction(
204    example::conf::direction::Enumeration field_value
205  ) const
206  {
207    const size_t index = 0;
208
209    const uint32_t raw_value = m_registers[index];
210    const uint32_t mask_shifted_inverse = ~example::conf::direction::mask_shifted;
211    const uint32_t base_value = raw_value & mask_shifted_inverse;
212
213    const uint32_t field_value_raw = get_conf_direction_to_raw(field_value);
214    const uint32_t register_value = base_value | field_value_raw;
215
216    m_registers[index] = register_value;
217  }
218
219  // Get the raw representation of a given 'direction' field value.
220  // Performs no operation on the register bus.
221  uint32_t Example::get_conf_direction_to_raw(example::conf::direction::Enumeration field_value) const
222  {
223    const uint32_t field_value_casted = static_cast<uint32_t>(field_value);
224    const uint32_t field_value_shifted = field_value_casted << example::conf::direction::shift;
225
226    return field_value_shifted;
227  }
228  // ---------------------------------------------------------------------------
229
230  // ---------------------------------------------------------------------------
231  // Methods for the 'status' register.
232  // Mode 'Read'.
233  // ---------------------------------------------------------------------------
234  // Read the whole register value over the register bus.
235  uint32_t Example::get_status() const
236  {
237    const size_t index = 1;
238    const uint32_t raw_value = m_registers[index];
239
240    return raw_value;
241  }
242  // ---------------------------------------------------------------------------
243
244  // ---------------------------------------------------------------------------
245  // Methods for the 'read_address' register within the 'channels' register array.
246  // Mode 'Read, Write'.
247  // ---------------------------------------------------------------------------
248  // Read the whole register value over the register bus.
249  uint32_t Example::get_channels_read_address(
250    size_t array_index
251  ) const
252  {
253    _ARRAY_INDEX_ASSERT_TRUE(
254      array_index < example::channels::array_length,
255      "Got 'channels' array index out of range: " << array_index
256    );
257    const size_t index = 2 + array_index * 2 + 0;
258    const uint32_t raw_value = m_registers[index];
259
260    return raw_value;
261  }
262
263  // Write the whole register value over the register bus.
264  void Example::set_channels_read_address(
265    size_t array_index,
266    uint32_t register_value
267  ) const
268  {
269    _ARRAY_INDEX_ASSERT_TRUE(
270      array_index < example::channels::array_length,
271      "Got 'channels' array index out of range: " << array_index
272    );
273    const size_t index = 2 + array_index * 2 + 0;
274    m_registers[index] = register_value;
275  }
276  // ---------------------------------------------------------------------------
277
278  // ---------------------------------------------------------------------------
279  // Methods for the 'conf' register within the 'channels' register array.
280  // Mode 'Write'.
281  // ---------------------------------------------------------------------------
282  // Write the whole register value over the register bus.
283  void Example::set_channels_conf(
284    size_t array_index,
285    example::channels::conf::Value register_value
286  ) const
287  {
288    const uint32_t enable_value = get_channels_conf_enable_to_raw(register_value.enable);
289    const uint32_t tuser_value = get_channels_conf_tuser_to_raw(register_value.tuser);
290    const uint32_t raw_value = enable_value | tuser_value;
291
292    set_channels_conf_raw(array_index, raw_value);
293  }
294
295  // Write the whole register value over the register bus.
296  // This method takes a raw register value and does not perform any type conversion.
297  void Example::set_channels_conf_raw(
298    size_t array_index,
299    uint32_t register_value
300  ) const
301  {
302    _ARRAY_INDEX_ASSERT_TRUE(
303      array_index < example::channels::array_length,
304      "Got 'channels' array index out of range: " << array_index
305    );
306    const size_t index = 2 + array_index * 2 + 1;
307    m_registers[index] = register_value;
308  }
309
310  // Write the 'enable' field value.
311  // Will write the register with all other fields set as default.
312  void Example::set_channels_conf_enable(
313    size_t array_index,
314    bool field_value
315  ) const
316  {
317    _ARRAY_INDEX_ASSERT_TRUE(
318      array_index < example::channels::array_length,
319      "Got 'channels' array index out of range: " << array_index
320    );
321    const size_t index = 2 + array_index * 2 + 1;
322
323    const uint32_t base_value = 0 | example::channels::conf::tuser::default_value_raw;
324
325    const uint32_t field_value_raw = get_channels_conf_enable_to_raw(field_value);
326    const uint32_t register_value = base_value | field_value_raw;
327
328    m_registers[index] = register_value;
329  }
330
331  // Get the raw representation of a given 'enable' field value.
332  // Performs no operation on the register bus.
333  uint32_t Example::get_channels_conf_enable_to_raw(bool field_value) const
334  {
335    const uint32_t field_value_casted = static_cast<uint32_t>(field_value);
336    const uint32_t field_value_shifted = field_value_casted << example::channels::conf::enable::shift;
337
338    return field_value_shifted;
339  }
340
341  // Write the 'tuser' field value.
342  // Will write the register with all other fields set as default.
343  void Example::set_channels_conf_tuser(
344    size_t array_index,
345    uint32_t field_value
346  ) const
347  {
348    _ARRAY_INDEX_ASSERT_TRUE(
349      array_index < example::channels::array_length,
350      "Got 'channels' array index out of range: " << array_index
351    );
352    const size_t index = 2 + array_index * 2 + 1;
353
354    const uint32_t base_value = 0 | example::channels::conf::enable::default_value_raw;
355
356    const uint32_t field_value_raw = get_channels_conf_tuser_to_raw(field_value);
357    const uint32_t register_value = base_value | field_value_raw;
358
359    m_registers[index] = register_value;
360  }
361
362  // Get the raw representation of a given 'tuser' field value.
363  // Performs no operation on the register bus.
364  uint32_t Example::get_channels_conf_tuser_to_raw(uint32_t field_value) const
365  {
366    _SETTER_ASSERT_TRUE(
367      field_value <= 255,
368      "Got 'tuser' value out of range: " << field_value
369    );
370
371    const uint32_t field_value_shifted = field_value << example::channels::conf::tuser::shift;
372
373    return field_value_shifted;
374  }
375  // ---------------------------------------------------------------------------
376
377} // namespace fpga_regs