Coverage for hdl_registers/register_cpp_generator.py: 99%

344 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2022-09-29 22:03 +0000

1# -------------------------------------------------------------------------------------------------- 

2# Copyright (c) Lukas Vik. All rights reserved. 

3# 

4# This file is part of the hdl_registers project, a HDL register generator fast enough to be run 

5# in real time. 

6# https://hdl-registers.com 

7# https://gitlab.com/tsfpga/hdl_registers 

8# -------------------------------------------------------------------------------------------------- 

9 

10from .register import REGISTER_MODES 

11from .register_array import RegisterArray 

12from .register_code_generator import RegisterCodeGenerator 

13 

14 

15class RegisterCppGenerator: 

16 """ 

17 Generate a C++ class with register definitions and methods. 

18 

19 There is only a very limited unit test of this class that checks the generated code. 

20 It is instead functionally tested in the file test_register_compilation.py. 

21 That test generates C++ code from an example register set, compiles it and performs some 

22 run-time assertions in a C++ program. 

23 That test is considered more meaningful and exhaustive than a unit test would be. 

24 """ 

25 

26 def __init__(self, module_name, generated_info): 

27 """ 

28 Arguments: 

29 module_name (str): The name of the register map. 

30 generated_info (list(str)): Will be placed in the file headers. 

31 """ 

32 self.module_name = module_name 

33 self.generated_info = generated_info 

34 

35 def get_interface(self, register_objects, constants): 

36 """ 

37 Get a complete C++ interface class header with all constant values and the signatures of 

38 all methods. 

39 

40 Arguments: 

41 register_objects (list): Register arrays and registers to be included. 

42 constants (list(Constant)): Constants to be included. 

43 

44 Returns: 

45 str: C++ code. 

46 """ 

47 generator = InterfaceGenerator( 

48 module_name=self.module_name, generated_info=self.generated_info 

49 ) 

50 return generator.get_interface(register_objects=register_objects, constants=constants) 

51 

52 def get_header(self, register_objects): 

53 """ 

54 Get a complete C++ class header for the implementation of all methods. 

55 

56 Arguments: 

57 register_objects (list): Register arrays and registers to be included. 

58 

59 Returns: 

60 str: C++ code. 

61 """ 

62 generator = HeaderGenerator( 

63 module_name=self.module_name, generated_info=self.generated_info 

64 ) 

65 return generator.get_header(register_objects=register_objects) 

66 

67 def get_implementation(self, register_objects): 

68 """ 

69 Get a complete C++ class implementation with all methods. 

70 

71 Arguments: 

72 register_objects (list): Register arrays and registers to be included. 

73 

74 Returns: 

75 str: C++ code. 

76 """ 

77 generator = ImplementationGenerator( 

78 module_name=self.module_name, generated_info=self.generated_info 

79 ) 

80 return generator.get_implementation(register_objects=register_objects) 

81 

82 

83class CommonGenerator(RegisterCodeGenerator): 

84 """ 

85 Class with common methods for generating C++ code. 

86 Do not use this directly, should use :class:`.RegisterCppGenerator`: 

87 """ 

88 

89 def __init__(self, module_name, generated_info): 

90 self.module_name = module_name 

91 

92 self._class_name = self._to_pascal_case(module_name) 

93 self._file_header = "".join([self._comment(header_line) for header_line in generated_info]) 

94 

95 @staticmethod 

96 def _get_separator_line(indentation): 

97 """ 

98 Get a separator line, e.g. " // ---------------------------------\n" 

99 """ 

100 result = " " * indentation + "// " 

101 num_dash = 80 - len(result) 

102 result += "-" * num_dash 

103 result += "\n" 

104 return result 

105 

106 @staticmethod 

107 def _comment(comment, indentation=0): 

108 indent = " " * indentation 

109 return f"{indent}// {comment}\n" 

110 

111 @staticmethod 

112 def _with_namespace(cpp_code_body): 

113 cpp_code = "namespace fpga_regs\n" 

114 cpp_code += "{\n\n" 

115 cpp_code += f"{cpp_code_body}" 

116 cpp_code += "\n} /* namespace fpga_regs */\n" 

117 return cpp_code 

118 

119 def _constructor_signature(self): 

