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

38 statements  

« prev     ^ index     » next       coverage.py v7.6.10, created at 2025-01-28 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# -------------------------------------------------------------------------------------------------- 

9 

10# Standard libraries 

11from pathlib import Path 

12from typing import Any 

13 

14# Local folder libraries 

15from .cpp_generator_common import CppGeneratorCommon 

16 

17 

18class CppHeaderGenerator(CppGeneratorCommon): 

19 """ 

20 Generate a C++ class header. 

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

22 

23 The class header will contain: 

24 

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

26 an ``uint``. 

27 

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

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

30 

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

32 depending on the mode of the register. 

33 """ 

34 

35 __version__ = "1.0.0" 

36 

37 SHORT_DESCRIPTION = "C++ header" 

38 

39 DEFAULT_INDENTATION_LEVEL = 4 

40 

41 @property 

42 def output_file(self) -> Path: 

43 """ 

44 Result will be placed in this file. 

45 """ 

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

47 

48 def get_code(self, **kwargs: Any) -> str: 

49 """ 

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

51 """ 

52 cpp_code = f"""\ 

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

54 { 

55 private: 

56 volatile uint32_t *m_registers; 

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

58 

59 public: 

60 /** 

61 * Class constructor. 

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

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

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

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

66 * virtual address, not the physical address. 

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

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

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

70 * boolean 'true'. 

71 */ 

72 {self._constructor_signature()}; 

73 

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

75""" 

76 

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

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

79 

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

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

82 

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

88 ) 

89 

90 if register.mode.software_can_read: 

91 signature = self._register_getter_function_signature( 

92 register=register, register_array=register_array 

93 ) 

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

95 

96 for field in register.fields: 

97 field_type_name = self._field_value_type_name( 

98 register=register, register_array=register_array, field=field 

99 ) 

100 

101 signature = self._field_getter_function_signature( 

102 register=register, 

103 register_array=register_array, 

104 field=field, 

105 from_value=False, 

106 ) 

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

108 

109 signature = self._field_getter_function_signature( 

110 register=register, 

111 register_array=register_array, 

112 field=field, 

113 from_value=True, 

114 ) 

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

116 

117 if register.mode.software_can_write: 

118 signature = self._register_setter_function_signature( 

119 register=register, register_array=register_array 

120 ) 

121 

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

123 

124 for field in register.fields: 

125 signature = self._field_setter_function_signature( 

126 register=register, 

127 register_array=register_array, 

128 field=field, 

129 from_value=False, 

130 ) 

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

132 

133 signature = self._field_setter_function_signature( 

134 register=register, 

135 register_array=register_array, 

136 field=field, 

137 from_value=True, 

138 ) 

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

140 

141 cpp_code += " };\n" 

142 

143 cpp_code_top = f"""\ 

144#pragma once 

145 

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

147 

148""" 

149 return cpp_code_top + self._with_namespace(cpp_code)