Coverage for hdl_registers/generator/cpp/implementation.py: 97%
134 statements
« prev ^ index » next coverage.py v7.6.8, created at 2024-12-01 20:50 +0000
« prev ^ index » next coverage.py v7.6.8, created at 2024-12-01 20:50 +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__ = "1.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" {self._class_name}::{self._constructor_signature()}\n"
65 cpp_code += " : m_registers(reinterpret_cast<volatile uint32_t *>(base_address))\n"
66 cpp_code += " {\n"
67 cpp_code += " // Empty\n"
68 cpp_code += " }\n\n"
70 for register, register_array in self.iterate_registers():
71 cpp_code += f"{self.get_separator_line(indent=2)}"
73 description = self._get_methods_description(
74 register=register, register_array=register_array
75 )
76 cpp_code += self.comment_block(
77 text=[description, "See interface header for documentation."], indent=2
78 )
79 cpp_code += "\n"
81 if register.mode.software_can_read:
82 cpp_code += self._register_getter_function(register, register_array)
84 for field in register.fields:
85 cpp_code += self._field_getter_function(register, register_array, field=field)
86 cpp_code += self._field_getter_function_from_value(
87 register, register_array, field=field
88 )
90 if register.mode.software_can_write:
91 cpp_code += self._register_setter_function(register, register_array)
93 for field in register.fields:
94 cpp_code += self._field_setter_function(register, register_array, field=field)
95 cpp_code += self._field_setter_function_from_value(
96 register, register_array, field=field
97 )
99 cpp_code_top = f"{self.header}\n"
100 cpp_code_top += f'#include "include/{self.name}.h"\n\n'
102 return cpp_code_top + self._with_namespace(cpp_code)
104 def _register_setter_function(
105 self, register: "Register", register_array: Optional["RegisterArray"]
106 ) -> str:
107 signature = self._register_setter_function_signature(
108 register=register, register_array=register_array, indent=2
109 )
110 cpp_code = f" void {self._class_name}::{signature} const\n"
111 cpp_code += " {\n"
113 if register_array:
114 cpp_code += (
115 f" assert(array_index < {self.name}::{register_array.name}::array_length);\n"
116 )
117 cpp_code += (
118 f" const size_t index = {register_array.base_index} "
119 f"+ array_index * {len(register_array.registers)} + {register.index};\n"
120 )
121 else:
122 cpp_code += f" const size_t index = {register.index};\n"
124 cpp_code += " m_registers[index] = register_value;\n"
125 cpp_code += " }\n\n"
126 return cpp_code
128 def _field_setter_function(
129 self,
130 register: "Register",
131 register_array: Optional["RegisterArray"],
132 field: "RegisterField",
133 ) -> str:
134 signature = self._field_setter_function_signature(
135 register=register,
136 register_array=register_array,
137 field=field,
138 from_value=False,
139 indent=2,
140 )
142 cpp_code = f" void {self._class_name}::{signature} const\n"
143 cpp_code += " {\n"
145 if self.field_setter_should_read_modify_write(register=register):
146 register_getter_function_name = self._register_getter_function_name(
147 register=register, register_array=register_array
148 )
149 cpp_code += self.comment(
150 comment="Get the current value of other fields by reading register on the bus."
151 )
152 current_register_value = f"{register_getter_function_name}("
153 if register_array:
154 current_register_value += "array_index"
155 current_register_value += ")"
157 else:
158 cpp_code += self.comment(
159 "Set everything except for the field to default when writing the value."
160 )
161 current_register_value = str(register.default_value)
163 cpp_code += f" const uint32_t current_register_value = {current_register_value};\n"
165 signature = self._field_setter_function_name(
166 register=register, register_array=register_array, field=field, from_value=True
167 )
168 cpp_code += (
169 " const uint32_t result_register_value = "
170 f"{signature}(current_register_value, field_value);\n"
171 )
173 register_setter_function_name = self._register_setter_function_name(
174 register=register, register_array=register_array
175 )
176 cpp_code += f" {register_setter_function_name}("
177 if register_array:
178 cpp_code += "array_index, "
179 cpp_code += "result_register_value);\n"
181 cpp_code += " }\n\n"
183 return cpp_code
185 def _field_setter_function_from_value(
186 self,
187 register: "Register",
188 register_array: Optional["RegisterArray"],
189 field: "RegisterField",
190 ) -> str:
191 signature = self._field_setter_function_signature(
192 register=register, register_array=register_array, field=field, from_value=True, indent=2
193 )
195 return f"""\
196 uint32_t {self._class_name}::{signature} const\
197 {{
198{self._get_field_shift_and_mask(field=field)}\
199{self._get_field_setter_value_checker(field=field)}\
200 const uint32_t field_value_masked = field_value & mask_at_base;
201 const uint32_t field_value_masked_and_shifted = field_value_masked << shift;
203 const uint32_t mask_shifted_inverse = ~mask_shifted;
204 const uint32_t register_value_masked = register_value & mask_shifted_inverse;
206 const uint32_t result_register_value = register_value_masked | field_value_masked_and_shifted;
208 return result_register_value;
209 }}
211"""
213 @staticmethod
214 def _get_field_shift_and_mask(field: "RegisterField") -> str:
215 return f"""\
216 const uint32_t shift = {field.base_index}uL;
217 const uint32_t mask_at_base = 0b{"1" * field.width}uL;
218 const uint32_t mask_shifted = mask_at_base << shift;
220"""
222 @staticmethod
223 def _get_field_setter_value_checker(field: "RegisterField") -> str:
224 comment = "// Check that field value is within the legal range."
225 if isinstance(field, Integer):
226 return f"""\
227 {comment}
228 assert(field_value >= {field.min_value});
229 assert(field_value <= {field.max_value});
231"""
233 if isinstance(field, (Bit, BitVector)):
234 return f"""\
235 {comment}
236 const uint32_t mask_at_base_inverse = ~mask_at_base;
237 assert((field_value & mask_at_base_inverse) == 0);
239"""
241 return ""
243 def _get_field_getter_value_checker(self, field: "RegisterField") -> str:
244 if isinstance(field, Integer):
245 return self._get_field_setter_value_checker(field=field)
247 return ""
249 def _register_getter_function(
250 self, register: "Register", register_array: Optional["RegisterArray"]
251 ) -> str:
252 signature = self._register_getter_function_signature(
253 register=register, register_array=register_array, indent=2
254 )
255 cpp_code = f" uint32_t {self._class_name}::{signature} const\n"
256 cpp_code += " {\n"
258 if register_array:
259 cpp_code += (
260 f" assert(array_index < {self.name}::{register_array.name}::array_length);\n"
261 )
262 cpp_code += (
263 f" const size_t index = {register_array.base_index} "
264 f"+ array_index * {len(register_array.registers)} + {register.index};\n"
265 )
266 else:
267 cpp_code += f" const size_t index = {register.index};\n"
269 cpp_code += " const uint32_t result = m_registers[index];\n\n"
270 cpp_code += " return result;\n"
271 cpp_code += " }\n\n"
272 return cpp_code
274 def _field_getter_function(
275 self,
276 register: "Register",
277 register_array: Optional["RegisterArray"],
278 field: "RegisterField",
279 ) -> str:
280 signature = self._field_getter_function_signature(
281 register=register,
282 register_array=register_array,
283 field=field,
284 from_value=False,
285 indent=2,
286 )
288 field_type_name = self._field_value_type_name(
289 register=register, register_array=register_array, field=field
290 )
292 cpp_code = f" {field_type_name} {self._class_name}::{signature} const\n"
293 cpp_code += " {\n"
295 register_getter_function_name = self._register_getter_function_name(
296 register=register, register_array=register_array
297 )
299 field_getter_from_value_function_name = self._field_getter_function_name(
300 register=register, register_array=register_array, field=field, from_value=True
301 )
303 cpp_code += f" const uint32_t register_value = {register_getter_function_name}("
304 if register_array:
305 cpp_code += "array_index"
306 cpp_code += ");\n"
308 cpp_code += (
309 f" const {field_type_name} field_value = "
310 f"{field_getter_from_value_function_name}(register_value);\n"
311 )
312 cpp_code += "\n return field_value;\n"
313 cpp_code += " }\n\n"
315 return cpp_code
317 def _field_getter_function_from_value(
318 self,
319 register: "Register",
320 register_array: Optional["RegisterArray"],
321 field: "RegisterField",
322 ) -> str:
323 signature = self._field_getter_function_signature(
324 register=register, register_array=register_array, field=field, from_value=True, indent=2
325 )
327 type_name = self._field_value_type_name(
328 register=register, register_array=register_array, field=field
329 )
331 cpp_code = f"""\
332 {type_name} {self._class_name}::{signature} const
333 {{
334{self._get_field_shift_and_mask(field=field)}\
335 const uint32_t result_masked = register_value & mask_shifted;
336 const uint32_t result_shifted = result_masked >> shift;
338 {type_name} field_value;
340"""
342 if type_name == "uint32_t":
343 cpp_code += """\
344 // No casting needed.
345 field_value = result_shifted;
346"""
348 else:
349 if isinstance(field, Enumeration):
350 cpp_code += f"""\
351 // "Cast" to the enum type.
352 field_value = {type_name}(result_shifted);
353"""
355 elif isinstance(field, Integer) and field.is_signed:
356 cpp_code += f"""\
357 const {type_name} sign_bit_mask = 1 << {field.width - 1};
359 if (result_shifted & sign_bit_mask)
360 {{
361 // Value is to be interpreted as negative.
362 // Sign extend it from the width of the field to the width of the return type.
363 field_value = result_shifted - 2 * sign_bit_mask;
364 }}
365 else
366 {{
367 // Value is positive.
368 field_value = result_shifted;
369 }}
370"""
371 else:
372 raise ValueError(f"Got unexpected field type: {type_name}")
374 cpp_code += f"""
375{self._get_field_getter_value_checker(field=field)}\
376 return field_value;
377 }}
379"""
381 return cpp_code