120 return f"{self._class_name}(volatile uint8_t *base_address)" 

121 

122 @staticmethod 

123 def _array_length_constant_name(register_array): 

124 return f"{register_array.name}_array_length" 

125 

126 @staticmethod 

127 def _get_methods_description(register, register_array): 

128 result = f'Methods for the "{register.name}" register' 

129 if register_array: 

130 result += f' within the "{register_array.name}" register array' 

131 result += "." 

132 

133 return result 

134 

135 @staticmethod 

136 def _field_value_type_name(): 

137 """ 

138 We represent all fields as uint32_t. In the future we might support enum types. 

139 """ 

140 return "uint32_t" 

141 

142 @staticmethod 

143 def _register_getter_function_name(register, register_array): 

144 result = "get" 

145 

146 if register_array: 

147 result += f"_{register_array.name}" 

148 

149 result += f"_{register.name}" 

150 

151 return result 

152 

153 def _register_getter_function_signature(self, register, register_array): 

154 function_name = self._register_getter_function_name( 

155 register=register, register_array=register_array 

156 ) 

157 result = f"{function_name}(" 

158 

159 if register_array: 

160 result += "size_t array_index" 

161 

162 result += ")" 

163 

164 return result 

165 

166 @staticmethod 

167 def _field_getter_function_name(register, register_array, field, from_value): 

168 result = "get" 

169 

170 if register_array: 

171 result += f"_{register_array.name}" 

172 

173 result += f"_{register.name}_{field.name}" 

174 

175 if from_value: 

176 result += "_from_value" 

177 

178 return result 

179 

180 def _field_getter_function_signature(self, register, register_array, field, from_value): 

181 function_name = self._field_getter_function_name( 

182 register=register, register_array=register_array, field=field, from_value=from_value 

183 ) 

184 result = f"{function_name}(" 

185 

186 if from_value: 

187 # Value is supplied by user 

188 result += "uint32_t register_value" 

189 elif register_array: 

190 # Value shall be read from bus, in which case we need to know array index if this 

191 # is an array 

192 result += "size_t array_index" 

193 

194 result += ")" 

195 

196 return result 

197 

198 @staticmethod 

199 def _get_shift_and_mask(field): 

200 cpp_code = f" const uint32_t shift = {field.base_index}uL;\n" 

201 cpp_code += f' const uint32_t mask_at_base = 0b{"1" * field.width}uL;\n' 

202 cpp_code += " const uint32_t mask_shifted = mask_at_base << shift;\n" 

203 return cpp_code 

204 

205 @staticmethod 

206 def _register_setter_function_name(register, register_array): 

207 result = "set" 

208 

209 if register_array: 

210 result += f"_{register_array.name}" 

211 

212 result += f"_{register.name}" 

213 

214 return result 

215 

216 def _register_setter_function_signature(self, register, register_array): 

217 function_name = self._register_setter_function_name( 

218 register=register, register_array=register_array 

219 ) 

220 result = f"{function_name}(" 

221 

222 if register_array: 

223 result += "size_t array_index, " 

224 

225 result += "uint32_t register_value)" 

226 

227 return result 

228 

229 @staticmethod 

230 def _field_setter_function_name(register, register_array, field, from_value): 

231 result = "set" 

232 

233 if register_array: 

234 result += f"_{register_array.name}" 

235 

236 result += f"_{register.name}_{field.name}" 

237 

238 if from_value: 

239 result += "_from_value" 

240 

241 return result 

242 

243 def _field_setter_function_signature(self, register, register_array, field, from_value): 

244 function_name = self._field_setter_function_name( 

245 register=register, register_array=register_array, field=field, from_value=from_value 

246 ) 

247 result = f"{function_name}(" 

248 

249 if from_value: 

250 # Current register value is supplied by user 

251 result += "uint32_t register_value, " 

252 elif register_array: 

253 # Current register value shall be read from bus, in which case we need to know array 

254 # index if this is an array 

255 result += "size_t array_index, " 

256 

257 result += f"{self._field_value_type_name()} field_value)" 

258 

259 return result 

260 

261 

262class InterfaceGenerator(CommonGenerator): 

263 """ 

264 Class to generate a C++ interface header. 

265 Do not use this directly, should use :class:`.RegisterCppGenerator`: 

266 """ 

