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

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 TYPE_CHECKING, Any, Optional 

13 

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 

19 

20# Local folder libraries 

21from .cpp_generator_common import CppGeneratorCommon 

22 

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 

28 

29 

30class CppImplementationGenerator(CppGeneratorCommon): 

31 """ 

32 Generate a C++ class implementation. 

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

34 

35 The class implementation will contain: 

36 

37 * for each register, implementation of getter and setter methods for reading/writing the 

38 register as an ``uint``. 

39 

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.). 

42 

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

44 depending on the mode of the register. 

45 """ 

46 

47 __version__ = "1.0.0" 

48 

49 SHORT_DESCRIPTION = "C++ implementation" 

50 

51 DEFAULT_INDENTATION_LEVEL = 4 

52 

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" 

59 

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" 

69 

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

71 cpp_code += f"{self.get_separator_line(indent=2)}" 

72 

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" 

80 

81 if register.mode.software_can_read: 

82 cpp_code += self._register_getter_function(register, register_array) 

83 

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 ) 

89 

90 if register.mode.software_can_write: 

91 cpp_code += self._register_setter_function(register, register_array) 

92 

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 ) 

98 

99 cpp_code_top = f"{self.header}\n" 

100 cpp_code_top += f'#include "include/{self.name}.h"\n\n' 

101 

102 return cpp_code_top + self._with_namespace(cpp_code) 

103 

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" 

112 

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" 

123 

124 cpp_code += " m_registers[index] = register_value;\n" 

125 cpp_code += " }\n\n" 

126 return cpp_code 

127 

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 ) 

141 

142 cpp_code = f" void {self._class_name}::{signature} const\n" 

143 cpp_code += " {\n" 

144 

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 += ")" 

156 

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) 

162 

163 cpp_code += f" const uint32_t current_register_value = {current_register_value};\n" 

164 

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 ) 

172 

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" 

180 

181 cpp_code += " }\n\n" 

182 

183 return cpp_code 

184 

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 ) 

194 

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; 

202 

203 const uint32_t mask_shifted_inverse = ~mask_shifted; 

204 const uint32_t register_value_masked = register_value & mask_shifted_inverse; 

205 

206 const uint32_t result_register_value = register_value_masked | field_value_masked_and_shifted; 

207 

208 return result_register_value; 

209 }} 

210 

211""" 

212 

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; 

219 

220""" 

221 

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}); 

230 

231""" 

232 

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); 

238 

239""" 

240 

241 return "" 

242 

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) 

246 

247 return "" 

248 

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" 

257 

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" 

268 

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 

273 

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 ) 

287 

288 field_type_name = self._field_value_type_name( 

289 register=register, register_array=register_array, field=field 

290 ) 

291 

292 cpp_code = f" {field_type_name} {self._class_name}::{signature} const\n" 

293 cpp_code += " {\n" 

294 

295 register_getter_function_name = self._register_getter_function_name( 

296 register=register, register_array=register_array 

297 ) 

298 

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 ) 

302 

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" 

307 

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" 

314 

315 return cpp_code 

316 

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 ) 

326 

327 type_name = self._field_value_type_name( 

328 register=register, register_array=register_array, field=field 

329 ) 

330 

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; 

337 

338 {type_name} field_value; 

339 

340""" 

341 

342 if type_name == "uint32_t": 

343 cpp_code += """\ 

344 // No casting needed. 

345 field_value = result_shifted; 

346""" 

347 

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

354 

355 elif isinstance(field, Integer) and field.is_signed: 

356 cpp_code += f"""\ 

357 const {type_name} sign_bit_mask = 1 << {field.width - 1}; 

358 

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}") 

373 

374 cpp_code += f""" 

375{self._get_field_getter_value_checker(field=field)}\ 

376 return field_value; 

377 }} 

378 

379""" 

380 

381 return cpp_code