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

38 statements  

« 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# -------------------------------------------------------------------------------------------------- 

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 void _assert_failed(const std::string *message) const; 

60 

61 public: 

62 /** 

63 * Class constructor. 

64 * @param base_address Pointer to where these registers are memory mapped. 

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

66 * physical address, not the virtual address. 

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

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

69 */ 

70 {self._constructor_signature()}; 

71 

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

73""" 

74 

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

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

77 

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

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

80 

81 description = self._get_methods_description( 

82 register=register, register_array=register_array 

83 ) 

84 cpp_code += self.comment_block( 

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

86 ) 

87 

88 if register.mode.software_can_read: 

89 signature = self._register_getter_function_signature( 

90 register=register, register_array=register_array 

91 ) 

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

93 

94 for field in register.fields: 

95 field_type_name = self._field_value_type_name( 

96 register=register, register_array=register_array, field=field 

97 ) 

98 

99 signature = self._field_getter_function_signature( 

100 register=register, 

101 register_array=register_array, 

102 field=field, 

103 from_value=False, 

104 ) 

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

106 

107 signature = self._field_getter_function_signature( 

108 register=register, 

109 register_array=register_array, 

110 field=field, 

111 from_value=True, 

112 ) 

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

114 

115 if register.mode.software_can_write: 

116 signature = self._register_setter_function_signature( 

117 register=register, register_array=register_array 

118 ) 

119 

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

121 

122 for field in register.fields: 

123 signature = self._field_setter_function_signature( 

124 register=register, 

125 register_array=register_array, 

126 field=field, 

127 from_value=False, 

128 ) 

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

130 

131 signature = self._field_setter_function_signature( 

132 register=register, 

133 register_array=register_array, 

134 field=field, 

135 from_value=True, 

136 ) 

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

138 

139 cpp_code += " };\n" 

140 

141 cpp_code_top = f"""\ 

142{self.header} 

143#pragma once 

144 

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

146 

147""" 

148 return cpp_code_top + self._with_namespace(cpp_code)