267 

268 def get_interface(self, register_objects, constants): 

269 """ 

270 Get a complete C++ interface class header. See :meth:`.RegisterCppGenerator.get_interface` 

271 for more details. 

272 """ 

273 cpp_code = f"class I{self._class_name}\n" 

274 cpp_code += "{\n" 

275 cpp_code += "public:\n" 

276 

277 for constant in constants: 

278 cpp_code += self._comment("Register constant.", indentation=2) 

279 cpp_code += f" static const int {constant.name} = {constant.value}L;\n" 

280 if constants: 

281 cpp_code += "\n" 

282 

283 cpp_code += self._num_registers(register_objects) 

284 

285 for register_object in register_objects: 

286 if isinstance(register_object, RegisterArray): 

287 cpp_code += self._comment( 

288 f'Length of the "{register_object.name}" register array', indentation=2 

289 ) 

290 constant_name = self._array_length_constant_name(register_object) 

291 cpp_code += ( 

292 f" static const size_t {constant_name} = {register_object.length}uL;\n\n" 

293 ) 

294 

295 cpp_code += f" virtual ~I{self._class_name}() {{ }}\n" 

296 

297 for register, register_array in self._iterate_registers(register_objects): 

298 cpp_code += f"\n{self._get_separator_line(indentation=2)}" 

299 

300 description = self._get_methods_description( 

301 register=register, register_array=register_array 

302 ) 

303 description += f' Mode "{REGISTER_MODES[register.mode].mode_readable}".' 

304 

305 cpp_code += self._comment(comment=description, indentation=2) 

306 cpp_code += "\n" 

307 

308 if register.is_bus_readable: 

309 cpp_code += self._comment( 

310 "Getter that will read the whole register's value over the register bus.", 

311 indentation=2, 

312 ) 

313 signature = self._register_getter_function_signature( 

314 register=register, register_array=register_array 

315 ) 

316 cpp_code += f" virtual uint32_t {signature} const = 0;\n\n" 

317 

318 if register.is_bus_writeable: 

319 cpp_code += self._comment( 

320 "Setter that will write the whole register's value over the register bus.", 

321 indentation=2, 

322 ) 

323 signature = self._register_setter_function_signature( 

324 register=register, register_array=register_array 

325 ) 

326 cpp_code += f" virtual void {signature} const = 0;\n\n" 

327 

328 cpp_code += self._field_interface(register, register_array) 

329 

330 cpp_code += "};\n" 

331 

332 cpp_code_top = f"""\ 

333{self._file_header} 

334#pragma once 

335 

336#include <cassert> 

337#include <cstdint> 

338#include <cstdlib> 

339 

340""" 

341 return cpp_code_top + self._with_namespace(cpp_code) 

342 

343 def _num_registers(self, register_objects): 

344 # It is possible that we have constants but no registers 

345 num_registers = 0 

346 if register_objects: 

347 num_registers = register_objects[-1].index + 1 

348 

349 cpp_code = self._comment("Number of registers within this register map.", indentation=2) 

350 cpp_code += f" static const size_t num_registers = {num_registers}uL;\n\n" 

351 return cpp_code 

352 

353 def _field_interface(self, register, register_array): 

354 def function(return_type_name, signature): 

355 return f" virtual {return_type_name} {signature} const = 0;\n" 

356 

357 cpp_code = "" 

358 for field in register.fields: 

359 register_description = f'in the "{register.name}" register' 

360 if register_array is not None: 

361 register_description += f' within the "{register_array.name}" register array' 

362 

363 if register.is_bus_readable: 

364 comment = ( 

365 f'Getter for the "{field.name}" field {register_description},\n' 

366 "which will read register value over the register bus." 

367 ) 

368 

369 cpp_code += self._comment_block(text=comment, indentation=2) 

370 

371 signature = self._field_getter_function_signature( 

372 register=register, 

373 register_array=register_array, 

374 field=field, 

375 from_value=False, 

376 ) 

377 cpp_code += function( 

378 return_type_name=self._field_value_type_name(), signature=signature 

379 ) 

380 

381 comment = ( 

382 f'Getter for the "{field.name}" field {register_description},\n' 

383 "given the register's current value." 

384 ) 

