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