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

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_vector import BitVector 

16from hdl_registers.field.enumeration import Enumeration 

17from hdl_registers.field.integer import Integer 

18 

19# Local folder libraries 

20from .cpp_generator_common import CppGeneratorCommon 

21 

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 

27 

28 

29class CppImplementationGenerator(CppGeneratorCommon): 

30 """ 

31 Generate a C++ class implementation. 

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

33 

34 The class implementation will contain: 

35 

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

37 register as an ``uint``. 

38 

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

41 

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

43 depending on the mode of the register. 

44 """ 

45 

46 __version__ = "1.0.0" 

47 

48 SHORT_DESCRIPTION = "C++ implementation" 

49 

50 DEFAULT_INDENTATION_LEVEL = 4 

51 

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" 

58 

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" 

68 

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

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

71 

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" 

79 

80 if register.mode.software_can_read: 

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

82 

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 ) 

88 

89 if register.mode.software_can_write: 

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

91 

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 ) 

97 

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

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

100 

101 return cpp_code_top + self._with_namespace(cpp_code) 

102 

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" 

111 

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" 

122 

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

124 cpp_code += " }\n\n" 

125 return cpp_code 

126 

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 ) 

140 

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

142 cpp_code += " {\n" 

143 

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

155 

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) 

161 

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

163 

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 ) 

171 

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" 

179 

180 cpp_code += " }\n\n" 

181 

182 return cpp_code 

183 

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 ) 

193 

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; 

201 

202 const uint32_t mask_shifted_inverse = ~mask_shifted; 

203 const uint32_t register_value_masked = register_value & mask_shifted_inverse; 

204 

205 const uint32_t result_register_value = register_value_masked | field_value_masked_and_shifted; 

206 

207 return result_register_value; 

208 }} 

209 

210""" 

211 

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; 

218 

219""" 

220 

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

229 

230""" 

231 

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

237 

238""" 

239 

240 return "" 

241 

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) 

245 

246 return "" 

247 

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" 

256 

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" 

267 

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 

272 

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 ) 

286 

287 field_type_name = self._field_value_type_name( 

288 register=register, register_array=register_array, field=field 

289 ) 

290 

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

292 cpp_code += " {\n" 

293 

294 register_getter_function_name = self._register_getter_function_name( 

295 register=register, register_array=register_array 

296 ) 

297 

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 ) 

301 

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" 

306 

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" 

313 

314 return cpp_code 

315 

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 ) 

325 

326 type_name = self._field_value_type_name( 

327 register=register, register_array=register_array, field=field 

328 ) 

329 

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; 

336 

337 {type_name} field_value; 

338 

339""" 

340 

341 if type_name == "uint32_t": 

342 cpp_code += """\ 

343 // No casting needed. 

344 field_value = result_shifted; 

345""" 

346 

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

353 

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

355 cpp_code += f"""\ 

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

357 

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

372 

373 cpp_code += f""" 

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

375 return field_value; 

376 }} 

377 

378""" 

379 

380 return cpp_code