385 cpp_code += self._comment_block(text=comment, indentation=2) 

386 

387 signature = self._field_getter_function_signature( 

388 register=register, 

389 register_array=register_array, 

390 field=field, 

391 from_value=True, 

392 ) 

393 cpp_code += function( 

394 return_type_name=self._field_value_type_name(), signature=signature 

395 ) 

396 

397 if register.is_bus_writeable: 

398 comment = f'Setter for the "{field.name}" field {register_description},\n' 

399 if register.mode == "r_w": 

400 comment += "which will read-modify-write over the register bus." 

401 elif register.mode in ["w", "wpulse", "r_wpulse"]: 

402 comment += ( 

403 "which will set the field to the given value, and all other bits to zero." 

404 ) 

405 else: 

406 raise ValueError(f"Can not handle this register's mode: {register}") 

407 

408 cpp_code += self._comment_block(text=comment, indentation=2) 

409 

410 signature = self._field_setter_function_signature( 

411 register=register, 

412 register_array=register_array, 

413 field=field, 

414 from_value=False, 

415 ) 

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

417 

418 comment = ( 

419 f'Setter for the "{field.name}" field {register_description},\n' 

420 "given the register's current value, which will return an updated value." 

421 ) 

422 cpp_code += self._comment_block(text=comment, indentation=2) 

423 

424 signature = self._field_setter_function_signature( 

425 register=register, 

426 register_array=register_array, 

427 field=field, 

428 from_value=True, 

429 ) 

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

431 

432 cpp_code += "\n" 

433 

434 return cpp_code 

435 

436 

437class HeaderGenerator(CommonGenerator): 

438 """ 

439 Class to generate a C++ header. 

440 Do not use this directly, should use :class:`.RegisterCppGenerator`: 

441 """ 

442 

443 def get_header(self, register_objects): 

444 """ 

445 Get a complete C++ class header for the implementation of all methods. 

446 See :meth:`.RegisterCppGenerator.get_header` for more details. 

447 """ 

448 cpp_code = f"class {self._class_name} : public I{self._class_name}\n" 

449 cpp_code += "{\n" 

450 

451 cpp_code += "private:\n" 

452 cpp_code += " volatile uint32_t *m_registers;\n\n" 

453 

454 cpp_code += "public:\n" 

455 cpp_code += f" {self._constructor_signature()};\n\n" 

456 cpp_code += f" virtual ~{self._class_name}() {{ }}\n" 

457 

458 def function(return_type_name, signature): 

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

460 

461 for register, register_array in self._iterate_registers(register_objects): 

462 cpp_code += f"\n{self._get_separator_line(indentation=2)}" 

463 

464 description = self._get_methods_description( 

465 register=register, register_array=register_array 

466 ) 

467 description += " See interface header for documentation." 

468 cpp_code += self._comment(comment=description, indentation=2) 

469 

470 if register.is_bus_readable: 

471 signature = self._register_getter_function_signature( 

472 register=register, 

473 register_array=register_array, 

474 ) 

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

476 

477 for field in register.fields: 

478 signature = self._field_getter_function_signature( 

479 register=register, 

480 register_array=register_array, 

481 field=field, 

482 from_value=False, 

483 ) 

484 cpp_code += function( 

485 return_type_name=self._field_value_type_name(), signature=signature 

486 ) 

487 

488 signature = self._field_getter_function_signature( 

489 register=register, 

490 register_array=register_array, 

491 field=field, 

492 from_value=True, 

493 ) 

494 cpp_code += function( 

495 return_type_name=self._field_value_type_name(), signature=signature 

496 ) 

497 

498 if register.is_bus_writeable: 

499 signature = self._register_setter_function_signature( 

500 register=register, register_array=register_array 

501 ) 

502 

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

504 

505 for field in register.fields: 

506 signature = self._field_setter_function_signature( 

507 register=register, 

508 register_array=register_array, 

509 field=field, 

510 from_value=False, 

511 ) 

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

513 

514 signature = self._field_setter_function_signature( 

515 register=register, 

516 register_array=register_array, 

517 field=field, 

518 from_value=True, 

519 ) 

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

521 

522 cpp_code += "};\n" 

