Coverage for hdl_registers/generator/cpp/implementation.py: 97%
143 statements
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-19 20:51 +0000
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-19 20:51 +0000
1# --------------------------------------------------------------------------------------------------
2# Copyright (c) Lukas Vik. All rights reserved.
3#
4# This file is part of the hdl-registers project, an HDL register generator fast enough to run
5# in real time.
6# https://hdl-registers.com
7# https://github.com/hdl-registers/hdl-registers
8# --------------------------------------------------------------------------------------------------
10# Standard libraries
11from pathlib import Path
12from typing import TYPE_CHECKING, Any, Optional
14# First party libraries
15from hdl_registers.field.bit import Bit
16from hdl_registers.field.bit_vector import BitVector
17from hdl_registers.field.enumeration import Enumeration
18from hdl_registers.field.integer import Integer
20# Local folder libraries
21from .cpp_generator_common import CppGeneratorCommon
23if TYPE_CHECKING:
24 # First party libraries
25 from hdl_registers.field.register_field import RegisterField
26 from hdl_registers.register import Register
27 from hdl_registers.register_array import RegisterArray
30class CppImplementationGenerator(CppGeneratorCommon):
31 """
32 Generate a C++ class implementation.
33 See the :ref:`generator_cpp` article for usage details.
35 The class implementation will contain:
37 * for each register, implementation of getter and setter methods for reading/writing the
38 register as an ``uint``.
40 * for each field in each register, implementation of getter and setter methods for
41 reading/writing the field as its native type (enumeration, positive/negative int, etc.).
43 * The setter will read-modify-write the register to update only the specified field,
44 depending on the mode of the register.
45 """
47 __version__ = "2.0.0"
49 SHORT_DESCRIPTION = "C++ implementation"
51 DEFAULT_INDENTATION_LEVEL = 4
53 @property
54 def output_file(self) -> Path:
55 """
56 Result will be placed in this file.
57 """
58 return self.output_folder / f"{self.name}.cpp"
60 def get_code(self, **kwargs: Any) -> str:
61 """
62 Get a complete C++ class implementation with all methods.
63 """
64 cpp_code = f"""\
65{self._macros()}\
66 {self._class_name}::{self._constructor_signature()}
67 : m_registers(reinterpret_cast<volatile uint32_t *>(base_address)),
68 m_assertion_handler(assertion_handler)
69 {
70 // Empty
71 }
73 void {self._class_name}::_assert_failed(const std::string *message) const
74 {
75 m_assertion_handler(message);
76 }
78"""
80 for register, register_array in self.iterate_registers():
81 cpp_code += f"{self.get_separator_line(indent=2)}"
83 description = self._get_methods_description(
84 register=register, register_array=register_array
85 )
86 cpp_code += self.comment_block(
87 text=[description, "See interface header for documentation."], indent=2
88 )
89 cpp_code += "\n"
91 if register.mode.software_can_read:
92 cpp_code += self._register_getter_function(register, register_array)
94 for field in register.fields:
95 cpp_code += self._field_getter_function(register, register_array, field=field)
96 cpp_code += self._field_getter_function_from_value(
97 register, register_array, field=field
98 )
100 if register.mode.software_can_write:
101 cpp_code += self._register_setter_function(register, register_array)
103 for field in register.fields:
104 cpp_code += self._field_setter_function(register, register_array, field=field)
105 cpp_code += self._field_setter_function_from_value(
106 register, register_array, field=field
107 )
109 cpp_code_top = f"{self.header}\n"
110 cpp_code_top += f'#include "include/{self.name}.h"\n\n'
112 return cpp_code_top + self._with_namespace(cpp_code)
114 def _macros(self) -> str:
115 def get_macro(name: str, message: str) -> str:
116 macro_name = f"_{name}_ASSERT_TRUE"
117 guard_name = f"NO_REGISTER_{name}_ASSERT"
118 name_space = " " * (38 - len(name))
119 message_space = " " * (21 - len(message))
120 base = """\
121#ifdef {guard_name}
123#define {macro_name}(expression, message) ((void)0)
125#else // Not {guard_name}.
127// This macro is called by the register code to check for runtime errors.
128#define {macro_name}(expression, message) {name_space}\\
129 {{ \\
130 if (!static_cast<bool>(expression)) {{ \\
131 std::ostringstream diagnostics; \\
132 diagnostics << "{message} out of range in " << __FILE__ << ":" {message_space}\\
133 << __LINE__ << ", message: " << message << "."; \\
134 std::string diagnostic_message = diagnostics.str(); \\
135 _assert_failed(&diagnostic_message); \\
136 }} \\
137 }}
139#endif // {guard_name}.
140"""
141 return base.format(
142 guard_name=guard_name,
143 macro_name=macro_name,
144 name=name,
145 name_space=name_space,
146 message=message,
147 message_space=message_space,
148 )
150 setter_assert = get_macro(name="SETTER", message="Tried to set value")
151 getter_assert = get_macro(name="GETTER", message="Got read value")
152 array_index_assert = get_macro(name="ARRAY_INDEX", message="Provided array index")
153 return f"""\
154{setter_assert}
155{getter_assert}
156{array_index_assert}
157"""
159 def _register_setter_function(
160 self, register: "Register", register_array: Optional["RegisterArray"]
161 ) -> str:
162 signature = self._register_setter_function_signature(
163 register=register, register_array=register_array, indent=2
164 )
165 cpp_code = f" void {self._class_name}::{signature} const\n"
166 cpp_code += " {\n"
168 if register_array:
169 cpp_code += f"""\
170 _ARRAY_INDEX_ASSERT_TRUE(
171 array_index < {self.name}::{register_array.name}::array_length,
172 "'{register_array.name}' array index out of range, got '" << array_index << "'"
173 );
174"""
175 cpp_code += (
176 f" const size_t index = {register_array.base_index} "
177 f"+ array_index * {len(register_array.registers)} + {register.index};\n"
178 )
179 else:
180 cpp_code += f" const size_t index = {register.index};\n"
182 cpp_code += " m_registers[index] = register_value;\n"
183 cpp_code += " }\n\n"
184 return cpp_code
186 def _field_setter_function(
187 self,
188 register: "Register",
189 register_array: Optional["RegisterArray"],
190 field: "RegisterField",
191 ) -> str:
192 signature = self._field_setter_function_signature(
193 register=register,
194 register_array=register_array,
195 field=field,
196 from_value=False,
197 indent=2,
198 )
200 cpp_code = f" void {self._class_name}::{signature} const\n"
201 cpp_code += " {\n"
203 if self.field_setter_should_read_modify_write(register=register):
204 register_getter_function_name = self._register_getter_function_name(
205 register=register, register_array=register_array
206 )
207 cpp_code += self.comment(
208 comment="Get the current value of other fields by reading register on the bus."
209 )
210 current_register_value = f"{register_getter_function_name}("
211 if register_array:
212 current_register_value += "array_index"
213 current_register_value += ")"
215 else:
216 cpp_code += self.comment(
217 "Set everything except for the field to default when writing the value."
218 )
219 current_register_value = str(register.default_value)
221 cpp_code += f" const uint32_t current_register_value = {current_register_value};\n"
223 signature = self._field_setter_function_name(
224 register=register, register_array=register_array, field=field, from_value=True
225 )
226 cpp_code += (
227 " const uint32_t result_register_value = "
228 f"{signature}(current_register_value, field_value);\n"
229 )
231 register_setter_function_name = self._register_setter_function_name(
232 register=register, register_array=register_array
233 )
234 cpp_code += f" {register_setter_function_name}("
235 if register_array:
236 cpp_code += "array_index, "
237 cpp_code += "result_register_value);\n"
239 cpp_code += " }\n\n"
241 return cpp_code
243 def _field_setter_function_from_value(
244 self,
245 register: "Register",
246 register_array: Optional["RegisterArray"],
247 field: "RegisterField",
248 ) -> str:
249 signature = self._field_setter_function_signature(
250 register=register, register_array=register_array, field=field, from_value=True, indent=2
251 )
253 return f"""\
254 uint32_t {self._class_name}::{signature} const\
255 {
256{self._get_field_shift_and_mask(field=field)}\
257{self._get_field_value_checker(field=field, setter_or_getter="setter")}\
258 const uint32_t field_value_masked = field_value & mask_at_base;
259 const uint32_t field_value_masked_and_shifted = field_value_masked << shift;
261 const uint32_t mask_shifted_inverse = ~mask_shifted;
262 const uint32_t register_value_masked = register_value & mask_shifted_inverse;
264 const uint32_t result_register_value = register_value_masked | field_value_masked_and_shifted;
266 return result_register_value;
267 }
269"""
271 @staticmethod
272 def _get_field_shift_and_mask(field: "RegisterField") -> str:
273 return f"""\
274 const uint32_t shift = {field.base_index}uL;
275 const uint32_t mask_at_base = 0b{"1" * field.width}uL;
276 const uint32_t mask_shifted = mask_at_base << shift;
278"""
280 @staticmethod
281 def _get_field_value_checker(field: "RegisterField", setter_or_getter: str) -> str:
282 comment = "// Check that field value is within the legal range."
283 assertion = f"_{setter_or_getter.upper()}_ASSERT_TRUE"
285 if isinstance(field, Integer):
286 return f"""\
287 {comment}
288 {assertion}(
289 field_value >= {field.min_value},
290 "'{field.name}' value too small, got '" << field_value << "'"
291 );
292 {assertion}(
293 field_value <= {field.max_value},
294 "'{field.name}' value too large, got '" << field_value << "'"
295 );
297"""
299 if isinstance(field, (Bit, BitVector)):
300 return f"""\
301 {comment}
302 const uint32_t mask_at_base_inverse = ~mask_at_base;
303 {assertion}(
304 (field_value & mask_at_base_inverse) == 0,
305 "'{field.name}' value too many bits used, got '" << field_value << "'"
306 );
308"""
310 return ""
312 def _get_field_getter_value_checker(self, field: "RegisterField") -> str:
313 if isinstance(field, Integer):
314 return self._get_field_value_checker(field=field, setter_or_getter="getter")
316 return ""
318 def _register_getter_function(
319 self, register: "Register", register_array: Optional["RegisterArray"]
320 ) -> str:
321 signature = self._register_getter_function_signature(
322 register=register, register_array=register_array, indent=2
323 )
324 cpp_code = f" uint32_t {self._class_name}::{signature} const\n"
325 cpp_code += " {\n"
327 if register_array:
328 cpp_code += f"""
329 _ARRAY_INDEX_ASSERT_TRUE(
330 array_index < {self.name}::{register_array.name}::array_length,
331 "'{register_array.name}' array index out of range, got '" << array_index << "'"
332 );
333"""
334 cpp_code += (
335 f" const size_t index = {register_array.base_index} "
336 f"+ array_index * {len(register_array.registers)} + {register.index};\n"
337 )
338 else:
339 cpp_code += f" const size_t index = {register.index};\n"
341 cpp_code += " const uint32_t result = m_registers[index];\n\n"
342 cpp_code += " return result;\n"
343 cpp_code += " }\n\n"
344 return cpp_code
346 def _field_getter_function(
347 self,
348 register: "Register",
349 register_array: Optional["RegisterArray"],
350 field: "RegisterField",
351 ) -> str:
352 signature = self._field_getter_function_signature(
353 register=register,
354 register_array=register_array,
355 field=field,
356 from_value=False,
357 indent=2,
358 )
360 field_type_name = self._field_value_type_name(
361 register=register, register_array=register_array, field=field
362 )
364 cpp_code = f" {field_type_name} {self._class_name}::{signature} const\n"
365 cpp_code += " {\n"
367 register_getter_function_name = self._register_getter_function_name(
368 register=register, register_array=register_array
369 )
371 field_getter_from_value_function_name = self._field_getter_function_name(
372 register=register, register_array=register_array, field=field, from_value=True
373 )
375 cpp_code += f" const uint32_t register_value = {register_getter_function_name}("
376 if register_array:
377 cpp_code += "array_index"
378 cpp_code += ");\n"
380 cpp_code += (
381 f" const {field_type_name} field_value = "
382 f"{field_getter_from_value_function_name}(register_value);\n"
383 )
384 cpp_code += "\n return field_value;\n"
385 cpp_code += " }\n\n"
387 return cpp_code
389 def _field_getter_function_from_value(
390 self,
391 register: "Register",
392 register_array: Optional["RegisterArray"],
393 field: "RegisterField",
394 ) -> str:
395 signature = self._field_getter_function_signature(
396 register=register, register_array=register_array, field=field, from_value=True, indent=2
397 )
399 type_name = self._field_value_type_name(
400 register=register, register_array=register_array, field=field
401 )
403 cpp_code = f"""\
404 {type_name} {self._class_name}::{signature} const
405 {
406{self._get_field_shift_and_mask(field=field)}\
407 const uint32_t result_masked = register_value & mask_shifted;
408 const uint32_t result_shifted = result_masked >> shift;
410 {type_name} field_value;
412"""
414 if type_name == "uint32_t":
415 cpp_code += """\
416 // No casting needed.
417 field_value = result_shifted;
418"""
420 else:
421 if isinstance(field, Enumeration):
422 cpp_code += f"""\
423 // "Cast" to the enum type.
424 field_value = {type_name}(result_shifted);
425"""
427 elif isinstance(field, Integer) and field.is_signed:
428 cpp_code += f"""\
429 const {type_name} sign_bit_mask = 1 << {field.width - 1};
431 if (result_shifted & sign_bit_mask)
432 {
433 // Value is to be interpreted as negative.
434 // Sign extend it from the width of the field to the width of the return type.
435 field_value = result_shifted - 2 * sign_bit_mask;
436 }
437 else
438 {
439 // Value is positive.
440 field_value = result_shifted;
441 }
442"""
443 else:
444 raise ValueError(f"Got unexpected field type: {type_name}")
446 cpp_code += f"""
447{self._get_field_getter_value_checker(field=field)}\
448 return field_value;
449 }
451"""
453 return cpp_code