Coverage for hdl_registers/generator/cpp/implementation.py: 97%
133 statements
« prev ^ index » next coverage.py v7.6.1, created at 2024-09-07 20:51 +0000
« prev ^ index » next coverage.py v7.6.1, created at 2024-09-07 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_vector import BitVector
16from hdl_registers.field.enumeration import Enumeration
17from hdl_registers.field.integer import Integer
19# Local folder libraries
20from .cpp_generator_common import CppGeneratorCommon
22if TYPE_CHECKING:
23 # First party libraries
24 from hdl_registers.field.register_field import RegisterField
25 from hdl_registers.register import Register
26 from hdl_registers.register_array import RegisterArray
29class CppImplementationGenerator(CppGeneratorCommon):
30 """
31 Generate a C++ class implementation.
32 See the :ref:`generator_cpp` article for usage details.
34 The class implementation will contain:
36 * for each register, implementation of getter and setter methods for reading/writing the
37 register as an ``uint``.
39 * for each field in each register, implementation of getter and setter methods for
40 reading/writing the field as its native type (enumeration, positive/negative int, etc.).
42 * The setter will read-modify-write the register to update only the specified field,
43 depending on the mode of the register.
44 """
46 __version__ = "1.0.0"
48 SHORT_DESCRIPTION = "C++ implementation"
50 DEFAULT_INDENTATION_LEVEL = 4
52 @property
53 def output_file(self) -> Path:
54 """
55 Result will be placed in this file.
56 """
57 return self.output_folder / f"{self.name}.cpp"
59 def get_code(self, **kwargs: Any) -> str:
60 """
61 Get a complete C++ class implementation with all methods.
62 """
63 cpp_code = f" {self._class_name}::{self._constructor_signature()}\n"
64 cpp_code += " : m_registers(reinterpret_cast<volatile uint32_t *>(base_address))\n"
65 cpp_code += " {\n"
66 cpp_code += " // Empty\n"
67 cpp_code += " }\n\n"
69 for register, register_array in self.iterate_registers():
70 cpp_code += f"{self.get_separator_line(indent=2)}"
72 description = self._get_methods_description(
73 register=register, register_array=register_array
74 )
75 cpp_code += self.comment_block(
76 text=[description, "See interface header for documentation."], indent=2
77 )
78 cpp_code += "\n"
80 if register.mode.software_can_read:
81 cpp_code += self._register_getter_function(register, register_array)
83 for field in register.fields:
84 cpp_code += self._field_getter_function(register, register_array, field=field)
85 cpp_code += self._field_getter_function_from_value(
86 register, register_array, field=field
87 )
89 if register.mode.software_can_write:
90 cpp_code += self._register_setter_function(register, register_array)
92 for field in register.fields:
93 cpp_code += self._field_setter_function(register, register_array, field=field)
94 cpp_code += self._field_setter_function_from_value(
95 register, register_array, field=field
96 )
98 cpp_code_top = f"{self.header}\n"
99 cpp_code_top += f'#include "include/{self.name}.h"\n\n'
101 return cpp_code_top + self._with_namespace(cpp_code)
103 def _register_setter_function(
104 self, register: "Register", register_array: Optional["RegisterArray"]
105 ) -> str:
106 signature = self._register_setter_function_signature(
107 register=register, register_array=register_array, indent=2
108 )
109 cpp_code = f" void {self._class_name}::{signature} const\n"
110 cpp_code += " {\n"
112 if register_array:
113 cpp_code += (
114 f" assert(array_index < {self.name}::{register_array.name}::array_length);\n"
115 )
116 cpp_code += (
117 f" const size_t index = {register_array.base_index} "
118 f"+ array_index * {len(register_array.registers)} + {register.index};\n"
119 )
120 else:
121 cpp_code += f" const size_t index = {register.index};\n"
123 cpp_code += " m_registers[index] = register_value;\n"
124 cpp_code += " }\n\n"
125 return cpp_code
127 def _field_setter_function(
128 self,
129 register: "Register",
130 register_array: Optional["RegisterArray"],
131 field: "RegisterField",
132 ) -> str:
133 signature = self._field_setter_function_signature(
134 register=register,
135 register_array=register_array,
136 field=field,
137 from_value=False,
138 indent=2,
139 )
141 cpp_code = f" void {self._class_name}::{signature} const\n"
142 cpp_code += " {\n"
144 if self.field_setter_should_read_modify_write(register=register):
145 register_getter_function_name = self._register_getter_function_name(
146 register=register, register_array=register_array
147 )
148 cpp_code += self.comment(
149 comment="Get the current value of other fields by reading register on the bus."
150 )
151 current_register_value = f"{register_getter_function_name}("
152 if register_array:
153 current_register_value += "array_index"
154 current_register_value += ")"
156 else:
157 cpp_code += self.comment(
158 "Set everything except for the field to default when writing the value."
159 )
160 current_register_value = str(register.default_value)
162 cpp_code += f" const uint32_t current_register_value = {current_register_value};\n"
164 signature = self._field_setter_function_name(
165 register=register, register_array=register_array, field=field, from_value=True
166 )
167 cpp_code += (
168 " const uint32_t result_register_value = "
169 f"{signature}(current_register_value, field_value);\n"
170 )
172 register_setter_function_name = self._register_setter_function_name(
173 register=register, register_array=register_array
174 )
175 cpp_code += f" {register_setter_function_name}("
176 if register_array:
177 cpp_code += "array_index, "
178 cpp_code += "result_register_value);\n"
180 cpp_code += " }\n\n"
182 return cpp_code
184 def _field_setter_function_from_value(
185 self,
186 register: "Register",
187 register_array: Optional["RegisterArray"],
188 field: "RegisterField",
189 ) -> str:
190 signature = self._field_setter_function_signature(
191 register=register, register_array=register_array, field=field, from_value=True, indent=2
192 )
194 return f"""\
195 uint32_t {self._class_name}::{signature} const\
196 {{
197{self._get_field_shift_and_mask(field=field)}\
198{self._get_field_setter_value_checker(field=field)}\
199 const uint32_t field_value_masked = field_value & mask_at_base;
200 const uint32_t field_value_masked_and_shifted = field_value_masked << shift;
202 const uint32_t mask_shifted_inverse = ~mask_shifted;
203 const uint32_t register_value_masked = register_value & mask_shifted_inverse;
205 const uint32_t result_register_value = register_value_masked | field_value_masked_and_shifted;
207 return result_register_value;
208 }}
210"""
212 @staticmethod
213 def _get_field_shift_and_mask(field: "RegisterField") -> str:
214 return f"""\
215 const uint32_t shift = {field.base_index}uL;
216 const uint32_t mask_at_base = 0b{"1" * field.width}uL;
217 const uint32_t mask_shifted = mask_at_base << shift;
219"""
221 @staticmethod
222 def _get_field_setter_value_checker(field: "RegisterField") -> str:
223 comment = "// Check that field value is within the legal range."
224 if isinstance(field, Integer):
225 return f"""\
226 {comment}
227 assert(field_value >= {field.min_value});
228 assert(field_value <= {field.max_value});
230"""
232 if isinstance(field, BitVector):
233 return f"""\
234 {comment}
235 const uint32_t mask_at_base_inverse = ~mask_at_base;
236 assert((field_value & mask_at_base_inverse) == 0);
238"""
240 return ""
242 def _get_field_getter_value_checker(self, field: "RegisterField") -> str:
243 if isinstance(field, Integer):
244 return self._get_field_setter_value_checker(field=field)
246 return ""
248 def _register_getter_function(
249 self, register: "Register", register_array: Optional["RegisterArray"]
250 ) -> str:
251 signature = self._register_getter_function_signature(
252 register=register, register_array=register_array, indent=2
253 )
254 cpp_code = f" uint32_t {self._class_name}::{signature} const\n"
255 cpp_code += " {\n"
257 if register_array:
258 cpp_code += (
259 f" assert(array_index < {self.name}::{register_array.name}::array_length);\n"
260 )
261 cpp_code += (
262 f" const size_t index = {register_array.base_index} "
263 f"+ array_index * {len(register_array.registers)} + {register.index};\n"
264 )
265 else:
266 cpp_code += f" const size_t index = {register.index};\n"
268 cpp_code += " const uint32_t result = m_registers[index];\n\n"
269 cpp_code += " return result;\n"
270 cpp_code += " }\n\n"
271 return cpp_code
273 def _field_getter_function(
274 self,
275 register: "Register",
276 register_array: Optional["RegisterArray"],
277 field: "RegisterField",
278 ) -> str:
279 signature = self._field_getter_function_signature(
280 register=register,
281 register_array=register_array,
282 field=field,
283 from_value=False,
284 indent=2,
285 )
287 field_type_name = self._field_value_type_name(
288 register=register, register_array=register_array, field=field
289 )
291 cpp_code = f" {field_type_name} {self._class_name}::{signature} const\n"
292 cpp_code += " {\n"
294 register_getter_function_name = self._register_getter_function_name(
295 register=register, register_array=register_array
296 )
298 field_getter_from_value_function_name = self._field_getter_function_name(
299 register=register, register_array=register_array, field=field, from_value=True
300 )
302 cpp_code += f" const uint32_t register_value = {register_getter_function_name}("
303 if register_array:
304 cpp_code += "array_index"
305 cpp_code += ");\n"
307 cpp_code += (
308 f" const {field_type_name} field_value = "
309 f"{field_getter_from_value_function_name}(register_value);\n"
310 )
311 cpp_code += "\n return field_value;\n"
312 cpp_code += " }\n\n"
314 return cpp_code
316 def _field_getter_function_from_value(
317 self,
318 register: "Register",
319 register_array: Optional["RegisterArray"],
320 field: "RegisterField",
321 ) -> str:
322 signature = self._field_getter_function_signature(
323 register=register, register_array=register_array, field=field, from_value=True, indent=2
324 )
326 type_name = self._field_value_type_name(
327 register=register, register_array=register_array, field=field
328 )
330 cpp_code = f"""\
331 {type_name} {self._class_name}::{signature} const
332 {{
333{self._get_field_shift_and_mask(field=field)}\
334 const uint32_t result_masked = register_value & mask_shifted;
335 const uint32_t result_shifted = result_masked >> shift;
337 {type_name} field_value;
339"""
341 if type_name == "uint32_t":
342 cpp_code += """\
343 // No casting needed.
344 field_value = result_shifted;
345"""
347 else:
348 if isinstance(field, Enumeration):
349 cpp_code += f"""\
350 // "Cast" to the enum type.
351 field_value = {type_name}(result_shifted);
352"""
354 elif isinstance(field, Integer) and field.is_signed:
355 cpp_code += f"""\
356 const {type_name} sign_bit_mask = 1 << {field.width - 1};
358 if (result_shifted & sign_bit_mask)
359 {{
360 // Value is to be interpreted as negative.
361 // Sign extend it from the width of the field to the width of the return type.
362 field_value = result_shifted - 2 * sign_bit_mask;
363 }}
364 else
365 {{
366 // Value is positive.
367 field_value = result_shifted;
368 }}
369"""
370 else:
371 raise ValueError(f"Got unexpected field type: {type_name}")
373 cpp_code += f"""
374{self._get_field_getter_value_checker(field=field)}\
375 return field_value;
376 }}
378"""
380 return cpp_code