523 

524 cpp_code_top = f"""\ 

525{self._file_header} 

526#pragma once 

527 

528#include "i_{self.module_name}.h" 

529 

530""" 

531 return cpp_code_top + self._with_namespace(cpp_code) 

532 

533 

534class ImplementationGenerator(CommonGenerator): 

535 """ 

536 Class to generate a C++ implementation. 

537 Do not use this directly, should use :class:`.RegisterCppGenerator`: 

538 """ 

539 

540 def get_implementation(self, register_objects): 

541 """ 

542 Get a complete C++ class implementation with all methods. 

543 See :meth:`.RegisterCppGenerator.get_implementation` for more details. 

544 """ 

545 cpp_code = f"{self._class_name}::{self._constructor_signature()}\n" 

546 cpp_code += " : m_registers(reinterpret_cast<volatile uint32_t *>(base_address))\n" 

547 cpp_code += "{\n" 

548 cpp_code += " // Empty\n" 

549 cpp_code += "}\n\n" 

550 

551 for register, register_array in self._iterate_registers(register_objects): 

552 cpp_code += f"\n{self._get_separator_line(indentation=0)}" 

553 

554 description = self._get_methods_description( 

555 register=register, register_array=register_array 

556 ) 

557 description += " See interface header for documentation.\n" 

558 cpp_code += self._comment(comment=description, indentation=0) 

559 

560 if register.is_bus_readable: 

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

562 

563 for field in register.fields: 

564 cpp_code += self._field_getter_function(register, register_array, field=field) 

565 cpp_code += self._field_getter_function_from_value( 

566 register, register_array, field=field 

567 ) 

568 

569 if register.is_bus_writeable: 

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

571 

572 for field in register.fields: 

573 cpp_code += self._field_setter_function(register, register_array, field=field) 

574 cpp_code += self._field_setter_function_from_value( 

575 register, register_array, field=field 

576 ) 

577 

578 cpp_code_top = f"{self._file_header}\n" 

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

580 

581 return cpp_code_top + self._with_namespace(cpp_code) 

582 

583 def _register_setter_function(self, register, register_array): 

584 signature = self._register_setter_function_signature( 

585 register=register, register_array=register_array 

586 ) 

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

588 cpp_code += "{\n" 

589 

590 if register_array: 

591 cpp_code += ( 

592 f" assert(array_index < {self._array_length_constant_name(register_array)});\n" 

593 ) 

594 cpp_code += ( 

595 f" const size_t index = {register_array.base_index} " 

596 f"+ array_index * {len(register_array.registers)} + {register.index};\n" 

597 ) 

598 else: 

599 cpp_code += f" const size_t index = {register.index};\n" 

600 

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

602 cpp_code += "}\n\n" 

603 return cpp_code 

604 

605 def _field_setter_function(self, register, register_array, field): 

606 signature = self._field_setter_function_signature( 

607 register=register, register_array=register_array, field=field, from_value=False 

608 ) 

609 

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

611 cpp_code += "{\n" 

612 

613 if register.mode == "r_w": 

614 register_getter_function_name = self._register_getter_function_name( 

615 register=register, register_array=register_array 

616 ) 

617 cpp_code += self._comment( 

618 "Get the current value of any other fields by reading register on the bus.", 

619 indentation=2, 

620 ) 

621 current_register_value = f"{register_getter_function_name}(" 

622 if register_array: 

623 current_register_value += "array_index" 

624 current_register_value += ")" 

625 elif register.mode in ["w", "wpulse", "r_wpulse"]: 

626 cpp_code += self._comment_block( 

627 "This register type's currently written value can not be read back.\n" 

628 "Hence set all other bits to zero when writing the value.", 

629 indentation=2, 

630 ) 

631 current_register_value = 0 

632 else: 

633 raise ValueError(f"Can not handle this register's mode: {register}") 

634 

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

636 

637 signature = self._field_setter_function_name( 

638 register=register, register_array=register_array, field=field, from_value=True 

639 ) 

640 cpp_code += ( 

641 " const uint32_t result_register_value = " 

642 f" {signature}(current_register_value, field_value);\n" 

643 ) 

644 

645 register_setter_function_name = self._register_setter_function_name( 

646 register=register, register_array=register_array 

647 ) 

