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 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.
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.
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