Coverage for hdl_registers/register_vhdl_generator.py: 100%

103 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 

10 

11from .register import Register 

12from .register_array import RegisterArray 

13from .register_code_generator import RegisterCodeGenerator 

14 

15 

16class RegisterVhdlGenerator(RegisterCodeGenerator): 

17 """ 

18 Generate a VHDL package with register information. 

19 """ 

20 

21 def __init__(self, module_name, generated_info): 

22 """ 

23 Arguments: 

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

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

26 """ 

27 self.module_name = module_name 

28 self.generated_info = generated_info 

29 

30 @staticmethod 

31 def _comment(comment, indentation=0): 

32 indent = " " * indentation 

33 return f"{indent}-- {comment}\n" 

34 

35 def _header(self): 

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

37 

38 def _register_name(self, register, register_array=None): 

39 if register_array is None: 

40 return f"{self.module_name}_{register.name}" 

41 return f"{self.module_name}_{register_array.name}_{register.name}" 

42 

43 def _register_function_signature(self, register, register_array): 

44 return ( 

45 "function " 

46 f"{self._register_name(register, register_array)}(array_index : natural) return natural" 

47 ) 

48 

49 def _register_indexes(self, register_objects): 

50 vhdl = "" 

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

52 if register_array is None: 

53 vhdl += ( 

54 f" constant {self._register_name(register)} : natural := {register.index};\n" 

55 ) 

56 else: 

57 vhdl += f" {self._register_function_signature(register, register_array)};\n" 

58 if vhdl: 

59 vhdl += "\n" 

60 

61 return vhdl 

62 

63 def _array_length_constant_name(self, register_array): 

64 return f"{self.module_name}_{register_array.name}_array_length" 

65 

66 def _array_constants(self, register_objects): 

67 vhdl = "" 

68 for register_object in register_objects: 

69 if isinstance(register_object, RegisterArray): 

70 constant = self._array_length_constant_name(register_object) 

71 vhdl += f" constant {constant} : natural := {register_object.length};\n" 

72 if vhdl: 

73 vhdl += "\n" 

74 

75 return vhdl 

76 

77 def _register_map(self, register_objects): 

78 if not register_objects: 

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

80 return "" 

81 

82 map_name = f"{self.module_name}_reg_map" 

83 range_name = f"{self.module_name}_reg_range" 

84 

85 last_index = register_objects[-1].index 

86 vhdl = f"""\ 

87 -- Declare register map constants here, but define them in body. 

88 -- This is done so that functions have been elaborated when they are called. 

89 subtype {range_name} is natural range 0 to {last_index}; 

90 constant {map_name} : reg_definition_vec_t({range_name}); 

91 

92 subtype {self.module_name}_regs_t is reg_vec_t({range_name}); 

93 constant {self.module_name}_regs_init : {self.module_name}_regs_t; 

94 

95 subtype {self.module_name}_reg_was_accessed_t is std_logic_vector({range_name}); 

96 

97""" 

98 

99 return vhdl 

100 

101 def _register_map_body(self, register_objects): 

102 if not register_objects: 

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

104 return "" 

105 

106 map_name = f"{self.module_name}_reg_map" 

107 range_name = f"{self.module_name}_reg_range" 

108 

109 register_definitions = [] 

110 default_values = [] 

111 vhdl_array_index = 0 

112 for register_object in register_objects: 

113 if isinstance(register_object, Register): 

114 idx = self._register_name(register_object) 

115 opening = f"{vhdl_array_index} => " 

116 

117 register_definitions.append( 

118 f"{opening}(idx => {idx}, reg_type => {register_object.mode})" 

119 ) 

120 default_values.append(f'{opening}"{register_object.default_value:032b}"') 

121 

122 vhdl_array_index = vhdl_array_index + 1 

123 else: 

124 for array_index in range(register_object.length): 

125 for register in register_object.registers: 

126 idx = f"{self._register_name(register, register_object)}({array_index})" 

127 opening = f"{vhdl_array_index} => " 

128 

129 register_definitions.append( 

130 f"{opening}(idx => {idx}, reg_type => {register.mode})" 

131 ) 

132 default_values.append(f'{opening}"{register.default_value:032b}"') 

133 

134 vhdl_array_index = vhdl_array_index + 1 

135 

136 array_element_separator = ",\n " 

137 vhdl = f"""\ 

138 constant {map_name} : reg_definition_vec_t({range_name}) := ( 

139 {array_element_separator.join(register_definitions)} 

140 ); 

141 

142 constant {self.module_name}_regs_init : {self.module_name}_regs_t := ( 

143 {array_element_separator.join(default_values)} 

144 ); 

145 

146""" 

147 

148 return vhdl 

149 

150 def _register_fields(self, register_objects): 

151 vhdl = "" 

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

153 for field in register.fields: 

154 name = f"{self._register_name(register, register_array)}_{field.name}" 

155 

156 if field.width == 1: 

157 vhdl += f" constant {name} : natural := {field.base_index};\n" 

158 else: 

159 vhdl += f"""\ 

160 subtype {name} is natural range {field.width + field.base_index - 1} downto {field.base_index}; 

161 constant {name}_width : positive := {field.width}; 

162 subtype {name}_t is {field.field_type.vhdl_typedef(bit_width=field.width)}; 

163""" 

164 

165 if register.fields: 

166 vhdl += "\n" 

167 

168 return vhdl 

169 

170 def _array_index_functions(self, register_objects): 

171 vhdl = "" 

172 for register_object in register_objects: 

173 if isinstance(register_object, RegisterArray): 

174 num_registers = len(register_object.registers) 

175 array_length = self._array_length_constant_name(register_object) 

176 for register in register_object.registers: 

177 vhdl += f"""\ 

178 {self._register_function_signature(register, register_object)} is 

179 begin 

180 assert array_index < {array_length} 

181 report "Array index out of bounds: " & natural'image(array_index) 

182 severity failure; 

183 return {register_object.base_index} + array_index * {num_registers} + {register.index}; 

184 end function; 

185 

186""" 

187 

188 return vhdl 

189 

190 def _constants(self, constants): 

191 vhdl = "" 

192 for constant in constants: 

193 vhdl += ( 

194 " constant " 

195 f"{self.module_name}_constant_{constant.name} : integer := {constant.value};\n" 

196 ) 

197 if vhdl: 

198 vhdl += "\n" 

199 

200 return vhdl 

201 

202 def get_package(self, register_objects, constants): 

203 """ 

204 Get a complete VHDL package with register and constant infomation. 

205 

206 Arguments: 

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

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

209 

210 Returns: 

211 str: VHDL code. 

212 """ 

213 pkg_name = f"{self.module_name}_regs_pkg" 

214 

215 vhdl = f"""\ 

216{self._header()} 

217library ieee; 

218use ieee.std_logic_1164.all; 

219use ieee.numeric_std.all; 

220use ieee.fixed_pkg.all; 

221 

222library reg_file; 

223use reg_file.reg_file_pkg.all; 

224 

225 

226package {pkg_name} is 

227 

228{self._register_indexes(register_objects)}\ 

229{self._array_constants(register_objects)}\ 

230{self._register_map(register_objects)}\ 

231{self._register_fields(register_objects)}\ 

232{self._constants(constants)}\ 

233end package; 

234 

235package body {pkg_name} is 

236 

237{self._array_index_functions(register_objects)}\ 

238{self._register_map_body(register_objects)}\ 

239end package body; 

240""" 

241 

242 return vhdl