Coverage for hdl_registers/generator/cpp/header.py: 100%

38 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-03-12 11:11 +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# -------------------------------------------------------------------------------------------------- 

9 

10from pathlib import Path 

11from typing import Any 

12 

13from .cpp_generator_common import CppGeneratorCommon 

14 

15 

16class CppHeaderGenerator(CppGeneratorCommon): 

17 """ 

18 Generate a C++ class header. 

19 See the :ref:`generator_cpp` article for usage details. 

20 

21 The class header will contain: 

22 

23 * for each register, signature of getter and setter methods for reading/writing the register as 

24 an ``uint``. 

25 

26 * for each field in each register, signature of getter and setter methods for reading/writing 

27 the field as its native type (enumeration, positive/negative int, etc.). 

28 

29 * The setter will read-modify-write the register to update only the specified field, 

30 depending on the mode of the register. 

31 """ 

32 

33 __version__ = "1.0.0" 

34 

35 SHORT_DESCRIPTION = "C++ header" 

36 

37 DEFAULT_INDENTATION_LEVEL = 4 

38 

39 @property 

40 def output_file(self) -> Path: 

41 """ 

42 Result will be placed in this file. 

43 """ 

44 return self.output_folder / f"{self.name}.h" 

45 

46 def get_code( 

47 self, 

48 **kwargs: Any, # noqa: ANN401, ARG002 

49 ) -> str: 

50 """ 

51 Get a complete C++ class header with methods for accessing registers and fields. 

52 """ 

53 cpp_code = f"""\ 

54 class {self._class_name} : public I{self._class_name} 

55 { 

56 private: 

57 volatile uint32_t *m_registers; 

58 bool (*m_assertion_handler) (const std::string*); 

59 

60 public: 

61 /** 

62 * Class constructor. 

63 * @param base_address Byte address where these registers are memory mapped. 

64 * Can be e.g. '0x43C00000' in bare metal, or e.g. 

65 * 'reinterpret_cast<uintptr_t>(mmap(...))' in Linux. 

66 * When using an operating system, care must be taken to pass the 

67 * virtual address, not the physical address. 

68 * When using bare metal, these are the same. 

69 * @param assertion_handler Function to call when an assertion fails. 

70 * Function takes a string pointer as an argument and must return a 

71 * boolean 'true'. 

72 */ 

73 {self._constructor_signature()}; 

74 

75 virtual ~{self._class_name}() { } 

76""" 

77 

78 def function(return_type_name: str, signature: str) -> str: 

79 return f" virtual {return_type_name} {signature} const override;\n" 

80 

81 for register, register_array in self.iterate_registers(): 

82 cpp_code += f"\n{self.get_separator_line()}" 

83 

84 description = self._get_methods_description( 

85 register=register, register_array=register_array 

86 ) 

87 cpp_code += self.comment_block( 

88 text=[description, "See interface header for documentation."] 

89 ) 

90 

91 if register.mode.software_can_read: 

92 signature = self._register_getter_function_signature( 

93 register=register, register_array=register_array 

94 ) 

95 cpp_code += function(return_type_name="uint32_t", signature=signature) 

96 

97 for field in register.fields: 

98 field_type_name = self._field_value_type_name( 

99 register=register, register_array=register_array, field=field 

100 ) 

101 

102 signature = self._field_getter_function_signature( 

103 register=register, 

104 register_array=register_array, 

105 field=field, 

106 from_value=False, 

107 ) 

108 cpp_code += function(return_type_name=field_type_name, signature=signature) 

109 

110 signature = self._field_getter_function_signature( 

111 register=register, 

112 register_array=register_array, 

113 field=field, 

114 from_value=True, 

115 ) 

116 cpp_code += function(return_type_name=field_type_name, signature=signature) 

117 

118 if register.mode.software_can_write: 

119 signature = self._register_setter_function_signature( 

120 register=register, register_array=register_array 

121 ) 

122 

123 cpp_code += function(return_type_name="void", signature=signature) 

124 

125 for field in register.fields: 

126 signature = self._field_setter_function_signature( 

127 register=register, 

128 register_array=register_array, 

129 field=field, 

130 from_value=False, 

131 ) 

132 cpp_code += function(return_type_name="void", signature=signature) 

133 

134 signature = self._field_setter_function_signature( 

135 register=register, 

136 register_array=register_array, 

137 field=field, 

138 from_value=True, 

139 ) 

140 cpp_code += function(return_type_name="uint32_t", signature=signature) 

141 

142 cpp_code += " };\n" 

143 

144 cpp_code_top = f"""\ 

145#pragma once 

146 

147#include "i_{self.name}.h" 

148 

149""" 

150 return cpp_code_top + self._with_namespace(cpp_code)