Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

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

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

3# 

4# This file is part of the tsfpga project. 

5# https://tsfpga.com 

6# https://gitlab.com/tsfpga/tsfpga 

7# -------------------------------------------------------------------------------------------------- 

8 

9from .register import Register, REGISTER_MODES 

10from .register_code_generator import RegisterCodeGenerator 

11 

12 

13class RegisterCGenerator(RegisterCodeGenerator): 

14 """ 

15 Generate a C code header with register information. 

16 

17 There is no unit test of this class that checks the generated code. It is instead functionally 

18 tested in the file test_register_compilation.py. That test generates C code from an example 

19 register set, compiles it and performs some run-time assertions in a C program. 

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

21 """ 

22 

23 def __init__(self, module_name, generated_info): 

24 self.module_name = module_name 

25 self.generated_info = generated_info 

26 

27 def get_header(self, register_objects, constants): 

28 define_name = self.module_name.upper() + "_REGS_H" 

29 

30 c_code = f"""\ 

31{self._file_header()} 

32#ifndef {define_name} 

33#define {define_name} 

34 

35{self._constants(constants)} 

36{self._number_of_registers(register_objects)} 

37{self._register_struct(register_objects)} 

38{self._register_defines(register_objects)}\ 

39#endif {self._comment(define_name)}""" 

40 

41 return c_code 

42 

43 @staticmethod 

44 def _comment(comment, indentation=0): 

45 indent = " " * indentation 

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

47 

48 def _file_header(self): 

49 return "".join([self._comment(header_line) for header_line in self.generated_info]) 

50 

51 def _register_struct(self, register_objects): 

52 array_structs = "" 

53 

54 register_struct_type = f"{self.module_name}_regs_t" 

55 register_struct = self._comment("Type for this register map.") 

56 register_struct += f"typedef struct {register_struct_type}\n" 

57 register_struct += "{\n" 

58 for register_object in register_objects: 

59 if isinstance(register_object, Register): 

60 register_struct += self._comment_block(register_object.description, indentation=2) 

61 register_struct += self._comment( 

62 f'Mode "{REGISTER_MODES[register_object.mode].mode_readable}".', indentation=2 

63 ) 

64 register_struct += f" uint32_t {register_object.name};\n" 

65 

66 else: 

67 array_struct_type = f"{self.module_name}_{register_object.name}_t" 

68 

69 array_structs += self._comment( 

70 f'Type for the "{register_object.name}" register array.' 

71 ) 

72 array_structs += f"typedef struct {array_struct_type}\n" 

73 array_structs += "{\n" 

74 for register in register_object.registers: 

75 array_structs += self._comment_block(register.description, indentation=2) 

76 array_structs += self._comment( 

77 f'Mode "{REGISTER_MODES[register.mode].mode_readable}".', indentation=2 

78 ) 

79 array_structs += f" uint32_t {register.name};\n" 

80 array_structs += f"}} {array_struct_type};\n\n" 

81 

82 register_struct += ( 

83 f" {array_struct_type} {register_object.name}[{register_object.length}];\n" 

84 ) 

85 register_struct += f"}} {register_struct_type};\n" 

86 return array_structs + register_struct 

87 

88 def _number_of_registers(self, register_objects): 

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

90 num_regs = 0 

91 if register_objects: 

92 num_regs = register_objects[-1].index + 1 

93 

94 c_code = self._comment("Number of registers within this register map.") 

95 c_code += f"#define {self.module_name.upper()}_NUM_REGS ({num_regs}u)\n" 

96 

97 return c_code 

98 

99 def _register_defines(self, register_objects): 

100 c_code = "" 

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

102 c_code += self._addr_define(register, register_array) 

103 c_code += self._field_definitions(register, register_array) 

104 c_code += "\n" 

105 

106 return c_code 

107 

108 def _addr_define(self, register, register_array): 

109 name = self._register_define_name(register, register_array) 

110 mode_string = f'Mode "{REGISTER_MODES[register.mode].mode_readable}".' 

111 

112 if register_array is None: 

113 c_code = self._comment(f'Address of the "{register.name}" register. {mode_string}') 

114 c_code += self._comment_block(register.description) 

115 

116 c_code += f"#define {name}_INDEX ({register.index}u)\n" 

117 c_code += f"#define {name}_ADDR (4u * {name}_INDEX)\n" 

118 else: 

119 title = ( 

120 f'Address of the "{register.name}" register within the "{register_array.name}"' 

121 f" register array (array_index < {register_array.length}). {mode_string}" 

122 ) 

123 c_code = self._comment(title) 

124 c_code += self._comment_block(register.description) 

125 

126 c_code += ( 

127 f"#define {name}_INDEX(array_index) ({register_array.base_index}u + " 

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

129 ) 

130 c_code += f"#define {name}_ADDR(array_index) (4u * {name}_INDEX(array_index))\n" 

131 

132 return c_code 

133 

134 def _field_definitions(self, register, register_array): 

135 register_name = self._register_define_name(register, register_array) 

136 register_string = f'"{register.name}" register' 

137 if register_array is not None: 

138 register_string += f' within the "{register_array.name}" register array' 

139 

140 c_code = "" 

141 for field in register.fields: 

142 c_code += self._comment( 

143 f'Mask and shift for the "{field.name}" field in the {register_string}.' 

144 ) 

145 c_code += self._comment_block(field.description) 

146 

147 field_name = f"{register_name}_{field.name.upper()}" 

148 c_code += f"#define {field_name}_SHIFT ({field.base_index}u)\n" 

149 c_code += ( 

150 f"#define {field_name}_MASK " f'(0b{"1" * field.width}u << {field.base_index}u)\n' 

151 ) 

152 

153 return c_code 

154 

155 def _register_define_name(self, register, register_array): 

156 if register_array is None: 

157 name = f"{self.module_name}_{register.name}" 

158 else: 

159 name = f"{self.module_name}_{register_array.name}_{register.name}" 

160 return name.upper() 

161 

162 def _constants(self, constants): 

163 c_code = "" 

164 for constant in constants: 

165 c_code += self._comment(f'Register constant "{constant.name}".') 

166 c_code += self._comment_block(constant.description) 

167 c_code += ( 

168 f"#define {self.module_name.upper()}_{constant.name.upper()} ({constant.value})\n" 

169 ) 

170 return c_code