648 cpp_code += f" {register_setter_function_name}(" 

649 if register_array: 

650 cpp_code += "array_index, " 

651 cpp_code += "result_register_value);\n" 

652 

653 cpp_code += "}\n\n" 

654 

655 return cpp_code 

656 

657 def _field_setter_function_from_value(self, register, register_array, field): 

658 signature = self._field_setter_function_signature( 

659 register=register, register_array=register_array, field=field, from_value=True 

660 ) 

661 

662 cpp_code = f"uint32_t {self._class_name}::{signature} const\n" 

663 cpp_code += "{\n" 

664 

665 cpp_code += self._get_shift_and_mask(field=field) 

666 cpp_code += "\n const uint32_t field_value_masked = field_value & mask_at_base;\n" 

667 cpp_code += ( 

668 " const uint32_t field_value_masked_and_shifted = field_value_masked << shift;\n\n" 

669 ) 

670 

671 cpp_code += " const uint32_t mask_shifted_inverse = ~mask_shifted;\n" 

672 cpp_code += ( 

673 " const uint32_t register_value_masked = register_value & mask_shifted_inverse;\n\n" 

674 ) 

675 

676 cpp_code += ( 

677 " const uint32_t result_register_value = " 

678 "register_value_masked | field_value_masked_and_shifted;\n\n" 

679 ) 

680 cpp_code += " return result_register_value;\n" 

681 

682 cpp_code += "}\n\n" 

683 

684 return cpp_code 

685 

686 def _register_getter_function(self, register, register_array): 

687 signature = self._register_getter_function_signature( 

688 register=register, register_array=register_array 

689 ) 

690 cpp_code = f"uint32_t {self._class_name}::{signature} const\n" 

691 cpp_code += "{\n" 

692 

693 if register_array: 

694 cpp_code += ( 

695 f" assert(array_index < {self._array_length_constant_name(register_array)});\n" 

696 ) 

697 cpp_code += ( 

698 f" const size_t index = {register_array.base_index} " 

699 f"+ array_index * {len(register_array.registers)} + {register.index};\n" 

700 ) 

701 else: 

702 cpp_code += f" const size_t index = {register.index};\n" 

703 

704 cpp_code += " const uint32_t result = m_registers[index];\n\n" 

705 cpp_code += " return result;\n" 

706 cpp_code += "}\n\n" 

707 return cpp_code 

708 

709 def _field_getter_function(self, register, register_array, field): 

710 signature = self._field_getter_function_signature( 

711 register=register, register_array=register_array, field=field, from_value=False 

712 ) 

713 

714 cpp_code = f"{self._field_value_type_name()} {self._class_name}::{signature} const\n" 

715 cpp_code += "{\n" 

716 

717 register_getter_function_name = self._register_getter_function_name( 

718 register=register, register_array=register_array 

719 ) 

720 

721 field_getter_from_value_function_name = self._field_getter_function_name( 

722 register=register, register_array=register_array, field=field, from_value=True 

723 ) 

724 

725 cpp_code += f" const uint32_t register_value = {register_getter_function_name}(" 

726 if register_array: 

727 cpp_code += "array_index" 

728 cpp_code += ");\n" 

729 

730 cpp_code += ( 

731 f" const uint32_t result = {field_getter_from_value_function_name}(register_value);\n" 

732 ) 

733 cpp_code += "\n return result;\n" 

734 cpp_code += "}\n\n" 

735 

736 return cpp_code 

737 

738 def _field_getter_function_from_value(self, register, register_array, field): 

739 signature = self._field_getter_function_signature( 

740 register=register, register_array=register_array, field=field, from_value=True 

741 ) 

742 

743 cpp_code = f"{self._field_value_type_name()} {self._class_name}::{signature} const\n" 

744 cpp_code += "{\n" 

745 

746 cpp_code += self._get_shift_and_mask(field=field) 

747 

748 cpp_code += "\n const uint32_t result_masked = register_value & mask_shifted;\n" 

749 cpp_code += " const uint32_t result_shifted = result_masked >> shift;\n" 

750 cpp_code += "\n return result_shifted;\n" 

751 cpp_code += "}\n\n" 

752 

753 return cpp_code